@ftptech/canton-agent-wallet 2.1.0 → 2.3.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.
Files changed (54) hide show
  1. package/README.md +53 -15
  2. package/dist/cli-args.d.ts +27 -0
  3. package/dist/cli-args.d.ts.map +1 -1
  4. package/dist/cli-args.js +74 -0
  5. package/dist/cli-args.js.map +1 -1
  6. package/dist/cli.js +139 -34
  7. package/dist/cli.js.map +1 -1
  8. package/dist/merge.d.ts +21 -2
  9. package/dist/merge.d.ts.map +1 -1
  10. package/dist/merge.js +194 -31
  11. package/dist/merge.js.map +1 -1
  12. package/dist/pay-lock.d.ts.map +1 -1
  13. package/dist/pay-lock.js +8 -14
  14. package/dist/pay-lock.js.map +1 -1
  15. package/dist/pay.d.ts +5 -1
  16. package/dist/pay.d.ts.map +1 -1
  17. package/dist/pay.js +43 -8
  18. package/dist/pay.js.map +1 -1
  19. package/dist/registry-parties.d.ts +6 -0
  20. package/dist/registry-parties.d.ts.map +1 -1
  21. package/dist/registry-parties.js +8 -0
  22. package/dist/registry-parties.js.map +1 -1
  23. package/dist/relay-client.d.ts +29 -0
  24. package/dist/relay-client.d.ts.map +1 -1
  25. package/dist/relay-client.js +83 -11
  26. package/dist/relay-client.js.map +1 -1
  27. package/dist/relay-signer.d.ts.map +1 -1
  28. package/dist/relay-signer.js +16 -1
  29. package/dist/relay-signer.js.map +1 -1
  30. package/dist/swap.d.ts +5 -0
  31. package/dist/swap.d.ts.map +1 -1
  32. package/dist/swap.js +29 -12
  33. package/dist/swap.js.map +1 -1
  34. package/dist/tx.d.ts +6 -11
  35. package/dist/tx.d.ts.map +1 -1
  36. package/dist/tx.js +11 -75
  37. package/dist/tx.js.map +1 -1
  38. package/dist/venue.d.ts +17 -11
  39. package/dist/venue.d.ts.map +1 -1
  40. package/dist/venue.js +20 -14
  41. package/dist/venue.js.map +1 -1
  42. package/dist/verify-prepared.d.ts +14 -26
  43. package/dist/verify-prepared.d.ts.map +1 -1
  44. package/dist/verify-prepared.js +12 -73
  45. package/dist/verify-prepared.js.map +1 -1
  46. package/dist/withdraw.d.ts +2 -1
  47. package/dist/withdraw.d.ts.map +1 -1
  48. package/dist/withdraw.js +70 -22
  49. package/dist/withdraw.js.map +1 -1
  50. package/package.json +4 -4
  51. package/dist/quest-fund.d.ts +0 -142
  52. package/dist/quest-fund.d.ts.map +0 -1
  53. package/dist/quest-fund.js +0 -355
  54. package/dist/quest-fund.js.map +0 -1
@@ -1,355 +0,0 @@
1
- /**
2
- * Quest-funded bootstrap client.
3
- *
4
- * WHY this exists: a bare public faucet that hands free CC to any fresh party is
5
- * farmable — a bot mints parties in a loop and drains it. So the raw facilitator
6
- * faucet is locked to the pay-proxy, and the ONLY way to get CC out of it is the
7
- * pay-proxy's quest flow, which binds the grant to a REAL x402 payment: it mints a
8
- * wallet, faucets it, immediately spends the bulk on a CanTrust image call, and
9
- * leaves the small change. An abuser therefore cannot extract the full grant — to
10
- * get the change they must make (and pay for) a real on-ledger transaction, which
11
- * is exactly the work we want, not free money.
12
- *
13
- * `auto_fund` uses this instead of a bare faucet: it runs the quest, then imports
14
- * the returned wallet key so the agent SELF-CUSTODIES the funded wallet (it holds
15
- * the private key afterwards; the pay-proxy holds nothing). The agent ends with a
16
- * funded wallet + a made image, having spent no human effort.
17
- *
18
- * The flow is the pay-proxy 2-step (both async POST→poll, because each leg has a
19
- * multi-second on-ledger tail):
20
- * STEP 1 POST /v1/quest/wallet/create → 202 { walletJobId }
21
- * GET /v1/quest/wallet/result?walletJobId → funded { secret, walletToken }
22
- * STEP 2 POST /v1/quest/wallet/pay { walletToken } → 202 { payJobId }
23
- * GET /v1/quest/wallet/pay-result?payJobId → done { updateId, image, balanceCc }
24
- */
25
- import { agentKeyFromPrivatePem } from "./keys.js";
26
- import { ensureWallet } from "./onboard.js";
27
- import { loadWallet, saveWallet, walletDir } from "./store.js";
28
- import { mkdirSync, writeFileSync } from "node:fs";
29
- import { join } from "node:path";
30
- import { RelayClient } from "./relay-client.js";
31
- /** A quest leg failed or the flow could not complete. `auto_fund` catches this
32
- * and falls back to the manual-funding ask, so a pay-proxy hiccup never turns
33
- * into a hard tool error. */
34
- /**
35
- * `recoverable` is set when the quest failed AFTER step 1 handed us a real
36
- * party and its private key. Losing that key loses custody of whatever the
37
- * faucet already put on that party — the throw used to discard it, and the CLI
38
- * then told the operator to ask their owner for CC while the grant sat on a
39
- * party nobody could act as any more.
40
- */
41
- export class QuestFundError extends Error {
42
- constructor(message, recoverable) {
43
- super(message);
44
- this.name = "QuestFundError";
45
- if (recoverable) {
46
- Object.defineProperty(this, "recoverable", {
47
- value: recoverable,
48
- enumerable: false,
49
- writable: false,
50
- configurable: false,
51
- });
52
- }
53
- }
54
- }
55
- /**
56
- * The parsed body, or undefined when the answer was not a readable JSON result.
57
- *
58
- * The distinction is the point. A reverse proxy in front of the pay-proxy
59
- * answers a restart or an upstream hiccup with a 502/504 HTML page, and a
60
- * rate-limiter answers 429 — none of which is the job telling us anything. The
61
- * old version flattened all of it to `{}`, which matched neither "pending" nor
62
- * the terminal status, so a poll that could not be read was reported as "the
63
- * quest failed" on the very first blip, with 39 polls of budget still unused.
64
- * The two POSTs in this file check `status !== 202` correctly; the rule was
65
- * simply dropped on the reads that decide the outcome.
66
- */
67
- async function jsonOf(r) {
68
- if (!r.ok)
69
- return undefined;
70
- const text = await r.text();
71
- try {
72
- return JSON.parse(text) ?? undefined;
73
- }
74
- catch {
75
- return undefined;
76
- }
77
- }
78
- /**
79
- * Run the pay-proxy quest and return a funded wallet (key + change + image).
80
- * Throws QuestFundError on any refusal / timeout — never a partial state.
81
- */
82
- export async function questFund(opts) {
83
- const base = opts.payProxyUrl.replace(/\/$/, "");
84
- const doFetch = opts.fetchImpl ?? fetch;
85
- const pollMs = opts.pollMs ?? 3000;
86
- const maxPolls = opts.maxPolls ?? 40;
87
- const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
88
- // --- STEP 1: create ---
89
- const createRes = await doFetch(`${base}/v1/quest/wallet/create`, {
90
- method: "POST",
91
- headers: { "content-type": "application/json" },
92
- body: "{}",
93
- });
94
- if (createRes.status !== 202) {
95
- throw new QuestFundError(`quest create returned ${createRes.status} (expected 202)`);
96
- }
97
- const walletJobId = (await jsonOf(createRes))?.walletJobId;
98
- if (typeof walletJobId !== "string" || !walletJobId) {
99
- throw new QuestFundError("quest create returned no walletJobId");
100
- }
101
- // --- STEP 1 poll: result ---
102
- let funded;
103
- for (let i = 0; i < maxPolls; i++) {
104
- await sleep(pollMs);
105
- const r = await doFetch(`${base}/v1/quest/wallet/result?walletJobId=${encodeURIComponent(walletJobId)}`);
106
- const body = await jsonOf(r);
107
- // Unreadable answer: not a verdict. Keep polling with the budget we have.
108
- if (!body)
109
- continue;
110
- if (body.status === "pending")
111
- continue;
112
- if (body.status === "funded") {
113
- funded = body;
114
- break;
115
- }
116
- throw new QuestFundError(`quest STEP 1 failed: ${String(body.error ?? body.status ?? "unknown")}`);
117
- }
118
- if (!funded)
119
- throw new QuestFundError("quest STEP 1 timed out");
120
- const secret = funded.secret;
121
- const walletToken = funded.walletToken;
122
- const party = funded.party;
123
- const network = funded.network;
124
- if (typeof secret !== "string" ||
125
- typeof walletToken !== "string" ||
126
- typeof party !== "string") {
127
- throw new QuestFundError("quest STEP 1 returned an incomplete funded body");
128
- }
129
- // --- STEP 2: pay (faucet + CanTrust image + change, on the minted wallet) ---
130
- const payRes = await doFetch(`${base}/v1/quest/wallet/pay`, {
131
- method: "POST",
132
- headers: { "content-type": "application/json" },
133
- body: JSON.stringify({
134
- walletToken,
135
- ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),
136
- }),
137
- });
138
- if (payRes.status !== 202) {
139
- throw new QuestFundError(`quest pay returned ${payRes.status} (expected 202)`);
140
- }
141
- const payJobId = (await jsonOf(payRes))?.payJobId;
142
- if (typeof payJobId !== "string" || !payJobId) {
143
- throw new QuestFundError("quest pay returned no payJobId");
144
- }
145
- // --- STEP 2 poll: pay-result ---
146
- let done;
147
- for (let i = 0; i < maxPolls; i++) {
148
- await sleep(pollMs);
149
- const r = await doFetch(`${base}/v1/quest/wallet/pay-result?payJobId=${encodeURIComponent(payJobId)}`);
150
- const body = await jsonOf(r);
151
- if (!body)
152
- continue;
153
- if (body.status === "pending")
154
- continue;
155
- if (body.status === "done") {
156
- done = body;
157
- break;
158
- }
159
- throw new QuestFundError(`quest STEP 2 failed: ${String(body.error ?? body.status ?? "unknown")}`, { secret, party, network: typeof network === "string" ? network : "canton:mainnet" });
160
- }
161
- if (!done) {
162
- throw new QuestFundError("quest STEP 2 timed out", {
163
- secret,
164
- party,
165
- network: typeof network === "string" ? network : "canton:mainnet",
166
- });
167
- }
168
- return {
169
- secret,
170
- party,
171
- network: typeof network === "string" ? network : "canton:mainnet",
172
- balanceCc: typeof done.balanceCc === "string" ? done.balanceCc : undefined,
173
- updateId: typeof done.updateId === "string" ? done.updateId : undefined,
174
- image: typeof done.image === "string" ? done.image : undefined,
175
- };
176
- }
177
- /**
178
- * Persist a key rescued from a failed quest, beside the wallet but never AS the
179
- * wallet.
180
- *
181
- * EXPORTED because the MCP server runs the same quest through the lower-level
182
- * `questFund` and needs the same rescue. It had none: the only copy of the
183
- * private key rode away inside the thrown Error and was collected, leaving
184
- * faucet CC on a MainNet party nobody can spend. One rescue, one place. Overwriting wallet.json here would destroy the private key of an
185
- * existing wallet on an error path — the exact loss this rescue exists to
186
- * prevent, aimed at the other wallet. The party goes in the filename so two
187
- * rescues cannot silently overwrite each other.
188
- */
189
- export function writeRescueKey(secret, party, _network) {
190
- const d = walletDir();
191
- mkdirSync(d, { recursive: true, mode: 0o700 });
192
- const safe = party.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 80);
193
- const p = join(d, `rescued-key-${safe}.pem`);
194
- writeFileSync(p, secret.endsWith("\n") ? secret : secret + "\n", { mode: 0o600 });
195
- return p;
196
- }
197
- /**
198
- * Bootstrap a funded self-custody wallet through the quest (mint → grant →
199
- * CanTrust payment → change) and INSTALL it (`saveWallet`) so the caller owns the
200
- * key. This is the ONLY non-farmable funding path: the grant is inseparable from a
201
- * real payment, so an abuser gets only the small change, not free CC.
202
- *
203
- * NO-CLOBBER: if a wallet already exists AND holds a balance, it is NEVER replaced
204
- * — the existing wallet is returned as `already_funded`. Only an absent or empty
205
- * wallet home is bootstrapped. Throws QuestFundError on quest failure (the caller
206
- * decides the fallback, e.g. manual funding).
207
- */
208
- export async function fundViaQuest(opts) {
209
- const load = opts.loadWalletImpl ?? loadWallet;
210
- const balanceOf = opts.balanceOf ??
211
- (async (relayUrl, party) => (await new RelayClient({ relayUrl }).balance(party)).cc);
212
- const pendingOf = opts.pendingOf ??
213
- (async (relayUrl, party) => (await new RelayClient({ relayUrl }).pending(party)).pending);
214
- const existing = load();
215
- if (existing) {
216
- // UNREADABLE IS NOT EMPTY.
217
- //
218
- // The guard below is the only thing standing between an existing wallet
219
- // and `saveWallet` overwriting it — and overwriting wallet.json destroys
220
- // the private key, which is the one thing here that cannot be undone. The
221
- // old code caught the balance read into `cc = "0"` and commented that as
222
- // "treat as empty and proceed to bootstrap": a relay blip, a DNS hiccup or
223
- // any 5xx therefore looked exactly like an empty wallet, and the key of a
224
- // wallet holding real CC was replaced.
225
- //
226
- // A wallet is only ever replaced when we KNOW it is empty. If the balance
227
- // cannot be read we refuse and say so; the caller retries when the relay
228
- // is back, and nothing was lost in the meantime.
229
- let cc;
230
- try {
231
- cc = await balanceOf(opts.relayUrl, existing.party);
232
- }
233
- catch (err) {
234
- throw new QuestFundError(`a wallet already exists (${existing.party}) but its balance could not ` +
235
- `be read (${err instanceof Error ? err.message : String(err)}) — ` +
236
- `refusing to overwrite it, because an unreadable balance is not an ` +
237
- `empty one and replacing the wallet would destroy its private key. ` +
238
- `Retry once the relay is reachable.`);
239
- }
240
- if (Number(cc) > 0) {
241
- return { kind: "already_funded", party: existing.party, balanceCc: cc };
242
- }
243
- // A BALANCE OF ZERO IS NOT PROOF OF AN EMPTY WALLET.
244
- //
245
- // The relay's /balance counts `Splice.Amulet:Amulet` contracts and nothing
246
- // else (facilitator routes/wallet.ts scopes the query to that template on
247
- // purpose). CC that someone has SENT to this party but that nobody has
248
- // accepted yet is not an Amulet — it is a pending TransferInstruction, and
249
- // it reads as 0.0000000000 here.
250
- //
251
- // That is the normal state of an agent wallet, not an exotic one: an agent
252
- // has no TransferPreapproval, which is precisely why a separate `claim`
253
- // step exists ("run after the owner has sent CC"). So the window between
254
- // "owner sent the funds" and "agent accepted them" is exactly the window in
255
- // which this guard called the wallet empty and `saveWallet` destroyed the
256
- // private key of the party those funds are addressed to. The CC stays on
257
- // the ledger, addressed to a party nobody can act as any more.
258
- //
259
- // Same rule as the balance read above, applied to the other half of the
260
- // question: unreadable is not empty, and neither is unclaimed.
261
- let pending;
262
- try {
263
- pending = await pendingOf(opts.relayUrl, existing.party);
264
- }
265
- catch (err) {
266
- throw new QuestFundError(`a wallet already exists (${existing.party}) and reads as empty, but ` +
267
- `its pending incoming transfers could not be read (${err instanceof Error ? err.message : String(err)}) — refusing to overwrite it, because a balance of zero only proves ` +
268
- `there are no ACCEPTED funds. Retry once the relay is reachable.`);
269
- }
270
- if (pending.length > 0) {
271
- const total = pending
272
- .reduce((sum, p) => sum + Number(p.amount ?? 0), 0)
273
- .toFixed(10);
274
- throw new QuestFundError(`a wallet already exists (${existing.party}) with ${pending.length} ` +
275
- `unaccepted incoming transfer(s) totalling ${total} CC — refusing to ` +
276
- `overwrite it, because replacing the wallet would destroy the private ` +
277
- `key those funds are addressed to and they could never be claimed. ` +
278
- `Run \`claim\` to accept them first.`);
279
- }
280
- }
281
- const runQuest = opts.questFundImpl ?? questFund;
282
- const rescueKey = opts.rescueKeyImpl ?? writeRescueKey;
283
- let funded;
284
- try {
285
- funded = await runQuest({
286
- payProxyUrl: opts.payProxyUrl,
287
- ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}),
288
- ...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}),
289
- });
290
- }
291
- catch (err) {
292
- // A QUEST THAT FAILS PAST STEP 1 STILL LEFT US HOLDING A KEY.
293
- //
294
- // Step 2 is the leg that faucets, accepts and spends, so by the time it can
295
- // fail the party may already hold real CC. Letting the exception carry the
296
- // only copy of its private key away turned a recoverable interruption into
297
- // funds nobody can ever move. We write the key out and name the file in the
298
- // error — deliberately NOT into wallet.json, which may hold another wallet
299
- // whose own key must not be destroyed by an error path.
300
- const rec = err instanceof QuestFundError ? err.recoverable : undefined;
301
- if (!rec)
302
- throw err;
303
- let where;
304
- try {
305
- where = rescueKey(rec.secret, rec.party, rec.network);
306
- }
307
- catch (writeErr) {
308
- throw new QuestFundError(`${err.message} — and the funded party's key could NOT be ` +
309
- `written to disk (${writeErr instanceof Error ? writeErr.message : String(writeErr)}). Party ${rec.party} may hold CC that is now unreachable; capture ` +
310
- `the key from this process before it exits.`, rec);
311
- }
312
- throw new QuestFundError(`${err.message} — the funded party's key was saved to ${where}. ` +
313
- `Party ${rec.party} may already hold CC: run ` +
314
- `\`canton-agent-wallet import --key-file ${where}\` in an empty wallet ` +
315
- `home to take custody, then \`claim\`.`, rec);
316
- }
317
- const install = opts.installKey ??
318
- (async (secret, relayUrl, network) => {
319
- const key = agentKeyFromPrivatePem(secret);
320
- // ensureWallet is LOAD-FIRST: with a wallet already on disk it returns
321
- // THAT wallet and silently ignores `key` (the CLI `import` refuses
322
- // non-empty homes for exactly this reason). We only reach here after the
323
- // no-clobber check DECIDED to replace (absent or empty wallet), so skip
324
- // the store read with `ephemeral` and persist the imported key
325
- // explicitly — otherwise the funded key is dropped and the empty boot
326
- // wallet survives (found live: MCP auto_fund reported the funded party
327
- // while wallet.json still held the empty boot wallet).
328
- const w = await ensureWallet({
329
- relayUrl,
330
- network,
331
- key,
332
- restore: true,
333
- ephemeral: true,
334
- });
335
- saveWallet(w);
336
- return w;
337
- });
338
- const wallet = await install(funded.secret, opts.relayUrl, funded.network);
339
- // FAIL LOUD, never lie: the installed wallet MUST be the funded party. Any
340
- // install path that keeps a different wallet (a load-first ensure, a stale
341
- // injected seam) would otherwise report success while the grant sits on a
342
- // party whose key was just dropped.
343
- if (wallet.party !== funded.party) {
344
- throw new QuestFundError(`installed wallet party ${wallet.party} is not the funded party ${funded.party} — ` +
345
- `the funded key was NOT persisted; refusing to report success`);
346
- }
347
- return {
348
- kind: "funded",
349
- wallet,
350
- balanceCc: funded.balanceCc,
351
- updateId: funded.updateId,
352
- image: funded.image,
353
- };
354
- }
355
- //# sourceMappingURL=quest-fund.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"quest-fund.js","sourceRoot":"","sources":["../src/quest-fund.ts"],"names":[],"mappings":"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"}