@ftptech/canton-agent-wallet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +134 -0
- package/dist/canton-hash.d.ts +61 -0
- package/dist/canton-hash.d.ts.map +1 -0
- package/dist/canton-hash.js +108 -0
- package/dist/canton-hash.js.map +1 -0
- package/dist/cli-args.d.ts +31 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +56 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +123 -0
- package/dist/cli.js.map +1 -0
- package/dist/hash-binding.d.ts +40 -0
- package/dist/hash-binding.d.ts.map +1 -0
- package/dist/hash-binding.js +20 -0
- package/dist/hash-binding.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +26 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +38 -0
- package/dist/keys.js.map +1 -0
- package/dist/onboard.d.ts +12 -0
- package/dist/onboard.d.ts.map +1 -0
- package/dist/onboard.js +152 -0
- package/dist/onboard.js.map +1 -0
- package/dist/pay.d.ts +16 -0
- package/dist/pay.d.ts.map +1 -0
- package/dist/pay.js +19 -0
- package/dist/pay.js.map +1 -0
- package/dist/relay-client.d.ts +128 -0
- package/dist/relay-client.d.ts.map +1 -0
- package/dist/relay-client.js +67 -0
- package/dist/relay-client.js.map +1 -0
- package/dist/relay-signer.d.ts +33 -0
- package/dist/relay-signer.d.ts.map +1 -0
- package/dist/relay-signer.js +44 -0
- package/dist/relay-signer.js.map +1 -0
- package/dist/store.d.ts +15 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +33 -0
- package/dist/store.js.map +1 -0
- package/dist/trusted-dso.d.ts +33 -0
- package/dist/trusted-dso.d.ts.map +1 -0
- package/dist/trusted-dso.js +36 -0
- package/dist/trusted-dso.js.map +1 -0
- package/dist/tx.d.ts +102 -0
- package/dist/tx.d.ts.map +1 -0
- package/dist/tx.js +328 -0
- package/dist/tx.js.map +1 -0
- package/dist/verify-prepared.d.ts +361 -0
- package/dist/verify-prepared.d.ts.map +1 -0
- package/dist/verify-prepared.js +2235 -0
- package/dist/verify-prepared.js.map +1 -0
- package/dist/withdraw.d.ts +18 -0
- package/dist/withdraw.d.ts.map +1 -0
- package/dist/withdraw.js +31 -0
- package/dist/withdraw.js.map +1 -0
- package/package.json +33 -0
package/dist/tx.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transfer primitives for the agent's self-custody wallet, all routed through
|
|
3
|
+
* the relay: resolve the factory / accept context (the agent has no Scan
|
|
4
|
+
* access), build the choice, sign the prepared-tx hash LOCALLY with the agent's
|
|
5
|
+
* key, execute via the relay. The relay only prepares + forwards; it can never
|
|
6
|
+
* sign, so it can never move the agent's funds.
|
|
7
|
+
*/
|
|
8
|
+
import { signHashB64 } from "./keys.js";
|
|
9
|
+
import { resolveHashBinding } from "./hash-binding.js";
|
|
10
|
+
import { assertHashBinding, assertPreparedTransferMatches, assertPreparedCreateTransferCommandMatches, assertPreparedAcceptMatches, } from "./verify-prepared.js";
|
|
11
|
+
const TI_IFACE = "#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferInstruction";
|
|
12
|
+
/**
|
|
13
|
+
* The instrument id the agent's self-custody wallet pays in: Canton Coin is the
|
|
14
|
+
* Splice "Amulet" instrument. This is CALLER INTENT — a fixed value the agent
|
|
15
|
+
* knows independently of the relay — so it can be used as a trust anchor when
|
|
16
|
+
* verifying the relay-prepared transfer. We deliberately do NOT anchor on the
|
|
17
|
+
* relay-resolved instrument ADMIN (the DSO party), because trusting a
|
|
18
|
+
* relay-supplied party as a whitelist is exactly the trust-boundary inversion a
|
|
19
|
+
* compromised relay would exploit. The recipient is pinned to caller intent and
|
|
20
|
+
* the instrument id to this constant; the admin is validated only positionally.
|
|
21
|
+
*/
|
|
22
|
+
const EXPECTED_INSTRUMENT_ID = "Amulet";
|
|
23
|
+
function rid(prefix) {
|
|
24
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* prepare (relay) → VERIFY → sign hash (local key) → execute (relay) → updateId.
|
|
28
|
+
*
|
|
29
|
+
* When `verify` is supplied (any command that MOVES the agent's funds), the
|
|
30
|
+
* EXACT `preparedTransaction` bytes that will be submitted to `execute` are
|
|
31
|
+
* structurally decoded and checked to encode exactly the intended
|
|
32
|
+
* sender/receiver/amount/(instrument|delegate) BEFORE the agent signs its hash,
|
|
33
|
+
* and the hash is bound to those same bytes. This is the self-custody guarantee:
|
|
34
|
+
* a compromised relay cannot get the agent to sign a command it did not author —
|
|
35
|
+
* any tamper either fails structural validation here, or (since the participant
|
|
36
|
+
* recomputes the hash from the submitted bytes on execute) produces a signature
|
|
37
|
+
* that the participant rejects. We fail closed: if validation or hash binding
|
|
38
|
+
* does not pass, we never sign. See `verify-prepared.ts`.
|
|
39
|
+
*
|
|
40
|
+
* SECURITY: `verify` is REQUIRED for EVERY path — no caller can reach
|
|
41
|
+
* `signHashB64` without a structural gate. The claim path (accepting incoming
|
|
42
|
+
* transfers) is NOT exempt: it passes `kind: "accept"`, which structurally
|
|
43
|
+
* proves the prepared transaction is a single `TransferInstruction_Accept`
|
|
44
|
+
* submitted by the agent and NOT a relay-injected outbound drain. `hashBinding`
|
|
45
|
+
* is likewise threaded on every path and enforced fail-closed.
|
|
46
|
+
*/
|
|
47
|
+
async function prepareSignExecute(relay, wallet, commands, disclosedContracts, verify, hashBinding,
|
|
48
|
+
/** Caller-intent synchronizer id to PREPARE on. When supplied we send it in
|
|
49
|
+
* the prepare body so the relay cannot silently fill its own — and the verify
|
|
50
|
+
* arm pins the SIGNED Metadata.synchronizer_id to it. Omitted for the claim
|
|
51
|
+
* (funds-in) path, whose accept carries no caller-intent domain. */
|
|
52
|
+
synchronizerId) {
|
|
53
|
+
const prep = await relay.submitPrepare({
|
|
54
|
+
userId: "agent", // relay overrides with the participant (m2m) user
|
|
55
|
+
commandId: rid("agent"),
|
|
56
|
+
actAs: [wallet.party],
|
|
57
|
+
commands,
|
|
58
|
+
disclosedContracts,
|
|
59
|
+
packageIdSelectionPreference: [],
|
|
60
|
+
verboseHashing: false,
|
|
61
|
+
// Pin the synchronizer to caller intent so the relay cannot prepare on (and
|
|
62
|
+
// sign the agent onto) a domain of its choosing. The verify arm additionally
|
|
63
|
+
// asserts the SIGNED Metadata.synchronizer_id equals this.
|
|
64
|
+
...(synchronizerId !== undefined ? { synchronizerId } : {}),
|
|
65
|
+
});
|
|
66
|
+
// Bind to the EXACT bytes we will submit (single source `prep`, no TOCTOU).
|
|
67
|
+
const preparedTransaction = prep.preparedTransaction;
|
|
68
|
+
// VERIFY-BEFORE-SIGN: never sign a relay-prepared command we didn't author.
|
|
69
|
+
// `verify` is required on EVERY path (transfer/createTransferCommand/accept),
|
|
70
|
+
// so there is no branch that reaches signHashB64 ungated.
|
|
71
|
+
if (verify.kind === "cip56") {
|
|
72
|
+
assertPreparedTransferMatches(preparedTransaction, verify.expect);
|
|
73
|
+
}
|
|
74
|
+
else if (verify.kind === "v1") {
|
|
75
|
+
assertPreparedCreateTransferCommandMatches(preparedTransaction, verify.expect);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// claim path: structurally prove the prepared tx is a single inbound
|
|
79
|
+
// TransferInstruction_Accept by the agent, not an outbound drain.
|
|
80
|
+
assertPreparedAcceptMatches(preparedTransaction, verify.expect);
|
|
81
|
+
}
|
|
82
|
+
// Hash binding: prove the hash we are about to sign is the hash OF THE BYTES
|
|
83
|
+
// we just validated, not an opaque relay-chosen value. Without this a
|
|
84
|
+
// compromised relay can return honest bytes + the hash of a tampered tx and
|
|
85
|
+
// swap the bytes on the way to the participant. Fail closed: if the binding
|
|
86
|
+
// cannot be established (no recompute available and no explicit opt-in to
|
|
87
|
+
// trust the relay hash) we never sign. See verify-prepared.ts.
|
|
88
|
+
await assertHashBinding(preparedTransaction, prep.hash, hashBinding ?? {});
|
|
89
|
+
const signature = signHashB64(prep.hash, wallet.privateKeyPkcs8Pem);
|
|
90
|
+
const exec = await relay.submitExecute({
|
|
91
|
+
submissionId: rid("agent-exec"),
|
|
92
|
+
preparedTransaction,
|
|
93
|
+
hashingSchemeVersion: "HASHING_SCHEME_VERSION_V2",
|
|
94
|
+
partySignatures: {
|
|
95
|
+
signatures: [
|
|
96
|
+
{
|
|
97
|
+
party: wallet.party,
|
|
98
|
+
signatures: [
|
|
99
|
+
{
|
|
100
|
+
format: "SIGNATURE_FORMAT_CONCAT",
|
|
101
|
+
signature,
|
|
102
|
+
signingAlgorithmSpec: "SIGNING_ALGORITHM_SPEC_ED25519",
|
|
103
|
+
signedBy: wallet.publicKeyFingerprint,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
deduplicationPeriod: { Empty: {} },
|
|
110
|
+
});
|
|
111
|
+
return exec.updateId;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Send CC from the agent to `receiver`. Returns the ledger updateId.
|
|
115
|
+
*
|
|
116
|
+
* `opts.expectInstrumentId` overrides the asset the verifier pins the prepared
|
|
117
|
+
* transfer to (defaults to Canton Coin / "Amulet"). It is CALLER INTENT, never
|
|
118
|
+
* taken from the relay.
|
|
119
|
+
*/
|
|
120
|
+
export async function transfer(relay, wallet, opts) {
|
|
121
|
+
const bal = await relay.balance(wallet.party);
|
|
122
|
+
const inputHoldingCids = bal.holdings.map((h) => h.cid);
|
|
123
|
+
const f = await relay.resolveTransferFactory({
|
|
124
|
+
sender: wallet.party,
|
|
125
|
+
receiver: opts.receiver,
|
|
126
|
+
amount: opts.amount,
|
|
127
|
+
...(opts.meta ? { meta: opts.meta } : {}),
|
|
128
|
+
});
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
const ex = {
|
|
131
|
+
ExerciseCommand: {
|
|
132
|
+
templateId: f.transferFactoryTemplateId,
|
|
133
|
+
contractId: f.factoryId,
|
|
134
|
+
choice: "TransferFactory_Transfer",
|
|
135
|
+
choiceArgument: {
|
|
136
|
+
expectedAdmin: f.instrumentId.admin,
|
|
137
|
+
transfer: {
|
|
138
|
+
sender: wallet.party,
|
|
139
|
+
receiver: opts.receiver,
|
|
140
|
+
amount: opts.amount,
|
|
141
|
+
instrumentId: f.instrumentId,
|
|
142
|
+
requestedAt: new Date(now - 2000).toISOString(),
|
|
143
|
+
executeBefore: new Date(now + 600_000).toISOString(),
|
|
144
|
+
inputHoldingCids,
|
|
145
|
+
meta: { values: opts.meta ?? {} },
|
|
146
|
+
},
|
|
147
|
+
extraArgs: { context: f.choiceContextData, meta: { values: {} } },
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
return prepareSignExecute(relay, wallet, [ex], f.disclosedContracts, {
|
|
152
|
+
kind: "cip56",
|
|
153
|
+
expect: {
|
|
154
|
+
// Trust anchors are CALLER INTENT only — never the relay's resolve response:
|
|
155
|
+
sender: wallet.party,
|
|
156
|
+
receiver: opts.receiver,
|
|
157
|
+
amount: opts.amount,
|
|
158
|
+
instrumentId: opts.expectInstrumentId ?? EXPECTED_INSTRUMENT_ID,
|
|
159
|
+
// Pin the exercise's target to the SAME factory cid we built the command
|
|
160
|
+
// against, so a relay cannot resolve one factory to us then prepare the
|
|
161
|
+
// exercise against another (resolve→prepare TOCTOU). Defense-in-depth on
|
|
162
|
+
// top of the all-nodes party backstop.
|
|
163
|
+
expectedContractId: f.factoryId,
|
|
164
|
+
// Optional caller-intent pins (off by default — the agent has no out-of-
|
|
165
|
+
// band DSO/domain in the base CC flow): the SIGNED synchronizer_id and
|
|
166
|
+
// the instrument admin (DSO). When supplied they close the relay-chosen-
|
|
167
|
+
// domain and unpinned-admin neutralization fully; always sanity-bound the
|
|
168
|
+
// SIGNED timing metadata via nowMs.
|
|
169
|
+
...(opts.expectSynchronizerId !== undefined
|
|
170
|
+
? { synchronizerId: opts.expectSynchronizerId }
|
|
171
|
+
: {}),
|
|
172
|
+
...(opts.expectInstrumentAdmin !== undefined
|
|
173
|
+
? { instrumentAdmin: opts.expectInstrumentAdmin }
|
|
174
|
+
: {}),
|
|
175
|
+
nowMs: Date.now(),
|
|
176
|
+
},
|
|
177
|
+
}, opts.hashBinding, opts.expectSynchronizerId);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* v1 (external-party-amulet-rules) — create a Splice `TransferCommand` the
|
|
181
|
+
* facilitator will later settle (it pays the GS traffic fee). The agent signs
|
|
182
|
+
* only an INTENT here: no gas, no preapproval. Mirrors the cip56 `transfer`
|
|
183
|
+
* flow — resolve refs via relay → build the create exercise → VERIFY-before-sign
|
|
184
|
+
* over the EXACT prepared bytes → sign locally → execute via relay → read back
|
|
185
|
+
* the created cid (ACS-polled by the relay) — but produces the v1 payload the
|
|
186
|
+
* x402 client puts in PaymentPayload: `{transferCommandCid, payerParty, nonce}`.
|
|
187
|
+
*
|
|
188
|
+
* SECURITY: every money-critical field the verifier pins (sender == own party,
|
|
189
|
+
* receiver == merchant payTo, amount == required, delegate == facilitatorParty)
|
|
190
|
+
* is CALLER INTENT passed in `opts`, NOT taken from the relay's resolve
|
|
191
|
+
* response. The relay-resolved EPAR/exercise templateIds + expectedDso are used
|
|
192
|
+
* only to BUILD the exercise; they widen nothing the agent will sign. The cid
|
|
193
|
+
* returned by the relay moves no funds on its own — the facilitator independently
|
|
194
|
+
* re-validates sender/receiver/amount/delegate/nonce at /verify + /settle.
|
|
195
|
+
*/
|
|
196
|
+
export async function createTransferCommand(relay, wallet, opts) {
|
|
197
|
+
// Resolve the v1 ledger refs (EPAR disclosed + exercise templateId +
|
|
198
|
+
// expectedDso + the agent's next nonce). NONE of these is a verify trust
|
|
199
|
+
// anchor — the verifier pins sender/receiver/amount/delegate to caller intent.
|
|
200
|
+
const r = await relay.resolveTransferCommand({ payerParty: wallet.party });
|
|
201
|
+
// The agent pins the DELEGATE to its OWN intent (the 402's facilitatorParty),
|
|
202
|
+
// not the relay's `r.delegate`. If the relay disagrees with caller intent,
|
|
203
|
+
// fail fast BEFORE building/prepare rather than silently using the relay's.
|
|
204
|
+
if (r.delegate !== opts.delegate) {
|
|
205
|
+
throw new Error(`relay resolve/transfer-command returned delegate ${JSON.stringify(r.delegate)} ` +
|
|
206
|
+
`but caller intent (extra.facilitatorParty) is ${JSON.stringify(opts.delegate)} — ` +
|
|
207
|
+
`refusing to build a TransferCommand with a relay-chosen delegate`);
|
|
208
|
+
}
|
|
209
|
+
// Likewise pin the synchronizer to caller intent.
|
|
210
|
+
if (r.synchronizerId !== opts.synchronizerId) {
|
|
211
|
+
throw new Error(`relay resolve/transfer-command returned synchronizerId ${JSON.stringify(r.synchronizerId)} ` +
|
|
212
|
+
`but caller intent (extra.synchronizerId) is ${JSON.stringify(opts.synchronizerId)} — ` +
|
|
213
|
+
`refusing to prepare on a relay-chosen synchronizer`);
|
|
214
|
+
}
|
|
215
|
+
const nonceStr = r.nextNonce;
|
|
216
|
+
const expiresAtMs = opts.expiresAtMs ?? Date.now() + 60_000;
|
|
217
|
+
const expiresAt = new Date(expiresAtMs).toISOString();
|
|
218
|
+
// Build the CreateTransferCommand exercise. Choice argument shape + the
|
|
219
|
+
// EPAR-only disclosure mirror the PROVEN KeyfileSigner v1 flow exactly. The
|
|
220
|
+
// exercise targets the resolved current-package templateId; the disclosed
|
|
221
|
+
// contract carries the EPAR's OWN templateId (must match its blob's package).
|
|
222
|
+
const ex = {
|
|
223
|
+
ExerciseCommand: {
|
|
224
|
+
templateId: r.exerciseTemplateId,
|
|
225
|
+
contractId: r.externalPartyAmuletRules.contractId,
|
|
226
|
+
choice: "ExternalPartyAmuletRules_CreateTransferCommand",
|
|
227
|
+
choiceArgument: {
|
|
228
|
+
sender: wallet.party,
|
|
229
|
+
receiver: opts.receiver,
|
|
230
|
+
delegate: opts.delegate,
|
|
231
|
+
amount: opts.amount,
|
|
232
|
+
expiresAt,
|
|
233
|
+
nonce: nonceStr,
|
|
234
|
+
description: opts.description,
|
|
235
|
+
expectedDso: r.expectedDso,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
const disclosedContracts = [
|
|
240
|
+
{
|
|
241
|
+
templateId: r.externalPartyAmuletRules.templateId,
|
|
242
|
+
contractId: r.externalPartyAmuletRules.contractId,
|
|
243
|
+
createdEventBlob: r.externalPartyAmuletRules.createdEventBlob,
|
|
244
|
+
synchronizerId: opts.synchronizerId,
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
// prepare → VERIFY-before-sign (v1 arm) → sign locally → execute. The verifier
|
|
248
|
+
// asserts the EXACT prepared bytes encode sender==own, receiver==payTo,
|
|
249
|
+
// amount==required, delegate==facilitator, nonce==expected; fail-closed.
|
|
250
|
+
const createUpdateId = await prepareSignExecute(relay, wallet, [ex], disclosedContracts, {
|
|
251
|
+
kind: "v1",
|
|
252
|
+
expect: {
|
|
253
|
+
sender: wallet.party,
|
|
254
|
+
receiver: opts.receiver,
|
|
255
|
+
amount: opts.amount,
|
|
256
|
+
delegate: opts.delegate,
|
|
257
|
+
nonce: nonceStr,
|
|
258
|
+
// Pin the exercise target to the SAME EPAR cid we built against (the one
|
|
259
|
+
// the relay resolved), so a relay cannot resolve one EPAR to us then
|
|
260
|
+
// prepare against another (resolve→prepare TOCTOU). Defense-in-depth on
|
|
261
|
+
// top of the all-nodes party backstop.
|
|
262
|
+
expectedContractId: r.externalPartyAmuletRules.contractId,
|
|
263
|
+
// Pin the SIGNED Metadata.synchronizer_id to caller intent (the merchant-
|
|
264
|
+
// advertised domain). The relay PREPAREs with the synchronizer it chooses
|
|
265
|
+
// and embeds it into the signed Metadata; without this pin the agent would
|
|
266
|
+
// blind-sign a relay-chosen domain even though the v1 resolve-response
|
|
267
|
+
// synchronizer was cross-checked (a claim-vs-signed-bytes divergence).
|
|
268
|
+
synchronizerId: opts.synchronizerId,
|
|
269
|
+
// Optional out-of-band DSO pin (off by default; never the relay's value).
|
|
270
|
+
...(opts.expectedDso !== undefined ? { expectedDso: opts.expectedDso } : {}),
|
|
271
|
+
nowMs: Date.now(),
|
|
272
|
+
},
|
|
273
|
+
}, opts.hashBinding, opts.synchronizerId);
|
|
274
|
+
// interactive execute is ASYNC — the create commits after execute returns. The
|
|
275
|
+
// agent is relay-only (no ledger/ACS access), so the relay ACS-polls the
|
|
276
|
+
// payer's TransferCommand at this (sender, nonce) and returns the cid. The cid
|
|
277
|
+
// alone moves no funds; the facilitator re-validates every field at settle.
|
|
278
|
+
const cidRes = await relay.transferCommandCid(wallet.party, nonceStr);
|
|
279
|
+
// Nonce as a number for the x402 v1 payload (CantonPaymentPayload.nonce: number).
|
|
280
|
+
// Counters in practice stay well within Number.MAX_SAFE_INTEGER.
|
|
281
|
+
return {
|
|
282
|
+
transferCommandCid: cidRes.transferCommandCid,
|
|
283
|
+
payerParty: wallet.party,
|
|
284
|
+
nonce: Number(nonceStr),
|
|
285
|
+
// The CreateTransferCommand execute updateId (burn #1, submitted via OUR
|
|
286
|
+
// node). Surfaced into the x402 v1 payload so the facilitator /settle links
|
|
287
|
+
// it to the Send burn (#2) for the Create+Send traffic attribution (PR #22).
|
|
288
|
+
createUpdateId,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Accept every pending incoming transfer (e.g. the agent's initial funding).
|
|
293
|
+
*
|
|
294
|
+
* SECURITY: even though this path is funds-IN, it is NOT exempt from
|
|
295
|
+
* verify-before-sign. A malicious relay returning an OUTBOUND drain
|
|
296
|
+
* (CreateTransferCommand / TransferFactory_Transfer sending the agent's balance
|
|
297
|
+
* to an attacker) instead of the accept the agent built would otherwise be
|
|
298
|
+
* blind-signed. We pass `kind: "accept"`, which structurally proves the prepared
|
|
299
|
+
* transaction is a single `TransferInstruction_Accept` submitted by the agent —
|
|
300
|
+
* any outbound leg is rejected — and we bind the signed hash to those bytes
|
|
301
|
+
* (fail-closed by default, exactly like the other paths). `opts.hashBinding`
|
|
302
|
+
* lets a programmatic caller supply a participant-conformant recompute; the CLI
|
|
303
|
+
* resolves it from the environment (default fail-closed).
|
|
304
|
+
*/
|
|
305
|
+
export async function claimAll(relay, wallet, opts = {}) {
|
|
306
|
+
const hashBinding = opts.hashBinding ?? resolveHashBinding();
|
|
307
|
+
const { pending } = await relay.pending(wallet.party);
|
|
308
|
+
const updateIds = [];
|
|
309
|
+
for (const p of pending) {
|
|
310
|
+
const ctx = await relay.resolveAccept({ instructionCid: p.cid });
|
|
311
|
+
const ex = {
|
|
312
|
+
ExerciseCommand: {
|
|
313
|
+
templateId: TI_IFACE,
|
|
314
|
+
contractId: p.cid,
|
|
315
|
+
choice: "TransferInstruction_Accept",
|
|
316
|
+
choiceArgument: {
|
|
317
|
+
extraArgs: { context: ctx.choiceContextData, meta: { values: {} } },
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
updateIds.push(await prepareSignExecute(relay, wallet, [ex], ctx.disclosedContracts,
|
|
322
|
+
// VERIFY-before-sign: the prepared tx MUST be a single inbound accept by
|
|
323
|
+
// the agent — never a relay-injected outbound drain.
|
|
324
|
+
{ kind: "accept", expect: { selfParty: wallet.party, nowMs: Date.now() } }, hashBinding));
|
|
325
|
+
}
|
|
326
|
+
return { claimed: pending.length, updateIds };
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=tx.js.map
|
package/dist/tx.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tx.js","sourceRoot":"","sources":["../src/tx.ts"],"names":[],"mappings":"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"}
|