@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.
- package/README.md +326 -0
- package/dist/api-client.d.ts +137 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +215 -0
- package/dist/api-client.js.map +1 -0
- package/dist/config.d.ts +56 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -0
- package/dist/create-flow.d.ts +62 -0
- package/dist/create-flow.d.ts.map +1 -0
- package/dist/create-flow.js +88 -0
- package/dist/create-flow.js.map +1 -0
- package/dist/examples/deposit-redeem-loop.d.ts +2 -0
- package/dist/examples/deposit-redeem-loop.d.ts.map +1 -0
- package/dist/examples/deposit-redeem-loop.js +67 -0
- package/dist/examples/deposit-redeem-loop.js.map +1 -0
- package/dist/examples/launch-deposit-redeem.d.ts +2 -0
- package/dist/examples/launch-deposit-redeem.d.ts.map +1 -0
- package/dist/examples/launch-deposit-redeem.js +166 -0
- package/dist/examples/launch-deposit-redeem.js.map +1 -0
- package/dist/examples/list-and-status.d.ts +2 -0
- package/dist/examples/list-and-status.d.ts.map +1 -0
- package/dist/examples/list-and-status.js +67 -0
- package/dist/examples/list-and-status.js.map +1 -0
- package/dist/manager-flow.d.ts +73 -0
- package/dist/manager-flow.d.ts.map +1 -0
- package/dist/manager-flow.js +110 -0
- package/dist/manager-flow.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +529 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/recovery-flow.d.ts +81 -0
- package/dist/recovery-flow.d.ts.map +1 -0
- package/dist/recovery-flow.js +123 -0
- package/dist/recovery-flow.js.map +1 -0
- package/dist/session.d.ts +52 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +107 -0
- package/dist/session.js.map +1 -0
- package/dist/signing.d.ts +30 -0
- package/dist/signing.d.ts.map +1 -0
- package/dist/signing.js +129 -0
- package/dist/signing.js.map +1 -0
- package/dist/submit.d.ts +31 -0
- package/dist/submit.d.ts.map +1 -0
- package/dist/submit.js +165 -0
- package/dist/submit.js.map +1 -0
- package/dist/types.d.ts +191 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/zap-v2-flow.d.ts +76 -0
- package/dist/zap-v2-flow.d.ts.map +1 -0
- package/dist/zap-v2-flow.js +176 -0
- package/dist/zap-v2-flow.js.map +1 -0
- package/package.json +60 -0
- package/skills.md +153 -0
package/dist/submit.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction submission + confirmation for the WRITE path.
|
|
3
|
+
*
|
|
4
|
+
* Only used by the gated zap-v2 / create lifecycles. Reads `config.rpcUrl`
|
|
5
|
+
* (Helius on mainnet — public RPC is refused for mainnet in config). The agent
|
|
6
|
+
* submits the locally-signed base64 v0 transactions returned by the `/prepare`
|
|
7
|
+
* endpoints.
|
|
8
|
+
*
|
|
9
|
+
* Robustness model:
|
|
10
|
+
* - One Connection per process (cached).
|
|
11
|
+
* - Each tx is resent while its blockhash is still valid; we poll the
|
|
12
|
+
* signature status ourselves rather than trusting a single
|
|
13
|
+
* `confirmTransaction`, so a dropped tx is rebroadcast inside the window.
|
|
14
|
+
* - On blockhash expiry we throw `BlockhashExpiredError` (a distinct,
|
|
15
|
+
* catchable type) so the caller can RE-PREPARE (the only correct recovery
|
|
16
|
+
* for an expired v0 tx — you cannot re-sign it with a new blockhash without
|
|
17
|
+
* re-fetching the instructions from the API).
|
|
18
|
+
* - On-chain failure throws with the decoded program error logs attached so an
|
|
19
|
+
* agent can act on the reason instead of an opaque `{"Custom":6040}`.
|
|
20
|
+
*
|
|
21
|
+
* REVIEW: real-money path — parent must review before enabling.
|
|
22
|
+
*/
|
|
23
|
+
import { Connection, VersionedTransaction } from '@solana/web3.js';
|
|
24
|
+
let cachedConn = null;
|
|
25
|
+
/** Thrown when a tx could not confirm before its blockhash expired. */
|
|
26
|
+
export class BlockhashExpiredError extends Error {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = 'BlockhashExpiredError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Thrown when a tx landed but the program reverted. Carries decoded logs. */
|
|
33
|
+
export class OnChainRevertError extends Error {
|
|
34
|
+
signature;
|
|
35
|
+
logs;
|
|
36
|
+
constructor(message, signature, logs) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.signature = signature;
|
|
39
|
+
this.logs = logs;
|
|
40
|
+
this.name = 'OnChainRevertError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function getConnection(config) {
|
|
44
|
+
if (!config.rpcUrl) {
|
|
45
|
+
throw new Error('No RPC endpoint configured. Set HELIUS_RPC_URL (or DFM_RPC_URL) to submit ' +
|
|
46
|
+
'signed transactions. The read tools do not need it.');
|
|
47
|
+
}
|
|
48
|
+
if (!cachedConn) {
|
|
49
|
+
cachedConn = new Connection(config.rpcUrl, 'confirmed');
|
|
50
|
+
}
|
|
51
|
+
return cachedConn;
|
|
52
|
+
}
|
|
53
|
+
async function sleep(ms) {
|
|
54
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Submit ONE locally-signed base64 v0 transaction and wait for `confirmed`.
|
|
58
|
+
* Returns the signature. Rebroadcasts while the blockhash is valid (durable
|
|
59
|
+
* against dropped txs), then:
|
|
60
|
+
* - throws {@link BlockhashExpiredError} if the window closed un-confirmed,
|
|
61
|
+
* - throws {@link OnChainRevertError} (with logs) if the program reverted.
|
|
62
|
+
*
|
|
63
|
+
* `blockhash` + `lastValidBlockHeight` come from the `/prepare` response.
|
|
64
|
+
*/
|
|
65
|
+
export async function submitSignedTx(config, signedBase64, blockhash, lastValidBlockHeight) {
|
|
66
|
+
const conn = getConnection(config);
|
|
67
|
+
const raw = VersionedTransaction.deserialize(Buffer.from(signedBase64, 'base64')).serialize();
|
|
68
|
+
// First broadcast. skipPreflight=false so a malformed/failing tx surfaces its
|
|
69
|
+
// simulation error immediately rather than silently never landing.
|
|
70
|
+
let signature;
|
|
71
|
+
try {
|
|
72
|
+
signature = await conn.sendRawTransaction(raw, { skipPreflight: false, maxRetries: 5 });
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
throw enrichSendError(e);
|
|
76
|
+
}
|
|
77
|
+
// Poll-and-rebroadcast loop. We drive confirmation ourselves (instead of a
|
|
78
|
+
// single `confirmTransaction`) so we can re-send the SAME signed tx while the
|
|
79
|
+
// blockhash is valid — the RPC may drop the first broadcast under load.
|
|
80
|
+
const POLL_MS = 2_000;
|
|
81
|
+
const REBROADCAST_EVERY = 2; // re-send every ~4s
|
|
82
|
+
let ticks = 0;
|
|
83
|
+
for (;;) {
|
|
84
|
+
const { value } = await conn.getSignatureStatus(signature, { searchTransactionHistory: false });
|
|
85
|
+
if (value) {
|
|
86
|
+
if (value.err) {
|
|
87
|
+
const logs = await fetchLogs(conn, signature);
|
|
88
|
+
throw new OnChainRevertError(`Transaction ${signature} reverted on-chain: ${JSON.stringify(value.err)}` +
|
|
89
|
+
(logs?.length ? `\nProgram logs:\n${logs.join('\n')}` : ''), signature, logs);
|
|
90
|
+
}
|
|
91
|
+
if (value.confirmationStatus === 'confirmed' || value.confirmationStatus === 'finalized') {
|
|
92
|
+
return signature;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Has the blockhash expired? Once the cluster's block height passes
|
|
96
|
+
// lastValidBlockHeight, the tx can never land — re-prepare is the only fix.
|
|
97
|
+
const height = await conn.getBlockHeight('confirmed');
|
|
98
|
+
if (height > lastValidBlockHeight) {
|
|
99
|
+
// Final status check to avoid a race where it confirmed on the last tick.
|
|
100
|
+
const final = await conn.getSignatureStatus(signature, { searchTransactionHistory: true });
|
|
101
|
+
if (final.value && !final.value.err)
|
|
102
|
+
return signature;
|
|
103
|
+
throw new BlockhashExpiredError(`Transaction ${signature} (blockhash ${blockhash.slice(0, 8)}…) did not confirm before ` +
|
|
104
|
+
`its blockhash expired (block height ${height} > lastValid ${lastValidBlockHeight}). ` +
|
|
105
|
+
`Re-prepare and resubmit — an expired v0 transaction cannot be re-signed with a new blockhash.`);
|
|
106
|
+
}
|
|
107
|
+
ticks += 1;
|
|
108
|
+
if (ticks % REBROADCAST_EVERY === 0) {
|
|
109
|
+
// Best-effort rebroadcast; ignore send errors here (the poll loop owns the
|
|
110
|
+
// success/expiry decision).
|
|
111
|
+
try {
|
|
112
|
+
await conn.sendRawTransaction(raw, { skipPreflight: true, maxRetries: 0 });
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
/* transient — the next poll re-evaluates */
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
await sleep(POLL_MS);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Submit a batch of signed base64 txs IN ORDER, confirming each before the next.
|
|
123
|
+
* The zap-v2 open/close `/prepare` endpoints can return more than one tx (large
|
|
124
|
+
* baskets / split-VAA); they share one blockhash and MUST land sequentially.
|
|
125
|
+
*
|
|
126
|
+
* Propagates {@link BlockhashExpiredError} / {@link OnChainRevertError} from the
|
|
127
|
+
* first failing tx with the index annotated.
|
|
128
|
+
*/
|
|
129
|
+
export async function submitSignedTxsSequential(config, signedBase64Txs, blockhash, lastValidBlockHeight) {
|
|
130
|
+
const sigs = [];
|
|
131
|
+
for (let i = 0; i < signedBase64Txs.length; i++) {
|
|
132
|
+
try {
|
|
133
|
+
sigs.push(await submitSignedTx(config, signedBase64Txs[i], blockhash, lastValidBlockHeight));
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
const prefix = signedBase64Txs.length > 1 ? `tx ${i + 1}/${signedBase64Txs.length}: ` : '';
|
|
137
|
+
if (e instanceof Error)
|
|
138
|
+
e.message = prefix + e.message;
|
|
139
|
+
throw e;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return sigs;
|
|
143
|
+
}
|
|
144
|
+
/** Attach simulation logs to a send-time failure when the RPC provides them. */
|
|
145
|
+
function enrichSendError(e) {
|
|
146
|
+
const err = e;
|
|
147
|
+
if (Array.isArray(err.logs) && err.logs.length > 0) {
|
|
148
|
+
return new Error(`${err.message}\nProgram logs:\n${err.logs.join('\n')}`);
|
|
149
|
+
}
|
|
150
|
+
return err instanceof Error ? err : new Error(String(e));
|
|
151
|
+
}
|
|
152
|
+
/** Best-effort fetch of the confirmed tx's program logs for diagnostics. */
|
|
153
|
+
async function fetchLogs(conn, signature) {
|
|
154
|
+
try {
|
|
155
|
+
const tx = await conn.getTransaction(signature, {
|
|
156
|
+
maxSupportedTransactionVersion: 0,
|
|
157
|
+
commitment: 'confirmed',
|
|
158
|
+
});
|
|
159
|
+
return tx?.meta?.logMessages ?? null;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../src/submit.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for agent responses.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the LIVE DFM v2 API (`/api/v2`, NestJS) response shapes as
|
|
5
|
+
* verified against https://n2-api.dfm.finance — NOT the older zap-v1 shapes the
|
|
6
|
+
* previous version of this file assumed. Key corrections vs the stale version:
|
|
7
|
+
* - vault identity field is `address` (base58 PDA), not `id`
|
|
8
|
+
* - name/symbol are `vaultName` / `vaultSymbol`
|
|
9
|
+
* - `tvl`, `totalSupply`, `totalAssets` are STRING-encoded (raw integers or
|
|
10
|
+
* decimal strings) — never assume `number`
|
|
11
|
+
* - basket lives in `underlyingAssets`, each `{ mint, allocationBps, ... }`
|
|
12
|
+
* - `GET /vaults/:address` wraps the doc under `{ vault, status, ... }`
|
|
13
|
+
* - `GET /portfolio` reads the wallet from the JWT (no address param)
|
|
14
|
+
*/
|
|
15
|
+
/** One basket leg as stored on the vault doc (`underlyingAssets[]`). */
|
|
16
|
+
export interface UnderlyingAsset {
|
|
17
|
+
mint: string;
|
|
18
|
+
/** Target weight in bps (sums to 10_000 across the basket). */
|
|
19
|
+
allocationBps?: number;
|
|
20
|
+
/** Some payloads also surface a live/current weight; optional. */
|
|
21
|
+
currentBps?: number;
|
|
22
|
+
symbol?: string;
|
|
23
|
+
decimals?: number;
|
|
24
|
+
/** Live USD weight (%), when the detail endpoint computes it. */
|
|
25
|
+
weightPercent?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Vault list item as returned by `GET /vaults` (under `{ vaults: [...] }`).
|
|
29
|
+
* Only the fields the agent surfaces are typed strictly; the rest are loose.
|
|
30
|
+
*/
|
|
31
|
+
export interface VaultListItem {
|
|
32
|
+
address: string;
|
|
33
|
+
vaultName: string;
|
|
34
|
+
vaultSymbol: string;
|
|
35
|
+
dtfType?: 'index' | 'yield' | 'perps' | string;
|
|
36
|
+
status?: 'active' | 'paused' | 'closed' | string;
|
|
37
|
+
paused?: boolean;
|
|
38
|
+
closed?: boolean;
|
|
39
|
+
category?: string;
|
|
40
|
+
/** STRING-encoded — raw USDC (6dp) or decimal string depending on endpoint. */
|
|
41
|
+
tvl?: string | number;
|
|
42
|
+
/** Share price as a number (USDC per share). */
|
|
43
|
+
sharePrice?: number;
|
|
44
|
+
entryFeeBps?: number;
|
|
45
|
+
exitFeeBps?: number;
|
|
46
|
+
managementFeeBps?: number;
|
|
47
|
+
totalSupply?: string;
|
|
48
|
+
totalShares?: string;
|
|
49
|
+
totalDepositors?: number;
|
|
50
|
+
apy?: number;
|
|
51
|
+
performance7d?: number;
|
|
52
|
+
underlyingAssets?: UnderlyingAsset[];
|
|
53
|
+
}
|
|
54
|
+
/** `GET /vaults` envelope. */
|
|
55
|
+
export interface VaultListResponse {
|
|
56
|
+
vaults: VaultListItem[];
|
|
57
|
+
total: number;
|
|
58
|
+
page: number;
|
|
59
|
+
limit: number;
|
|
60
|
+
totalPages: number;
|
|
61
|
+
}
|
|
62
|
+
/** `GET /vaults/:address` envelope (the vault doc is nested under `vault`). */
|
|
63
|
+
export interface VaultDetailResponse {
|
|
64
|
+
vault: VaultListItem & Record<string, unknown>;
|
|
65
|
+
status?: unknown;
|
|
66
|
+
currentWeights?: unknown;
|
|
67
|
+
deviations?: unknown;
|
|
68
|
+
feeStructure?: unknown;
|
|
69
|
+
maxVaultTvlUsdc?: string | number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Decoded `ZapEscrowV2` from `GET /vaults/:address/zap-v2/status/:user`.
|
|
73
|
+
* Returns `null` when the user has no open escrow for that vault. Auth-gated:
|
|
74
|
+
* the caller JWT wallet must equal `:user` (or be the vault admin).
|
|
75
|
+
* `mode`: 0 = zap-in (deposit), 1 = zap-out (redeem).
|
|
76
|
+
*/
|
|
77
|
+
export interface ZapV2Status {
|
|
78
|
+
escrowPda: string;
|
|
79
|
+
vault: string;
|
|
80
|
+
user: string;
|
|
81
|
+
mode: number;
|
|
82
|
+
state: number;
|
|
83
|
+
nAssets: number;
|
|
84
|
+
assetMints: string[];
|
|
85
|
+
filledMask: number;
|
|
86
|
+
legProgress: boolean[];
|
|
87
|
+
legsFilled: number;
|
|
88
|
+
legsTotal: number;
|
|
89
|
+
/** True once every leg is cranked AND the escrow is in its terminal pre-close state. */
|
|
90
|
+
readyToClose: boolean;
|
|
91
|
+
legFailures: Array<{
|
|
92
|
+
count: number;
|
|
93
|
+
lastError: string;
|
|
94
|
+
} | null>;
|
|
95
|
+
openedAt: number;
|
|
96
|
+
expiresAt: number;
|
|
97
|
+
isExpired: boolean;
|
|
98
|
+
slippageBps: number;
|
|
99
|
+
plannedAmountIn: string[];
|
|
100
|
+
minOuts: string[];
|
|
101
|
+
actualOuts: string[];
|
|
102
|
+
inputAmount: string;
|
|
103
|
+
sharesIn: string;
|
|
104
|
+
minSharesOut: string;
|
|
105
|
+
minUsdcOut: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Common HTTP shape for the zap-v2 user-signed boundary builders
|
|
109
|
+
* (`zap-in-v2/open`, `zap-in-v2/close`, `zap-out-v2/open`, `zap-out-v2/close`).
|
|
110
|
+
* `transactions` are base64-encoded v0 `VersionedTransaction`s sharing one
|
|
111
|
+
* blockhash; the agent must sign EACH locally with the test keypair, then submit.
|
|
112
|
+
*/
|
|
113
|
+
export interface ZapV2PrepareResponse {
|
|
114
|
+
transactions: string[];
|
|
115
|
+
blockhash: string;
|
|
116
|
+
lastValidBlockHeight: number;
|
|
117
|
+
computeUnits: number;
|
|
118
|
+
escrowPda: string;
|
|
119
|
+
/** zap-out OPEN additionally returns these (redeem economics). */
|
|
120
|
+
minUsdcOut?: string;
|
|
121
|
+
expectedUsdc?: string;
|
|
122
|
+
minOuts?: string[];
|
|
123
|
+
}
|
|
124
|
+
/** Single-tx cancel/update-envelope prepare shape. */
|
|
125
|
+
export interface ZapV2SingleTxResponse {
|
|
126
|
+
transaction: string;
|
|
127
|
+
blockhash: string;
|
|
128
|
+
lastValidBlockHeight: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* One basket leg as the create flow takes it. The API's `UnderlyingAssetDto`
|
|
132
|
+
* requires `mint` + `symbol` + `mintBps` (target weight, bps). `pythFeedId` is
|
|
133
|
+
* OPTIONAL — the API auto-looks-it-up from its `MINT_TO_PYTH_FEED` map and
|
|
134
|
+
* rejects an unmapped non-USD mint, so for known assets the agent can omit it.
|
|
135
|
+
*/
|
|
136
|
+
export interface CreateAssetInput {
|
|
137
|
+
mint: string;
|
|
138
|
+
symbol: string;
|
|
139
|
+
/** Target weight in bps; the basket must sum to 10_000. */
|
|
140
|
+
mintBps: number;
|
|
141
|
+
pythFeedId?: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* `POST /vaults/create/prepare` response. The create tx is a SINGLE v0
|
|
145
|
+
* `VersionedTransaction` (base64 `transaction`). `vaultAddress` is the PDA the
|
|
146
|
+
* vault will live at once the tx confirms — needed verbatim for `/create/confirm`.
|
|
147
|
+
* A server-built per-create ALT (`altAddress`) is referenced by the tx.
|
|
148
|
+
*/
|
|
149
|
+
export interface CreatePrepareResponse {
|
|
150
|
+
transaction: string;
|
|
151
|
+
versioned: boolean;
|
|
152
|
+
blockhash: string;
|
|
153
|
+
lastValidBlockHeight: number;
|
|
154
|
+
computeUnits?: number;
|
|
155
|
+
vaultAddress: string;
|
|
156
|
+
vaultMint: string;
|
|
157
|
+
vaultIndex: number;
|
|
158
|
+
altAddress: string;
|
|
159
|
+
/** Factory per-vault TVL cap (raw 6dp USDC; "0" = unlimited). Best-effort. */
|
|
160
|
+
maxVaultTvlUsdc?: string;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* `POST /vaults/create/confirm` response. The API records the vault doc AFTER
|
|
164
|
+
* the on-chain create tx has confirmed. The confirm MUST land inside the
|
|
165
|
+
* prepare-cache TTL (~15 min) or it 400s ("Prepare session expired") — the
|
|
166
|
+
* on-chain vault still exists, but the Mongo record won't be written.
|
|
167
|
+
*/
|
|
168
|
+
export interface CreateConfirmResponse {
|
|
169
|
+
status: string;
|
|
170
|
+
signature: string;
|
|
171
|
+
vault: Record<string, unknown>;
|
|
172
|
+
}
|
|
173
|
+
/** SIWS nonce response (`POST /auth/nonce`). */
|
|
174
|
+
export interface NonceResponse {
|
|
175
|
+
nonce: string;
|
|
176
|
+
/** The EXACT message the wallet must sign — do not rebuild it client-side. */
|
|
177
|
+
message: string;
|
|
178
|
+
}
|
|
179
|
+
/** SIWS sign-in response for a `native` client (`POST /auth/siws`). */
|
|
180
|
+
export interface NativeAuthTokens {
|
|
181
|
+
accessToken: string;
|
|
182
|
+
refreshToken: string;
|
|
183
|
+
wallet: string;
|
|
184
|
+
expiresIn: string;
|
|
185
|
+
}
|
|
186
|
+
/** Public access-gate status (`GET /access/status?wallet=`). */
|
|
187
|
+
export interface AccessStatus {
|
|
188
|
+
enabled: boolean;
|
|
189
|
+
allowed: boolean;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for agent responses.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the LIVE DFM v2 API (`/api/v2`, NestJS) response shapes as
|
|
5
|
+
* verified against https://n2-api.dfm.finance — NOT the older zap-v1 shapes the
|
|
6
|
+
* previous version of this file assumed. Key corrections vs the stale version:
|
|
7
|
+
* - vault identity field is `address` (base58 PDA), not `id`
|
|
8
|
+
* - name/symbol are `vaultName` / `vaultSymbol`
|
|
9
|
+
* - `tvl`, `totalSupply`, `totalAssets` are STRING-encoded (raw integers or
|
|
10
|
+
* decimal strings) — never assume `number`
|
|
11
|
+
* - basket lives in `underlyingAssets`, each `{ mint, allocationBps, ... }`
|
|
12
|
+
* - `GET /vaults/:address` wraps the doc under `{ vault, status, ... }`
|
|
13
|
+
* - `GET /portfolio` reads the wallet from the JWT (no address param)
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zap-v2 deposit/redeem LIFECYCLE driver (the real-money WRITE path).
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ GATED. Reachable only when DFM_AGENT_WRITE_ENABLED=true. Every method here
|
|
5
|
+
* moves real funds on mainnet. The parent must review before enabling.
|
|
6
|
+
* REVIEW: real-money path — parent must review before enabling.
|
|
7
|
+
*
|
|
8
|
+
* ─── Why a driver (not a single call) ──────────────────────────────────────
|
|
9
|
+
* zap-v2 is a STATEFUL lifecycle, NOT a one-shot. The Jupiter swaps run as
|
|
10
|
+
* PERMISSIONLESS per-leg cranks executed by the BACKEND orchestrator
|
|
11
|
+
* (ZapSwapOrchestratorService) — the agent does NOT crank them. The agent only
|
|
12
|
+
* signs the two user-side boundary transactions:
|
|
13
|
+
*
|
|
14
|
+
* DEPOSIT (zap-in):
|
|
15
|
+
* 1. POST zap-in-v2/open/prepare → sign+submit (pulls USDC, pins plan,
|
|
16
|
+
* creates escrow + per-asset ATAs)
|
|
17
|
+
* 2. POLL zap-v2/status/:user until `readyToClose` (orchestrator cranks the
|
|
18
|
+
* USDC→asset legs server-side; `filledMask` fills in)
|
|
19
|
+
* 3. POST zap-in-v2/close/prepare → sign+submit (CPI mint_in_kind_v2,
|
|
20
|
+
* forward shares, close escrow)
|
|
21
|
+
*
|
|
22
|
+
* REDEEM (zap-out):
|
|
23
|
+
* 1. POST zap-out-v2/open/prepare → sign+submit (burn shares → escrow
|
|
24
|
+
* basket via finalize_redeem_in_kind, pin plan)
|
|
25
|
+
* 2. POLL zap-v2/status/:user until `readyToClose` (orchestrator cranks the
|
|
26
|
+
* asset→USDC legs)
|
|
27
|
+
* 3. POST zap-out-v2/close/prepare → sign+submit (exit fee, pay net USDC)
|
|
28
|
+
*
|
|
29
|
+
* If a deposit/redeem STALLS mid-crank (a leg can't meet its pinned floor), the
|
|
30
|
+
* recovery levers are `update-envelope` (loosen floors) or `cancel` (return
|
|
31
|
+
* escrow holdings as-is). Those are EXPOSED as separate tools, not auto-driven
|
|
32
|
+
* here — recovery is an operator decision, not something to silently retry.
|
|
33
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
34
|
+
*/
|
|
35
|
+
import type { AgentConfig } from './config.js';
|
|
36
|
+
import type { DfmApiClient } from './api-client.js';
|
|
37
|
+
import type { ZapV2Status } from './types.js';
|
|
38
|
+
export interface ZapFlowResult {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
vault: string;
|
|
41
|
+
/** 'deposit' | 'redeem' */
|
|
42
|
+
kind: 'deposit' | 'redeem';
|
|
43
|
+
openSignatures: string[];
|
|
44
|
+
closeSignatures: string[];
|
|
45
|
+
escrowPda: string;
|
|
46
|
+
/** Final escrow status snapshot just before close (for diagnostics). */
|
|
47
|
+
finalStatus?: ZapV2Status | null;
|
|
48
|
+
message: string;
|
|
49
|
+
}
|
|
50
|
+
interface PollOptions {
|
|
51
|
+
/** Max seconds to wait for the orchestrator to fill all legs. */
|
|
52
|
+
timeoutSecs: number;
|
|
53
|
+
/** Seconds between status polls. */
|
|
54
|
+
intervalSecs: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Drive a full DEPOSIT (USDC → basket → shares). `usdcAmountRaw` is 6-dp raw
|
|
58
|
+
* units (e.g. "12000000" = $12). Returns when shares are minted (close confirmed)
|
|
59
|
+
* or throws with a recovery hint.
|
|
60
|
+
*/
|
|
61
|
+
export declare function runDeposit(config: AgentConfig, api: DfmApiClient, user: string, vault: string, usdcAmountRaw: string, opts?: {
|
|
62
|
+
slippageBps?: number;
|
|
63
|
+
expirySecs?: number;
|
|
64
|
+
poll?: Partial<PollOptions>;
|
|
65
|
+
}): Promise<ZapFlowResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Drive a full REDEEM (shares → basket → USDC). `sharesRaw` is 6-dp raw units.
|
|
68
|
+
* Returns when net USDC is paid (close confirmed) or throws with a recovery hint.
|
|
69
|
+
*/
|
|
70
|
+
export declare function runRedeem(config: AgentConfig, api: DfmApiClient, user: string, vault: string, sharesRaw: string, opts?: {
|
|
71
|
+
slippageBps?: number;
|
|
72
|
+
expirySecs?: number;
|
|
73
|
+
poll?: Partial<PollOptions>;
|
|
74
|
+
}): Promise<ZapFlowResult>;
|
|
75
|
+
export {};
|
|
76
|
+
//# sourceMappingURL=zap-v2-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zap-v2-flow.d.ts","sourceRoot":"","sources":["../src/zap-v2-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAwB,MAAM,YAAY,CAAC;AAIpE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,WAAW;IACnB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;CACtB;AAoHD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;CAAE,GAChF,OAAO,CAAC,aAAa,CAAC,CA+CxB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;CAAE,GAChF,OAAO,CAAC,aAAa,CAAC,CA6CxB"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { signBase64Transaction } from './signing.js';
|
|
2
|
+
import { submitSignedTxsSequential, BlockhashExpiredError } from './submit.js';
|
|
3
|
+
const DEFAULT_POLL = { timeoutSecs: 180, intervalSecs: 4 };
|
|
4
|
+
async function sleep(secs) {
|
|
5
|
+
await new Promise((r) => setTimeout(r, secs * 1000));
|
|
6
|
+
}
|
|
7
|
+
/** Sign every tx in a prepare response locally, submit them in order. */
|
|
8
|
+
async function signAndSubmit(config, prepared) {
|
|
9
|
+
const signed = prepared.transactions.map((t) => signBase64Transaction(config, t));
|
|
10
|
+
return submitSignedTxsSequential(config, signed, prepared.blockhash, prepared.lastValidBlockHeight);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Submit the OPEN side. On blockhash expiry we DON'T auto-retry (the open pulls
|
|
14
|
+
* funds + creates the escrow — re-running blindly could double-open), but we
|
|
15
|
+
* rewrite the error into an actionable hint: check zap_status to see whether an
|
|
16
|
+
* escrow was created (poll → close) or not (safe to re-run the deposit/redeem).
|
|
17
|
+
*/
|
|
18
|
+
async function submitOpen(config, prepared, kind) {
|
|
19
|
+
try {
|
|
20
|
+
return await signAndSubmit(config, prepared);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (e instanceof BlockhashExpiredError) {
|
|
24
|
+
throw new Error(`The ${kind} OPEN tx did not confirm before its blockhash expired. Check zap_status: ` +
|
|
25
|
+
`if an escrow now EXISTS, the open landed — poll it then close (re-run this ${kind} call ` +
|
|
26
|
+
`once an escrow is open will resume it); if NO escrow exists, nothing happened and it is ` +
|
|
27
|
+
`safe to re-run the ${kind}. Original: ${e.message}`);
|
|
28
|
+
}
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Run the CLOSE side with a blockhash-expiry retry. The escrow is already
|
|
34
|
+
* READY_TO_CLOSE at this point, so re-preparing + re-signing the close is safe
|
|
35
|
+
* and idempotent (it does not re-pull funds). We retry only on blockhash expiry
|
|
36
|
+
* — an on-chain revert is surfaced immediately. Up to `attempts` re-prepares.
|
|
37
|
+
*/
|
|
38
|
+
async function closeWithRetry(config, prepareClose, attempts = 3) {
|
|
39
|
+
let lastErr = null;
|
|
40
|
+
for (let i = 0; i < attempts; i++) {
|
|
41
|
+
try {
|
|
42
|
+
const close = await prepareClose();
|
|
43
|
+
return await signAndSubmit(config, close);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
if (e instanceof BlockhashExpiredError) {
|
|
47
|
+
lastErr = e;
|
|
48
|
+
continue; // re-prepare with a fresh blockhash; escrow stays ready.
|
|
49
|
+
}
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Close did not confirm within ${attempts} fresh-blockhash attempts (last: ${lastErr?.message}). ` +
|
|
54
|
+
`The escrow is still READY — re-run the same deposit/redeem call to retry the close, ` +
|
|
55
|
+
`or inspect with zap_status.`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Poll `zap-v2/status` until the escrow is `readyToClose`, it expires, or we
|
|
59
|
+
* time out. Returns the last status seen. Throws on expiry/timeout so the caller
|
|
60
|
+
* can surface a clear recovery hint (update-envelope / cancel).
|
|
61
|
+
*/
|
|
62
|
+
async function pollUntilReady(api, vault, user, poll) {
|
|
63
|
+
const deadline = Date.now() + poll.timeoutSecs * 1000;
|
|
64
|
+
let last = null;
|
|
65
|
+
while (Date.now() < deadline) {
|
|
66
|
+
last = await api.getZapV2Status(vault, user);
|
|
67
|
+
if (!last) {
|
|
68
|
+
throw new Error('Escrow disappeared during polling (cancelled or already closed?).');
|
|
69
|
+
}
|
|
70
|
+
if (last.readyToClose)
|
|
71
|
+
return last;
|
|
72
|
+
if (last.isExpired) {
|
|
73
|
+
throw new Error(`Escrow expired before all legs filled (${last.legsFilled}/${last.legsTotal}). ` +
|
|
74
|
+
`Use zap_v2_cancel to recover the held funds, or zap_v2_update_envelope to ` +
|
|
75
|
+
`loosen floors and retry.`);
|
|
76
|
+
}
|
|
77
|
+
await sleep(poll.intervalSecs);
|
|
78
|
+
}
|
|
79
|
+
const tail = last
|
|
80
|
+
? `${last.legsFilled}/${last.legsTotal} legs filled; lastFailures=${JSON.stringify(last.legFailures)}`
|
|
81
|
+
: 'no status';
|
|
82
|
+
throw new Error(`Timed out after ${poll.timeoutSecs}s waiting for the orchestrator to fill all legs (${tail}). ` +
|
|
83
|
+
`The escrow is still open — poll zap_status, then zap_v2_update_envelope or zap_v2_cancel.`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Drive a full DEPOSIT (USDC → basket → shares). `usdcAmountRaw` is 6-dp raw
|
|
87
|
+
* units (e.g. "12000000" = $12). Returns when shares are minted (close confirmed)
|
|
88
|
+
* or throws with a recovery hint.
|
|
89
|
+
*/
|
|
90
|
+
export async function runDeposit(config, api, user, vault, usdcAmountRaw, opts) {
|
|
91
|
+
const poll = { ...DEFAULT_POLL, ...(opts?.poll ?? {}) };
|
|
92
|
+
// 0. RESUME GUARD — if an escrow is ALREADY open for this (vault, user), don't
|
|
93
|
+
// re-open (the escrow PDA is Anchor-`init` → a second open reverts, and we'd
|
|
94
|
+
// risk double-pulling USDC). Resume it: poll → close. This makes the deposit
|
|
95
|
+
// call idempotent against a prior open whose close never landed.
|
|
96
|
+
const existing = await api.getZapV2Status(vault, user);
|
|
97
|
+
let openSignatures = [];
|
|
98
|
+
let escrowPda;
|
|
99
|
+
if (existing) {
|
|
100
|
+
if (existing.mode !== 0) {
|
|
101
|
+
throw new Error(`An open REDEEM escrow already exists for this vault+wallet — cancel or finish it ` +
|
|
102
|
+
`(zap_v2_cancel / redeem) before depositing.`);
|
|
103
|
+
}
|
|
104
|
+
escrowPda = existing.escrowPda;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// 1. OPEN — pull USDC into escrow, pin the plan.
|
|
108
|
+
const open = await api.prepareZapInOpenV2(vault, usdcAmountRaw, {
|
|
109
|
+
slippageBps: opts?.slippageBps,
|
|
110
|
+
expirySecs: opts?.expirySecs,
|
|
111
|
+
});
|
|
112
|
+
openSignatures = await submitOpen(config, open, 'deposit');
|
|
113
|
+
escrowPda = open.escrowPda;
|
|
114
|
+
}
|
|
115
|
+
// 2. POLL — wait for the backend orchestrator to crank every USDC→asset leg.
|
|
116
|
+
const ready = await pollUntilReady(api, vault, user, poll);
|
|
117
|
+
// 3. CLOSE — mint_in_kind_v2, forward shares, close escrow. Retries on
|
|
118
|
+
// blockhash expiry (escrow stays READY between attempts).
|
|
119
|
+
const closeSignatures = await closeWithRetry(config, () => api.prepareZapInCloseV2(vault));
|
|
120
|
+
return {
|
|
121
|
+
ok: true,
|
|
122
|
+
vault,
|
|
123
|
+
kind: 'deposit',
|
|
124
|
+
openSignatures,
|
|
125
|
+
closeSignatures,
|
|
126
|
+
escrowPda,
|
|
127
|
+
finalStatus: ready,
|
|
128
|
+
message: (existing ? 'Resumed an already-open deposit escrow. ' : '') +
|
|
129
|
+
`Deposit complete: ${usdcAmountRaw} raw USDC → vault ${vault.slice(0, 8)}…. Shares minted.`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Drive a full REDEEM (shares → basket → USDC). `sharesRaw` is 6-dp raw units.
|
|
134
|
+
* Returns when net USDC is paid (close confirmed) or throws with a recovery hint.
|
|
135
|
+
*/
|
|
136
|
+
export async function runRedeem(config, api, user, vault, sharesRaw, opts) {
|
|
137
|
+
const poll = { ...DEFAULT_POLL, ...(opts?.poll ?? {}) };
|
|
138
|
+
// 0. RESUME GUARD — mirror the deposit path: if a redeem escrow is already
|
|
139
|
+
// open, resume it rather than re-burning shares into a second escrow.
|
|
140
|
+
const existing = await api.getZapV2Status(vault, user);
|
|
141
|
+
let openSignatures = [];
|
|
142
|
+
let escrowPda;
|
|
143
|
+
if (existing) {
|
|
144
|
+
if (existing.mode !== 1) {
|
|
145
|
+
throw new Error(`An open DEPOSIT escrow already exists for this vault+wallet — finish or cancel it ` +
|
|
146
|
+
`(deposit / zap_v2_cancel) before redeeming.`);
|
|
147
|
+
}
|
|
148
|
+
escrowPda = existing.escrowPda;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// 1. OPEN — burn shares → escrow basket (oracle-free pro-rata), pin the plan.
|
|
152
|
+
const open = await api.prepareZapOutOpenV2(vault, sharesRaw, {
|
|
153
|
+
slippageBps: opts?.slippageBps,
|
|
154
|
+
expirySecs: opts?.expirySecs,
|
|
155
|
+
});
|
|
156
|
+
openSignatures = await submitOpen(config, open, 'redeem');
|
|
157
|
+
escrowPda = open.escrowPda;
|
|
158
|
+
}
|
|
159
|
+
// 2. POLL — wait for the orchestrator to crank every asset→USDC leg.
|
|
160
|
+
const ready = await pollUntilReady(api, vault, user, poll);
|
|
161
|
+
// 3. CLOSE — apply exit fee, pay net USDC, close escrow. Retries on blockhash
|
|
162
|
+
// expiry (escrow stays READY between attempts).
|
|
163
|
+
const closeSignatures = await closeWithRetry(config, () => api.prepareZapOutCloseV2(vault));
|
|
164
|
+
return {
|
|
165
|
+
ok: true,
|
|
166
|
+
vault,
|
|
167
|
+
kind: 'redeem',
|
|
168
|
+
openSignatures,
|
|
169
|
+
closeSignatures,
|
|
170
|
+
escrowPda,
|
|
171
|
+
finalStatus: ready,
|
|
172
|
+
message: (existing ? 'Resumed an already-open redeem escrow. ' : '') +
|
|
173
|
+
`Redeem complete: ${sharesRaw} raw shares from vault ${vault.slice(0, 8)}…. Net USDC paid.`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=zap-v2-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zap-v2-flow.js","sourceRoot":"","sources":["../src/zap-v2-flow.ts"],"names":[],"mappings":"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"}
|