@perena/vault-sdk 1.0.18
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 +569 -0
- package/dist/index.d.ts +13974 -0
- package/dist/index.js +17968 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
# Vault SDK
|
|
2
|
+
|
|
3
|
+
TypeScript helpers for the Bankineco vault program. The SDK wraps PDA derivation,
|
|
4
|
+
account fetching, and instruction building behind a single `VaultClient`. Every
|
|
5
|
+
on-chain instruction has a **transaction builder** on `client.tx` that returns a
|
|
6
|
+
`VaultTransactionPlan` you can sign and send.
|
|
7
|
+
|
|
8
|
+
For runnable CLI examples, see [`scripts/README.md`](scripts/README.md).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
From the monorepo (workspace package name is `vault`):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm install
|
|
16
|
+
pnpm --filter vault run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
In another workspace package:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"vault": "workspace:*"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
### Option A — `createVaultClient` (scripts and backend services)
|
|
32
|
+
|
|
33
|
+
Use this when targeting deployed `test` or `prod` networks. It wires RPC,
|
|
34
|
+
keypair, and program id from env vars (see [`.env.example`](.env.example)).
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { createVaultClient } from "vault";
|
|
38
|
+
|
|
39
|
+
const { client, payer, signer } = createVaultClient("test", {
|
|
40
|
+
role: "vault", // default keypair: ~/.config/solana/vault-test.json
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const vault = "..." as Address; // vault PDA
|
|
44
|
+
const vaultAccount = await client.account.fetchVault(vault);
|
|
45
|
+
|
|
46
|
+
const plan = await client.tx.executeDeposit.getTx({
|
|
47
|
+
user: signer,
|
|
48
|
+
vault,
|
|
49
|
+
assetMint: vaultAccount.config.baseAssetMint,
|
|
50
|
+
shareMint: vaultAccount.config.shareMint,
|
|
51
|
+
amount: 1_000_000n, // base units (6 decimals → 1.0 UI)
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const signature = await client.sendTransaction(payer, plan);
|
|
55
|
+
console.log(signature);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Option B — manual `VaultClient` (tests, custom integrations)
|
|
59
|
+
|
|
60
|
+
Use this when you already have a `Connection` and signer:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { AnchorProvider } from "@anchor-lang/core";
|
|
64
|
+
import { Connection, Keypair } from "@solana/web3.js";
|
|
65
|
+
import { fromWeb3Pk } from "common";
|
|
66
|
+
import { VaultClient, makeProvider } from "vault";
|
|
67
|
+
|
|
68
|
+
const connection = new Connection("http://127.0.0.1:8899", "confirmed");
|
|
69
|
+
const payer = Keypair.generate();
|
|
70
|
+
const client = new VaultClient(makeProvider(connection, payer));
|
|
71
|
+
|
|
72
|
+
const [vault] = await client.pda.deriveVaultPda(0); // vault id
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Creating transactions
|
|
76
|
+
|
|
77
|
+
### The builder pattern
|
|
78
|
+
|
|
79
|
+
Every instruction lives on `client.tx.<builderName>`. Builders follow the same
|
|
80
|
+
contract:
|
|
81
|
+
|
|
82
|
+
| Method | Returns | When to use |
|
|
83
|
+
| --------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `getTx(txArgs)` | `VaultTransactionPlan` | **Preferred.** Derives PDAs/ATAs, prepends setup ixs (e.g. idempotent ATA creates), and attaches cache invalidation metadata. |
|
|
85
|
+
| `getIx(ixArgs)` | `Instruction` | Low-level. You supply every account address yourself. |
|
|
86
|
+
|
|
87
|
+
`TxArgs` types are the high-level inputs (curator, vault, amounts as `bigint`,
|
|
88
|
+
optional PDAs). `IxArgs` types are the fully-resolved account sets the program
|
|
89
|
+
expects. Type definitions live in
|
|
90
|
+
[`src/client/builders/args.ts`](src/client/builders/args.ts).
|
|
91
|
+
|
|
92
|
+
A typical flow:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// 1. Build a plan
|
|
96
|
+
const plan = await client.tx.executeDeposit.getTx({
|
|
97
|
+
user: signer,
|
|
98
|
+
vault,
|
|
99
|
+
assetMint,
|
|
100
|
+
shareMint,
|
|
101
|
+
amount: 500_000n,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// 2. Send it (signs, confirms, clears relevant account cache)
|
|
105
|
+
const sig = await client.sendTransaction(payer, plan);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`VaultTransactionPlan` contains:
|
|
109
|
+
|
|
110
|
+
- `instructions` — ordered `@solana/kit` instructions (preamble + program ix)
|
|
111
|
+
- `lookupTables?` — optional address lookup tables for v0 transactions
|
|
112
|
+
- `postSuccessCacheInvalidations?` — vault cache keys to clear after success
|
|
113
|
+
|
|
114
|
+
### Direct Rust CPI integrations
|
|
115
|
+
|
|
116
|
+
For integrations that build a Rust CPI into the vault program, some builders also
|
|
117
|
+
expose the resolved Anchor account map and method arguments separately:
|
|
118
|
+
|
|
119
|
+
- `getIxAccounts(ixArgs)` — named accounts passed to Anchor's `accountsPartial`
|
|
120
|
+
- `getIxData(ixArgs)` — instruction method arguments, such as amounts and
|
|
121
|
+
tranche kind
|
|
122
|
+
|
|
123
|
+
These helpers are currently available on:
|
|
124
|
+
|
|
125
|
+
- `client.tx.executeDeposit`
|
|
126
|
+
- `client.tx.executeWithdraw`
|
|
127
|
+
- `client.tx.executeTrancheDeposit`
|
|
128
|
+
- `client.tx.executeTrancheWithdraw`
|
|
129
|
+
|
|
130
|
+
Use these when a TypeScript integration wants the SDK to stay the source of
|
|
131
|
+
truth for the account layout and argument shape, but your on-chain Rust program
|
|
132
|
+
performs the final CPI. They accept fully-resolved `IxArgs`, so derive PDAs/ATAs
|
|
133
|
+
with `client.pda`, account fetches, or `getAtaAddress(...)` before calling them.
|
|
134
|
+
The returned data is not serialized instruction bytes; it is the same account
|
|
135
|
+
map and argument values that `getIx(...)` uses internally.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { BN } from "@anchor-lang/core";
|
|
139
|
+
|
|
140
|
+
const ixArgs = {
|
|
141
|
+
user,
|
|
142
|
+
vault,
|
|
143
|
+
vaultOracle,
|
|
144
|
+
vaultTrancheState: null,
|
|
145
|
+
assetMint,
|
|
146
|
+
shareMint,
|
|
147
|
+
amount: new BN("1000000"),
|
|
148
|
+
assetTokenProgram,
|
|
149
|
+
shareTokenProgram,
|
|
150
|
+
userAssetAta,
|
|
151
|
+
vaultAssetAta,
|
|
152
|
+
feeVault,
|
|
153
|
+
feeVaultAta,
|
|
154
|
+
userShareAta,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const accounts = client.tx.executeDeposit.getIxAccounts(ixArgs);
|
|
158
|
+
const data = client.tx.executeDeposit.getIxData(ixArgs);
|
|
159
|
+
|
|
160
|
+
// Example payload to hand to your Rust integration layer.
|
|
161
|
+
const cpiPayload = {
|
|
162
|
+
accounts: Object.fromEntries(
|
|
163
|
+
Object.entries(accounts).map(([name, pubkey]) => [
|
|
164
|
+
name,
|
|
165
|
+
pubkey?.toString() ?? null,
|
|
166
|
+
])
|
|
167
|
+
),
|
|
168
|
+
data: {
|
|
169
|
+
amount: data.amount.toString(),
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
In Rust, map those account addresses into the matching Anchor CPI account struct
|
|
175
|
+
and pass the data fields into the generated CPI method. For example,
|
|
176
|
+
`executeDeposit.getIxData(...)` returns `{ amount }`, which corresponds to the
|
|
177
|
+
`amount` argument on the vault program's `execute_deposit` CPI.
|
|
178
|
+
|
|
179
|
+
## Quoting conversions
|
|
180
|
+
|
|
181
|
+
Use `client.quote.quote(...)` to calculate expected output amounts before
|
|
182
|
+
building a transaction. Quotes fetch the current vault/tranche state, calculate
|
|
183
|
+
using the same fee formulas as the program, and require a `signer` address so
|
|
184
|
+
the SDK can check whether the signer is owned by a fee-exempt program.
|
|
185
|
+
|
|
186
|
+
All amounts are base units. `expectedAmountOut` is the net amount after fees;
|
|
187
|
+
`grossAmountOut`, `feeAmount`, `feeBps`, and `feeExempt` explain the quote.
|
|
188
|
+
|
|
189
|
+
### Regular share mint
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Asset -> regular vault shares
|
|
193
|
+
const depositQuote = await client.quote.quote({
|
|
194
|
+
shareClass: "regular",
|
|
195
|
+
direction: "deposit",
|
|
196
|
+
signer,
|
|
197
|
+
vault,
|
|
198
|
+
assetMint,
|
|
199
|
+
amount: 1_000_000n,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
console.log(depositQuote.expectedAmountOut); // regular shares to receive
|
|
203
|
+
console.log(depositQuote.feeExempt); // true when signer owner is whitelisted
|
|
204
|
+
|
|
205
|
+
// Regular vault shares -> asset
|
|
206
|
+
const withdrawQuote = await client.quote.quote({
|
|
207
|
+
shareClass: "regular",
|
|
208
|
+
direction: "withdraw",
|
|
209
|
+
signer,
|
|
210
|
+
vault,
|
|
211
|
+
assetMint,
|
|
212
|
+
amount: 500_000n, // share amount to burn
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
console.log(withdrawQuote.expectedAmountOut); // asset tokens to receive
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Junior and senior tranches
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Asset -> junior tranche shares
|
|
222
|
+
const juniorDepositQuote = await client.quote.quote({
|
|
223
|
+
shareClass: "junior",
|
|
224
|
+
direction: "deposit",
|
|
225
|
+
signer,
|
|
226
|
+
vault,
|
|
227
|
+
assetMint,
|
|
228
|
+
amount: 1_000_000n,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Senior works the same way.
|
|
232
|
+
const seniorDepositQuote = await client.quote.quote({
|
|
233
|
+
shareClass: "senior",
|
|
234
|
+
direction: "deposit",
|
|
235
|
+
signer,
|
|
236
|
+
vault,
|
|
237
|
+
assetMint,
|
|
238
|
+
amount: 1_000_000n,
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
For junior withdrawals, pass `withdrawalMode: "instant"` to quote
|
|
243
|
+
`executeTrancheWithdraw`, or `withdrawalMode: "queued"` to quote
|
|
244
|
+
`fulfillJuniorTrancheWithdraw` after lockup. Senior withdrawals are already
|
|
245
|
+
fee-free, but still support the same quote shape.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Junior tranche shares -> asset through instant withdrawal.
|
|
249
|
+
const instantJuniorWithdrawQuote = await client.quote.quote({
|
|
250
|
+
shareClass: "junior",
|
|
251
|
+
direction: "withdraw",
|
|
252
|
+
withdrawalMode: "instant",
|
|
253
|
+
signer,
|
|
254
|
+
vault,
|
|
255
|
+
assetMint,
|
|
256
|
+
amount: 100_000n, // junior shares to burn
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Junior tranche shares -> asset through queued fulfillment.
|
|
260
|
+
const queuedJuniorWithdrawQuote = await client.quote.quote({
|
|
261
|
+
shareClass: "junior",
|
|
262
|
+
direction: "withdraw",
|
|
263
|
+
withdrawalMode: "queued",
|
|
264
|
+
signer,
|
|
265
|
+
vault,
|
|
266
|
+
assetMint,
|
|
267
|
+
amount: 100_000n,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Senior tranche shares -> asset.
|
|
271
|
+
const seniorWithdrawQuote = await client.quote.quote({
|
|
272
|
+
shareClass: "senior",
|
|
273
|
+
direction: "withdraw",
|
|
274
|
+
signer,
|
|
275
|
+
vault,
|
|
276
|
+
assetMint,
|
|
277
|
+
amount: 100_000n,
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
If you already derived the tranche state PDA, pass `vaultTrancheState` to avoid
|
|
282
|
+
an extra PDA derivation/fetch. Pass `fresh: true` when quoting immediately after
|
|
283
|
+
another transaction and you want to bypass the SDK account cache.
|
|
284
|
+
|
|
285
|
+
### Example: deposit
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
const plan = await client.tx.executeDeposit.getTx({
|
|
289
|
+
user: signer,
|
|
290
|
+
vault,
|
|
291
|
+
assetMint,
|
|
292
|
+
shareMint,
|
|
293
|
+
amount: 1_000_000n,
|
|
294
|
+
});
|
|
295
|
+
await client.sendTransaction(payer, plan);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The builder automatically:
|
|
299
|
+
|
|
300
|
+
- Derives `vaultOracle` from the vault PDA
|
|
301
|
+
- Computes user/vault ATAs
|
|
302
|
+
- Prepends idempotent ATA-create instructions where needed
|
|
303
|
+
|
|
304
|
+
### Example: withdraw
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const plan = await client.tx.executeWithdraw.getTx({
|
|
308
|
+
user: signer,
|
|
309
|
+
vault,
|
|
310
|
+
assetMint,
|
|
311
|
+
shareMint,
|
|
312
|
+
shareAmount: 500_000n,
|
|
313
|
+
});
|
|
314
|
+
await client.sendTransaction(payer, plan);
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
For withdrawals routed through external liquidity (CPI), pass
|
|
318
|
+
`externalWithdrawIxRefs`, `externalWithdrawAccounts`, and optionally
|
|
319
|
+
`lookupTables` — see `ExecuteWithdrawTxArgs` in `args.ts`.
|
|
320
|
+
|
|
321
|
+
### Example: vault setup (multi-step)
|
|
322
|
+
|
|
323
|
+
Deploy flows compose several builders in sequence:
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
const curator = fromWeb3Pk(payer.publicKey);
|
|
327
|
+
|
|
328
|
+
await client.sendTransaction(
|
|
329
|
+
payer,
|
|
330
|
+
await client.tx.createVault.getTx({
|
|
331
|
+
curator,
|
|
332
|
+
shareMint,
|
|
333
|
+
strictAssetMint: assetMint,
|
|
334
|
+
assetDecimals: 6,
|
|
335
|
+
})
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
await client.sendTransaction(
|
|
339
|
+
payer,
|
|
340
|
+
await client.tx.createTrancheState.getTx({
|
|
341
|
+
curator,
|
|
342
|
+
vault,
|
|
343
|
+
juniorShareMint,
|
|
344
|
+
seniorShareMint,
|
|
345
|
+
seniorFixedApyBps: 1_000,
|
|
346
|
+
})
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
await client.sendTransaction(
|
|
350
|
+
payer,
|
|
351
|
+
await client.tx.updateConsensusSigners.getTx({
|
|
352
|
+
curator,
|
|
353
|
+
vault,
|
|
354
|
+
signers: [curator],
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Example: tranche deposit
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
const plan = await client.tx.executeTrancheDeposit.getTx({
|
|
363
|
+
user: signer,
|
|
364
|
+
vault,
|
|
365
|
+
assetMint,
|
|
366
|
+
trancheShareMint: juniorMint,
|
|
367
|
+
kind: { junior: {} }, // or { senior: {} }
|
|
368
|
+
amount: 1_000_000n,
|
|
369
|
+
});
|
|
370
|
+
await client.sendTransaction(payer, plan);
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Example: junior withdrawal queue
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
// User queues a locked junior withdraw
|
|
377
|
+
await client.sendTransaction(
|
|
378
|
+
payer,
|
|
379
|
+
await client.tx.requestJuniorTrancheWithdraw.getTx({
|
|
380
|
+
owner: signer,
|
|
381
|
+
vault,
|
|
382
|
+
juniorMint,
|
|
383
|
+
queueId: 0,
|
|
384
|
+
shareAmount: 100_000n,
|
|
385
|
+
})
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
// Fulfiller pays out after lockup (see WithdrawalQueueService for batch logic)
|
|
389
|
+
await client.sendTransaction(
|
|
390
|
+
fulfiller,
|
|
391
|
+
await client.tx.fulfillJuniorTrancheWithdraw.getTx({
|
|
392
|
+
fulfiller: fromWeb3Pk(fulfiller.publicKey),
|
|
393
|
+
owner,
|
|
394
|
+
vault,
|
|
395
|
+
queueId: 0,
|
|
396
|
+
})
|
|
397
|
+
);
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Sending transactions
|
|
401
|
+
|
|
402
|
+
### Built-in helper
|
|
403
|
+
|
|
404
|
+
`VaultClient.sendTransaction` builds a legacy `Transaction`, signs with the
|
|
405
|
+
fee payer, sends, confirms, and applies cache invalidations from the plan:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
const signature = await client.sendTransaction(payer, plan);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Versioned transactions (lookup tables)
|
|
412
|
+
|
|
413
|
+
Some builders (e.g. `executeWithdraw`, `protocolInteraction`, `jupiterSwap`)
|
|
414
|
+
return `lookupTables` on the plan. `sendTransaction` does **not** compile v0
|
|
415
|
+
messages — use `sendVersionedTransaction` from `common` instead:
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import { fromKitInstruction, sendVersionedTransaction } from "common";
|
|
419
|
+
|
|
420
|
+
const plan = await client.tx.protocolInteraction.getTx({
|
|
421
|
+
/* ... */
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const signature = await sendVersionedTransaction({
|
|
425
|
+
connection: client.provider.connection,
|
|
426
|
+
payer,
|
|
427
|
+
instructions: plan.instructions.map(fromKitInstruction),
|
|
428
|
+
lookupTables: plan.lookupTables ?? [],
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
client.applyCacheInvalidations(plan);
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Composing your own transaction
|
|
435
|
+
|
|
436
|
+
You can merge instructions from multiple builders or mix in custom ixs:
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
const depositPlan = await client.tx.executeDeposit.getTx({ /* ... */ });
|
|
440
|
+
const customIx = /* your instruction */;
|
|
441
|
+
|
|
442
|
+
const combined: VaultTransactionPlan = {
|
|
443
|
+
instructions: [...depositPlan.instructions, customIx],
|
|
444
|
+
postSuccessCacheInvalidations: depositPlan.postSuccessCacheInvalidations,
|
|
445
|
+
};
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Or call `getIx` directly when you only need the program instruction:
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
const ix = await client.tx.executeDeposit.getIx({
|
|
452
|
+
user: signer,
|
|
453
|
+
vault,
|
|
454
|
+
vaultOracle,
|
|
455
|
+
vaultTrancheState: null,
|
|
456
|
+
assetMint,
|
|
457
|
+
shareMint,
|
|
458
|
+
amount: new BN("1000000"),
|
|
459
|
+
assetTokenProgram: TOKEN_PROGRAM_ID,
|
|
460
|
+
shareTokenProgram: TOKEN_PROGRAM_ID,
|
|
461
|
+
userAssetAta,
|
|
462
|
+
vaultAssetAta,
|
|
463
|
+
userShareAta,
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Reading on-chain state
|
|
468
|
+
|
|
469
|
+
Use `client.account` to fetch decoded vault accounts (cached by default, TTL
|
|
470
|
+
60s):
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
const vaultAccount = await client.account.fetchVault(vault);
|
|
474
|
+
const oracle = await client.account.fetchVaultOracle(vaultOraclePda);
|
|
475
|
+
const trancheState = await client.account.fetchVaultTrancheState(tranchePda);
|
|
476
|
+
|
|
477
|
+
// Force a fresh read after an external tx
|
|
478
|
+
const fresh = await client.account.fetchVault(vault, { fresh: true });
|
|
479
|
+
client.clearAllCache();
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Derive PDAs with `client.pda`:
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
const [vault] = await client.pda.deriveVaultPda(vaultId);
|
|
486
|
+
const [vaultOracle] = await client.pda.deriveVaultOraclePda(vault);
|
|
487
|
+
const [trancheState] = await client.pda.deriveVaultTrancheStatePda(vault);
|
|
488
|
+
const [queue] = await client.pda.deriveWithdrawalQueuePda(
|
|
489
|
+
vault,
|
|
490
|
+
owner,
|
|
491
|
+
queueId
|
|
492
|
+
);
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Available transaction builders
|
|
496
|
+
|
|
497
|
+
All builders are on `client.tx`:
|
|
498
|
+
|
|
499
|
+
| Builder | Program instruction | Typical signer |
|
|
500
|
+
| ------------------------------ | --------------------------------- | ---------------- |
|
|
501
|
+
| `createVault` | `create_vault` | Curator |
|
|
502
|
+
| `createAssetHolding` | `create_asset_holding` | HW manager |
|
|
503
|
+
| `removeAssetHolding` | `remove_asset_holding` | HW manager |
|
|
504
|
+
| `updateConsensusSigners` | `update_consensus_signers` | Curator |
|
|
505
|
+
| `createTrancheState` | `create_tranche_state` | Curator |
|
|
506
|
+
| `setVaultConfig` | `set_vault_config` | Curator |
|
|
507
|
+
| `updateTrancheConfig` | `update_tranche_config` | Curator |
|
|
508
|
+
| `activateCircuitBreaker` | `activate_circuit_breaker` | CB trigger |
|
|
509
|
+
| `disableCircuitBreaker` | `disable_circuit_breaker` | Curator |
|
|
510
|
+
| `updateConsensusOracle` | `update_consensus_oracle` | Consensus signer |
|
|
511
|
+
| `executeDeposit` | `execute_deposit` | User |
|
|
512
|
+
| `executeTrancheDeposit` | `execute_tranche_deposit` | User |
|
|
513
|
+
| `executeTrancheWithdraw` | `execute_tranche_withdraw` | User |
|
|
514
|
+
| `requestJuniorTrancheWithdraw` | `request_junior_tranche_withdraw` | Owner |
|
|
515
|
+
| `cancelJuniorTrancheWithdraw` | `cancel_junior_tranche_withdraw` | Owner |
|
|
516
|
+
| `fulfillJuniorTrancheWithdraw` | `fulfill_junior_tranche_withdraw` | Fulfiller |
|
|
517
|
+
| `executeWithdraw` | `execute_withdraw` | User |
|
|
518
|
+
| `managerWithdrawAsset` | `manager_withdraw_asset` | HW manager |
|
|
519
|
+
| `managerRedepositAsset` | `manager_redeposit_asset` | HW manager |
|
|
520
|
+
| `protocolInteraction` | `protocol_interaction` | HW manager |
|
|
521
|
+
| `jupiterSwap` | `jupiter_swap` | HW manager |
|
|
522
|
+
| `setExternalLiquidity` | `set_external_liquidity` | HW manager |
|
|
523
|
+
| `setAssetPriceOracle` | `set_asset_price_oracle` | Curator |
|
|
524
|
+
| `updateAssetPrice` | `update_asset_price` | Oracle keeper |
|
|
525
|
+
| `vaultReallocation` | `vault_reallocation` | HW manager |
|
|
526
|
+
| `withdrawProtocolFees` | `withdraw_protocol_fees` | Curator |
|
|
527
|
+
| `withdrawTrancheFees` | `withdraw_tranche_fees` | Curator |
|
|
528
|
+
|
|
529
|
+
Argument shapes for each builder: [`src/client/builders/args.ts`](src/client/builders/args.ts).
|
|
530
|
+
|
|
531
|
+
## Higher-level services
|
|
532
|
+
|
|
533
|
+
For recurring backend work, prefer the services layer over reimplementing
|
|
534
|
+
discovery logic in your app:
|
|
535
|
+
|
|
536
|
+
- **`WithdrawalQueueService`** — scan and fulfill eligible junior withdrawal
|
|
537
|
+
queues (`src/services/withdrawalQueueService.ts`)
|
|
538
|
+
- **`OracleService`** — consensus oracle / asset price updates
|
|
539
|
+
(`src/services/oracleService.ts`)
|
|
540
|
+
|
|
541
|
+
These services call the same `client.tx.*.getTx` builders internally.
|
|
542
|
+
|
|
543
|
+
## Environment and RPC
|
|
544
|
+
|
|
545
|
+
Copy [`.env.example`](.env.example) to `.env`. RPC resolution order:
|
|
546
|
+
|
|
547
|
+
1. `VAULT_RPC_URL_TEST` / `VAULT_RPC_URL_PROD`
|
|
548
|
+
2. `RPC_URL`
|
|
549
|
+
3. `HELIUS_API_KEY` (auto-built Helius URL)
|
|
550
|
+
|
|
551
|
+
Program ids per environment: `getVaultProgramId("test" | "prod")` in
|
|
552
|
+
[`src/env.ts`](src/env.ts).
|
|
553
|
+
|
|
554
|
+
## CLI scripts
|
|
555
|
+
|
|
556
|
+
Thin wrappers around the SDK live in [`scripts/`](scripts/). From the repo root:
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
pnpm deposit test <VAULT_PDA> 100
|
|
560
|
+
pnpm inspect prod <VAULT_PDA>
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
See [`scripts/README.md`](scripts/README.md) for the full command list.
|
|
564
|
+
|
|
565
|
+
## Types and addresses
|
|
566
|
+
|
|
567
|
+
- Public keys use `@solana/kit` `Address` strings in builder args.
|
|
568
|
+
- Convert from web3.js: `fromWeb3Pk(keypair.publicKey)` (from `common`).
|
|
569
|
+
- Amounts in `TxArgs` are `bigint` base units unless noted otherwise.
|