@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
package/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # @dfm-fi/agent — DFM v2 Agent Test Harness (MCP)
2
+
3
+ An MCP (Model Context Protocol) server that lets an external AI agent drive the
4
+ full DFM v2 **launch → deposit → redeem** DTF flow against the **live API**
5
+ (`https://n2-api.dfm.finance/api/v2`) programmatically — no web-UI clicking.
6
+
7
+ This is a **test harness for the founder + partner**: point your own AI agent
8
+ (Claude Desktop / Claude Code / any MCP client) at the live closed-mainnet API,
9
+ authenticate with your **own test-wallet keypair loaded locally**, and run the
10
+ whole vault lifecycle — create a DTF, deposit USDC, redeem back to USDC — from
11
+ the agent.
12
+
13
+ > ⚠️ This is a **real-money Solana mainnet** system. Read the Security section.
14
+
15
+ ## Prerequisites
16
+
17
+ - **Node 20+** (the repo targets Node; ESM build).
18
+ - A clone of the `dfm-v2` monorepo with its workspace deps installed at the
19
+ repo root (this package uses the hoisted `node_modules` — do **not** run
20
+ `npm install` inside `agent/`).
21
+ - A **dedicated throwaway Solana test wallet** (NOT the protocol wallet), funded
22
+ with a few dollars of **USDC** (mainnet mint `EPjFW…`) + a little **SOL** for
23
+ fees, and **allowlisted** for the closed alpha (send its pubkey to an admin).
24
+ - For the write path only: a **Helius mainnet RPC URL** (`HELIUS_RPC_URL`).
25
+
26
+ ## Security model (read first)
27
+
28
+ - The agent authenticates as **its own test wallet**, whose keypair is loaded
29
+ **locally by you** from a file path (`DFM_AGENT_KEYPAIR_PATH`) or an inline env
30
+ (`DFM_AGENT_KEYPAIR_JSON`). The keypair **never crosses the MCP boundary** — it
31
+ is never a tool argument, never in a tool result, never logged. Only the
32
+ **public key** is ever surfaced.
33
+ - **Never** use the protocol wallet (`9GjE…`) here. Use a **dedicated throwaway
34
+ test wallet** funded with a few dollars of USDC. The harness hard-refuses to
35
+ load the known protocol pubkey as a tripwire.
36
+ - The test wallet must be on the **closed-alpha access allowlist** — otherwise
37
+ SIWS sign-in is rejected **server-side** (403), so it can't reach any protected
38
+ endpoint. An admin adds it via the `/ops` Access panel (`POST /access/allowlist`).
39
+ - All **real-money WRITE tools** (deposit / redeem) are **gated behind
40
+ `DFM_AGENT_WRITE_ENABLED=true` and default OFF**. With write off, those tools
41
+ refuse and never touch the chain or load the keypair.
42
+
43
+ ## Auth + signing flow (how it works)
44
+
45
+ SIWS (Sign In With Solana), signed locally, exchanged for a Bearer session:
46
+
47
+ 1. `POST /auth/nonce { wallet }` → `{ nonce, message }` — the **server builds the
48
+ exact message** (domain-bound to `n2.dfm.finance`, nonce embedded).
49
+ 2. Sign **that exact message** locally with the test keypair (Ed25519 → base58).
50
+ 3. `POST /auth/siws { wallet, signature, message, client: 'native' }` →
51
+ `{ accessToken, … }`. The server also enforces the access gate here.
52
+ 4. Authed calls send `Authorization: Bearer <accessToken>`; a 401 triggers one
53
+ transparent re-auth + retry.
54
+
55
+ The WRITE flows then follow **prepare → sign locally → submit → (confirm/poll)**:
56
+ - **launch**: `/vaults/create/prepare` → one unsigned v0 tx → sign → submit →
57
+ `/vaults/create/confirm`.
58
+ - **deposit / redeem**: `/zap-…-v2/open/prepare` → sign → submit → poll
59
+ `/zap-v2/status` until the backend orchestrator has cranked all swap legs →
60
+ `/zap-…-v2/close/prepare` → sign → submit. The agent signs **only** the two
61
+ user-side boundary transactions; the backend cranks the permissionless legs.
62
+
63
+ ## Tools
64
+
65
+ | Tool | Surface | Endpoint | Notes |
66
+ |------|---------|----------|-------|
67
+ | `whoami` | read | `/access/status` | Test-wallet pubkey, cluster, write flag, gate status. **Call first.** |
68
+ | `list_dtfs` | read | `GET /vaults` | Lists vaults (address, symbol, TVL, fees, basket). Public. |
69
+ | `get_vault` | read | `GET /vaults/:address` | Full vault detail + weights + fee structure. Public. |
70
+ | `zap_status` | read (auth) | `GET /vaults/:address/zap-v2/status/:user` | Decoded escrow + per-leg crank progress, or null. |
71
+ | `get_portfolio` | read (auth) | `GET /portfolio` | Session wallet's positions (API reads wallet from JWT). |
72
+ | `launch_vault` | **write (gated)** | `create prepare/confirm` | Create a DTF. Basket sums to 10000 bps, ≤15 assets. |
73
+ | `deposit` | **write (gated)** | `zap-in-v2 open/close` | Full zap-in lifecycle. RAW 6dp USDC. Resumes an open escrow. |
74
+ | `redeem` | **write (gated)** | `zap-out-v2 open/close` | Full zap-out lifecycle. RAW 6dp shares. Resumes an open escrow. |
75
+ | `zap_v2_cancel` | **write (gated)** | `zap-v2/cancel/prepare` | Return a stalled escrow's holdings to the wallet, as-is. |
76
+ | `zap_v2_update_envelope` | **write (gated)** | `zap-v2/update-envelope/prepare` | Loosen the pinned floors (auto-derived from the live escrow) to unstick a crank. |
77
+ | `update_vault_assets` | **write (gated)** | `assets/prepare + confirm` | MANAGER: full-replace a vault's basket (sums to 10000, ≤15, no dupes; manual-mode + 24h timelock). Your own vault only. |
78
+ | `update_management_fee` | **write (gated)** | `PATCH :address/fees` | MANAGER: set the management fee (≤2000 bps). Reverts on immutable-fee vaults (which is what this agent creates). |
79
+ | `transfer_admin` | **write (gated)** | `:address/transfer-admin` | ⚠️ MANAGER, HIGH-SENSITIVITY: initiate handing vault control to another key (the new admin must ACCEPT). Your own vault only. |
80
+
81
+ ### Prompt-injection / safety model
82
+
83
+ The harness is **boxed in by design**, so a prompt-injected agent (tricked by malicious text it reads while browsing vaults) is bounded:
84
+ - **No "send funds to an address" tool exists.** `redeem` always pays *your own* wallet; `deposit` pulls from it. There is no way to route money to an attacker.
85
+ - **Every write only touches a vault/wallet the signed-in test wallet OWNS or ADMINS** (the API enforces `vault.admin == caller`), and amounts/slippage are capped by the on-chain guards (≤10% slippage, per-leg `min_outs`, the drain-guard, $10 floor, ≤15 assets, immutable fees).
86
+ - **The keypair never enters the agent's context** (only the pubkey), so injection can't exfiltrate it; the write-gate (`DFM_AGENT_WRITE_ENABLED`) is a hard local kill-switch.
87
+ - So the worst a hijacked agent can do is make *you* mis-spend *your own* money within the contract limits — **never the protocol, never other users, never key theft.** The one action to watch is `transfer_admin` (it gives away control of your own vault) — only invoke it when you explicitly intend it, never inferred from a vault's name/description.
88
+
89
+ ## Install
90
+
91
+ ### One line — once `@dfm-fi/agent` is published to npm
92
+
93
+ The package is **self-contained** (no monorepo deps) and ships its built `dist/`, so `npx` fetches + runs it — no clone, no build:
94
+
95
+ **Claude Code:**
96
+ ```bash
97
+ claude mcp add dfm \
98
+ --env DFM_AGENT_KEYPAIR_PATH=/abs/path/test-wallet.json \
99
+ --env HELIUS_RPC_URL=https://mainnet.helius-rpc.com/?api-key=YOUR_KEY \
100
+ --env DFM_AGENT_WRITE_ENABLED=true \
101
+ -- npx -y @dfm-fi/agent
102
+ ```
103
+
104
+ **Claude Desktop** (`claude_desktop_config.json`):
105
+ ```json
106
+ {
107
+ "mcpServers": {
108
+ "dfm": {
109
+ "command": "npx",
110
+ "args": ["-y", "@dfm-fi/agent"],
111
+ "env": {
112
+ "DFM_AGENT_KEYPAIR_PATH": "/abs/path/test-wallet.json",
113
+ "HELIUS_RPC_URL": "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY",
114
+ "DFM_AGENT_WRITE_ENABLED": "true"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+ (For read-only, drop `HELIUS_RPC_URL` + `DFM_AGENT_WRITE_ENABLED` — the read tools need neither.)
121
+
122
+ > **Publish it (one-time, owner only):** `cd agent && npm login && npm publish --access public`. After that, everyone installs with the one-liner above. (Needs the `@dfm` npm scope — create it free on npmjs.com, or rename the package.)
123
+
124
+ ### From source — works today, no publish needed
125
+
126
+ ```bash
127
+ cd dfm-v2/agent && npm run build # tsc -b → dist/
128
+ # then point your MCP client at the built binary (one line):
129
+ claude mcp add dfm -- node /abs/path/dfm-v2/agent/dist/mcp-server.js
130
+ ```
131
+
132
+ ## Quick start (read-only — safe)
133
+
134
+ ```bash
135
+ # Run the MCP server against the live API
136
+ DFM_API_URL=https://n2-api.dfm.finance \
137
+ DFM_AGENT_KEYPAIR_PATH=/abs/path/test-wallet.json \
138
+ npm start # = node dist/mcp-server.js
139
+ ```
140
+
141
+ Or exercise the read path without MCP:
142
+
143
+ ```bash
144
+ DFM_API_URL=https://n2-api.dfm.finance \
145
+ DFM_AGENT_KEYPAIR_PATH=/abs/path/test-wallet.json \
146
+ npx tsx src/examples/list-and-status.ts
147
+ ```
148
+
149
+ ## Loading the test keypair
150
+
151
+ Generate a dedicated throwaway wallet and fund it with a little USDC + SOL:
152
+
153
+ ```bash
154
+ solana-keygen new --no-bip39-passphrase -o ~/dfm-test-wallet.json
155
+ solana-keygen pubkey ~/dfm-test-wallet.json # send this pubkey to an admin to allowlist
156
+ ```
157
+
158
+ Then either point the agent at the file (preferred):
159
+
160
+ ```bash
161
+ export DFM_AGENT_KEYPAIR_PATH=$HOME/dfm-test-wallet.json
162
+ ```
163
+
164
+ …or inline the JSON array (e.g. in a secret manager):
165
+
166
+ ```bash
167
+ export DFM_AGENT_KEYPAIR_JSON="$(cat ~/dfm-test-wallet.json)"
168
+ ```
169
+
170
+ ## Enabling the real-money launch → deposit → redeem loop
171
+
172
+ Only after the parent has reviewed the write path (`create-flow.ts`,
173
+ `zap-v2-flow.ts`, `recovery-flow.ts`, `signing.ts`, `submit.ts`):
174
+
175
+ ```bash
176
+ export DFM_API_URL=https://n2-api.dfm.finance
177
+ export HELIUS_RPC_URL=https://mainnet.helius-rpc.com/?api-key=YOUR_KEY # required for submit
178
+ export DFM_AGENT_KEYPAIR_PATH=$HOME/dfm-test-wallet.json # allowlisted + funded
179
+ export DFM_AGENT_WRITE_ENABLED=true # the kill-switch
180
+
181
+ # End-to-end example: launch a demo DTF, deposit $12, redeem the full position.
182
+ # (Runs as a SAFE DRY-RUN — printing the calls it would make — when write is OFF.)
183
+ npx tsx src/examples/launch-deposit-redeem.ts
184
+ ```
185
+
186
+ ### Copy-paste walkthrough (in an MCP client / agent)
187
+
188
+ ```
189
+ 1. whoami
190
+ → confirm the test-wallet pubkey + that accessGate.allowed is true.
191
+
192
+ 2. launch_vault
193
+ {
194
+ "name": "My First DTF",
195
+ "symbol": "MYDTF",
196
+ "assets": [
197
+ { "mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", "symbol": "ETH", "allocationBps": 5000 },
198
+ { "mint": "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", "symbol": "JUP", "allocationBps": 5000 }
199
+ ],
200
+ "managementFeeBps": 100,
201
+ "exitFeeBps": 100
202
+ }
203
+ → returns { vault: "<address>", signature, ... }. Note the vault address.
204
+ (These two mints are already registered + Pyth-mapped on mainnet. To use
205
+ others, list candidates with GET /assets and make sure each is registered.)
206
+
207
+ 3. deposit
208
+ { "vault": "<address from step 2>", "usdcAmount": "12000000" } // $12 raw (6dp)
209
+ → drives open → orchestrator cranks → close; returns when shares are minted.
210
+
211
+ 4. get_portfolio
212
+ → read the resulting raw share balance for that vault.
213
+
214
+ 5. redeem
215
+ { "vault": "<address>", "shares": "<raw shares from step 4>" }
216
+ → drives open → cranks → close; returns net USDC paid (minus the 1% exit fee).
217
+
218
+ If a deposit/redeem STALLS:
219
+ zap_status { vault, user } → inspect per-leg crank progress + failures
220
+ zap_v2_update_envelope { vault } → loosen the floors 5% and let the crank retry
221
+ zap_v2_cancel { vault } → give up and get the held funds back, as-is
222
+ ```
223
+
224
+ Notes:
225
+ - **Amounts are RAW 6-decimal**: $12 = `"12000000"`, 1 share = `"1000000"`.
226
+ - The **first deposit** into a vault must clear ~**$12** so it stays above the
227
+ $10 floor after slippage.
228
+ - `allocationBps` MUST sum to exactly **10000** across the basket; **≤15 assets**
229
+ on mainnet.
230
+ - `deposit`/`redeem` are **resumable**: if a prior open landed but its close
231
+ never did, calling the same tool again resumes (poll → close) instead of
232
+ re-opening.
233
+
234
+ ## Configure Claude Desktop
235
+
236
+ `~/Library/Application Support/Claude/claude_desktop_config.json`:
237
+
238
+ ```json
239
+ {
240
+ "mcpServers": {
241
+ "dfm": {
242
+ "command": "node",
243
+ "args": ["/abs/path/dfm-v2/agent/dist/mcp-server.js"],
244
+ "env": {
245
+ "DFM_API_URL": "https://n2-api.dfm.finance",
246
+ "DFM_AGENT_KEYPAIR_PATH": "/abs/path/dfm-test-wallet.json",
247
+ "SOLANA_CLUSTER": "mainnet-beta"
248
+ }
249
+ }
250
+ }
251
+ }
252
+ ```
253
+
254
+ (Leave `DFM_AGENT_WRITE_ENABLED` unset for a read-only agent. Add
255
+ `HELIUS_RPC_URL` + `DFM_AGENT_WRITE_ENABLED=true` only when enabling writes.)
256
+
257
+ ## Environment variables
258
+
259
+ | Variable | Required | Default | Description |
260
+ |----------|----------|---------|-------------|
261
+ | `DFM_API_URL` | No | `https://n2-api.dfm.finance` | API base (the `/api/v2` prefix is auto-appended). |
262
+ | `DFM_AGENT_KEYPAIR_PATH` | For auth | — | Path to a Solana secret-key JSON file (preferred). The wallet must be **allowlisted** + **funded** (USDC + a little SOL). |
263
+ | `DFM_AGENT_KEYPAIR_JSON` | For auth | — | The secret-key JSON array inline (alternative; e.g. injected from a secret manager). |
264
+ | `DFM_AGENT_WRITE_ENABLED` | No | `false` | Master kill-switch for **all** write tools (launch/deposit/redeem/cancel/update-envelope). |
265
+ | `HELIUS_RPC_URL` / `DFM_RPC_URL` | For write | — | RPC to submit signed txs (mainnet refuses the public RPC fallback). |
266
+ | `SOLANA_CLUSTER` | No | `mainnet-beta` | `mainnet-beta` or `devnet`. |
267
+
268
+ ## Architecture
269
+
270
+ ```
271
+ Agent / MCP client
272
+ │ stdio (MCP)
273
+
274
+ MCP server (this package)
275
+ ├─ read tools ─────────► DFM v2 API (public + authed GET)
276
+ └─ write tools (gated) ─► DFM v2 API /prepare ──► unsigned v0 tx(s)
277
+
278
+ sign LOCALLY with test keypair (signing.ts)
279
+
280
+ submit via RPC (submit.ts) — rebroadcast in-window,
281
+ │ re-prepare on blockhash expiry
282
+ ┌─────────────────────┴─────────────────────┐
283
+ launch: confirm via /create/confirm deposit/redeem: poll /zap-v2/status
284
+ until legs cranked,
285
+ then /close → sign → submit
286
+ ```
287
+
288
+ The backend orchestrator (server-side) cranks the permissionless Jupiter swap
289
+ legs — the agent only signs the two user-side boundary transactions. The agent
290
+ does **not** crank legs and does **not** hold the protocol key.
291
+
292
+ ## Source map
293
+
294
+ | File | Role |
295
+ |------|------|
296
+ | `src/mcp-server.ts` | MCP stdio server; registers the 10 tools + the write gate. |
297
+ | `src/config.ts` | Env → `AgentConfig` (API URL, cluster, RPC, write flag, keypair source). |
298
+ | `src/session.ts` | SIWS sign-in → Bearer session; in-flight dedup; transparent re-auth on 401. |
299
+ | `src/signing.ts` | The signing boundary — loads the local keypair, signs SIWS + v0 txs. Refuses the protocol wallet; never logs key material. |
300
+ | `src/submit.ts` | RPC submit + confirm; rebroadcast in-window; `BlockhashExpiredError` / `OnChainRevertError`. |
301
+ | `src/api-client.ts` | Typed DFM v2 API client (public + authed; create + zap-v2 prepare/confirm). |
302
+ | `src/create-flow.ts` | `launch_vault` driver: prepare → sign → submit → confirm (+ ghost-vault recovery). |
303
+ | `src/zap-v2-flow.ts` | `deposit` / `redeem` lifecycle drivers (resume-aware, close-retry). |
304
+ | `src/recovery-flow.ts` | `zap_v2_cancel` + `zap_v2_update_envelope` (floors auto-derived from the live escrow). |
305
+ | `src/types.ts` | Response shapes mirrored against the live API. |
306
+
307
+ ## What remains for the parent to review/enable
308
+
309
+ All write tools are **fully implemented** but gated OFF (`DFM_AGENT_WRITE_ENABLED`
310
+ unset). Before flipping the gate, review the real-money path (search for the
311
+ `// REVIEW: real-money` markers):
312
+
313
+ - **`launch_vault`** (`create-flow.ts`) — pulls the on-chain creation fee from
314
+ the test wallet; the test wallet becomes the vault admin. Confirm the basket /
315
+ fee defaults are what you want.
316
+ - **`deposit` / `redeem`** (`zap-v2-flow.ts`) — move USDC ↔ shares. They are
317
+ resume-aware (won't double-open) and retry the close on blockhash expiry.
318
+ - **`zap_v2_cancel` / `zap_v2_update_envelope`** (`recovery-flow.ts`) — stall
319
+ recovery. `update_envelope` only ever LOOSENS, with the new floors derived from
320
+ the live escrow's pinned `minOuts` (never hand-supplied).
321
+ - **`signing.ts` / `submit.ts`** — the signing boundary + submit robustness.
322
+ Confirm the protocol-wallet tripwire + the "secret never leaves this module"
323
+ invariant.
324
+
325
+ To roll back at any time: unset `DFM_AGENT_WRITE_ENABLED` (the write tools then
326
+ refuse and never touch the chain or load the keypair).
@@ -0,0 +1,137 @@
1
+ /**
2
+ * DFM v2 API client.
3
+ *
4
+ * Two request surfaces:
5
+ * - `publicRequest` — no auth (for `GET /vaults`, `/vaults/:address`,
6
+ * `/access/status`). These are `@Public()` on the API.
7
+ * - `authRequest` — attaches `Authorization: Bearer <token>` from the SIWS
8
+ * session; on a 401 it re-authenticates once and retries. Used for
9
+ * `/portfolio`, `/vaults/:address/zap-v2/status/:user`, and every
10
+ * `/prepare` endpoint.
11
+ *
12
+ * All addresses are validated as base58 before hitting the network. The client
13
+ * NEVER sees the secret key — signing is delegated to `signing.ts` via the
14
+ * write methods, and auth is delegated to `SiwsSession`.
15
+ */
16
+ import type { AgentConfig } from './config.js';
17
+ import { SiwsSession } from './session.js';
18
+ import type { VaultListResponse, VaultDetailResponse, ZapV2Status, ZapV2PrepareResponse, ZapV2SingleTxResponse, AccessStatus, CreateAssetInput, CreatePrepareResponse, CreateConfirmResponse } from './types.js';
19
+ export declare class DfmApiClient {
20
+ private readonly session;
21
+ private readonly baseUrl;
22
+ constructor(config: AgentConfig, session: SiwsSession);
23
+ private publicRequest;
24
+ private authRequest;
25
+ /** `GET /vaults` (public). Supports the API's documented query params. */
26
+ listVaults(params?: {
27
+ category?: string;
28
+ dtfType?: string;
29
+ status?: string;
30
+ sortBy?: string;
31
+ page?: number;
32
+ limit?: number;
33
+ }): Promise<VaultListResponse>;
34
+ /** `GET /vaults/:address` (public) — wraps the doc under `{ vault, ... }`. */
35
+ getVault(address: string): Promise<VaultDetailResponse>;
36
+ /** `GET /access/status?wallet=` (public) — closed-alpha gate decision. */
37
+ getAccessStatus(wallet: string): Promise<AccessStatus>;
38
+ /**
39
+ * `GET /vaults/:address/zap-v2/status/:user` (auth) — decoded ZapEscrowV2 or
40
+ * null. The session wallet must equal `user` (or be the vault admin), else 403.
41
+ * Returns `null` when the user has no open escrow.
42
+ */
43
+ getZapV2Status(vaultAddress: string, user: string): Promise<ZapV2Status | null>;
44
+ /**
45
+ * `GET /portfolio` (auth) — the API reads the wallet from the JWT; there is NO
46
+ * portfolio-by-arbitrary-address endpoint. So this returns the SESSION
47
+ * wallet's positions. (To inspect another wallet you'd need that wallet's
48
+ * keypair / session.)
49
+ */
50
+ getPortfolioPositions(): Promise<unknown>;
51
+ /** `GET /portfolio/summary` (auth) — total value + PnL for the session wallet. */
52
+ getPortfolioSummary(): Promise<unknown>;
53
+ /** `POST /vaults/:address/zap-in-v2/open/prepare` — pull USDC, pin plan. */
54
+ prepareZapInOpenV2(vaultAddress: string, usdcAmountRaw: string, opts?: {
55
+ slippageBps?: number;
56
+ expirySecs?: number;
57
+ }): Promise<ZapV2PrepareResponse>;
58
+ /** `POST /vaults/:address/zap-in-v2/close/prepare` — CPI mint_in_kind_v2. */
59
+ prepareZapInCloseV2(vaultAddress: string): Promise<ZapV2PrepareResponse>;
60
+ /** `POST /vaults/:address/zap-out-v2/open/prepare` — burn shares → escrow. */
61
+ prepareZapOutOpenV2(vaultAddress: string, sharesRaw: string, opts?: {
62
+ slippageBps?: number;
63
+ expirySecs?: number;
64
+ }): Promise<ZapV2PrepareResponse>;
65
+ /** `POST /vaults/:address/zap-out-v2/close/prepare` — exit fee, pay net USDC. */
66
+ prepareZapOutCloseV2(vaultAddress: string): Promise<ZapV2PrepareResponse>;
67
+ /**
68
+ * `POST /vaults/:address/zap-v2/cancel/prepare` — return the escrow's current
69
+ * USDC + per-asset balances to the test wallet as-is (no swaps, no oracle),
70
+ * then close it. 404 server-side when no escrow is open. Single v0 tx.
71
+ */
72
+ prepareZapCancelV2(vaultAddress: string): Promise<ZapV2SingleTxResponse>;
73
+ /**
74
+ * `POST /vaults/:address/zap-v2/update-envelope/prepare` — LOOSEN the pinned
75
+ * per-leg floors + slippage (and optionally extend expiry) so a stalled escrow
76
+ * can complete. Monotonic loosening is enforced on-chain; the API rejects any
77
+ * non-positive `newMinOuts`. Single v0 tx.
78
+ */
79
+ prepareUpdateEnvelopeV2(vaultAddress: string, body: {
80
+ newMinOuts: string[];
81
+ newSlippageBps: number;
82
+ newMinUsdcOut?: string;
83
+ extendSecs?: number;
84
+ }): Promise<ZapV2SingleTxResponse>;
85
+ /**
86
+ * `POST /vaults/create/prepare` — build the on-chain `create_vault` tx. The
87
+ * creator is the SESSION wallet (from the JWT), not a body field. Returns a
88
+ * single unsigned v0 tx + the `vaultAddress` PDA + a server-built ALT.
89
+ */
90
+ prepareCreateVault(params: {
91
+ name: string;
92
+ symbol: string;
93
+ dtfType: string;
94
+ category: number;
95
+ assets: CreateAssetInput[];
96
+ entryFeeBps: number;
97
+ exitFeeBps: number;
98
+ managementFeeBps: number;
99
+ description?: string;
100
+ metadataUri?: string;
101
+ rebalanceType?: number;
102
+ rebalanceThresholdBps?: number;
103
+ tags?: number[];
104
+ immutable?: boolean;
105
+ }): Promise<CreatePrepareResponse>;
106
+ /**
107
+ * `POST /vaults/create/confirm` — record the vault doc after the create tx
108
+ * confirms. Only `signature` + `vaultAddress` are authoritative; the API reads
109
+ * the economic params back from its prepare-cache (so they can't be tampered
110
+ * post-prepare). MUST be called inside the cache TTL (~15 min).
111
+ */
112
+ confirmCreateVault(signature: string, vaultAddress: string): Promise<CreateConfirmResponse>;
113
+ /**
114
+ * `POST /vaults/:address/assets/prepare` (vault admin) — build an
115
+ * `update_vault_assets` FULL-REPLACE basket tx. The API enforces the same
116
+ * guards as the chain (manual mode, 24h timelock, Σ bps == 10000, no dupes,
117
+ * ≤15 on mainnet) → clean 4xx instead of a chain revert.
118
+ */
119
+ prepareUpdateAssets(vaultAddress: string, assets: CreateAssetInput[]): Promise<ZapV2SingleTxResponse>;
120
+ /** `POST /vaults/:address/assets/confirm` — record the basket change post-broadcast. */
121
+ confirmUpdateAssets(vaultAddress: string, signature: string): Promise<{
122
+ status: string;
123
+ signature: string;
124
+ }>;
125
+ /**
126
+ * `PATCH /vaults/:address/fees` (vault admin) — build an `update_management_fee`
127
+ * tx (bps ≤2000). Reverts on a fees-immutable vault.
128
+ */
129
+ prepareUpdateManagementFee(vaultAddress: string, managementFeeBps: number): Promise<ZapV2SingleTxResponse>;
130
+ /**
131
+ * `POST /vaults/:address/transfer-admin` (vault admin) — initiate transferring
132
+ * vault admin to `newAdmin` (the new admin must ACCEPT separately). HIGH
133
+ * sensitivity — gates the agent's `transfer_admin` tool.
134
+ */
135
+ prepareTransferAdmin(vaultAddress: string, newAdmin: string): Promise<ZapV2SingleTxResponse>;
136
+ }
137
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}