@dfm-fi/agent 0.2.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 (59) hide show
  1. package/README.md +326 -0
  2. package/dist/api-client.d.ts +137 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +215 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/config.d.ts +56 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +55 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/create-flow.d.ts +62 -0
  11. package/dist/create-flow.d.ts.map +1 -0
  12. package/dist/create-flow.js +88 -0
  13. package/dist/create-flow.js.map +1 -0
  14. package/dist/examples/deposit-redeem-loop.d.ts +2 -0
  15. package/dist/examples/deposit-redeem-loop.d.ts.map +1 -0
  16. package/dist/examples/deposit-redeem-loop.js +67 -0
  17. package/dist/examples/deposit-redeem-loop.js.map +1 -0
  18. package/dist/examples/launch-deposit-redeem.d.ts +2 -0
  19. package/dist/examples/launch-deposit-redeem.d.ts.map +1 -0
  20. package/dist/examples/launch-deposit-redeem.js +166 -0
  21. package/dist/examples/launch-deposit-redeem.js.map +1 -0
  22. package/dist/examples/list-and-status.d.ts +2 -0
  23. package/dist/examples/list-and-status.d.ts.map +1 -0
  24. package/dist/examples/list-and-status.js +67 -0
  25. package/dist/examples/list-and-status.js.map +1 -0
  26. package/dist/manager-flow.d.ts +73 -0
  27. package/dist/manager-flow.d.ts.map +1 -0
  28. package/dist/manager-flow.js +110 -0
  29. package/dist/manager-flow.js.map +1 -0
  30. package/dist/mcp-server.d.ts +3 -0
  31. package/dist/mcp-server.d.ts.map +1 -0
  32. package/dist/mcp-server.js +529 -0
  33. package/dist/mcp-server.js.map +1 -0
  34. package/dist/recovery-flow.d.ts +81 -0
  35. package/dist/recovery-flow.d.ts.map +1 -0
  36. package/dist/recovery-flow.js +123 -0
  37. package/dist/recovery-flow.js.map +1 -0
  38. package/dist/session.d.ts +52 -0
  39. package/dist/session.d.ts.map +1 -0
  40. package/dist/session.js +107 -0
  41. package/dist/session.js.map +1 -0
  42. package/dist/signing.d.ts +30 -0
  43. package/dist/signing.d.ts.map +1 -0
  44. package/dist/signing.js +129 -0
  45. package/dist/signing.js.map +1 -0
  46. package/dist/submit.d.ts +31 -0
  47. package/dist/submit.d.ts.map +1 -0
  48. package/dist/submit.js +165 -0
  49. package/dist/submit.js.map +1 -0
  50. package/dist/types.d.ts +191 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +16 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/zap-v2-flow.d.ts +76 -0
  55. package/dist/zap-v2-flow.d.ts.map +1 -0
  56. package/dist/zap-v2-flow.js +176 -0
  57. package/dist/zap-v2-flow.js.map +1 -0
  58. package/package.json +60 -0
  59. package/skills.md +153 -0
@@ -0,0 +1,123 @@
1
+ import { signBase64Transaction } from './signing.js';
2
+ import { submitSignedTx } from './submit.js';
3
+ const MAX_SLIPPAGE_BPS = 1_000; // MAX_ZAP_SLIPPAGE_BPS — the per-leg on-chain cap.
4
+ /**
5
+ * Cancel a stalled escrow and return its current holdings to the test wallet.
6
+ * Reads the live escrow first (for a clean "no escrow" message + to report the
7
+ * held balances), then prepare → sign → submit.
8
+ */
9
+ export async function runCancel(config, api, user, vault) {
10
+ const before = await api.getZapV2Status(vault, user);
11
+ if (!before) {
12
+ throw new Error(`No open zap-v2 escrow for vault ${vault.slice(0, 8)}… and this wallet — nothing to cancel.`);
13
+ }
14
+ const prepared = await api.prepareZapCancelV2(vault);
15
+ const signed = signBase64Transaction(config, prepared.transaction);
16
+ const signature = await submitSignedTx(config, signed, prepared.blockhash, prepared.lastValidBlockHeight);
17
+ return {
18
+ ok: true,
19
+ vault,
20
+ signature,
21
+ escrowBefore: {
22
+ mode: before.mode,
23
+ state: before.state,
24
+ legsFilled: before.legsFilled,
25
+ legsTotal: before.legsTotal,
26
+ minOuts: before.minOuts,
27
+ actualOuts: before.actualOuts,
28
+ },
29
+ message: `Cancelled escrow on vault ${vault.slice(0, 8)}… (${before.legsFilled}/${before.legsTotal} legs ` +
30
+ `had filled). Held USDC + basket returned to the test wallet as-is; escrow closed. ` +
31
+ `${before.mode === 0 ? 'For a deposit, you keep the USDC + any swapped basket dust.' : 'For a redeem, you keep the partially-sold basket + USDC.'}`,
32
+ };
33
+ }
34
+ /**
35
+ * Compute SAFE loosened per-leg floors from the live pinned `minOuts` by relaxing
36
+ * each by `loosenPct` percent (default 5%). Each result is `floor(old * (100 -
37
+ * pct) / 100)`, clamped to ≥1 (the API rejects non-positive floors) and never
38
+ * above the old value (on-chain monotonic-loosening rule). Returns the new floor
39
+ * array in basket order.
40
+ */
41
+ export function computeLoosenedMinOuts(oldMinOuts, loosenPct) {
42
+ if (loosenPct < 0 || loosenPct > 50) {
43
+ throw new Error(`loosenPct must be 0..50; got ${loosenPct}.`);
44
+ }
45
+ const num = BigInt(Math.round(100 - loosenPct));
46
+ return oldMinOuts.map((s) => {
47
+ const old = BigInt(s);
48
+ if (old <= 0n)
49
+ return '1'; // already a sentinel — keep it positive for the API.
50
+ let relaxed = (old * num) / 100n;
51
+ if (relaxed < 1n)
52
+ relaxed = 1n; // floor at 1 raw unit (API rejects 0).
53
+ if (relaxed > old)
54
+ relaxed = old; // never tighten.
55
+ return relaxed.toString();
56
+ });
57
+ }
58
+ /**
59
+ * Loosen a stalled escrow's pinned floors so the orchestrator can finish. The
60
+ * new floors are DERIVED from the live escrow (`minOuts` relaxed by `loosenPct`),
61
+ * never hand-supplied — the only knobs an operator turns are HOW MUCH to relax
62
+ * (`loosenPct`), the new slippage, and an optional expiry extension.
63
+ *
64
+ * `newSlippageBps` is clamped to ≥ the current pinned slippage (the on-chain rule
65
+ * forbids tightening) and ≤ the 1000-bps cap.
66
+ */
67
+ export async function runUpdateEnvelope(config, api, user, vault, opts) {
68
+ const live = await api.getZapV2Status(vault, user);
69
+ if (!live) {
70
+ throw new Error(`No open zap-v2 escrow for vault ${vault.slice(0, 8)}… and this wallet — nothing to update.`);
71
+ }
72
+ if (live.readyToClose) {
73
+ throw new Error(`Escrow is already READY to close (${live.legsFilled}/${live.legsTotal} legs filled) — ` +
74
+ `call the deposit/redeem close path, not update-envelope.`);
75
+ }
76
+ const loosenPct = opts.loosenPct ?? 5;
77
+ const newMinOuts = computeLoosenedMinOuts(live.minOuts, loosenPct);
78
+ // Slippage may only LOOSEN (≥ current pinned), capped at the on-chain max.
79
+ const requested = opts.newSlippageBps ?? live.slippageBps;
80
+ const newSlippageBps = Math.min(MAX_SLIPPAGE_BPS, Math.max(live.slippageBps, requested));
81
+ // Redeem-only NET-USDC floor: relax it by the same pct (≤ current; ≥0 allowed).
82
+ let newMinUsdcOut;
83
+ if (live.mode === 1) {
84
+ const oldUsdc = BigInt(live.minUsdcOut || '0');
85
+ if (oldUsdc > 0n) {
86
+ let relaxed = (oldUsdc * BigInt(Math.round(100 - loosenPct))) / 100n;
87
+ if (relaxed > oldUsdc)
88
+ relaxed = oldUsdc;
89
+ newMinUsdcOut = relaxed.toString();
90
+ }
91
+ else {
92
+ newMinUsdcOut = '0';
93
+ }
94
+ }
95
+ const extendSecs = opts.extendSecs ?? 0;
96
+ const prepared = await api.prepareUpdateEnvelopeV2(vault, {
97
+ newMinOuts,
98
+ newSlippageBps,
99
+ newMinUsdcOut,
100
+ extendSecs,
101
+ });
102
+ const signed = signBase64Transaction(config, prepared.transaction);
103
+ const signature = await submitSignedTx(config, signed, prepared.blockhash, prepared.lastValidBlockHeight);
104
+ return {
105
+ ok: true,
106
+ vault,
107
+ signature,
108
+ loosening: {
109
+ oldMinOuts: live.minOuts,
110
+ newMinOuts,
111
+ oldSlippageBps: live.slippageBps,
112
+ newSlippageBps,
113
+ oldMinUsdcOut: live.mode === 1 ? live.minUsdcOut : undefined,
114
+ newMinUsdcOut,
115
+ extendSecs,
116
+ loosenPct,
117
+ },
118
+ message: `Loosened the escrow floors by ${loosenPct}% (slippage ${live.slippageBps}→${newSlippageBps} bps` +
119
+ `${extendSecs ? `, +${extendSecs}s expiry` : ''}). The orchestrator will retry the stuck legs. ` +
120
+ `Poll zap_status — if it still won't fill, cancel to recover the holdings.`,
121
+ };
122
+ }
123
+ //# sourceMappingURL=recovery-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-flow.js","sourceRoot":"","sources":["../src/recovery-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * SIWS session manager — turns the local test keypair into an authenticated
3
+ * Bearer session against the DFM v2 API.
4
+ *
5
+ * AUTH DESIGN (matches api/src/modules/auth):
6
+ * 1. POST /auth/nonce { wallet } → { nonce, message }
7
+ * The server BUILDS the exact `message` (domain-bound, nonce-embedded). The
8
+ * client must sign THAT string verbatim — it must not reconstruct it.
9
+ * 2. sign `message` locally with the test keypair (Ed25519 → base58 sig)
10
+ * 3. POST /auth/siws { wallet, signature, message, client: 'native' }
11
+ * → { accessToken, refreshToken, wallet, expiresIn } (Bearer tokens)
12
+ * The server ALSO enforces the closed-alpha access gate here: a wallet not
13
+ * on the allowlist gets 403 and never receives a token.
14
+ * 4. Subsequent calls send `Authorization: Bearer <accessToken>`.
15
+ * 5. On 401 (token expired/rotated), re-run 1–3 once and retry.
16
+ *
17
+ * We use the `native` client surface (Bearer tokens in the body) rather than the
18
+ * `web` surface (httpOnly cookies) because an MCP agent is not a browser and has
19
+ * no cookie jar — Bearer is the correct programmatic path.
20
+ *
21
+ * The session caches the access token in-memory only (process lifetime). It is
22
+ * never persisted, never logged, never returned through MCP.
23
+ */
24
+ import type { AgentConfig } from './config.js';
25
+ export declare class SiwsSession {
26
+ private readonly config;
27
+ private accessToken;
28
+ private wallet;
29
+ /** Epoch ms when the cached access token should be considered stale. */
30
+ private expiresAtMs;
31
+ /**
32
+ * In-flight sign-in promise — dedupes concurrent token requests so a burst of
33
+ * parallel authed calls (or a StrictMode-style double fire) does NOT trigger
34
+ * multiple SIWS round-trips (which churn nonces + can trip the /auth/siws
35
+ * rate limit). The first caller signs in; the rest await the same promise.
36
+ */
37
+ private signInPromise;
38
+ constructor(config: AgentConfig);
39
+ /** The authenticated wallet (test-wallet pubkey). Loads the keypair on first use. */
40
+ get walletAddress(): string;
41
+ /**
42
+ * Return a valid Bearer access token, signing in (or refreshing) if needed.
43
+ * `force` re-authenticates even if a cached token looks valid (used after a
44
+ * 401 from a protected call).
45
+ */
46
+ getAccessToken(force?: boolean): Promise<string>;
47
+ private signIn;
48
+ private parseExpiryMs;
49
+ /** POST helper used for the unauthenticated auth endpoints. */
50
+ private postJson;
51
+ }
52
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,qBAAa,WAAW;IAaV,OAAO,CAAC,QAAQ,CAAC,MAAM;IAZnC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,MAAM,CAAuB;IACrC,wEAAwE;IACxE,OAAO,CAAC,WAAW,CAAK;IACxB;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAAgC;gBAExB,MAAM,EAAE,WAAW;IAEhD,qFAAqF;IACrF,IAAI,aAAa,IAAI,MAAM,CAK1B;IAED;;;;OAIG;IACG,cAAc,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;YAatC,MAAM;IA2CpB,OAAO,CAAC,aAAa;IAarB,+DAA+D;YACjD,QAAQ;CAYvB"}
@@ -0,0 +1,107 @@
1
+ import { getTestWalletPubkey, signSiwsMessage } from './signing.js';
2
+ export class SiwsSession {
3
+ config;
4
+ accessToken = null;
5
+ wallet = null;
6
+ /** Epoch ms when the cached access token should be considered stale. */
7
+ expiresAtMs = 0;
8
+ /**
9
+ * In-flight sign-in promise — dedupes concurrent token requests so a burst of
10
+ * parallel authed calls (or a StrictMode-style double fire) does NOT trigger
11
+ * multiple SIWS round-trips (which churn nonces + can trip the /auth/siws
12
+ * rate limit). The first caller signs in; the rest await the same promise.
13
+ */
14
+ signInPromise = null;
15
+ constructor(config) {
16
+ this.config = config;
17
+ }
18
+ /** The authenticated wallet (test-wallet pubkey). Loads the keypair on first use. */
19
+ get walletAddress() {
20
+ if (!this.wallet) {
21
+ this.wallet = getTestWalletPubkey(this.config);
22
+ }
23
+ return this.wallet;
24
+ }
25
+ /**
26
+ * Return a valid Bearer access token, signing in (or refreshing) if needed.
27
+ * `force` re-authenticates even if a cached token looks valid (used after a
28
+ * 401 from a protected call).
29
+ */
30
+ async getAccessToken(force = false) {
31
+ const now = Date.now();
32
+ if (!force && this.accessToken && now < this.expiresAtMs) {
33
+ return this.accessToken;
34
+ }
35
+ // Coalesce concurrent sign-ins onto a single in-flight promise.
36
+ if (this.signInPromise)
37
+ return this.signInPromise;
38
+ this.signInPromise = this.signIn().finally(() => {
39
+ this.signInPromise = null;
40
+ });
41
+ return this.signInPromise;
42
+ }
43
+ async signIn() {
44
+ const wallet = this.walletAddress;
45
+ // Step 1 — nonce + server-built message.
46
+ const nonceRes = await this.postJson('/auth/nonce', { wallet });
47
+ if (!nonceRes?.message) {
48
+ throw new Error('SIWS nonce response missing `message` — cannot sign in.');
49
+ }
50
+ // Step 2 — sign the EXACT message locally.
51
+ const signature = signSiwsMessage(this.config, nonceRes.message);
52
+ // Step 3 — exchange for Bearer tokens (native client surface).
53
+ let tokens;
54
+ try {
55
+ tokens = await this.postJson('/auth/siws', {
56
+ wallet,
57
+ signature,
58
+ message: nonceRes.message,
59
+ client: 'native',
60
+ });
61
+ }
62
+ catch (e) {
63
+ const msg = e.message;
64
+ // The closed-alpha gate denies non-allowlisted wallets at sign-in.
65
+ if (/403/.test(msg) || /access list/i.test(msg)) {
66
+ throw new Error(`Sign-in rejected for test wallet ${wallet.slice(0, 8)}… — it is not on the ` +
67
+ `closed-alpha access allowlist. An admin must add it via the /ops Access ` +
68
+ `panel (POST /access/allowlist). Original: ${msg}`);
69
+ }
70
+ throw e;
71
+ }
72
+ if (!tokens?.accessToken) {
73
+ throw new Error('SIWS sign-in succeeded but returned no accessToken.');
74
+ }
75
+ this.accessToken = tokens.accessToken;
76
+ // Parse `expiresIn` (e.g. "1h") conservatively; default to a 5-min skew floor.
77
+ this.expiresAtMs = Date.now() + this.parseExpiryMs(tokens.expiresIn) - 60_000;
78
+ return this.accessToken;
79
+ }
80
+ parseExpiryMs(expiresIn) {
81
+ if (!expiresIn)
82
+ return 60 * 60 * 1000; // default 1h
83
+ const m = /^(\d+)\s*([smhd])$/.exec(expiresIn.trim());
84
+ if (!m) {
85
+ const n = Number(expiresIn);
86
+ return Number.isFinite(n) ? n * 1000 : 60 * 60 * 1000; // bare seconds, else 1h
87
+ }
88
+ const value = Number(m[1]);
89
+ const unit = m[2];
90
+ const mult = unit === 's' ? 1000 : unit === 'm' ? 60_000 : unit === 'h' ? 3_600_000 : 86_400_000;
91
+ return value * mult;
92
+ }
93
+ /** POST helper used for the unauthenticated auth endpoints. */
94
+ async postJson(path, body) {
95
+ const res = await fetch(`${this.config.apiUrl}${path}`, {
96
+ method: 'POST',
97
+ headers: { 'Content-Type': 'application/json' },
98
+ body: JSON.stringify(body),
99
+ });
100
+ if (!res.ok) {
101
+ const text = await res.text().catch(() => '');
102
+ throw new Error(`POST ${path} → ${res.status}: ${text.slice(0, 300)}`);
103
+ }
104
+ return (await res.json());
105
+ }
106
+ }
107
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Keypair } from '@solana/web3.js';
2
+ import type { AgentConfig } from './config.js';
3
+ /**
4
+ * Load (and cache) the operator's local test keypair. Throws a clear,
5
+ * key-material-free error if no source is configured or the material is invalid.
6
+ * Caller MUST have already verified `config.writeEnabled` — this function does
7
+ * not gate on the write flag (separation of concerns), but it is only reachable
8
+ * from the write path.
9
+ */
10
+ export declare function loadTestKeypair(config: AgentConfig): Keypair;
11
+ /** The agent's test-wallet PUBLIC key (base58). Safe to surface + log. */
12
+ export declare function getTestWalletPubkey(config: AgentConfig): string;
13
+ /**
14
+ * Sign a UTF-8 SIWS message with the test keypair, returning a base58-encoded
15
+ * Ed25519 signature — exactly what `POST /auth/siws` expects in `signature`.
16
+ * The message MUST be the verbatim string the API returned from `POST
17
+ * /auth/nonce` (the server re-derives the domain + nonce and verifies the
18
+ * signature over that exact text).
19
+ */
20
+ export declare function signSiwsMessage(config: AgentConfig, message: string): string;
21
+ /**
22
+ * Sign one base64-encoded v0 VersionedTransaction with the test keypair and
23
+ * return it re-serialized to base64, ready to submit. Used by the zap-v2 write
24
+ * path: every tx the `/prepare` endpoints return is signed locally here.
25
+ *
26
+ * The tx already carries the API's recent blockhash + fee-payer (the user/test
27
+ * wallet); we only attach the test wallet's signature.
28
+ */
29
+ export declare function signBase64Transaction(config: AgentConfig, base64Tx: string): string;
30
+ //# sourceMappingURL=signing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,OAAO,EAAwB,MAAM,iBAAiB,CAAC;AAGhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAoC/C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAuC5D;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAK5E;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKnF"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * LOCAL signing — the security boundary of the agent.
3
+ *
4
+ * ──────────────────────────────────────────────────────────────────────────
5
+ * SECURITY INVARIANTS (do not weaken):
6
+ * 1. The test-wallet secret key is loaded ONLY here, ONLY from a local source
7
+ * the operator controls: a file path (`DFM_AGENT_KEYPAIR_PATH`) or an
8
+ * env-injected JSON array (`DFM_AGENT_KEYPAIR_JSON`).
9
+ * 2. The secret key NEVER crosses the MCP boundary: it is never a tool
10
+ * argument, never part of a tool result, and never logged. Only the PUBLIC
11
+ * key (base58) is ever surfaced.
12
+ * 3. Any error thrown from here is scrubbed of key material (we only ever
13
+ * include the public key or a generic reason).
14
+ * 4. This module refuses to load the protocol wallet by accident is NOT
15
+ * something we can detect by pubkey alone — so the operator guidance is to
16
+ * use a dedicated throwaway test wallet. We DO hard-block the well-known
17
+ * protocol pubkey as a defense-in-depth tripwire (see PROTOCOL_WALLET).
18
+ * ──────────────────────────────────────────────────────────────────────────
19
+ *
20
+ * The keypair is loaded lazily (first WRITE call), so the read-only tools and
21
+ * `npx tsx` smoke runs never touch key material.
22
+ */
23
+ import { readFileSync } from 'node:fs';
24
+ import { Keypair, VersionedTransaction } from '@solana/web3.js';
25
+ import nacl from 'tweetnacl';
26
+ import bs58 from 'bs58';
27
+ /**
28
+ * The single hot Protocol Wallet (DIEGO_2) — `factory.admin` + fee recipient +
29
+ * upgrade authority + backend signer. The agent must NEVER sign with this. If a
30
+ * loaded keypair resolves to this pubkey we refuse immediately: a test agent
31
+ * holding the protocol key is a critical misconfiguration.
32
+ */
33
+ const PROTOCOL_WALLET = '9GjEBsZ1Cos2J6inmgwhBKv9pXGNtLSJ7xQ9xZb29bET';
34
+ let cachedKeypair = null;
35
+ /** Parse a Solana 64-byte secret-key JSON array into a Keypair. */
36
+ function keypairFromJsonArray(json, source) {
37
+ let arr;
38
+ try {
39
+ arr = JSON.parse(json);
40
+ }
41
+ catch {
42
+ // Do NOT echo the content — it may BE the secret.
43
+ throw new Error(`Test keypair from ${source} is not valid JSON (expected a 64-number array).`);
44
+ }
45
+ if (!Array.isArray(arr) || (arr.length !== 64 && arr.length !== 32)) {
46
+ throw new Error(`Test keypair from ${source} must be a JSON array of 64 (full secret) or 32 (seed) bytes; got length ${Array.isArray(arr) ? arr.length : 'non-array'}.`);
47
+ }
48
+ const bytes = Uint8Array.from(arr);
49
+ try {
50
+ return bytes.length === 32 ? Keypair.fromSeed(bytes) : Keypair.fromSecretKey(bytes);
51
+ }
52
+ catch {
53
+ throw new Error(`Test keypair from ${source} is not a valid Ed25519 secret key.`);
54
+ }
55
+ }
56
+ /**
57
+ * Load (and cache) the operator's local test keypair. Throws a clear,
58
+ * key-material-free error if no source is configured or the material is invalid.
59
+ * Caller MUST have already verified `config.writeEnabled` — this function does
60
+ * not gate on the write flag (separation of concerns), but it is only reachable
61
+ * from the write path.
62
+ */
63
+ export function loadTestKeypair(config) {
64
+ if (cachedKeypair)
65
+ return cachedKeypair;
66
+ let kp;
67
+ if (config.keypairPath) {
68
+ let raw;
69
+ try {
70
+ raw = readFileSync(config.keypairPath, 'utf8');
71
+ }
72
+ catch (e) {
73
+ const code = e.code ?? 'read error';
74
+ throw new Error(`Could not read test keypair file at DFM_AGENT_KEYPAIR_PATH (${code}). ` +
75
+ `Set it to a Solana secret-key JSON file the operator controls locally.`);
76
+ }
77
+ kp = keypairFromJsonArray(raw, 'DFM_AGENT_KEYPAIR_PATH');
78
+ }
79
+ else if (config.keypairJsonEnvPresent) {
80
+ // Read straight from the env at use-time (not cached as a string anywhere).
81
+ kp = keypairFromJsonArray(process.env.DFM_AGENT_KEYPAIR_JSON, 'DFM_AGENT_KEYPAIR_JSON');
82
+ }
83
+ else {
84
+ throw new Error('No test keypair configured. Set DFM_AGENT_KEYPAIR_PATH (path to a Solana ' +
85
+ 'secret-key JSON file) or DFM_AGENT_KEYPAIR_JSON (the JSON array inline). ' +
86
+ 'Use a DEDICATED throwaway test wallet — never the protocol wallet.');
87
+ }
88
+ const pubkey = kp.publicKey.toBase58();
89
+ if (pubkey === PROTOCOL_WALLET) {
90
+ // Wipe and refuse.
91
+ kp.secretKey.fill(0);
92
+ throw new Error('REFUSING to load the protocol wallet as the agent test keypair. The agent ' +
93
+ 'must sign with a dedicated throwaway test wallet, never the protocol hot wallet.');
94
+ }
95
+ cachedKeypair = kp;
96
+ return kp;
97
+ }
98
+ /** The agent's test-wallet PUBLIC key (base58). Safe to surface + log. */
99
+ export function getTestWalletPubkey(config) {
100
+ return loadTestKeypair(config).publicKey.toBase58();
101
+ }
102
+ /**
103
+ * Sign a UTF-8 SIWS message with the test keypair, returning a base58-encoded
104
+ * Ed25519 signature — exactly what `POST /auth/siws` expects in `signature`.
105
+ * The message MUST be the verbatim string the API returned from `POST
106
+ * /auth/nonce` (the server re-derives the domain + nonce and verifies the
107
+ * signature over that exact text).
108
+ */
109
+ export function signSiwsMessage(config, message) {
110
+ const kp = loadTestKeypair(config);
111
+ const messageBytes = new TextEncoder().encode(message);
112
+ const sig = nacl.sign.detached(messageBytes, kp.secretKey);
113
+ return bs58.encode(sig);
114
+ }
115
+ /**
116
+ * Sign one base64-encoded v0 VersionedTransaction with the test keypair and
117
+ * return it re-serialized to base64, ready to submit. Used by the zap-v2 write
118
+ * path: every tx the `/prepare` endpoints return is signed locally here.
119
+ *
120
+ * The tx already carries the API's recent blockhash + fee-payer (the user/test
121
+ * wallet); we only attach the test wallet's signature.
122
+ */
123
+ export function signBase64Transaction(config, base64Tx) {
124
+ const kp = loadTestKeypair(config);
125
+ const tx = VersionedTransaction.deserialize(Buffer.from(base64Tx, 'base64'));
126
+ tx.sign([kp]);
127
+ return Buffer.from(tx.serialize()).toString('base64');
128
+ }
129
+ //# sourceMappingURL=signing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.js","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { AgentConfig } from './config.js';
2
+ /** Thrown when a tx could not confirm before its blockhash expired. */
3
+ export declare class BlockhashExpiredError extends Error {
4
+ constructor(message: string);
5
+ }
6
+ /** Thrown when a tx landed but the program reverted. Carries decoded logs. */
7
+ export declare class OnChainRevertError extends Error {
8
+ readonly signature: string;
9
+ readonly logs: string[] | null;
10
+ constructor(message: string, signature: string, logs: string[] | null);
11
+ }
12
+ /**
13
+ * Submit ONE locally-signed base64 v0 transaction and wait for `confirmed`.
14
+ * Returns the signature. Rebroadcasts while the blockhash is valid (durable
15
+ * against dropped txs), then:
16
+ * - throws {@link BlockhashExpiredError} if the window closed un-confirmed,
17
+ * - throws {@link OnChainRevertError} (with logs) if the program reverted.
18
+ *
19
+ * `blockhash` + `lastValidBlockHeight` come from the `/prepare` response.
20
+ */
21
+ export declare function submitSignedTx(config: AgentConfig, signedBase64: string, blockhash: string, lastValidBlockHeight: number): Promise<string>;
22
+ /**
23
+ * Submit a batch of signed base64 txs IN ORDER, confirming each before the next.
24
+ * The zap-v2 open/close `/prepare` endpoints can return more than one tx (large
25
+ * baskets / split-VAA); they share one blockhash and MUST land sequentially.
26
+ *
27
+ * Propagates {@link BlockhashExpiredError} / {@link OnChainRevertError} from the
28
+ * first failing tx with the index annotated.
29
+ */
30
+ export declare function submitSignedTxsSequential(config: AgentConfig, signedBase64Txs: string[], blockhash: string, lastValidBlockHeight: number): Promise<string[]>;
31
+ //# sourceMappingURL=submit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../src/submit.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,uEAAuE;AACvE,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,8EAA8E;AAC9E,qBAAa,kBAAmB,SAAQ,KAAK;IAGzC,QAAQ,CAAC,SAAS,EAAE,MAAM;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;gBAF9B,OAAO,EAAE,MAAM,EACN,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;CAKjC;AAmBD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC,MAAM,CAAC,CA8DjB;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,WAAW,EACnB,eAAe,EAAE,MAAM,EAAE,EACzB,SAAS,EAAE,MAAM,EACjB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB"}