@tbookdev/vault-sdk 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,4359 @@
1
+ 'use strict';
2
+
3
+ var anchor = require('@coral-xyz/anchor');
4
+ var web3_js = require('@solana/web3.js');
5
+ var crypto = require('crypto');
6
+ var bs58 = require('bs58');
7
+ var BN = require('bn.js');
8
+ var splToken = require('@solana/spl-token');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var bs58__default = /*#__PURE__*/_interopDefault(bs58);
13
+ var BN__default = /*#__PURE__*/_interopDefault(BN);
14
+
15
+ // src/client.ts
16
+ var USDC_DECIMALS = 6;
17
+ var SHARE_DECIMALS = 6;
18
+ var ONE_USDC = 1e6;
19
+ var ONE_SHARE = 1e6;
20
+ var DEFAULT_CANCEL_FEE_BPS = 10;
21
+ var DEFAULT_RPC_TIMEOUT_MS = 3e4;
22
+ var DEFAULT_RPC = {
23
+ devnet: "https://api.devnet.solana.com",
24
+ "mainnet-beta": "https://api.mainnet-beta.solana.com"
25
+ };
26
+ function getDefaultRpcUrl(network) {
27
+ return DEFAULT_RPC[network];
28
+ }
29
+ var SHARE_PRICE_API_URL = "https://d5a6giwxrgpzqpxktgpgufpvtq0ltxgk.lambda-url.ap-southeast-1.on.aws/share-price";
30
+ var EXPLORER_BASE = "https://explorer.solana.com";
31
+ function explorerUrl(type, value, network) {
32
+ const cluster = network === "mainnet-beta" ? "" : `?cluster=${network}`;
33
+ return `${EXPLORER_BASE}/${type}/${value}${cluster}`;
34
+ }
35
+ var BUILT_IN_VAULTS = {
36
+ "devnet:rcUSDP": {
37
+ id: "rcUSDP",
38
+ programId: new web3_js.PublicKey("BdeE87CsE9kvxJJcxaJqxNsC2nC6hFft3UBzcgAm5X1i"),
39
+ // Circle devnet USDC — must match the mint the on-chain vault was initialized with
40
+ usdcMint: new web3_js.PublicKey("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"),
41
+ network: "devnet"
42
+ }
43
+ // mainnet config will be added when contract is deployed
44
+ // "mainnet-beta:rcUSDP": { ... },
45
+ };
46
+ function getVaultConfig(vaultId, network) {
47
+ return BUILT_IN_VAULTS[`${network}:${vaultId}`];
48
+ }
49
+ function listBuiltInVaults(network) {
50
+ return Object.values(BUILT_IN_VAULTS).filter((v) => v.network === network).map((v) => ({
51
+ id: v.id,
52
+ name: `${v.id} Vault`,
53
+ description: "RWA yield vault powered by TBook",
54
+ programId: v.programId.toBase58(),
55
+ network: v.network,
56
+ usdcMint: v.usdcMint.toBase58(),
57
+ shareToken: { symbol: v.id, decimals: SHARE_DECIMALS },
58
+ status: "active"
59
+ }));
60
+ }
61
+ var DEFAULT_VAULT_ID = "rcUSDP";
62
+
63
+ // src/errors.ts
64
+ var VaultSdkError = class extends Error {
65
+ /** Machine-readable error code. */
66
+ code;
67
+ /** Non-technical message suitable for displaying to end users. */
68
+ userFriendlyMessage;
69
+ constructor(code, message, userFriendlyMessage) {
70
+ super(message);
71
+ this.name = "VaultSdkError";
72
+ this.code = code;
73
+ this.userFriendlyMessage = userFriendlyMessage ?? "Something went wrong. Please try again.";
74
+ }
75
+ };
76
+ var VaultPausedError = class extends VaultSdkError {
77
+ constructor() {
78
+ super(
79
+ "VAULT_PAUSED",
80
+ "The vault is currently paused. Only claim operations are allowed.",
81
+ "The service is temporarily unavailable. Please try again later."
82
+ );
83
+ this.name = "VaultPausedError";
84
+ }
85
+ };
86
+ var MinDepositError = class extends VaultSdkError {
87
+ /** The minimum required deposit in USDC. */
88
+ minDeposit;
89
+ constructor(minDeposit) {
90
+ super(
91
+ "MIN_DEPOSIT",
92
+ `Minimum deposit is ${minDeposit} USDC.`,
93
+ `The deposit amount is too small. Minimum is ${minDeposit} USDC.`
94
+ );
95
+ this.name = "MinDepositError";
96
+ this.minDeposit = minDeposit;
97
+ }
98
+ };
99
+ var MaxEpochDepositError = class extends VaultSdkError {
100
+ maxEpochDeposit;
101
+ constructor(maxEpochDeposit) {
102
+ super(
103
+ "MAX_EPOCH_DEPOSIT",
104
+ `This deposit would exceed the epoch limit of ${maxEpochDeposit} USDC.`,
105
+ `The deposit amount exceeds the current limit of ${maxEpochDeposit} USDC.`
106
+ );
107
+ this.name = "MaxEpochDepositError";
108
+ this.maxEpochDeposit = maxEpochDeposit;
109
+ }
110
+ };
111
+ var EpochNotOpenError = class extends VaultSdkError {
112
+ constructor(epochType, status) {
113
+ super(
114
+ "EPOCH_NOT_OPEN",
115
+ `The ${epochType} epoch is currently "${status}", not "Open".`,
116
+ "This operation is not available right now. Please try again later."
117
+ );
118
+ this.name = "EpochNotOpenError";
119
+ }
120
+ };
121
+ var VaultNotFoundError = class extends VaultSdkError {
122
+ constructor() {
123
+ super(
124
+ "VAULT_NOT_FOUND",
125
+ "VaultMirror account not found on-chain. Is the program deployed?",
126
+ "The vault service is currently unreachable. Please try again later."
127
+ );
128
+ this.name = "VaultNotFoundError";
129
+ }
130
+ };
131
+ var UserAccountNotFoundError = class extends VaultSdkError {
132
+ constructor(pubkey) {
133
+ super(
134
+ "USER_NOT_FOUND",
135
+ `No vault user account found for ${pubkey}.`,
136
+ "No account found. Please make a deposit first to create your account."
137
+ );
138
+ this.name = "UserAccountNotFoundError";
139
+ }
140
+ };
141
+ var UnknownVaultError = class extends VaultSdkError {
142
+ constructor(vaultId) {
143
+ super(
144
+ "UNKNOWN_VAULT",
145
+ `Vault "${vaultId}" is not registered. Use listVaults() to see available vaults.`,
146
+ "The requested vault is not available."
147
+ );
148
+ this.name = "UnknownVaultError";
149
+ }
150
+ };
151
+ var SharePriceUnavailableError = class extends VaultSdkError {
152
+ constructor(reason) {
153
+ super(
154
+ "PRICE_UNAVAILABLE",
155
+ `Share price data is unavailable${reason ? `: ${reason}` : "."}`,
156
+ "Price information is temporarily unavailable. Please try again in a few minutes."
157
+ );
158
+ this.name = "SharePriceUnavailableError";
159
+ }
160
+ };
161
+ var NoPendingDepositError = class extends VaultSdkError {
162
+ constructor() {
163
+ super(
164
+ "NO_PENDING_DEPOSIT",
165
+ "No pending deposit to cancel. The user has no active deposit in the current epoch.",
166
+ "You don't have a pending deposit to cancel."
167
+ );
168
+ this.name = "NoPendingDepositError";
169
+ }
170
+ };
171
+ var RpcError = class extends VaultSdkError {
172
+ /** The underlying error from the RPC library. */
173
+ cause;
174
+ constructor(operation, cause) {
175
+ const msg = cause instanceof Error ? cause.message : String(cause);
176
+ super(
177
+ "RPC_ERROR",
178
+ `RPC call failed during ${operation}: ${msg}`,
179
+ "A network error occurred. Please check your connection and try again."
180
+ );
181
+ this.name = "RpcError";
182
+ this.cause = cause;
183
+ }
184
+ };
185
+ var RpcTimeoutError = class extends VaultSdkError {
186
+ /** The timeout duration in milliseconds. */
187
+ timeoutMs;
188
+ constructor(operation, timeoutMs) {
189
+ super(
190
+ "RPC_TIMEOUT",
191
+ `RPC call timed out after ${timeoutMs}ms during ${operation}`,
192
+ "The request timed out. Please try again."
193
+ );
194
+ this.name = "RpcTimeoutError";
195
+ this.timeoutMs = timeoutMs;
196
+ }
197
+ };
198
+ var TransactionExpiredError = class extends VaultSdkError {
199
+ /** The transaction signature. */
200
+ signature;
201
+ constructor(signature) {
202
+ super(
203
+ "TX_EXPIRED",
204
+ `Transaction ${signature} expired (blockhash no longer valid)`,
205
+ "The transaction expired. Please try again."
206
+ );
207
+ this.name = "TransactionExpiredError";
208
+ this.signature = signature;
209
+ }
210
+ };
211
+ var TransactionFailedError = class extends VaultSdkError {
212
+ /** The transaction signature. */
213
+ signature;
214
+ /** The on-chain error object. */
215
+ txError;
216
+ constructor(signature, txError) {
217
+ super(
218
+ "TX_FAILED",
219
+ `Transaction ${signature} failed on-chain: ${JSON.stringify(txError)}`,
220
+ "The transaction failed. Please try again or contact support."
221
+ );
222
+ this.name = "TransactionFailedError";
223
+ this.signature = signature;
224
+ this.txError = txError;
225
+ }
226
+ };
227
+ function getVaultMirrorPda(programId) {
228
+ return web3_js.PublicKey.findProgramAddressSync(
229
+ [Buffer.from("vault_mirror")],
230
+ programId
231
+ );
232
+ }
233
+ function getUsdcVaultPda(vaultMirror, programId) {
234
+ return web3_js.PublicKey.findProgramAddressSync(
235
+ [Buffer.from("usdc_vault"), vaultMirror.toBuffer()],
236
+ programId
237
+ );
238
+ }
239
+ function getUserPda(vaultMirror, user, programId) {
240
+ return web3_js.PublicKey.findProgramAddressSync(
241
+ [Buffer.from("user"), vaultMirror.toBuffer(), user.toBuffer()],
242
+ programId
243
+ );
244
+ }
245
+ function getDepositEpochPda(vaultMirror, epoch, programId) {
246
+ return web3_js.PublicKey.findProgramAddressSync(
247
+ [
248
+ Buffer.from("deposit_epoch"),
249
+ vaultMirror.toBuffer(),
250
+ epochToLeBytes(epoch)
251
+ ],
252
+ programId
253
+ );
254
+ }
255
+ function getRedeemEpochPda(vaultMirror, epoch, programId) {
256
+ return web3_js.PublicKey.findProgramAddressSync(
257
+ [
258
+ Buffer.from("redeem_epoch"),
259
+ vaultMirror.toBuffer(),
260
+ epochToLeBytes(epoch)
261
+ ],
262
+ programId
263
+ );
264
+ }
265
+ function epochToLeBytes(epoch) {
266
+ return Buffer.from(
267
+ new Uint8Array(new BigUint64Array([BigInt(epoch)]).buffer)
268
+ );
269
+ }
270
+
271
+ // src/types.ts
272
+ var STATUS_MAP = {
273
+ 0: "Open",
274
+ 1: "Frozen",
275
+ 2: "Bridging",
276
+ 3: "Settled",
277
+ 4: "RolledBack"
278
+ };
279
+
280
+ // src/queries.ts
281
+ async function fetchVaultInfo(connection, programId, program) {
282
+ const [vaultMirrorPda] = getVaultMirrorPda(programId);
283
+ if (program) {
284
+ try {
285
+ return await fetchVaultInfoAnchor(connection, programId, program, vaultMirrorPda);
286
+ } catch {
287
+ }
288
+ }
289
+ return fetchVaultInfoRaw(connection, programId, vaultMirrorPda);
290
+ }
291
+ async function fetchVaultInfoAnchor(connection, programId, program, vaultMirrorPda) {
292
+ const v = await program.account.vaultMirror.fetch(vaultMirrorPda);
293
+ const [usdcVaultPda] = getUsdcVaultPda(vaultMirrorPda, programId);
294
+ const vaultUsdcBalance = await safeTokenBalance(connection, usdcVaultPda);
295
+ const currentDepositEpoch = v.currentDepositEpoch.toNumber();
296
+ const currentRedeemEpoch = v.currentRedeemEpoch.toNumber();
297
+ const vault = {
298
+ admin: v.authority.toString(),
299
+ curator: v.curator.toString(),
300
+ operator: v.operator.toString(),
301
+ totalShares: v.totalShares.toNumber() / 10 ** SHARE_DECIMALS,
302
+ currentDepositEpoch,
303
+ currentRedeemEpoch,
304
+ maxEpochDeposit: v.maxEpochDeposit.toNumber() / 10 ** USDC_DECIMALS,
305
+ minDeposit: v.minDeposit.toNumber() / 10 ** USDC_DECIMALS,
306
+ paused: v.paused,
307
+ usdcMint: v.usdcMint,
308
+ vaultUsdcBalance,
309
+ tvlEstimate: vaultUsdcBalance,
310
+ cancelFeeBps: DEFAULT_CANCEL_FEE_BPS
311
+ };
312
+ const depositEpoch = await fetchDepositEpochAnchor(program, programId, vaultMirrorPda, currentDepositEpoch);
313
+ const redeemEpoch = await fetchRedeemEpochAnchor(program, programId, vaultMirrorPda, currentRedeemEpoch);
314
+ return { vault, depositEpoch, redeemEpoch };
315
+ }
316
+ async function fetchVaultInfoRaw(connection, programId, vaultMirrorPda) {
317
+ let accountInfo;
318
+ try {
319
+ accountInfo = await connection.getAccountInfo(vaultMirrorPda);
320
+ } catch (err) {
321
+ throw new RpcError("fetchVaultInfo", err);
322
+ }
323
+ if (!accountInfo) {
324
+ return { vault: null, depositEpoch: null, redeemEpoch: null };
325
+ }
326
+ const data = accountInfo.data;
327
+ const o = 8;
328
+ const admin = new web3_js.PublicKey(data.subarray(o, o + 32));
329
+ const curator = new web3_js.PublicKey(data.subarray(o + 32, o + 64));
330
+ const operator = new web3_js.PublicKey(data.subarray(o + 64, o + 96));
331
+ const usdcMintKey = new web3_js.PublicKey(data.subarray(o + 96, o + 128));
332
+ const usdcVaultKey = new web3_js.PublicKey(data.subarray(o + 128, o + 160));
333
+ const totalShares = Number(data.readBigUInt64LE(o + 160)) / 10 ** SHARE_DECIMALS;
334
+ const currentDepositEpoch = Number(data.readBigUInt64LE(o + 168));
335
+ const currentRedeemEpoch = Number(data.readBigUInt64LE(o + 176));
336
+ const maxEpochDeposit = Number(data.readBigUInt64LE(o + 184)) / 10 ** USDC_DECIMALS;
337
+ const minDeposit = Number(data.readBigUInt64LE(o + 192)) / 10 ** USDC_DECIMALS;
338
+ const paused = data[o + 200] !== 0;
339
+ const vaultUsdcBalance = await safeTokenBalance(connection, usdcVaultKey);
340
+ const vault = {
341
+ admin: admin.toString(),
342
+ curator: curator.toString(),
343
+ operator: operator.toString(),
344
+ totalShares,
345
+ currentDepositEpoch,
346
+ currentRedeemEpoch,
347
+ maxEpochDeposit,
348
+ minDeposit,
349
+ paused,
350
+ usdcMint: usdcMintKey,
351
+ vaultUsdcBalance,
352
+ tvlEstimate: vaultUsdcBalance,
353
+ cancelFeeBps: DEFAULT_CANCEL_FEE_BPS
354
+ };
355
+ const depositEpoch = await fetchDepositEpochRaw(connection, programId, getVaultMirrorPda(programId)[0], currentDepositEpoch);
356
+ const redeemEpoch = await fetchRedeemEpochRaw(connection, programId, getVaultMirrorPda(programId)[0], currentRedeemEpoch);
357
+ return { vault, depositEpoch, redeemEpoch };
358
+ }
359
+ async function fetchDepositEpochAnchor(program, programId, vaultMirrorPda, epoch) {
360
+ try {
361
+ const [pda] = getDepositEpochPda(vaultMirrorPda, epoch, programId);
362
+ const e = await program.account.depositEpoch.fetch(pda);
363
+ const statusKey = Object.keys(e.status)[0];
364
+ return {
365
+ epoch: e.epoch.toNumber(),
366
+ status: statusKey.charAt(0).toUpperCase() + statusKey.slice(1),
367
+ totalDepositUsdc: e.totalDepositUsdc.toNumber() / 10 ** USDC_DECIMALS,
368
+ depositUserCount: e.depositUserCount,
369
+ settledSharesMinted: e.settledSharesMinted.toNumber() / 10 ** SHARE_DECIMALS
370
+ };
371
+ } catch (err) {
372
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
373
+ return null;
374
+ }
375
+ throw err;
376
+ }
377
+ }
378
+ async function fetchRedeemEpochAnchor(program, programId, vaultMirrorPda, epoch) {
379
+ try {
380
+ const [pda] = getRedeemEpochPda(vaultMirrorPda, epoch, programId);
381
+ const e = await program.account.redeemEpoch.fetch(pda);
382
+ const statusKey = Object.keys(e.status)[0];
383
+ return {
384
+ epoch: e.epoch.toNumber(),
385
+ status: statusKey.charAt(0).toUpperCase() + statusKey.slice(1),
386
+ totalRedeemShares: e.totalRedeemShares.toNumber() / 10 ** SHARE_DECIMALS,
387
+ redeemUserCount: e.redeemUserCount,
388
+ settledUsdcForRedeems: e.settledUsdcForRedeems.toNumber() / 10 ** USDC_DECIMALS
389
+ };
390
+ } catch (err) {
391
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
392
+ return null;
393
+ }
394
+ throw err;
395
+ }
396
+ }
397
+ async function fetchDepositEpochRaw(connection, programId, vaultMirrorPda, epoch) {
398
+ try {
399
+ const [pda] = getDepositEpochPda(vaultMirrorPda, epoch, programId);
400
+ const info = await connection.getAccountInfo(pda);
401
+ if (!info) return null;
402
+ const d = info.data;
403
+ const eo = 8;
404
+ return {
405
+ epoch: Number(d.readBigUInt64LE(eo)),
406
+ status: STATUS_MAP[d[eo + 8]] || "Open",
407
+ totalDepositUsdc: Number(d.readBigUInt64LE(eo + 9)) / 10 ** USDC_DECIMALS,
408
+ depositUserCount: d.readUInt32LE(eo + 17),
409
+ settledSharesMinted: Number(d.readBigUInt64LE(eo + 21)) / 10 ** SHARE_DECIMALS
410
+ };
411
+ } catch (err) {
412
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
413
+ return null;
414
+ }
415
+ throw err;
416
+ }
417
+ }
418
+ async function fetchRedeemEpochRaw(connection, programId, vaultMirrorPda, epoch) {
419
+ try {
420
+ const [pda] = getRedeemEpochPda(vaultMirrorPda, epoch, programId);
421
+ const info = await connection.getAccountInfo(pda);
422
+ if (!info) return null;
423
+ const d = info.data;
424
+ const eo = 8;
425
+ return {
426
+ epoch: Number(d.readBigUInt64LE(eo)),
427
+ status: STATUS_MAP[d[eo + 8]] || "Open",
428
+ totalRedeemShares: Number(d.readBigUInt64LE(eo + 9)) / 10 ** SHARE_DECIMALS,
429
+ redeemUserCount: d.readUInt32LE(eo + 17),
430
+ settledUsdcForRedeems: Number(d.readBigUInt64LE(eo + 21)) / 10 ** USDC_DECIMALS
431
+ };
432
+ } catch (err) {
433
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
434
+ return null;
435
+ }
436
+ throw err;
437
+ }
438
+ }
439
+ async function fetchUserAccount(connection, programId, user, program) {
440
+ const [vaultMirrorPda] = getVaultMirrorPda(programId);
441
+ const [userPda] = getUserPda(vaultMirrorPda, user, programId);
442
+ if (!program) {
443
+ return null;
444
+ }
445
+ let userAccount;
446
+ try {
447
+ userAccount = await program.account.userAccount.fetch(userPda);
448
+ } catch (err) {
449
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
450
+ return null;
451
+ }
452
+ throw err;
453
+ }
454
+ const shares = userAccount.shares.toNumber() / 10 ** SHARE_DECIMALS;
455
+ const pendingDepositUsdc = userAccount.pendingDepositUsdc.toNumber() / 10 ** USDC_DECIMALS;
456
+ const pendingDepositEpoch = userAccount.pendingDepositEpoch.toNumber();
457
+ const pendingRedeemShares = userAccount.pendingRedeemShares.toNumber() / 10 ** SHARE_DECIMALS;
458
+ const pendingRedeemEpoch = userAccount.pendingRedeemEpoch.toNumber();
459
+ const claimableUsdc = userAccount.claimableUsdc.toNumber() / 10 ** USDC_DECIMALS;
460
+ const effective = await computeEffectiveBalance(
461
+ connection,
462
+ programId,
463
+ program,
464
+ vaultMirrorPda,
465
+ {
466
+ shares: BigInt(userAccount.shares.toString()),
467
+ claimableUsdc: BigInt(userAccount.claimableUsdc.toString()),
468
+ pendingDepositUsdc: BigInt(userAccount.pendingDepositUsdc.toString()),
469
+ pendingDepositEpoch,
470
+ pendingRedeemShares: BigInt(userAccount.pendingRedeemShares.toString()),
471
+ pendingRedeemEpoch
472
+ }
473
+ );
474
+ return {
475
+ shares,
476
+ pendingDepositUsdc,
477
+ pendingDepositEpoch,
478
+ pendingRedeemShares,
479
+ pendingRedeemEpoch,
480
+ claimableUsdc,
481
+ effectiveShares: Number(effective.shares) / 10 ** SHARE_DECIMALS,
482
+ effectiveClaimableUsdc: Number(effective.claimableUsdc) / 10 ** USDC_DECIMALS
483
+ };
484
+ }
485
+ async function computeEffectiveBalance(connection, programId, program, vaultMirrorPda, raw) {
486
+ let shares = raw.shares;
487
+ let claimableUsdc = raw.claimableUsdc;
488
+ let vaultState;
489
+ try {
490
+ vaultState = await program.account.vaultMirror.fetch(vaultMirrorPda);
491
+ } catch (err) {
492
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
493
+ return { shares, claimableUsdc };
494
+ }
495
+ throw err;
496
+ }
497
+ const currentDepositEpoch = vaultState.currentDepositEpoch.toNumber();
498
+ const currentRedeemEpoch = vaultState.currentRedeemEpoch.toNumber();
499
+ if (raw.pendingDepositUsdc > 0n && raw.pendingDepositEpoch !== currentDepositEpoch) {
500
+ try {
501
+ const [pda] = getDepositEpochPda(vaultMirrorPda, raw.pendingDepositEpoch, programId);
502
+ const epoch = await program.account.depositEpoch.fetch(pda);
503
+ const status = epoch.status;
504
+ if ("settled" in status) {
505
+ const totalDeposit = BigInt(epoch.totalDepositUsdc.toString());
506
+ const sharesMinted = BigInt(epoch.settledSharesMinted.toString());
507
+ if (totalDeposit > 0n) {
508
+ shares += raw.pendingDepositUsdc * sharesMinted / totalDeposit;
509
+ }
510
+ } else if ("rolledBack" in status) {
511
+ claimableUsdc += raw.pendingDepositUsdc;
512
+ }
513
+ } catch (err) {
514
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) ; else {
515
+ throw err;
516
+ }
517
+ }
518
+ }
519
+ if (raw.pendingRedeemShares > 0n && raw.pendingRedeemEpoch !== currentRedeemEpoch) {
520
+ try {
521
+ const [pda] = getRedeemEpochPda(vaultMirrorPda, raw.pendingRedeemEpoch, programId);
522
+ const epoch = await program.account.redeemEpoch.fetch(pda);
523
+ const status = epoch.status;
524
+ if ("settled" in status) {
525
+ const totalRedeem = BigInt(epoch.totalRedeemShares.toString());
526
+ const usdcForRedeems = BigInt(epoch.settledUsdcForRedeems.toString());
527
+ if (totalRedeem > 0n) {
528
+ claimableUsdc += raw.pendingRedeemShares * usdcForRedeems / totalRedeem;
529
+ }
530
+ } else if ("rolledBack" in status) {
531
+ shares += raw.pendingRedeemShares;
532
+ }
533
+ } catch (err) {
534
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) ; else {
535
+ throw err;
536
+ }
537
+ }
538
+ }
539
+ return { shares, claimableUsdc };
540
+ }
541
+ async function getLazySettleRemainingAccounts(program, programId, vaultMirrorPda, userPda) {
542
+ try {
543
+ const userAccount = await program.account.userAccount.fetch(userPda);
544
+ const pendingDepositEpoch = userAccount.pendingDepositEpoch.toNumber();
545
+ const pendingRedeemEpoch = userAccount.pendingRedeemEpoch.toNumber();
546
+ const hasPendingDeposit = userAccount.pendingDepositUsdc.toNumber() > 0;
547
+ const hasPendingRedeem = userAccount.pendingRedeemShares.toNumber() > 0;
548
+ if (!hasPendingDeposit && !hasPendingRedeem) return [];
549
+ const accounts = [];
550
+ if (hasPendingDeposit) {
551
+ const [pda] = getDepositEpochPda(vaultMirrorPda, pendingDepositEpoch, programId);
552
+ accounts.push({ pubkey: pda, isWritable: false, isSigner: false });
553
+ }
554
+ if (hasPendingRedeem) {
555
+ const [pda] = getRedeemEpochPda(vaultMirrorPda, pendingRedeemEpoch, programId);
556
+ accounts.push({ pubkey: pda, isWritable: false, isSigner: false });
557
+ }
558
+ return accounts;
559
+ } catch (err) {
560
+ if (err instanceof Error && (err.message.includes("Account does not exist") || err.message.includes("could not find account"))) {
561
+ return [];
562
+ }
563
+ throw err;
564
+ }
565
+ }
566
+ async function safeTokenBalance(connection, tokenAccount) {
567
+ try {
568
+ const info = await connection.getTokenAccountBalance(tokenAccount);
569
+ return info.value.uiAmount ?? 0;
570
+ } catch {
571
+ return 0;
572
+ }
573
+ }
574
+
575
+ // src/share-price-cache.ts
576
+ var DEFAULT_MAX_STALE_MS = 6e5;
577
+ var DEFAULT_FAILURE_THRESHOLD = 3;
578
+ var DEFAULT_CIRCUIT_RESET_MS = 6e4;
579
+ var SharePriceCache = class {
580
+ /** Maximum age (in ms) before cached data is considered stale. */
581
+ maxStaleMs;
582
+ data = null;
583
+ storedAt = 0;
584
+ // Circuit breaker state
585
+ failureCount = 0;
586
+ failureThreshold;
587
+ circuitOpenedAt = 0;
588
+ circuitResetMs;
589
+ constructor(opts) {
590
+ this.maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
591
+ this.failureThreshold = opts?.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD;
592
+ this.circuitResetMs = opts?.circuitResetMs ?? DEFAULT_CIRCUIT_RESET_MS;
593
+ }
594
+ /**
595
+ * Return cached data if it is fresher than `maxAge` milliseconds.
596
+ * Returns `null` if the cache is empty or the data is too old.
597
+ *
598
+ * @param maxAge - Override the default freshness window (pass `Infinity` for stale-ok)
599
+ */
600
+ get(maxAge) {
601
+ if (!this.data) return null;
602
+ const age = Date.now() - this.storedAt;
603
+ const threshold = maxAge ?? this.maxStaleMs;
604
+ if (age > threshold) return null;
605
+ return this.data;
606
+ }
607
+ /** Store fresh share price data. */
608
+ set(data) {
609
+ this.data = data;
610
+ this.storedAt = Date.now();
611
+ }
612
+ /** Whether the circuit breaker is currently open (API calls should be skipped). */
613
+ isCircuitOpen() {
614
+ if (this.failureCount < this.failureThreshold) return false;
615
+ if (Date.now() - this.circuitOpenedAt >= this.circuitResetMs) {
616
+ return false;
617
+ }
618
+ return true;
619
+ }
620
+ /** Record a failed API call. Opens the circuit after the threshold is reached. */
621
+ recordFailure() {
622
+ this.failureCount += 1;
623
+ if (this.failureCount >= this.failureThreshold) {
624
+ this.circuitOpenedAt = Date.now();
625
+ }
626
+ }
627
+ /** Record a successful API call. Resets the circuit breaker. */
628
+ recordSuccess() {
629
+ this.failureCount = 0;
630
+ this.circuitOpenedAt = 0;
631
+ }
632
+ };
633
+ var sharePriceCache = new SharePriceCache();
634
+
635
+ // src/share-price.ts
636
+ var API_FETCH_TIMEOUT_MS = 5e3;
637
+ async function fetchSharePrice(options) {
638
+ const opts = typeof options === "string" ? { apiUrl: options } : options ?? {};
639
+ const apiUrl = opts.apiUrl ?? SHARE_PRICE_API_URL;
640
+ const cached = sharePriceCache.get();
641
+ if (cached) {
642
+ return { ...cached, source: "cache", stale: false };
643
+ }
644
+ if (!sharePriceCache.isCircuitOpen()) {
645
+ try {
646
+ const data = await fetchFromApi(apiUrl);
647
+ sharePriceCache.set(data);
648
+ sharePriceCache.recordSuccess();
649
+ return { ...data, source: "api" };
650
+ } catch {
651
+ sharePriceCache.recordFailure();
652
+ }
653
+ }
654
+ const stale = sharePriceCache.get(Infinity);
655
+ if (stale) {
656
+ return { ...stale, source: "cache", stale: true };
657
+ }
658
+ throw new SharePriceUnavailableError("All price sources exhausted");
659
+ }
660
+ async function fetchFromApi(apiUrl) {
661
+ const controller = new AbortController();
662
+ const timer = setTimeout(() => controller.abort(), API_FETCH_TIMEOUT_MS);
663
+ let res;
664
+ try {
665
+ res = await fetch(apiUrl, { signal: controller.signal });
666
+ } catch (err) {
667
+ throw new SharePriceUnavailableError(
668
+ err instanceof Error ? err.message : "Network error"
669
+ );
670
+ } finally {
671
+ clearTimeout(timer);
672
+ }
673
+ if (!res.ok) {
674
+ throw new SharePriceUnavailableError(`API returned HTTP ${res.status}`);
675
+ }
676
+ let data;
677
+ try {
678
+ data = await res.json();
679
+ } catch {
680
+ throw new SharePriceUnavailableError("Invalid JSON response");
681
+ }
682
+ if (!data.success || !data.sharePrice) {
683
+ throw new SharePriceUnavailableError("Missing sharePrice in response");
684
+ }
685
+ const priceNum = parseFloat(data.sharePrice);
686
+ if (!Number.isFinite(priceNum) || priceNum <= 0) {
687
+ throw new SharePriceUnavailableError(
688
+ `Invalid sharePrice value: ${data.sharePrice}`
689
+ );
690
+ }
691
+ return {
692
+ price: data.sharePrice,
693
+ priceNum,
694
+ apy: data.apy || "0",
695
+ date: data.date || "",
696
+ fetchedAt: data.fetchedAt || (/* @__PURE__ */ new Date()).toISOString()
697
+ };
698
+ }
699
+ function anchorDiscriminator(name) {
700
+ return crypto.createHash("sha256").update(`global:${name}`).digest().subarray(0, 8);
701
+ }
702
+ var DISCRIMINATORS = {
703
+ deposit: {
704
+ disc: anchorDiscriminator("deposit"),
705
+ type: "deposit",
706
+ label: "Deposit"
707
+ },
708
+ request_redeem: {
709
+ disc: anchorDiscriminator("request_redeem"),
710
+ type: "redeem",
711
+ label: "Request Redeem"
712
+ },
713
+ claim: {
714
+ disc: anchorDiscriminator("claim"),
715
+ type: "claim",
716
+ label: "Claim"
717
+ },
718
+ cancel_deposit: {
719
+ disc: anchorDiscriminator("cancel_deposit"),
720
+ type: "cancel_deposit",
721
+ label: "Cancel Deposit"
722
+ }
723
+ };
724
+ var DISCRIMINATOR_ENTRIES = Object.values(DISCRIMINATORS);
725
+ function classifyInstruction(ixData) {
726
+ if (ixData.length < 8) {
727
+ return { type: "unknown", label: "Unknown" };
728
+ }
729
+ const prefix = Buffer.from(ixData.subarray(0, 8));
730
+ for (const entry of DISCRIMINATOR_ENTRIES) {
731
+ if (prefix.equals(entry.disc)) {
732
+ return { type: entry.type, label: entry.label };
733
+ }
734
+ }
735
+ return { type: "unknown", label: "Unknown" };
736
+ }
737
+ async function fetchTransactionHistory(connection, userPda, programId, options) {
738
+ const limit = options?.limit ?? 20;
739
+ const signatures = await connection.getSignaturesForAddress(userPda, {
740
+ limit,
741
+ before: options?.before
742
+ });
743
+ if (signatures.length === 0) {
744
+ return [];
745
+ }
746
+ const sigStrings = signatures.map((s) => s.signature);
747
+ const parsedTxs = await connection.getParsedTransactions(sigStrings, {
748
+ maxSupportedTransactionVersion: 0
749
+ });
750
+ return signatures.map((sig, index) => {
751
+ const parsed = parsedTxs[index];
752
+ let type = "unknown";
753
+ let description = "Vault transaction";
754
+ if (parsed?.transaction?.message?.instructions) {
755
+ for (const ix of parsed.transaction.message.instructions) {
756
+ if ("data" in ix && ix.programId.equals(programId)) {
757
+ try {
758
+ const data = Buffer.from(bs58__default.default.decode(ix.data));
759
+ const classified = classifyInstruction(data);
760
+ type = classified.type;
761
+ description = classified.label;
762
+ } catch {
763
+ }
764
+ break;
765
+ }
766
+ }
767
+ if (type === "unknown" && parsed.meta?.innerInstructions) {
768
+ for (const inner of parsed.meta.innerInstructions) {
769
+ for (const ix of inner.instructions) {
770
+ if ("data" in ix && ix.programId.equals(programId)) {
771
+ try {
772
+ const data = Buffer.from(bs58__default.default.decode(ix.data));
773
+ const classified = classifyInstruction(data);
774
+ type = classified.type;
775
+ description = classified.label;
776
+ } catch {
777
+ }
778
+ if (type !== "unknown") break;
779
+ }
780
+ }
781
+ if (type !== "unknown") break;
782
+ }
783
+ }
784
+ }
785
+ if (sig.err) {
786
+ description = `Failed: ${description}`;
787
+ }
788
+ return {
789
+ signature: sig.signature,
790
+ type,
791
+ timestamp: sig.blockTime ?? 0,
792
+ slot: sig.slot,
793
+ success: sig.err === null,
794
+ description
795
+ };
796
+ });
797
+ }
798
+
799
+ // src/rpc-utils.ts
800
+ function sleep(ms) {
801
+ return new Promise((resolve) => setTimeout(resolve, ms));
802
+ }
803
+ async function withTimeout(promise, ms, label) {
804
+ if (ms <= 0 || !Number.isFinite(ms)) return promise;
805
+ const controller = new AbortController();
806
+ const timer = setTimeout(() => controller.abort(), ms);
807
+ try {
808
+ const result = await Promise.race([
809
+ promise,
810
+ new Promise((_, reject) => {
811
+ controller.signal.addEventListener(
812
+ "abort",
813
+ () => reject(new RpcTimeoutError(label, ms))
814
+ );
815
+ })
816
+ ]);
817
+ return result;
818
+ } finally {
819
+ clearTimeout(timer);
820
+ }
821
+ }
822
+ async function confirmTransactionWithRetry(opts) {
823
+ const {
824
+ connection,
825
+ signature,
826
+ blockhash: _blockhash,
827
+ lastValidBlockHeight,
828
+ commitment = "confirmed",
829
+ timeoutMs = 6e4,
830
+ initialIntervalMs = 2e3
831
+ } = opts;
832
+ const COMMITMENT_LEVELS = ["processed", "confirmed", "finalized"];
833
+ const desiredLevel = COMMITMENT_LEVELS.indexOf(commitment);
834
+ const start = Date.now();
835
+ let interval = initialIntervalMs;
836
+ const MAX_INTERVAL = 5e3;
837
+ while (Date.now() - start < timeoutMs) {
838
+ try {
839
+ const blockHeight = await connection.getBlockHeight();
840
+ if (blockHeight > lastValidBlockHeight) {
841
+ throw new TransactionExpiredError(signature);
842
+ }
843
+ } catch (err) {
844
+ if (err instanceof TransactionExpiredError) throw err;
845
+ }
846
+ try {
847
+ const { value } = await connection.getSignatureStatuses([signature]);
848
+ const status = value?.[0];
849
+ if (status?.err) {
850
+ throw new TransactionFailedError(signature, status.err);
851
+ }
852
+ if (status?.confirmationStatus) {
853
+ const actualLevel = COMMITMENT_LEVELS.indexOf(
854
+ status.confirmationStatus
855
+ );
856
+ if (actualLevel >= desiredLevel) {
857
+ return;
858
+ }
859
+ }
860
+ } catch (err) {
861
+ if (err instanceof TransactionFailedError) throw err;
862
+ }
863
+ await sleep(interval);
864
+ interval = Math.min(interval * 1.5, MAX_INTERVAL);
865
+ }
866
+ throw new RpcTimeoutError("confirmTransaction", timeoutMs);
867
+ }
868
+
869
+ // src/transactions.ts
870
+ async function finalizeTx(tx, program, feePayer, timeoutMs = DEFAULT_RPC_TIMEOUT_MS) {
871
+ const connection = program.provider.connection;
872
+ const { blockhash, lastValidBlockHeight } = await withTimeout(
873
+ connection.getLatestBlockhash(),
874
+ timeoutMs,
875
+ "getLatestBlockhash"
876
+ );
877
+ tx.recentBlockhash = blockhash;
878
+ tx.lastValidBlockHeight = lastValidBlockHeight;
879
+ tx.feePayer = feePayer;
880
+ return {
881
+ transaction: tx,
882
+ serialized: bs58__default.default.encode(tx.serialize({ requireAllSignatures: false })),
883
+ blockhash,
884
+ lastValidBlockHeight
885
+ };
886
+ }
887
+ function usdcToRaw(amount) {
888
+ const str = amount.toFixed(USDC_DECIMALS);
889
+ const [whole, frac = ""] = str.split(".");
890
+ const raw = whole + frac.padEnd(USDC_DECIMALS, "0").slice(0, USDC_DECIMALS);
891
+ return new BN__default.default(raw);
892
+ }
893
+ function sharesToRaw(amount) {
894
+ const str = amount.toFixed(SHARE_DECIMALS);
895
+ const [whole, frac = ""] = str.split(".");
896
+ const raw = whole + frac.padEnd(SHARE_DECIMALS, "0").slice(0, SHARE_DECIMALS);
897
+ return new BN__default.default(raw);
898
+ }
899
+ async function buildDepositTx(program, params, options) {
900
+ const { user, amountUsdc } = params;
901
+ const programId = program.programId;
902
+ const [vaultMirrorPda] = getVaultMirrorPda(programId);
903
+ const [usdcVaultPda] = getUsdcVaultPda(vaultMirrorPda, programId);
904
+ const [userPda] = getUserPda(vaultMirrorPda, user, programId);
905
+ let vaultMirrorAccount;
906
+ try {
907
+ vaultMirrorAccount = await program.account.vaultMirror.fetch(vaultMirrorPda);
908
+ } catch (err) {
909
+ throw new RpcError("buildDepositTx:fetchVaultMirror", err);
910
+ }
911
+ if (vaultMirrorAccount.paused) {
912
+ throw new VaultPausedError();
913
+ }
914
+ const minDeposit = vaultMirrorAccount.minDeposit.toNumber() / 10 ** USDC_DECIMALS;
915
+ if (amountUsdc < minDeposit) {
916
+ throw new MinDepositError(minDeposit);
917
+ }
918
+ const currentDepositEpoch = vaultMirrorAccount.currentDepositEpoch.toNumber();
919
+ vaultMirrorAccount.currentRedeemEpoch.toNumber();
920
+ const [depositEpochPda] = getDepositEpochPda(vaultMirrorPda, currentDepositEpoch, programId);
921
+ try {
922
+ const epochAccount = await program.account.depositEpoch.fetch(depositEpochPda);
923
+ if (!("open" in epochAccount.status)) {
924
+ const statusKey = Object.keys(epochAccount.status)[0] || "unknown";
925
+ throw new EpochNotOpenError("deposit", statusKey);
926
+ }
927
+ } catch (err) {
928
+ if (err instanceof EpochNotOpenError) throw err;
929
+ }
930
+ const usdcMint = vaultMirrorAccount.usdcMint;
931
+ const userUsdc = await splToken.getAssociatedTokenAddress(usdcMint, user, true);
932
+ const amountBn = usdcToRaw(amountUsdc);
933
+ const remainingAccounts = await getLazySettleRemainingAccounts(
934
+ program,
935
+ programId,
936
+ vaultMirrorPda,
937
+ userPda
938
+ );
939
+ const tx = await program.methods.deposit(amountBn).accounts({
940
+ user,
941
+ vaultMirror: vaultMirrorPda,
942
+ userAccount: userPda,
943
+ depositEpoch: depositEpochPda,
944
+ userUsdc,
945
+ usdcVault: usdcVaultPda,
946
+ usdcMint,
947
+ tokenProgram: splToken.TOKEN_PROGRAM_ID,
948
+ systemProgram: web3_js.SystemProgram.programId
949
+ }).remainingAccounts(remainingAccounts).transaction();
950
+ const finalized = await finalizeTx(tx, program, user, options?.timeoutMs);
951
+ return {
952
+ ...finalized,
953
+ message: `Deposit ${amountUsdc} USDC into TBook Vault (Epoch #${currentDepositEpoch})`
954
+ };
955
+ }
956
+ async function buildRedeemTx(program, params, options) {
957
+ const { user, shares } = params;
958
+ const programId = program.programId;
959
+ const [vaultMirrorPda] = getVaultMirrorPda(programId);
960
+ const [userPda] = getUserPda(vaultMirrorPda, user, programId);
961
+ let vaultMirrorAccount;
962
+ try {
963
+ vaultMirrorAccount = await program.account.vaultMirror.fetch(vaultMirrorPda);
964
+ } catch (err) {
965
+ throw new RpcError("buildRedeemTx:fetchVaultMirror", err);
966
+ }
967
+ if (vaultMirrorAccount.paused) {
968
+ throw new VaultPausedError();
969
+ }
970
+ vaultMirrorAccount.currentDepositEpoch.toNumber();
971
+ const currentRedeemEpoch = vaultMirrorAccount.currentRedeemEpoch.toNumber();
972
+ const [redeemEpochPda] = getRedeemEpochPda(vaultMirrorPda, currentRedeemEpoch, programId);
973
+ try {
974
+ const epochAccount = await program.account.redeemEpoch.fetch(redeemEpochPda);
975
+ if (!("open" in epochAccount.status)) {
976
+ const statusKey = Object.keys(epochAccount.status)[0] || "unknown";
977
+ throw new EpochNotOpenError("redeem", statusKey);
978
+ }
979
+ } catch (err) {
980
+ if (err instanceof EpochNotOpenError) throw err;
981
+ }
982
+ const sharesBn = sharesToRaw(shares);
983
+ const remainingAccounts = await getLazySettleRemainingAccounts(
984
+ program,
985
+ programId,
986
+ vaultMirrorPda,
987
+ userPda
988
+ );
989
+ const tx = await program.methods.requestRedeem(sharesBn).accounts({
990
+ user,
991
+ vaultMirror: vaultMirrorPda,
992
+ userAccount: userPda,
993
+ redeemEpoch: redeemEpochPda,
994
+ systemProgram: web3_js.SystemProgram.programId
995
+ }).remainingAccounts(remainingAccounts).transaction();
996
+ const finalized = await finalizeTx(tx, program, user, options?.timeoutMs);
997
+ return {
998
+ ...finalized,
999
+ message: `Request redeem of ${shares} vault shares (Epoch #${currentRedeemEpoch})`
1000
+ };
1001
+ }
1002
+ async function buildClaimTx(program, params, options) {
1003
+ const { user } = params;
1004
+ const programId = program.programId;
1005
+ const [vaultMirrorPda] = getVaultMirrorPda(programId);
1006
+ const [usdcVaultPda] = getUsdcVaultPda(vaultMirrorPda, programId);
1007
+ const [userPda] = getUserPda(vaultMirrorPda, user, programId);
1008
+ let vaultMirrorAccount;
1009
+ try {
1010
+ vaultMirrorAccount = await program.account.vaultMirror.fetch(vaultMirrorPda);
1011
+ } catch (err) {
1012
+ throw new RpcError("buildClaimTx:fetchVaultMirror", err);
1013
+ }
1014
+ const usdcMint = vaultMirrorAccount.usdcMint;
1015
+ const userUsdc = await splToken.getAssociatedTokenAddress(usdcMint, user, true);
1016
+ const remainingAccounts = await getLazySettleRemainingAccounts(
1017
+ program,
1018
+ programId,
1019
+ vaultMirrorPda,
1020
+ userPda
1021
+ );
1022
+ const tx = await program.methods.claim().accounts({
1023
+ user,
1024
+ vaultMirror: vaultMirrorPda,
1025
+ userAccount: userPda,
1026
+ userUsdc,
1027
+ usdcVault: usdcVaultPda,
1028
+ tokenProgram: splToken.TOKEN_PROGRAM_ID
1029
+ }).remainingAccounts(remainingAccounts).transaction();
1030
+ const finalized = await finalizeTx(tx, program, user, options?.timeoutMs);
1031
+ return {
1032
+ ...finalized,
1033
+ message: "Claim USDC from TBook Vault"
1034
+ };
1035
+ }
1036
+ async function buildCancelDepositTx(program, params, options) {
1037
+ const { user } = params;
1038
+ const programId = program.programId;
1039
+ const [vaultMirrorPda] = getVaultMirrorPda(programId);
1040
+ const [usdcVaultPda] = getUsdcVaultPda(vaultMirrorPda, programId);
1041
+ const [userPda] = getUserPda(vaultMirrorPda, user, programId);
1042
+ let vaultMirrorAccount;
1043
+ try {
1044
+ vaultMirrorAccount = await program.account.vaultMirror.fetch(vaultMirrorPda);
1045
+ } catch (err) {
1046
+ throw new RpcError("buildCancelDepositTx:fetchVaultMirror", err);
1047
+ }
1048
+ const usdcMint = vaultMirrorAccount.usdcMint;
1049
+ const userUsdc = await splToken.getAssociatedTokenAddress(usdcMint, user, true);
1050
+ let userAccount;
1051
+ try {
1052
+ userAccount = await program.account.userAccount.fetchNullable(userPda);
1053
+ } catch (err) {
1054
+ throw new RpcError("buildCancelDepositTx:fetchUserAccount", err);
1055
+ }
1056
+ if (!userAccount) {
1057
+ throw new NoPendingDepositError();
1058
+ }
1059
+ if (userAccount.pendingDepositUsdc && userAccount.pendingDepositUsdc.toNumber() === 0) {
1060
+ throw new NoPendingDepositError();
1061
+ }
1062
+ const depositEpochNum = userAccount.pendingDepositEpoch.toNumber();
1063
+ const [depositEpochPda] = getDepositEpochPda(vaultMirrorPda, depositEpochNum, programId);
1064
+ const remainingAccounts = await getLazySettleRemainingAccounts(
1065
+ program,
1066
+ programId,
1067
+ vaultMirrorPda,
1068
+ userPda
1069
+ );
1070
+ const tx = await program.methods.cancelDeposit().accounts({
1071
+ user,
1072
+ vaultMirror: vaultMirrorPda,
1073
+ userAccount: userPda,
1074
+ depositEpoch: depositEpochPda,
1075
+ userUsdc,
1076
+ usdcVault: usdcVaultPda,
1077
+ tokenProgram: splToken.TOKEN_PROGRAM_ID
1078
+ }).remainingAccounts(remainingAccounts).transaction();
1079
+ const finalized = await finalizeTx(tx, program, user, options?.timeoutMs);
1080
+ return {
1081
+ ...finalized,
1082
+ message: "Cancel pending deposit (0.1% fee applies)"
1083
+ };
1084
+ }
1085
+
1086
+ // src/idl/vault-gateway-devnet.json
1087
+ var vault_gateway_devnet_default = {
1088
+ address: "BdeE87CsE9kvxJJcxaJqxNsC2nC6hFft3UBzcgAm5X1i",
1089
+ metadata: {
1090
+ name: "vault_gateway",
1091
+ version: "0.1.0",
1092
+ spec: "0.1.0",
1093
+ description: "Solana Vault Gateway - Cross-chain entry point for TBook Vault investment"
1094
+ },
1095
+ instructions: [
1096
+ {
1097
+ name: "cancel_deposit",
1098
+ docs: [
1099
+ "Cancel a pending deposit in the current open deposit epoch (with fee)."
1100
+ ],
1101
+ discriminator: [
1102
+ 207,
1103
+ 37,
1104
+ 219,
1105
+ 229,
1106
+ 183,
1107
+ 50,
1108
+ 54,
1109
+ 245
1110
+ ],
1111
+ accounts: [
1112
+ {
1113
+ name: "user",
1114
+ writable: true,
1115
+ signer: true
1116
+ },
1117
+ {
1118
+ name: "vault_mirror",
1119
+ pda: {
1120
+ seeds: [
1121
+ {
1122
+ kind: "const",
1123
+ value: [
1124
+ 118,
1125
+ 97,
1126
+ 117,
1127
+ 108,
1128
+ 116,
1129
+ 95,
1130
+ 109,
1131
+ 105,
1132
+ 114,
1133
+ 114,
1134
+ 111,
1135
+ 114
1136
+ ]
1137
+ }
1138
+ ]
1139
+ }
1140
+ },
1141
+ {
1142
+ name: "user_account",
1143
+ writable: true,
1144
+ pda: {
1145
+ seeds: [
1146
+ {
1147
+ kind: "const",
1148
+ value: [
1149
+ 117,
1150
+ 115,
1151
+ 101,
1152
+ 114
1153
+ ]
1154
+ },
1155
+ {
1156
+ kind: "account",
1157
+ path: "vault_mirror"
1158
+ },
1159
+ {
1160
+ kind: "account",
1161
+ path: "user"
1162
+ }
1163
+ ]
1164
+ }
1165
+ },
1166
+ {
1167
+ name: "deposit_epoch",
1168
+ docs: [
1169
+ "Current open deposit epoch"
1170
+ ],
1171
+ writable: true,
1172
+ pda: {
1173
+ seeds: [
1174
+ {
1175
+ kind: "const",
1176
+ value: [
1177
+ 100,
1178
+ 101,
1179
+ 112,
1180
+ 111,
1181
+ 115,
1182
+ 105,
1183
+ 116,
1184
+ 95,
1185
+ 101,
1186
+ 112,
1187
+ 111,
1188
+ 99,
1189
+ 104
1190
+ ]
1191
+ },
1192
+ {
1193
+ kind: "account",
1194
+ path: "vault_mirror"
1195
+ },
1196
+ {
1197
+ kind: "account",
1198
+ path: "vault_mirror.current_deposit_epoch",
1199
+ account: "VaultMirror"
1200
+ }
1201
+ ]
1202
+ }
1203
+ },
1204
+ {
1205
+ name: "user_usdc",
1206
+ writable: true
1207
+ },
1208
+ {
1209
+ name: "usdc_vault",
1210
+ writable: true
1211
+ },
1212
+ {
1213
+ name: "token_program",
1214
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
1215
+ }
1216
+ ],
1217
+ args: []
1218
+ },
1219
+ {
1220
+ name: "claim",
1221
+ docs: [
1222
+ "Claim available USDC (works even when paused)."
1223
+ ],
1224
+ discriminator: [
1225
+ 62,
1226
+ 198,
1227
+ 214,
1228
+ 193,
1229
+ 213,
1230
+ 159,
1231
+ 108,
1232
+ 210
1233
+ ],
1234
+ accounts: [
1235
+ {
1236
+ name: "user",
1237
+ writable: true,
1238
+ signer: true
1239
+ },
1240
+ {
1241
+ name: "vault_mirror",
1242
+ pda: {
1243
+ seeds: [
1244
+ {
1245
+ kind: "const",
1246
+ value: [
1247
+ 118,
1248
+ 97,
1249
+ 117,
1250
+ 108,
1251
+ 116,
1252
+ 95,
1253
+ 109,
1254
+ 105,
1255
+ 114,
1256
+ 114,
1257
+ 111,
1258
+ 114
1259
+ ]
1260
+ }
1261
+ ]
1262
+ }
1263
+ },
1264
+ {
1265
+ name: "user_account",
1266
+ writable: true,
1267
+ pda: {
1268
+ seeds: [
1269
+ {
1270
+ kind: "const",
1271
+ value: [
1272
+ 117,
1273
+ 115,
1274
+ 101,
1275
+ 114
1276
+ ]
1277
+ },
1278
+ {
1279
+ kind: "account",
1280
+ path: "vault_mirror"
1281
+ },
1282
+ {
1283
+ kind: "account",
1284
+ path: "user"
1285
+ }
1286
+ ]
1287
+ }
1288
+ },
1289
+ {
1290
+ name: "user_usdc",
1291
+ writable: true
1292
+ },
1293
+ {
1294
+ name: "usdc_vault",
1295
+ writable: true
1296
+ },
1297
+ {
1298
+ name: "token_program",
1299
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
1300
+ }
1301
+ ],
1302
+ args: []
1303
+ },
1304
+ {
1305
+ name: "deposit",
1306
+ docs: [
1307
+ "Deposit USDC into the current open deposit epoch.",
1308
+ "Pass previous DepositEpoch/RedeemEpoch PDAs as remaining_accounts for lazy settlement."
1309
+ ],
1310
+ discriminator: [
1311
+ 242,
1312
+ 35,
1313
+ 198,
1314
+ 137,
1315
+ 82,
1316
+ 225,
1317
+ 242,
1318
+ 182
1319
+ ],
1320
+ accounts: [
1321
+ {
1322
+ name: "user",
1323
+ writable: true,
1324
+ signer: true
1325
+ },
1326
+ {
1327
+ name: "vault_mirror",
1328
+ pda: {
1329
+ seeds: [
1330
+ {
1331
+ kind: "const",
1332
+ value: [
1333
+ 118,
1334
+ 97,
1335
+ 117,
1336
+ 108,
1337
+ 116,
1338
+ 95,
1339
+ 109,
1340
+ 105,
1341
+ 114,
1342
+ 114,
1343
+ 111,
1344
+ 114
1345
+ ]
1346
+ }
1347
+ ]
1348
+ }
1349
+ },
1350
+ {
1351
+ name: "user_account",
1352
+ writable: true,
1353
+ pda: {
1354
+ seeds: [
1355
+ {
1356
+ kind: "const",
1357
+ value: [
1358
+ 117,
1359
+ 115,
1360
+ 101,
1361
+ 114
1362
+ ]
1363
+ },
1364
+ {
1365
+ kind: "account",
1366
+ path: "vault_mirror"
1367
+ },
1368
+ {
1369
+ kind: "account",
1370
+ path: "user"
1371
+ }
1372
+ ]
1373
+ }
1374
+ },
1375
+ {
1376
+ name: "deposit_epoch",
1377
+ docs: [
1378
+ "Current open deposit epoch"
1379
+ ],
1380
+ writable: true,
1381
+ pda: {
1382
+ seeds: [
1383
+ {
1384
+ kind: "const",
1385
+ value: [
1386
+ 100,
1387
+ 101,
1388
+ 112,
1389
+ 111,
1390
+ 115,
1391
+ 105,
1392
+ 116,
1393
+ 95,
1394
+ 101,
1395
+ 112,
1396
+ 111,
1397
+ 99,
1398
+ 104
1399
+ ]
1400
+ },
1401
+ {
1402
+ kind: "account",
1403
+ path: "vault_mirror"
1404
+ },
1405
+ {
1406
+ kind: "account",
1407
+ path: "vault_mirror.current_deposit_epoch",
1408
+ account: "VaultMirror"
1409
+ }
1410
+ ]
1411
+ }
1412
+ },
1413
+ {
1414
+ name: "user_usdc",
1415
+ docs: [
1416
+ "User's USDC token account"
1417
+ ],
1418
+ writable: true
1419
+ },
1420
+ {
1421
+ name: "usdc_vault",
1422
+ docs: [
1423
+ "Vault USDC token account"
1424
+ ],
1425
+ writable: true
1426
+ },
1427
+ {
1428
+ name: "token_program",
1429
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
1430
+ },
1431
+ {
1432
+ name: "system_program",
1433
+ address: "11111111111111111111111111111111"
1434
+ }
1435
+ ],
1436
+ args: [
1437
+ {
1438
+ name: "amount",
1439
+ type: "u64"
1440
+ }
1441
+ ]
1442
+ },
1443
+ {
1444
+ name: "deposit_to_vault",
1445
+ docs: [
1446
+ "Deposit USDC back into the PDA vault (curator \u2192 vault).",
1447
+ "Used after bridging redeemed USDC back from Sui to make it claimable."
1448
+ ],
1449
+ discriminator: [
1450
+ 18,
1451
+ 62,
1452
+ 110,
1453
+ 8,
1454
+ 26,
1455
+ 106,
1456
+ 248,
1457
+ 151
1458
+ ],
1459
+ accounts: [
1460
+ {
1461
+ name: "curator",
1462
+ writable: true,
1463
+ signer: true
1464
+ },
1465
+ {
1466
+ name: "vault_mirror",
1467
+ pda: {
1468
+ seeds: [
1469
+ {
1470
+ kind: "const",
1471
+ value: [
1472
+ 118,
1473
+ 97,
1474
+ 117,
1475
+ 108,
1476
+ 116,
1477
+ 95,
1478
+ 109,
1479
+ 105,
1480
+ 114,
1481
+ 114,
1482
+ 111,
1483
+ 114
1484
+ ]
1485
+ }
1486
+ ]
1487
+ }
1488
+ },
1489
+ {
1490
+ name: "usdc_vault",
1491
+ writable: true
1492
+ },
1493
+ {
1494
+ name: "curator_usdc",
1495
+ writable: true
1496
+ },
1497
+ {
1498
+ name: "token_program",
1499
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
1500
+ }
1501
+ ],
1502
+ args: [
1503
+ {
1504
+ name: "amount",
1505
+ type: "u64"
1506
+ }
1507
+ ]
1508
+ },
1509
+ {
1510
+ name: "emergency_withdraw",
1511
+ docs: [
1512
+ "Emergency withdraw: Authority can withdraw USDC from the vault."
1513
+ ],
1514
+ discriminator: [
1515
+ 239,
1516
+ 45,
1517
+ 203,
1518
+ 64,
1519
+ 150,
1520
+ 73,
1521
+ 218,
1522
+ 92
1523
+ ],
1524
+ accounts: [
1525
+ {
1526
+ name: "authority",
1527
+ writable: true,
1528
+ signer: true
1529
+ },
1530
+ {
1531
+ name: "vault_mirror",
1532
+ pda: {
1533
+ seeds: [
1534
+ {
1535
+ kind: "const",
1536
+ value: [
1537
+ 118,
1538
+ 97,
1539
+ 117,
1540
+ 108,
1541
+ 116,
1542
+ 95,
1543
+ 109,
1544
+ 105,
1545
+ 114,
1546
+ 114,
1547
+ 111,
1548
+ 114
1549
+ ]
1550
+ }
1551
+ ]
1552
+ }
1553
+ },
1554
+ {
1555
+ name: "usdc_vault",
1556
+ writable: true
1557
+ },
1558
+ {
1559
+ name: "authority_usdc",
1560
+ writable: true
1561
+ },
1562
+ {
1563
+ name: "token_program",
1564
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
1565
+ }
1566
+ ],
1567
+ args: [
1568
+ {
1569
+ name: "amount",
1570
+ type: "u64"
1571
+ }
1572
+ ]
1573
+ },
1574
+ {
1575
+ name: "freeze_deposit_epoch",
1576
+ docs: [
1577
+ "Freeze the current open deposit epoch and create a new one.",
1578
+ "Rejects if epoch has no deposits.",
1579
+ "Serial constraint: previous deposit epoch must be Settled or RolledBack.",
1580
+ "Routine operation \u2014 requires operator (1-of-3)."
1581
+ ],
1582
+ discriminator: [
1583
+ 120,
1584
+ 11,
1585
+ 158,
1586
+ 152,
1587
+ 237,
1588
+ 62,
1589
+ 188,
1590
+ 235
1591
+ ],
1592
+ accounts: [
1593
+ {
1594
+ name: "operator",
1595
+ writable: true,
1596
+ signer: true
1597
+ },
1598
+ {
1599
+ name: "vault_mirror",
1600
+ writable: true,
1601
+ pda: {
1602
+ seeds: [
1603
+ {
1604
+ kind: "const",
1605
+ value: [
1606
+ 118,
1607
+ 97,
1608
+ 117,
1609
+ 108,
1610
+ 116,
1611
+ 95,
1612
+ 109,
1613
+ 105,
1614
+ 114,
1615
+ 114,
1616
+ 111,
1617
+ 114
1618
+ ]
1619
+ }
1620
+ ]
1621
+ }
1622
+ },
1623
+ {
1624
+ name: "current_deposit_epoch",
1625
+ docs: [
1626
+ "Current deposit epoch to freeze"
1627
+ ],
1628
+ writable: true,
1629
+ pda: {
1630
+ seeds: [
1631
+ {
1632
+ kind: "const",
1633
+ value: [
1634
+ 100,
1635
+ 101,
1636
+ 112,
1637
+ 111,
1638
+ 115,
1639
+ 105,
1640
+ 116,
1641
+ 95,
1642
+ 101,
1643
+ 112,
1644
+ 111,
1645
+ 99,
1646
+ 104
1647
+ ]
1648
+ },
1649
+ {
1650
+ kind: "account",
1651
+ path: "vault_mirror"
1652
+ },
1653
+ {
1654
+ kind: "account",
1655
+ path: "vault_mirror.current_deposit_epoch",
1656
+ account: "VaultMirror"
1657
+ }
1658
+ ]
1659
+ }
1660
+ },
1661
+ {
1662
+ name: "previous_deposit_epoch",
1663
+ docs: [
1664
+ "Previous deposit epoch (optional \u2014 only needed if current > 0 for serial constraint)"
1665
+ ],
1666
+ optional: true
1667
+ },
1668
+ {
1669
+ name: "next_deposit_epoch",
1670
+ docs: [
1671
+ "Next deposit epoch to create"
1672
+ ],
1673
+ writable: true,
1674
+ pda: {
1675
+ seeds: [
1676
+ {
1677
+ kind: "const",
1678
+ value: [
1679
+ 100,
1680
+ 101,
1681
+ 112,
1682
+ 111,
1683
+ 115,
1684
+ 105,
1685
+ 116,
1686
+ 95,
1687
+ 101,
1688
+ 112,
1689
+ 111,
1690
+ 99,
1691
+ 104
1692
+ ]
1693
+ },
1694
+ {
1695
+ kind: "account",
1696
+ path: "vault_mirror"
1697
+ },
1698
+ {
1699
+ kind: "account",
1700
+ path: "vault_mirror.current_deposit_epoch.checked_add(1)",
1701
+ account: "VaultMirror"
1702
+ }
1703
+ ]
1704
+ }
1705
+ },
1706
+ {
1707
+ name: "system_program",
1708
+ address: "11111111111111111111111111111111"
1709
+ }
1710
+ ],
1711
+ args: []
1712
+ },
1713
+ {
1714
+ name: "freeze_redeem_epoch",
1715
+ docs: [
1716
+ "Freeze the current open redeem epoch and create a new one.",
1717
+ "Rejects if epoch has no redeems.",
1718
+ "Serial constraint: previous redeem epoch must be Settled or RolledBack.",
1719
+ "Routine operation \u2014 requires operator (1-of-3)."
1720
+ ],
1721
+ discriminator: [
1722
+ 233,
1723
+ 155,
1724
+ 202,
1725
+ 214,
1726
+ 205,
1727
+ 1,
1728
+ 50,
1729
+ 15
1730
+ ],
1731
+ accounts: [
1732
+ {
1733
+ name: "operator",
1734
+ writable: true,
1735
+ signer: true
1736
+ },
1737
+ {
1738
+ name: "vault_mirror",
1739
+ writable: true,
1740
+ pda: {
1741
+ seeds: [
1742
+ {
1743
+ kind: "const",
1744
+ value: [
1745
+ 118,
1746
+ 97,
1747
+ 117,
1748
+ 108,
1749
+ 116,
1750
+ 95,
1751
+ 109,
1752
+ 105,
1753
+ 114,
1754
+ 114,
1755
+ 111,
1756
+ 114
1757
+ ]
1758
+ }
1759
+ ]
1760
+ }
1761
+ },
1762
+ {
1763
+ name: "current_redeem_epoch",
1764
+ docs: [
1765
+ "Current redeem epoch to freeze"
1766
+ ],
1767
+ writable: true,
1768
+ pda: {
1769
+ seeds: [
1770
+ {
1771
+ kind: "const",
1772
+ value: [
1773
+ 114,
1774
+ 101,
1775
+ 100,
1776
+ 101,
1777
+ 101,
1778
+ 109,
1779
+ 95,
1780
+ 101,
1781
+ 112,
1782
+ 111,
1783
+ 99,
1784
+ 104
1785
+ ]
1786
+ },
1787
+ {
1788
+ kind: "account",
1789
+ path: "vault_mirror"
1790
+ },
1791
+ {
1792
+ kind: "account",
1793
+ path: "vault_mirror.current_redeem_epoch",
1794
+ account: "VaultMirror"
1795
+ }
1796
+ ]
1797
+ }
1798
+ },
1799
+ {
1800
+ name: "previous_redeem_epoch",
1801
+ docs: [
1802
+ "Previous redeem epoch (optional \u2014 only needed if current > 0 for serial constraint)"
1803
+ ],
1804
+ optional: true
1805
+ },
1806
+ {
1807
+ name: "next_redeem_epoch",
1808
+ docs: [
1809
+ "Next redeem epoch to create"
1810
+ ],
1811
+ writable: true,
1812
+ pda: {
1813
+ seeds: [
1814
+ {
1815
+ kind: "const",
1816
+ value: [
1817
+ 114,
1818
+ 101,
1819
+ 100,
1820
+ 101,
1821
+ 101,
1822
+ 109,
1823
+ 95,
1824
+ 101,
1825
+ 112,
1826
+ 111,
1827
+ 99,
1828
+ 104
1829
+ ]
1830
+ },
1831
+ {
1832
+ kind: "account",
1833
+ path: "vault_mirror"
1834
+ },
1835
+ {
1836
+ kind: "account",
1837
+ path: "vault_mirror.current_redeem_epoch.checked_add(1)",
1838
+ account: "VaultMirror"
1839
+ }
1840
+ ]
1841
+ }
1842
+ },
1843
+ {
1844
+ name: "system_program",
1845
+ address: "11111111111111111111111111111111"
1846
+ }
1847
+ ],
1848
+ args: []
1849
+ },
1850
+ {
1851
+ name: "initialize",
1852
+ docs: [
1853
+ "Initialize the vault mirror, first deposit epoch (0, Open), and first redeem epoch (0, Open)"
1854
+ ],
1855
+ discriminator: [
1856
+ 175,
1857
+ 175,
1858
+ 109,
1859
+ 31,
1860
+ 13,
1861
+ 152,
1862
+ 155,
1863
+ 237
1864
+ ],
1865
+ accounts: [
1866
+ {
1867
+ name: "authority",
1868
+ writable: true,
1869
+ signer: true
1870
+ },
1871
+ {
1872
+ name: "vault_mirror",
1873
+ writable: true,
1874
+ pda: {
1875
+ seeds: [
1876
+ {
1877
+ kind: "const",
1878
+ value: [
1879
+ 118,
1880
+ 97,
1881
+ 117,
1882
+ 108,
1883
+ 116,
1884
+ 95,
1885
+ 109,
1886
+ 105,
1887
+ 114,
1888
+ 114,
1889
+ 111,
1890
+ 114
1891
+ ]
1892
+ }
1893
+ ]
1894
+ }
1895
+ },
1896
+ {
1897
+ name: "usdc_vault",
1898
+ docs: [
1899
+ "USDC token account owned by VaultMirror PDA"
1900
+ ],
1901
+ writable: true,
1902
+ pda: {
1903
+ seeds: [
1904
+ {
1905
+ kind: "const",
1906
+ value: [
1907
+ 117,
1908
+ 115,
1909
+ 100,
1910
+ 99,
1911
+ 95,
1912
+ 118,
1913
+ 97,
1914
+ 117,
1915
+ 108,
1916
+ 116
1917
+ ]
1918
+ },
1919
+ {
1920
+ kind: "account",
1921
+ path: "vault_mirror"
1922
+ }
1923
+ ]
1924
+ }
1925
+ },
1926
+ {
1927
+ name: "usdc_mint"
1928
+ },
1929
+ {
1930
+ name: "deposit_epoch",
1931
+ docs: [
1932
+ "First deposit epoch (epoch 0)"
1933
+ ],
1934
+ writable: true,
1935
+ pda: {
1936
+ seeds: [
1937
+ {
1938
+ kind: "const",
1939
+ value: [
1940
+ 100,
1941
+ 101,
1942
+ 112,
1943
+ 111,
1944
+ 115,
1945
+ 105,
1946
+ 116,
1947
+ 95,
1948
+ 101,
1949
+ 112,
1950
+ 111,
1951
+ 99,
1952
+ 104
1953
+ ]
1954
+ },
1955
+ {
1956
+ kind: "account",
1957
+ path: "vault_mirror"
1958
+ },
1959
+ {
1960
+ kind: "const",
1961
+ value: [
1962
+ 0,
1963
+ 0,
1964
+ 0,
1965
+ 0,
1966
+ 0,
1967
+ 0,
1968
+ 0,
1969
+ 0
1970
+ ]
1971
+ }
1972
+ ]
1973
+ }
1974
+ },
1975
+ {
1976
+ name: "redeem_epoch",
1977
+ docs: [
1978
+ "First redeem epoch (epoch 0)"
1979
+ ],
1980
+ writable: true,
1981
+ pda: {
1982
+ seeds: [
1983
+ {
1984
+ kind: "const",
1985
+ value: [
1986
+ 114,
1987
+ 101,
1988
+ 100,
1989
+ 101,
1990
+ 101,
1991
+ 109,
1992
+ 95,
1993
+ 101,
1994
+ 112,
1995
+ 111,
1996
+ 99,
1997
+ 104
1998
+ ]
1999
+ },
2000
+ {
2001
+ kind: "account",
2002
+ path: "vault_mirror"
2003
+ },
2004
+ {
2005
+ kind: "const",
2006
+ value: [
2007
+ 0,
2008
+ 0,
2009
+ 0,
2010
+ 0,
2011
+ 0,
2012
+ 0,
2013
+ 0,
2014
+ 0
2015
+ ]
2016
+ }
2017
+ ]
2018
+ }
2019
+ },
2020
+ {
2021
+ name: "token_program",
2022
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
2023
+ },
2024
+ {
2025
+ name: "system_program",
2026
+ address: "11111111111111111111111111111111"
2027
+ },
2028
+ {
2029
+ name: "rent",
2030
+ address: "SysvarRent111111111111111111111111111111111"
2031
+ }
2032
+ ],
2033
+ args: [
2034
+ {
2035
+ name: "curator",
2036
+ type: "pubkey"
2037
+ },
2038
+ {
2039
+ name: "operator",
2040
+ type: "pubkey"
2041
+ },
2042
+ {
2043
+ name: "max_epoch_deposit",
2044
+ type: "u64"
2045
+ }
2046
+ ]
2047
+ },
2048
+ {
2049
+ name: "mark_bridging",
2050
+ docs: [
2051
+ "Mark a frozen deposit epoch as bridging and extract USDC to curator's wallet for CCTP.",
2052
+ "Sensitive operation \u2014 requires curator (2-of-3)."
2053
+ ],
2054
+ discriminator: [
2055
+ 161,
2056
+ 92,
2057
+ 108,
2058
+ 165,
2059
+ 34,
2060
+ 123,
2061
+ 227,
2062
+ 110
2063
+ ],
2064
+ accounts: [
2065
+ {
2066
+ name: "curator",
2067
+ writable: true,
2068
+ signer: true
2069
+ },
2070
+ {
2071
+ name: "vault_mirror",
2072
+ writable: true,
2073
+ pda: {
2074
+ seeds: [
2075
+ {
2076
+ kind: "const",
2077
+ value: [
2078
+ 118,
2079
+ 97,
2080
+ 117,
2081
+ 108,
2082
+ 116,
2083
+ 95,
2084
+ 109,
2085
+ 105,
2086
+ 114,
2087
+ 114,
2088
+ 111,
2089
+ 114
2090
+ ]
2091
+ }
2092
+ ]
2093
+ }
2094
+ },
2095
+ {
2096
+ name: "deposit_epoch",
2097
+ writable: true
2098
+ },
2099
+ {
2100
+ name: "usdc_vault",
2101
+ docs: [
2102
+ "Vault USDC token account (PDA-owned, source of funds)"
2103
+ ],
2104
+ writable: true
2105
+ },
2106
+ {
2107
+ name: "curator_usdc",
2108
+ docs: [
2109
+ "Curator's USDC token account (destination for CCTP bridge)"
2110
+ ],
2111
+ writable: true
2112
+ },
2113
+ {
2114
+ name: "token_program",
2115
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
2116
+ }
2117
+ ],
2118
+ args: [
2119
+ {
2120
+ name: "nonce",
2121
+ type: "u64"
2122
+ }
2123
+ ]
2124
+ },
2125
+ {
2126
+ name: "request_redeem",
2127
+ docs: [
2128
+ "Request redemption of shares in the current open redeem epoch."
2129
+ ],
2130
+ discriminator: [
2131
+ 105,
2132
+ 49,
2133
+ 44,
2134
+ 38,
2135
+ 207,
2136
+ 241,
2137
+ 33,
2138
+ 173
2139
+ ],
2140
+ accounts: [
2141
+ {
2142
+ name: "user",
2143
+ writable: true,
2144
+ signer: true
2145
+ },
2146
+ {
2147
+ name: "vault_mirror",
2148
+ pda: {
2149
+ seeds: [
2150
+ {
2151
+ kind: "const",
2152
+ value: [
2153
+ 118,
2154
+ 97,
2155
+ 117,
2156
+ 108,
2157
+ 116,
2158
+ 95,
2159
+ 109,
2160
+ 105,
2161
+ 114,
2162
+ 114,
2163
+ 111,
2164
+ 114
2165
+ ]
2166
+ }
2167
+ ]
2168
+ }
2169
+ },
2170
+ {
2171
+ name: "user_account",
2172
+ writable: true,
2173
+ pda: {
2174
+ seeds: [
2175
+ {
2176
+ kind: "const",
2177
+ value: [
2178
+ 117,
2179
+ 115,
2180
+ 101,
2181
+ 114
2182
+ ]
2183
+ },
2184
+ {
2185
+ kind: "account",
2186
+ path: "vault_mirror"
2187
+ },
2188
+ {
2189
+ kind: "account",
2190
+ path: "user"
2191
+ }
2192
+ ]
2193
+ }
2194
+ },
2195
+ {
2196
+ name: "redeem_epoch",
2197
+ docs: [
2198
+ "Current open redeem epoch"
2199
+ ],
2200
+ writable: true,
2201
+ pda: {
2202
+ seeds: [
2203
+ {
2204
+ kind: "const",
2205
+ value: [
2206
+ 114,
2207
+ 101,
2208
+ 100,
2209
+ 101,
2210
+ 101,
2211
+ 109,
2212
+ 95,
2213
+ 101,
2214
+ 112,
2215
+ 111,
2216
+ 99,
2217
+ 104
2218
+ ]
2219
+ },
2220
+ {
2221
+ kind: "account",
2222
+ path: "vault_mirror"
2223
+ },
2224
+ {
2225
+ kind: "account",
2226
+ path: "vault_mirror.current_redeem_epoch",
2227
+ account: "VaultMirror"
2228
+ }
2229
+ ]
2230
+ }
2231
+ }
2232
+ ],
2233
+ args: [
2234
+ {
2235
+ name: "shares",
2236
+ type: "u64"
2237
+ }
2238
+ ]
2239
+ },
2240
+ {
2241
+ name: "rollback_deposit_epoch",
2242
+ docs: [
2243
+ "Rollback a deposit epoch (Frozen or Bridging \u2192 RolledBack).",
2244
+ "Users auto-rollback via lazy settlement: deposits become claimable USDC.",
2245
+ "Sensitive operation \u2014 requires curator (2-of-3)."
2246
+ ],
2247
+ discriminator: [
2248
+ 119,
2249
+ 99,
2250
+ 137,
2251
+ 62,
2252
+ 80,
2253
+ 139,
2254
+ 61,
2255
+ 181
2256
+ ],
2257
+ accounts: [
2258
+ {
2259
+ name: "curator",
2260
+ signer: true
2261
+ },
2262
+ {
2263
+ name: "vault_mirror",
2264
+ writable: true,
2265
+ pda: {
2266
+ seeds: [
2267
+ {
2268
+ kind: "const",
2269
+ value: [
2270
+ 118,
2271
+ 97,
2272
+ 117,
2273
+ 108,
2274
+ 116,
2275
+ 95,
2276
+ 109,
2277
+ 105,
2278
+ 114,
2279
+ 114,
2280
+ 111,
2281
+ 114
2282
+ ]
2283
+ }
2284
+ ]
2285
+ }
2286
+ },
2287
+ {
2288
+ name: "deposit_epoch",
2289
+ writable: true
2290
+ }
2291
+ ],
2292
+ args: []
2293
+ },
2294
+ {
2295
+ name: "rollback_redeem_epoch",
2296
+ docs: [
2297
+ "Rollback a redeem epoch (Frozen \u2192 RolledBack).",
2298
+ "Users auto-rollback via lazy settlement: locked shares are restored.",
2299
+ "Sensitive operation \u2014 requires curator (2-of-3)."
2300
+ ],
2301
+ discriminator: [
2302
+ 172,
2303
+ 217,
2304
+ 168,
2305
+ 112,
2306
+ 217,
2307
+ 37,
2308
+ 157,
2309
+ 218
2310
+ ],
2311
+ accounts: [
2312
+ {
2313
+ name: "curator",
2314
+ signer: true
2315
+ },
2316
+ {
2317
+ name: "vault_mirror",
2318
+ writable: true,
2319
+ pda: {
2320
+ seeds: [
2321
+ {
2322
+ kind: "const",
2323
+ value: [
2324
+ 118,
2325
+ 97,
2326
+ 117,
2327
+ 108,
2328
+ 116,
2329
+ 95,
2330
+ 109,
2331
+ 105,
2332
+ 114,
2333
+ 114,
2334
+ 111,
2335
+ 114
2336
+ ]
2337
+ }
2338
+ ]
2339
+ }
2340
+ },
2341
+ {
2342
+ name: "redeem_epoch",
2343
+ writable: true
2344
+ }
2345
+ ],
2346
+ args: []
2347
+ },
2348
+ {
2349
+ name: "set_authority",
2350
+ docs: [
2351
+ "Transfer authority to a new address"
2352
+ ],
2353
+ discriminator: [
2354
+ 133,
2355
+ 250,
2356
+ 37,
2357
+ 21,
2358
+ 110,
2359
+ 163,
2360
+ 26,
2361
+ 121
2362
+ ],
2363
+ accounts: [
2364
+ {
2365
+ name: "authority",
2366
+ signer: true
2367
+ },
2368
+ {
2369
+ name: "vault_mirror",
2370
+ writable: true,
2371
+ pda: {
2372
+ seeds: [
2373
+ {
2374
+ kind: "const",
2375
+ value: [
2376
+ 118,
2377
+ 97,
2378
+ 117,
2379
+ 108,
2380
+ 116,
2381
+ 95,
2382
+ 109,
2383
+ 105,
2384
+ 114,
2385
+ 114,
2386
+ 111,
2387
+ 114
2388
+ ]
2389
+ }
2390
+ ]
2391
+ }
2392
+ }
2393
+ ],
2394
+ args: [
2395
+ {
2396
+ name: "new_authority",
2397
+ type: "pubkey"
2398
+ }
2399
+ ]
2400
+ },
2401
+ {
2402
+ name: "set_curator",
2403
+ docs: [
2404
+ "Change the curator address"
2405
+ ],
2406
+ discriminator: [
2407
+ 115,
2408
+ 127,
2409
+ 196,
2410
+ 219,
2411
+ 235,
2412
+ 198,
2413
+ 96,
2414
+ 253
2415
+ ],
2416
+ accounts: [
2417
+ {
2418
+ name: "authority",
2419
+ signer: true
2420
+ },
2421
+ {
2422
+ name: "vault_mirror",
2423
+ writable: true,
2424
+ pda: {
2425
+ seeds: [
2426
+ {
2427
+ kind: "const",
2428
+ value: [
2429
+ 118,
2430
+ 97,
2431
+ 117,
2432
+ 108,
2433
+ 116,
2434
+ 95,
2435
+ 109,
2436
+ 105,
2437
+ 114,
2438
+ 114,
2439
+ 111,
2440
+ 114
2441
+ ]
2442
+ }
2443
+ ]
2444
+ }
2445
+ }
2446
+ ],
2447
+ args: [
2448
+ {
2449
+ name: "new_curator",
2450
+ type: "pubkey"
2451
+ }
2452
+ ]
2453
+ },
2454
+ {
2455
+ name: "set_max_epoch_deposit",
2456
+ docs: [
2457
+ "Update the maximum epoch deposit cap"
2458
+ ],
2459
+ discriminator: [
2460
+ 205,
2461
+ 115,
2462
+ 249,
2463
+ 24,
2464
+ 108,
2465
+ 6,
2466
+ 169,
2467
+ 224
2468
+ ],
2469
+ accounts: [
2470
+ {
2471
+ name: "authority",
2472
+ signer: true
2473
+ },
2474
+ {
2475
+ name: "vault_mirror",
2476
+ writable: true,
2477
+ pda: {
2478
+ seeds: [
2479
+ {
2480
+ kind: "const",
2481
+ value: [
2482
+ 118,
2483
+ 97,
2484
+ 117,
2485
+ 108,
2486
+ 116,
2487
+ 95,
2488
+ 109,
2489
+ 105,
2490
+ 114,
2491
+ 114,
2492
+ 111,
2493
+ 114
2494
+ ]
2495
+ }
2496
+ ]
2497
+ }
2498
+ }
2499
+ ],
2500
+ args: [
2501
+ {
2502
+ name: "new_max",
2503
+ type: "u64"
2504
+ }
2505
+ ]
2506
+ },
2507
+ {
2508
+ name: "set_min_deposit",
2509
+ docs: [
2510
+ "Update the minimum deposit amount."
2511
+ ],
2512
+ discriminator: [
2513
+ 15,
2514
+ 182,
2515
+ 74,
2516
+ 248,
2517
+ 251,
2518
+ 148,
2519
+ 186,
2520
+ 171
2521
+ ],
2522
+ accounts: [
2523
+ {
2524
+ name: "authority",
2525
+ signer: true
2526
+ },
2527
+ {
2528
+ name: "vault_mirror",
2529
+ writable: true,
2530
+ pda: {
2531
+ seeds: [
2532
+ {
2533
+ kind: "const",
2534
+ value: [
2535
+ 118,
2536
+ 97,
2537
+ 117,
2538
+ 108,
2539
+ 116,
2540
+ 95,
2541
+ 109,
2542
+ 105,
2543
+ 114,
2544
+ 114,
2545
+ 111,
2546
+ 114
2547
+ ]
2548
+ }
2549
+ ]
2550
+ }
2551
+ }
2552
+ ],
2553
+ args: [
2554
+ {
2555
+ name: "new_min",
2556
+ type: "u64"
2557
+ }
2558
+ ]
2559
+ },
2560
+ {
2561
+ name: "set_operator",
2562
+ docs: [
2563
+ "Change the operator address"
2564
+ ],
2565
+ discriminator: [
2566
+ 238,
2567
+ 153,
2568
+ 101,
2569
+ 169,
2570
+ 243,
2571
+ 131,
2572
+ 36,
2573
+ 1
2574
+ ],
2575
+ accounts: [
2576
+ {
2577
+ name: "authority",
2578
+ signer: true
2579
+ },
2580
+ {
2581
+ name: "vault_mirror",
2582
+ writable: true,
2583
+ pda: {
2584
+ seeds: [
2585
+ {
2586
+ kind: "const",
2587
+ value: [
2588
+ 118,
2589
+ 97,
2590
+ 117,
2591
+ 108,
2592
+ 116,
2593
+ 95,
2594
+ 109,
2595
+ 105,
2596
+ 114,
2597
+ 114,
2598
+ 111,
2599
+ 114
2600
+ ]
2601
+ }
2602
+ ]
2603
+ }
2604
+ }
2605
+ ],
2606
+ args: [
2607
+ {
2608
+ name: "new_operator",
2609
+ type: "pubkey"
2610
+ }
2611
+ ]
2612
+ },
2613
+ {
2614
+ name: "set_pause",
2615
+ docs: [
2616
+ "Toggle pause state. When paused, deposit and redeem are blocked, but claim still works."
2617
+ ],
2618
+ discriminator: [
2619
+ 63,
2620
+ 32,
2621
+ 154,
2622
+ 2,
2623
+ 56,
2624
+ 103,
2625
+ 79,
2626
+ 45
2627
+ ],
2628
+ accounts: [
2629
+ {
2630
+ name: "authority",
2631
+ signer: true
2632
+ },
2633
+ {
2634
+ name: "vault_mirror",
2635
+ writable: true,
2636
+ pda: {
2637
+ seeds: [
2638
+ {
2639
+ kind: "const",
2640
+ value: [
2641
+ 118,
2642
+ 97,
2643
+ 117,
2644
+ 108,
2645
+ 116,
2646
+ 95,
2647
+ 109,
2648
+ 105,
2649
+ 114,
2650
+ 114,
2651
+ 111,
2652
+ 114
2653
+ ]
2654
+ }
2655
+ ]
2656
+ }
2657
+ }
2658
+ ],
2659
+ args: [
2660
+ {
2661
+ name: "paused",
2662
+ type: "bool"
2663
+ }
2664
+ ]
2665
+ },
2666
+ {
2667
+ name: "settle_deposits",
2668
+ docs: [
2669
+ "Settle a deposit epoch: lock in shares minted and mark as Settled.",
2670
+ "Updates vault_mirror.total_shares.",
2671
+ "Sensitive operation \u2014 requires curator (2-of-3)."
2672
+ ],
2673
+ discriminator: [
2674
+ 216,
2675
+ 163,
2676
+ 126,
2677
+ 212,
2678
+ 189,
2679
+ 105,
2680
+ 226,
2681
+ 91
2682
+ ],
2683
+ accounts: [
2684
+ {
2685
+ name: "curator",
2686
+ signer: true
2687
+ },
2688
+ {
2689
+ name: "vault_mirror",
2690
+ writable: true,
2691
+ pda: {
2692
+ seeds: [
2693
+ {
2694
+ kind: "const",
2695
+ value: [
2696
+ 118,
2697
+ 97,
2698
+ 117,
2699
+ 108,
2700
+ 116,
2701
+ 95,
2702
+ 109,
2703
+ 105,
2704
+ 114,
2705
+ 114,
2706
+ 111,
2707
+ 114
2708
+ ]
2709
+ }
2710
+ ]
2711
+ }
2712
+ },
2713
+ {
2714
+ name: "deposit_epoch",
2715
+ writable: true
2716
+ }
2717
+ ],
2718
+ args: [
2719
+ {
2720
+ name: "shares_minted",
2721
+ type: "u64"
2722
+ }
2723
+ ]
2724
+ },
2725
+ {
2726
+ name: "settle_redeems",
2727
+ docs: [
2728
+ "Settle a redeem epoch: lock in USDC for redeemers and mark as Settled.",
2729
+ "Updates vault_mirror.total_shares.",
2730
+ "Curator must have called deposit_to_vault first to fund the PDA.",
2731
+ "Sensitive operation \u2014 requires curator (2-of-3)."
2732
+ ],
2733
+ discriminator: [
2734
+ 41,
2735
+ 238,
2736
+ 144,
2737
+ 152,
2738
+ 241,
2739
+ 69,
2740
+ 163,
2741
+ 71
2742
+ ],
2743
+ accounts: [
2744
+ {
2745
+ name: "curator",
2746
+ signer: true
2747
+ },
2748
+ {
2749
+ name: "vault_mirror",
2750
+ writable: true,
2751
+ pda: {
2752
+ seeds: [
2753
+ {
2754
+ kind: "const",
2755
+ value: [
2756
+ 118,
2757
+ 97,
2758
+ 117,
2759
+ 108,
2760
+ 116,
2761
+ 95,
2762
+ 109,
2763
+ 105,
2764
+ 114,
2765
+ 114,
2766
+ 111,
2767
+ 114
2768
+ ]
2769
+ }
2770
+ ]
2771
+ }
2772
+ },
2773
+ {
2774
+ name: "redeem_epoch",
2775
+ writable: true
2776
+ }
2777
+ ],
2778
+ args: [
2779
+ {
2780
+ name: "usdc_for_redeems",
2781
+ type: "u64"
2782
+ }
2783
+ ]
2784
+ }
2785
+ ],
2786
+ accounts: [
2787
+ {
2788
+ name: "DepositEpoch",
2789
+ discriminator: [
2790
+ 113,
2791
+ 170,
2792
+ 28,
2793
+ 39,
2794
+ 59,
2795
+ 253,
2796
+ 178,
2797
+ 123
2798
+ ]
2799
+ },
2800
+ {
2801
+ name: "RedeemEpoch",
2802
+ discriminator: [
2803
+ 151,
2804
+ 138,
2805
+ 181,
2806
+ 158,
2807
+ 40,
2808
+ 74,
2809
+ 85,
2810
+ 44
2811
+ ]
2812
+ },
2813
+ {
2814
+ name: "UserAccount",
2815
+ discriminator: [
2816
+ 211,
2817
+ 33,
2818
+ 136,
2819
+ 16,
2820
+ 186,
2821
+ 110,
2822
+ 242,
2823
+ 127
2824
+ ]
2825
+ },
2826
+ {
2827
+ name: "VaultMirror",
2828
+ discriminator: [
2829
+ 187,
2830
+ 198,
2831
+ 62,
2832
+ 71,
2833
+ 138,
2834
+ 173,
2835
+ 117,
2836
+ 230
2837
+ ]
2838
+ }
2839
+ ],
2840
+ events: [
2841
+ {
2842
+ name: "AuthorityChanged",
2843
+ discriminator: [
2844
+ 31,
2845
+ 19,
2846
+ 174,
2847
+ 152,
2848
+ 4,
2849
+ 82,
2850
+ 215,
2851
+ 226
2852
+ ]
2853
+ },
2854
+ {
2855
+ name: "CuratorChanged",
2856
+ discriminator: [
2857
+ 87,
2858
+ 59,
2859
+ 49,
2860
+ 50,
2861
+ 194,
2862
+ 244,
2863
+ 0,
2864
+ 178
2865
+ ]
2866
+ },
2867
+ {
2868
+ name: "DepositCancelled",
2869
+ discriminator: [
2870
+ 233,
2871
+ 23,
2872
+ 42,
2873
+ 206,
2874
+ 203,
2875
+ 207,
2876
+ 147,
2877
+ 35
2878
+ ]
2879
+ },
2880
+ {
2881
+ name: "DepositEpochBridging",
2882
+ discriminator: [
2883
+ 135,
2884
+ 188,
2885
+ 190,
2886
+ 180,
2887
+ 130,
2888
+ 52,
2889
+ 8,
2890
+ 188
2891
+ ]
2892
+ },
2893
+ {
2894
+ name: "DepositEpochFrozen",
2895
+ discriminator: [
2896
+ 212,
2897
+ 27,
2898
+ 141,
2899
+ 46,
2900
+ 207,
2901
+ 146,
2902
+ 142,
2903
+ 61
2904
+ ]
2905
+ },
2906
+ {
2907
+ name: "DepositEpochRolledBack",
2908
+ discriminator: [
2909
+ 66,
2910
+ 33,
2911
+ 209,
2912
+ 58,
2913
+ 163,
2914
+ 10,
2915
+ 48,
2916
+ 130
2917
+ ]
2918
+ },
2919
+ {
2920
+ name: "DepositLazySettled",
2921
+ discriminator: [
2922
+ 200,
2923
+ 161,
2924
+ 186,
2925
+ 180,
2926
+ 2,
2927
+ 93,
2928
+ 11,
2929
+ 155
2930
+ ]
2931
+ },
2932
+ {
2933
+ name: "DepositsSettled",
2934
+ discriminator: [
2935
+ 202,
2936
+ 56,
2937
+ 60,
2938
+ 238,
2939
+ 125,
2940
+ 34,
2941
+ 71,
2942
+ 245
2943
+ ]
2944
+ },
2945
+ {
2946
+ name: "EmergencyWithdrawn",
2947
+ discriminator: [
2948
+ 116,
2949
+ 226,
2950
+ 36,
2951
+ 3,
2952
+ 37,
2953
+ 92,
2954
+ 138,
2955
+ 76
2956
+ ]
2957
+ },
2958
+ {
2959
+ name: "MaxEpochDepositChanged",
2960
+ discriminator: [
2961
+ 111,
2962
+ 5,
2963
+ 240,
2964
+ 109,
2965
+ 254,
2966
+ 93,
2967
+ 243,
2968
+ 97
2969
+ ]
2970
+ },
2971
+ {
2972
+ name: "MinDepositChanged",
2973
+ discriminator: [
2974
+ 110,
2975
+ 94,
2976
+ 102,
2977
+ 242,
2978
+ 183,
2979
+ 121,
2980
+ 89,
2981
+ 244
2982
+ ]
2983
+ },
2984
+ {
2985
+ name: "OperatorChanged",
2986
+ discriminator: [
2987
+ 231,
2988
+ 79,
2989
+ 62,
2990
+ 226,
2991
+ 190,
2992
+ 139,
2993
+ 176,
2994
+ 51
2995
+ ]
2996
+ },
2997
+ {
2998
+ name: "RedeemEpochFrozen",
2999
+ discriminator: [
3000
+ 25,
3001
+ 105,
3002
+ 245,
3003
+ 218,
3004
+ 51,
3005
+ 117,
3006
+ 30,
3007
+ 200
3008
+ ]
3009
+ },
3010
+ {
3011
+ name: "RedeemEpochRolledBack",
3012
+ discriminator: [
3013
+ 186,
3014
+ 177,
3015
+ 42,
3016
+ 37,
3017
+ 248,
3018
+ 170,
3019
+ 149,
3020
+ 196
3021
+ ]
3022
+ },
3023
+ {
3024
+ name: "RedeemLazySettled",
3025
+ discriminator: [
3026
+ 196,
3027
+ 65,
3028
+ 102,
3029
+ 125,
3030
+ 173,
3031
+ 10,
3032
+ 31,
3033
+ 23
3034
+ ]
3035
+ },
3036
+ {
3037
+ name: "RedeemRequested",
3038
+ discriminator: [
3039
+ 5,
3040
+ 130,
3041
+ 67,
3042
+ 249,
3043
+ 243,
3044
+ 168,
3045
+ 11,
3046
+ 88
3047
+ ]
3048
+ },
3049
+ {
3050
+ name: "RedeemsSettled",
3051
+ discriminator: [
3052
+ 233,
3053
+ 221,
3054
+ 150,
3055
+ 195,
3056
+ 102,
3057
+ 11,
3058
+ 229,
3059
+ 220
3060
+ ]
3061
+ },
3062
+ {
3063
+ name: "UserClaimed",
3064
+ discriminator: [
3065
+ 222,
3066
+ 173,
3067
+ 163,
3068
+ 173,
3069
+ 82,
3070
+ 10,
3071
+ 133,
3072
+ 226
3073
+ ]
3074
+ },
3075
+ {
3076
+ name: "UserDeposited",
3077
+ discriminator: [
3078
+ 83,
3079
+ 166,
3080
+ 194,
3081
+ 102,
3082
+ 87,
3083
+ 104,
3084
+ 88,
3085
+ 137
3086
+ ]
3087
+ },
3088
+ {
3089
+ name: "VaultFunded",
3090
+ discriminator: [
3091
+ 192,
3092
+ 119,
3093
+ 245,
3094
+ 193,
3095
+ 55,
3096
+ 223,
3097
+ 195,
3098
+ 50
3099
+ ]
3100
+ },
3101
+ {
3102
+ name: "VaultInitialized",
3103
+ discriminator: [
3104
+ 180,
3105
+ 43,
3106
+ 207,
3107
+ 2,
3108
+ 18,
3109
+ 71,
3110
+ 3,
3111
+ 75
3112
+ ]
3113
+ },
3114
+ {
3115
+ name: "VaultPaused",
3116
+ discriminator: [
3117
+ 198,
3118
+ 157,
3119
+ 22,
3120
+ 151,
3121
+ 68,
3122
+ 100,
3123
+ 162,
3124
+ 35
3125
+ ]
3126
+ }
3127
+ ],
3128
+ errors: [
3129
+ {
3130
+ code: 6e3,
3131
+ name: "VaultPaused",
3132
+ msg: "Vault is paused"
3133
+ },
3134
+ {
3135
+ code: 6001,
3136
+ name: "DepositBelowMinimum",
3137
+ msg: "Deposit amount below minimum"
3138
+ },
3139
+ {
3140
+ code: 6002,
3141
+ name: "EpochCapExceeded",
3142
+ msg: "Epoch deposit cap exceeded"
3143
+ },
3144
+ {
3145
+ code: 6003,
3146
+ name: "InvalidEpochStatus",
3147
+ msg: "Invalid epoch status for this operation"
3148
+ },
3149
+ {
3150
+ code: 6004,
3151
+ name: "EmptyDepositEpoch",
3152
+ msg: "Deposit epoch has no deposits"
3153
+ },
3154
+ {
3155
+ code: 6005,
3156
+ name: "EmptyRedeemEpoch",
3157
+ msg: "Redeem epoch has no redeems"
3158
+ },
3159
+ {
3160
+ code: 6006,
3161
+ name: "PreviousDepositEpochUnsettled",
3162
+ msg: "Previous deposit epoch not yet settled or rolled back"
3163
+ },
3164
+ {
3165
+ code: 6007,
3166
+ name: "PreviousRedeemEpochUnsettled",
3167
+ msg: "Previous redeem epoch not yet settled or rolled back"
3168
+ },
3169
+ {
3170
+ code: 6008,
3171
+ name: "NoPendingDeposit",
3172
+ msg: "No pending deposit to cancel"
3173
+ },
3174
+ {
3175
+ code: 6009,
3176
+ name: "InsufficientShares",
3177
+ msg: "Insufficient shares for redemption"
3178
+ },
3179
+ {
3180
+ code: 6010,
3181
+ name: "NothingToClaim",
3182
+ msg: "No claimable USDC"
3183
+ },
3184
+ {
3185
+ code: 6011,
3186
+ name: "NotCurator",
3187
+ msg: "Unauthorized: not curator"
3188
+ },
3189
+ {
3190
+ code: 6012,
3191
+ name: "NotOperator",
3192
+ msg: "Unauthorized: not operator"
3193
+ },
3194
+ {
3195
+ code: 6013,
3196
+ name: "NotAuthority",
3197
+ msg: "Unauthorized: not authority"
3198
+ },
3199
+ {
3200
+ code: 6014,
3201
+ name: "MathOverflow",
3202
+ msg: "Math overflow"
3203
+ },
3204
+ {
3205
+ code: 6015,
3206
+ name: "InvalidDepositEpoch",
3207
+ msg: "Invalid deposit epoch PDA passed for lazy settlement"
3208
+ },
3209
+ {
3210
+ code: 6016,
3211
+ name: "InvalidRedeemEpoch",
3212
+ msg: "Invalid redeem epoch PDA passed for lazy settlement"
3213
+ },
3214
+ {
3215
+ code: 6017,
3216
+ name: "CannotRollbackSettled",
3217
+ msg: "Cannot rollback a settled epoch"
3218
+ },
3219
+ {
3220
+ code: 6018,
3221
+ name: "PendingDepositUnsettled",
3222
+ msg: "User has unsettled pending deposit from a different epoch"
3223
+ },
3224
+ {
3225
+ code: 6019,
3226
+ name: "PendingRedeemUnsettled",
3227
+ msg: "User has unsettled pending redeem from a different epoch"
3228
+ },
3229
+ {
3230
+ code: 6020,
3231
+ name: "ZeroAmount",
3232
+ msg: "Amount must be greater than zero"
3233
+ },
3234
+ {
3235
+ code: 6021,
3236
+ name: "MinDepositTooLow",
3237
+ msg: "Minimum deposit must be at least 1 token (smallest unit)"
3238
+ },
3239
+ {
3240
+ code: 6022,
3241
+ name: "NoDepositActivity",
3242
+ msg: "Deposit epoch has no activity to settle"
3243
+ },
3244
+ {
3245
+ code: 6023,
3246
+ name: "NoRedeemActivity",
3247
+ msg: "Redeem epoch has no activity to settle"
3248
+ }
3249
+ ],
3250
+ types: [
3251
+ {
3252
+ name: "AuthorityChanged",
3253
+ type: {
3254
+ kind: "struct",
3255
+ fields: [
3256
+ {
3257
+ name: "old_authority",
3258
+ type: "pubkey"
3259
+ },
3260
+ {
3261
+ name: "new_authority",
3262
+ type: "pubkey"
3263
+ }
3264
+ ]
3265
+ }
3266
+ },
3267
+ {
3268
+ name: "CuratorChanged",
3269
+ type: {
3270
+ kind: "struct",
3271
+ fields: [
3272
+ {
3273
+ name: "old_curator",
3274
+ type: "pubkey"
3275
+ },
3276
+ {
3277
+ name: "new_curator",
3278
+ type: "pubkey"
3279
+ }
3280
+ ]
3281
+ }
3282
+ },
3283
+ {
3284
+ name: "DepositCancelled",
3285
+ type: {
3286
+ kind: "struct",
3287
+ fields: [
3288
+ {
3289
+ name: "user",
3290
+ type: "pubkey"
3291
+ },
3292
+ {
3293
+ name: "amount_returned",
3294
+ type: "u64"
3295
+ },
3296
+ {
3297
+ name: "fee",
3298
+ type: "u64"
3299
+ },
3300
+ {
3301
+ name: "deposit_epoch",
3302
+ type: "u64"
3303
+ }
3304
+ ]
3305
+ }
3306
+ },
3307
+ {
3308
+ name: "DepositEpoch",
3309
+ docs: [
3310
+ "Deposit epoch \u2014 tracks a batch of user deposits (Solana \u2192 Sui path)",
3311
+ 'Seeds: [b"deposit_epoch", vault_mirror.key(), epoch.to_le_bytes()]',
3312
+ "",
3313
+ "Lifecycle: Open \u2192 Frozen \u2192 Bridging \u2192 Settled (or RolledBack from Frozen/Bridging)"
3314
+ ],
3315
+ type: {
3316
+ kind: "struct",
3317
+ fields: [
3318
+ {
3319
+ name: "epoch",
3320
+ docs: [
3321
+ "Deposit epoch number"
3322
+ ],
3323
+ type: "u64"
3324
+ },
3325
+ {
3326
+ name: "status",
3327
+ docs: [
3328
+ "Current status"
3329
+ ],
3330
+ type: {
3331
+ defined: {
3332
+ name: "EpochStatus"
3333
+ }
3334
+ }
3335
+ },
3336
+ {
3337
+ name: "total_deposit_usdc",
3338
+ docs: [
3339
+ "Total USDC deposited by users in this epoch"
3340
+ ],
3341
+ type: "u64"
3342
+ },
3343
+ {
3344
+ name: "deposit_user_count",
3345
+ docs: [
3346
+ "Number of users who deposited"
3347
+ ],
3348
+ type: "u32"
3349
+ },
3350
+ {
3351
+ name: "settled_shares_minted",
3352
+ docs: [
3353
+ "Total new shares minted for depositors (set by settle_deposits)"
3354
+ ],
3355
+ type: "u64"
3356
+ },
3357
+ {
3358
+ name: "frozen_at",
3359
+ docs: [
3360
+ "Timestamp when epoch was frozen"
3361
+ ],
3362
+ type: "i64"
3363
+ },
3364
+ {
3365
+ name: "bridge_nonce",
3366
+ docs: [
3367
+ "CCTP bridge nonce (set by mark_bridging)"
3368
+ ],
3369
+ type: "u64"
3370
+ },
3371
+ {
3372
+ name: "bump",
3373
+ docs: [
3374
+ "Bump for this PDA"
3375
+ ],
3376
+ type: "u8"
3377
+ }
3378
+ ]
3379
+ }
3380
+ },
3381
+ {
3382
+ name: "DepositEpochBridging",
3383
+ type: {
3384
+ kind: "struct",
3385
+ fields: [
3386
+ {
3387
+ name: "epoch",
3388
+ type: "u64"
3389
+ },
3390
+ {
3391
+ name: "nonce",
3392
+ type: "u64"
3393
+ }
3394
+ ]
3395
+ }
3396
+ },
3397
+ {
3398
+ name: "DepositEpochFrozen",
3399
+ type: {
3400
+ kind: "struct",
3401
+ fields: [
3402
+ {
3403
+ name: "epoch",
3404
+ type: "u64"
3405
+ },
3406
+ {
3407
+ name: "total_deposit_usdc",
3408
+ type: "u64"
3409
+ },
3410
+ {
3411
+ name: "deposit_user_count",
3412
+ type: "u32"
3413
+ }
3414
+ ]
3415
+ }
3416
+ },
3417
+ {
3418
+ name: "DepositEpochRolledBack",
3419
+ type: {
3420
+ kind: "struct",
3421
+ fields: [
3422
+ {
3423
+ name: "epoch",
3424
+ type: "u64"
3425
+ },
3426
+ {
3427
+ name: "deposits_returned",
3428
+ type: "u64"
3429
+ }
3430
+ ]
3431
+ }
3432
+ },
3433
+ {
3434
+ name: "DepositLazySettled",
3435
+ docs: [
3436
+ "Emitted when a user's pending deposit is lazily settled"
3437
+ ],
3438
+ type: {
3439
+ kind: "struct",
3440
+ fields: [
3441
+ {
3442
+ name: "user",
3443
+ type: "pubkey"
3444
+ },
3445
+ {
3446
+ name: "deposit_epoch",
3447
+ type: "u64"
3448
+ },
3449
+ {
3450
+ name: "shares_received",
3451
+ type: "u64"
3452
+ },
3453
+ {
3454
+ name: "is_rollback",
3455
+ type: "bool"
3456
+ }
3457
+ ]
3458
+ }
3459
+ },
3460
+ {
3461
+ name: "DepositsSettled",
3462
+ type: {
3463
+ kind: "struct",
3464
+ fields: [
3465
+ {
3466
+ name: "epoch",
3467
+ type: "u64"
3468
+ },
3469
+ {
3470
+ name: "shares_minted",
3471
+ type: "u64"
3472
+ }
3473
+ ]
3474
+ }
3475
+ },
3476
+ {
3477
+ name: "EmergencyWithdrawn",
3478
+ type: {
3479
+ kind: "struct",
3480
+ fields: [
3481
+ {
3482
+ name: "authority",
3483
+ type: "pubkey"
3484
+ },
3485
+ {
3486
+ name: "amount",
3487
+ type: "u64"
3488
+ }
3489
+ ]
3490
+ }
3491
+ },
3492
+ {
3493
+ name: "EpochStatus",
3494
+ docs: [
3495
+ "Epoch lifecycle for deposits: Open \u2192 Frozen \u2192 Bridging \u2192 Settled (or RolledBack)",
3496
+ "Epoch lifecycle for redeems: Open \u2192 Frozen \u2192 Settled (or RolledBack)"
3497
+ ],
3498
+ type: {
3499
+ kind: "enum",
3500
+ variants: [
3501
+ {
3502
+ name: "Open"
3503
+ },
3504
+ {
3505
+ name: "Frozen"
3506
+ },
3507
+ {
3508
+ name: "Bridging"
3509
+ },
3510
+ {
3511
+ name: "Settled"
3512
+ },
3513
+ {
3514
+ name: "RolledBack"
3515
+ }
3516
+ ]
3517
+ }
3518
+ },
3519
+ {
3520
+ name: "MaxEpochDepositChanged",
3521
+ type: {
3522
+ kind: "struct",
3523
+ fields: [
3524
+ {
3525
+ name: "old_value",
3526
+ type: "u64"
3527
+ },
3528
+ {
3529
+ name: "new_value",
3530
+ type: "u64"
3531
+ }
3532
+ ]
3533
+ }
3534
+ },
3535
+ {
3536
+ name: "MinDepositChanged",
3537
+ type: {
3538
+ kind: "struct",
3539
+ fields: [
3540
+ {
3541
+ name: "old_value",
3542
+ type: "u64"
3543
+ },
3544
+ {
3545
+ name: "new_value",
3546
+ type: "u64"
3547
+ }
3548
+ ]
3549
+ }
3550
+ },
3551
+ {
3552
+ name: "OperatorChanged",
3553
+ type: {
3554
+ kind: "struct",
3555
+ fields: [
3556
+ {
3557
+ name: "old_operator",
3558
+ type: "pubkey"
3559
+ },
3560
+ {
3561
+ name: "new_operator",
3562
+ type: "pubkey"
3563
+ }
3564
+ ]
3565
+ }
3566
+ },
3567
+ {
3568
+ name: "RedeemEpoch",
3569
+ docs: [
3570
+ "Redeem epoch \u2014 tracks a batch of user redeems (Sui \u2192 Solana path)",
3571
+ 'Seeds: [b"redeem_epoch", vault_mirror.key(), epoch.to_le_bytes()]',
3572
+ "",
3573
+ "Lifecycle: Open \u2192 Frozen \u2192 Settled (or RolledBack from Frozen)",
3574
+ "No Bridging state \u2014 the Sui\u2192Solana bridge is handled off-chain by the curator."
3575
+ ],
3576
+ type: {
3577
+ kind: "struct",
3578
+ fields: [
3579
+ {
3580
+ name: "epoch",
3581
+ docs: [
3582
+ "Redeem epoch number"
3583
+ ],
3584
+ type: "u64"
3585
+ },
3586
+ {
3587
+ name: "status",
3588
+ docs: [
3589
+ "Current status"
3590
+ ],
3591
+ type: {
3592
+ defined: {
3593
+ name: "EpochStatus"
3594
+ }
3595
+ }
3596
+ },
3597
+ {
3598
+ name: "total_redeem_shares",
3599
+ docs: [
3600
+ "Total shares queued for redemption in this epoch"
3601
+ ],
3602
+ type: "u64"
3603
+ },
3604
+ {
3605
+ name: "redeem_user_count",
3606
+ docs: [
3607
+ "Number of users who redeemed"
3608
+ ],
3609
+ type: "u32"
3610
+ },
3611
+ {
3612
+ name: "settled_usdc_for_redeems",
3613
+ docs: [
3614
+ "Total USDC allocated for redeemers (set by settle_redeems)"
3615
+ ],
3616
+ type: "u64"
3617
+ },
3618
+ {
3619
+ name: "frozen_at",
3620
+ docs: [
3621
+ "Timestamp when epoch was frozen"
3622
+ ],
3623
+ type: "i64"
3624
+ },
3625
+ {
3626
+ name: "bump",
3627
+ docs: [
3628
+ "Bump for this PDA"
3629
+ ],
3630
+ type: "u8"
3631
+ }
3632
+ ]
3633
+ }
3634
+ },
3635
+ {
3636
+ name: "RedeemEpochFrozen",
3637
+ type: {
3638
+ kind: "struct",
3639
+ fields: [
3640
+ {
3641
+ name: "epoch",
3642
+ type: "u64"
3643
+ },
3644
+ {
3645
+ name: "total_redeem_shares",
3646
+ type: "u64"
3647
+ },
3648
+ {
3649
+ name: "redeem_user_count",
3650
+ type: "u32"
3651
+ }
3652
+ ]
3653
+ }
3654
+ },
3655
+ {
3656
+ name: "RedeemEpochRolledBack",
3657
+ type: {
3658
+ kind: "struct",
3659
+ fields: [
3660
+ {
3661
+ name: "epoch",
3662
+ type: "u64"
3663
+ },
3664
+ {
3665
+ name: "shares_restored",
3666
+ type: "u64"
3667
+ }
3668
+ ]
3669
+ }
3670
+ },
3671
+ {
3672
+ name: "RedeemLazySettled",
3673
+ docs: [
3674
+ "Emitted when a user's pending redeem is lazily settled"
3675
+ ],
3676
+ type: {
3677
+ kind: "struct",
3678
+ fields: [
3679
+ {
3680
+ name: "user",
3681
+ type: "pubkey"
3682
+ },
3683
+ {
3684
+ name: "redeem_epoch",
3685
+ type: "u64"
3686
+ },
3687
+ {
3688
+ name: "usdc_received",
3689
+ type: "u64"
3690
+ },
3691
+ {
3692
+ name: "is_rollback",
3693
+ type: "bool"
3694
+ }
3695
+ ]
3696
+ }
3697
+ },
3698
+ {
3699
+ name: "RedeemRequested",
3700
+ type: {
3701
+ kind: "struct",
3702
+ fields: [
3703
+ {
3704
+ name: "user",
3705
+ type: "pubkey"
3706
+ },
3707
+ {
3708
+ name: "shares",
3709
+ type: "u64"
3710
+ },
3711
+ {
3712
+ name: "redeem_epoch",
3713
+ type: "u64"
3714
+ }
3715
+ ]
3716
+ }
3717
+ },
3718
+ {
3719
+ name: "RedeemsSettled",
3720
+ type: {
3721
+ kind: "struct",
3722
+ fields: [
3723
+ {
3724
+ name: "epoch",
3725
+ type: "u64"
3726
+ },
3727
+ {
3728
+ name: "usdc_for_redeems",
3729
+ type: "u64"
3730
+ }
3731
+ ]
3732
+ }
3733
+ },
3734
+ {
3735
+ name: "UserAccount",
3736
+ docs: [
3737
+ "Per-user account tracking shares and pending operations",
3738
+ 'Seeds: [b"user", vault_mirror.key(), user_pubkey]',
3739
+ "",
3740
+ "pending_deposit_epoch refers to a DepositEpoch number.",
3741
+ "pending_redeem_epoch refers to a RedeemEpoch number.",
3742
+ "The two are completely independent."
3743
+ ],
3744
+ type: {
3745
+ kind: "struct",
3746
+ fields: [
3747
+ {
3748
+ name: "owner",
3749
+ docs: [
3750
+ "User wallet pubkey"
3751
+ ],
3752
+ type: "pubkey"
3753
+ },
3754
+ {
3755
+ name: "shares",
3756
+ docs: [
3757
+ "Settled (confirmed) shares"
3758
+ ],
3759
+ type: "u64"
3760
+ },
3761
+ {
3762
+ name: "pending_deposit_usdc",
3763
+ docs: [
3764
+ "USDC amount pending deposit in current open deposit epoch"
3765
+ ],
3766
+ type: "u64"
3767
+ },
3768
+ {
3769
+ name: "pending_deposit_epoch",
3770
+ docs: [
3771
+ "DepositEpoch number of pending deposit"
3772
+ ],
3773
+ type: "u64"
3774
+ },
3775
+ {
3776
+ name: "pending_redeem_shares",
3777
+ docs: [
3778
+ "Shares pending redemption in current open redeem epoch"
3779
+ ],
3780
+ type: "u64"
3781
+ },
3782
+ {
3783
+ name: "pending_redeem_epoch",
3784
+ docs: [
3785
+ "RedeemEpoch number of pending redeem"
3786
+ ],
3787
+ type: "u64"
3788
+ },
3789
+ {
3790
+ name: "claimable_usdc",
3791
+ docs: [
3792
+ "USDC available for user to claim"
3793
+ ],
3794
+ type: "u64"
3795
+ },
3796
+ {
3797
+ name: "bump",
3798
+ docs: [
3799
+ "Bump for this PDA"
3800
+ ],
3801
+ type: "u8"
3802
+ }
3803
+ ]
3804
+ }
3805
+ },
3806
+ {
3807
+ name: "UserClaimed",
3808
+ type: {
3809
+ kind: "struct",
3810
+ fields: [
3811
+ {
3812
+ name: "user",
3813
+ type: "pubkey"
3814
+ },
3815
+ {
3816
+ name: "amount",
3817
+ type: "u64"
3818
+ }
3819
+ ]
3820
+ }
3821
+ },
3822
+ {
3823
+ name: "UserDeposited",
3824
+ type: {
3825
+ kind: "struct",
3826
+ fields: [
3827
+ {
3828
+ name: "user",
3829
+ type: "pubkey"
3830
+ },
3831
+ {
3832
+ name: "amount",
3833
+ type: "u64"
3834
+ },
3835
+ {
3836
+ name: "deposit_epoch",
3837
+ type: "u64"
3838
+ },
3839
+ {
3840
+ name: "total_pending",
3841
+ type: "u64"
3842
+ }
3843
+ ]
3844
+ }
3845
+ },
3846
+ {
3847
+ name: "VaultFunded",
3848
+ type: {
3849
+ kind: "struct",
3850
+ fields: [
3851
+ {
3852
+ name: "curator",
3853
+ type: "pubkey"
3854
+ },
3855
+ {
3856
+ name: "amount",
3857
+ type: "u64"
3858
+ }
3859
+ ]
3860
+ }
3861
+ },
3862
+ {
3863
+ name: "VaultInitialized",
3864
+ type: {
3865
+ kind: "struct",
3866
+ fields: [
3867
+ {
3868
+ name: "authority",
3869
+ type: "pubkey"
3870
+ },
3871
+ {
3872
+ name: "curator",
3873
+ type: "pubkey"
3874
+ },
3875
+ {
3876
+ name: "usdc_mint",
3877
+ type: "pubkey"
3878
+ },
3879
+ {
3880
+ name: "max_epoch_deposit",
3881
+ type: "u64"
3882
+ }
3883
+ ]
3884
+ }
3885
+ },
3886
+ {
3887
+ name: "VaultMirror",
3888
+ docs: [
3889
+ "Global vault mirror \u2014 single PDA holding all state",
3890
+ 'Seeds: [b"vault_mirror"]'
3891
+ ],
3892
+ type: {
3893
+ kind: "struct",
3894
+ fields: [
3895
+ {
3896
+ name: "authority",
3897
+ docs: [
3898
+ "Admin authority (can pause, set curator/operator, change config)"
3899
+ ],
3900
+ type: "pubkey"
3901
+ },
3902
+ {
3903
+ name: "curator",
3904
+ docs: [
3905
+ "Curator multisig (2-of-3) \u2014 sensitive ops: mark_bridging, settle, rollback"
3906
+ ],
3907
+ type: "pubkey"
3908
+ },
3909
+ {
3910
+ name: "operator",
3911
+ docs: [
3912
+ "Operator multisig (1-of-3) \u2014 routine ops: freeze epochs"
3913
+ ],
3914
+ type: "pubkey"
3915
+ },
3916
+ {
3917
+ name: "usdc_mint",
3918
+ docs: [
3919
+ "USDC SPL token mint"
3920
+ ],
3921
+ type: "pubkey"
3922
+ },
3923
+ {
3924
+ name: "usdc_vault",
3925
+ docs: [
3926
+ "PDA token account holding all USDC deposits"
3927
+ ],
3928
+ type: "pubkey"
3929
+ },
3930
+ {
3931
+ name: "total_shares",
3932
+ docs: [
3933
+ "Total shares across all users"
3934
+ ],
3935
+ type: "u64"
3936
+ },
3937
+ {
3938
+ name: "current_deposit_epoch",
3939
+ docs: [
3940
+ "Current deposit epoch number (independent of redeem epochs)"
3941
+ ],
3942
+ type: "u64"
3943
+ },
3944
+ {
3945
+ name: "current_redeem_epoch",
3946
+ docs: [
3947
+ "Current redeem epoch number (independent of deposit epochs)"
3948
+ ],
3949
+ type: "u64"
3950
+ },
3951
+ {
3952
+ name: "max_epoch_deposit",
3953
+ docs: [
3954
+ "Global cap on deposits per epoch"
3955
+ ],
3956
+ type: "u64"
3957
+ },
3958
+ {
3959
+ name: "min_deposit",
3960
+ docs: [
3961
+ "Minimum deposit amount (e.g. 1 USDC = 1_000_000)"
3962
+ ],
3963
+ type: "u64"
3964
+ },
3965
+ {
3966
+ name: "paused",
3967
+ docs: [
3968
+ "Whether deposits and redeems are paused (claim always works)"
3969
+ ],
3970
+ type: "bool"
3971
+ },
3972
+ {
3973
+ name: "bump",
3974
+ docs: [
3975
+ "Bump for VaultMirror PDA"
3976
+ ],
3977
+ type: "u8"
3978
+ },
3979
+ {
3980
+ name: "vault_bump",
3981
+ docs: [
3982
+ "Bump for usdc_vault token account PDA"
3983
+ ],
3984
+ type: "u8"
3985
+ }
3986
+ ]
3987
+ }
3988
+ },
3989
+ {
3990
+ name: "VaultPaused",
3991
+ type: {
3992
+ kind: "struct",
3993
+ fields: [
3994
+ {
3995
+ name: "paused",
3996
+ type: "bool"
3997
+ }
3998
+ ]
3999
+ }
4000
+ }
4001
+ ]
4002
+ };
4003
+
4004
+ // src/client.ts
4005
+ var TBookVault = class _TBookVault {
4006
+ /** Solana RPC connection. */
4007
+ connection;
4008
+ /** Active network. */
4009
+ network;
4010
+ /** Default timeout for RPC calls in milliseconds. */
4011
+ timeoutMs;
4012
+ apiKey;
4013
+ /** Cache of Anchor programs, keyed by vault ID. */
4014
+ programs = /* @__PURE__ */ new Map();
4015
+ /** Timestamps of when each cached program was created. */
4016
+ programCreatedAt = /* @__PURE__ */ new Map();
4017
+ /** Maximum age for cached programs (5 minutes). */
4018
+ static PROGRAM_CACHE_TTL_MS = 5 * 60 * 1e3;
4019
+ constructor(options) {
4020
+ this.network = options.network;
4021
+ this.apiKey = options.apiKey;
4022
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_RPC_TIMEOUT_MS;
4023
+ this.connection = new web3_js.Connection(
4024
+ options.rpcUrl ?? getDefaultRpcUrl(options.network),
4025
+ {
4026
+ commitment: "confirmed",
4027
+ confirmTransactionInitialTimeout: this.timeoutMs
4028
+ }
4029
+ );
4030
+ }
4031
+ // ── Vault Registry ──
4032
+ /**
4033
+ * List all available vaults on the current network.
4034
+ *
4035
+ * Currently returns built-in vaults only. In the future, this will
4036
+ * also query the TBook API for dynamically registered vaults.
4037
+ */
4038
+ async listVaults() {
4039
+ return listBuiltInVaults(this.network);
4040
+ }
4041
+ // ── Read Operations ──
4042
+ /**
4043
+ * Fetch global vault state and current epoch info.
4044
+ *
4045
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4046
+ */
4047
+ async getVaultInfo(vaultId) {
4048
+ const config = this.resolveVault(vaultId);
4049
+ const program = this.getProgram(config);
4050
+ return fetchVaultInfo(this.connection, config.programId, program);
4051
+ }
4052
+ /**
4053
+ * Fetch a user's vault account with effective balances.
4054
+ *
4055
+ * Returns `null` if the user has never interacted with the vault.
4056
+ *
4057
+ * @param user - User's Solana public key (string or PublicKey)
4058
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4059
+ */
4060
+ async getUserAccount(user, vaultId) {
4061
+ const config = this.resolveVault(vaultId);
4062
+ const program = this.getProgram(config);
4063
+ const pubkey = typeof user === "string" ? new web3_js.PublicKey(user) : user;
4064
+ return fetchUserAccount(this.connection, config.programId, pubkey, program);
4065
+ }
4066
+ /**
4067
+ * Fetch current share price from the NAV oracle.
4068
+ *
4069
+ * Uses a 3-layer fallback: fresh cache -> API fetch -> stale cache.
4070
+ * The API endpoint (NAV oracle) is the authoritative price source.
4071
+ *
4072
+ * @param vaultId - Vault identifier. Currently all registered vaults share
4073
+ * one NAV source; per-vault price URLs land with the multi-asset registry
4074
+ * (VaultConfig.sharePriceUrl) in 0.2.0.
4075
+ */
4076
+ async getSharePrice(vaultId) {
4077
+ if (vaultId) this.resolveVault(vaultId);
4078
+ return fetchSharePrice();
4079
+ }
4080
+ // ── Write Operations (unsigned TX builders) ──
4081
+ /**
4082
+ * Build an unsigned deposit transaction.
4083
+ *
4084
+ * @param params - Deposit parameters (user + amount)
4085
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4086
+ * @returns Unsigned transaction + base58 serialization + description
4087
+ */
4088
+ async buildDeposit(params, vaultId) {
4089
+ const config = this.resolveVault(vaultId);
4090
+ const program = this.getProgram(config);
4091
+ return buildDepositTx(program, params, { timeoutMs: this.timeoutMs });
4092
+ }
4093
+ /**
4094
+ * Build an unsigned redeem transaction.
4095
+ *
4096
+ * @param params - Redeem parameters (user + shares)
4097
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4098
+ */
4099
+ async buildRedeem(params, vaultId) {
4100
+ const config = this.resolveVault(vaultId);
4101
+ const program = this.getProgram(config);
4102
+ return buildRedeemTx(program, params, { timeoutMs: this.timeoutMs });
4103
+ }
4104
+ /**
4105
+ * Build an unsigned claim transaction.
4106
+ * Claim always works even when the vault is paused.
4107
+ *
4108
+ * @param params - User parameters
4109
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4110
+ */
4111
+ async buildClaim(params, vaultId) {
4112
+ const config = this.resolveVault(vaultId);
4113
+ const program = this.getProgram(config);
4114
+ return buildClaimTx(program, params, { timeoutMs: this.timeoutMs });
4115
+ }
4116
+ /**
4117
+ * Build an unsigned cancel-deposit transaction.
4118
+ * Returns pending USDC minus 0.1% fee.
4119
+ *
4120
+ * @param params - User parameters
4121
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4122
+ */
4123
+ async buildCancelDeposit(params, vaultId) {
4124
+ const config = this.resolveVault(vaultId);
4125
+ const program = this.getProgram(config);
4126
+ return buildCancelDepositTx(program, params, { timeoutMs: this.timeoutMs });
4127
+ }
4128
+ // ── History ──
4129
+ /**
4130
+ * Fetch vault transaction history for a user.
4131
+ *
4132
+ * Returns classified transactions (deposit, redeem, claim, cancel_deposit)
4133
+ * by querying the user's PDA account for signatures and parsing instruction data.
4134
+ *
4135
+ * @param userAddress - User's Solana wallet address (string or PublicKey)
4136
+ * @param options - Pagination options (limit, before cursor)
4137
+ * @param vaultId - Vault identifier (default: "rcUSDP")
4138
+ * @returns Array of classified vault transactions, newest first
4139
+ */
4140
+ async getTransactionHistory(userAddress, options, vaultId) {
4141
+ const config = this.resolveVault(vaultId);
4142
+ const pubkey = typeof userAddress === "string" ? new web3_js.PublicKey(userAddress) : userAddress;
4143
+ const [vaultMirror] = getVaultMirrorPda(config.programId);
4144
+ const [userPda] = getUserPda(vaultMirror, pubkey, config.programId);
4145
+ return fetchTransactionHistory(
4146
+ this.connection,
4147
+ userPda,
4148
+ config.programId,
4149
+ options
4150
+ );
4151
+ }
4152
+ // ── Utility Methods ──
4153
+ /**
4154
+ * Estimate the number of shares that a USDC deposit would yield
4155
+ * at the current share price.
4156
+ *
4157
+ * @param amountUsdc - USDC amount (human-readable)
4158
+ * @returns Estimated shares as a string, or null if price unavailable
4159
+ */
4160
+ async estimateShares(amountUsdc) {
4161
+ try {
4162
+ const price = await this.getSharePrice();
4163
+ if (price.priceNum <= 0) return null;
4164
+ const shares = amountUsdc / price.priceNum;
4165
+ return shares.toFixed(6);
4166
+ } catch {
4167
+ return null;
4168
+ }
4169
+ }
4170
+ /**
4171
+ * Estimate the USDC value of a given number of shares
4172
+ * at the current share price.
4173
+ *
4174
+ * @param shares - Number of shares (human-readable)
4175
+ * @returns Estimated USDC value as a string, or null if price unavailable
4176
+ */
4177
+ async estimateUsdc(shares) {
4178
+ try {
4179
+ const price = await this.getSharePrice();
4180
+ const usdc = shares * price.priceNum;
4181
+ return usdc.toFixed(6);
4182
+ } catch {
4183
+ return null;
4184
+ }
4185
+ }
4186
+ // ── Internal ──
4187
+ /**
4188
+ * Resolve a vault config by ID, falling back to the default vault.
4189
+ * @throws {UnknownVaultError} If the vault ID is not registered
4190
+ */
4191
+ resolveVault(vaultId) {
4192
+ const id = vaultId ?? DEFAULT_VAULT_ID;
4193
+ const config = getVaultConfig(id, this.network);
4194
+ if (!config) {
4195
+ throw new UnknownVaultError(id);
4196
+ }
4197
+ return config;
4198
+ }
4199
+ /**
4200
+ * Get or create a cached Anchor Program instance for a vault.
4201
+ *
4202
+ * Uses a read-only provider (no signer) since the SDK only builds
4203
+ * transactions — it never signs or submits them.
4204
+ */
4205
+ getProgram(config) {
4206
+ const key = `${config.network}:${config.id}`;
4207
+ let program = this.programs.get(key);
4208
+ const createdAt = this.programCreatedAt.get(key);
4209
+ if (program && createdAt && Date.now() - createdAt > _TBookVault.PROGRAM_CACHE_TTL_MS) {
4210
+ this.programs.delete(key);
4211
+ this.programCreatedAt.delete(key);
4212
+ program = void 0;
4213
+ }
4214
+ if (!program) {
4215
+ const dummyWallet = {
4216
+ publicKey: web3_js.Keypair.generate().publicKey,
4217
+ signTransaction: async (tx) => tx,
4218
+ signAllTransactions: async (txs) => txs
4219
+ };
4220
+ const provider = new anchor.AnchorProvider(this.connection, dummyWallet, {
4221
+ commitment: "confirmed"
4222
+ });
4223
+ const idl = this.resolveIdl(config);
4224
+ program = new anchor.Program(idl, provider);
4225
+ this.programs.set(key, program);
4226
+ this.programCreatedAt.set(key, Date.now());
4227
+ }
4228
+ return program;
4229
+ }
4230
+ /**
4231
+ * Resolve the Anchor IDL for a given vault configuration.
4232
+ * Currently only the built-in rcUSDP devnet IDL is supported.
4233
+ */
4234
+ resolveIdl(config) {
4235
+ return vault_gateway_devnet_default;
4236
+ }
4237
+ };
4238
+
4239
+ // src/utils.ts
4240
+ function truncateNumber(value, decimals) {
4241
+ const factor = Math.pow(10, decimals);
4242
+ return Math.trunc(value * factor) / factor;
4243
+ }
4244
+ function formatTruncated(value, decimals) {
4245
+ return truncateNumber(value, decimals).toFixed(decimals);
4246
+ }
4247
+ function formatNumber(value, decimals = 2) {
4248
+ const truncated = truncateNumber(value, decimals);
4249
+ return new Intl.NumberFormat("en-US", {
4250
+ minimumFractionDigits: decimals,
4251
+ maximumFractionDigits: decimals
4252
+ }).format(truncated);
4253
+ }
4254
+ function formatCurrency(value, currency = "USD") {
4255
+ const truncated = truncateNumber(value, 2);
4256
+ return new Intl.NumberFormat("en-US", {
4257
+ style: "currency",
4258
+ currency,
4259
+ minimumFractionDigits: 2,
4260
+ maximumFractionDigits: 2
4261
+ }).format(truncated);
4262
+ }
4263
+ function formatPercentage(value, decimals = 2) {
4264
+ return `${formatNumber(value, decimals)}%`;
4265
+ }
4266
+ function shortenAddress(address, chars = 4) {
4267
+ if (address.length <= chars * 2 + 3) return address;
4268
+ return `${address.slice(0, chars)}...${address.slice(-chars)}`;
4269
+ }
4270
+ function formatUsdc(raw) {
4271
+ return formatNumber(Number(raw) / 10 ** USDC_DECIMALS, USDC_DECIMALS);
4272
+ }
4273
+ function formatShares(raw) {
4274
+ return formatNumber(Number(raw) / 10 ** SHARE_DECIMALS, SHARE_DECIMALS);
4275
+ }
4276
+ function rawToUi(raw, decimals) {
4277
+ return Number(raw) / Math.pow(10, decimals);
4278
+ }
4279
+ function uiToRaw(ui, decimals) {
4280
+ return Math.floor(ui * Math.pow(10, decimals));
4281
+ }
4282
+ function validateAmount(amount, balance, action, token, min, max) {
4283
+ const numericAmount = Number(amount);
4284
+ if (isNaN(numericAmount) || numericAmount <= 0) {
4285
+ return { valid: false, error: "Please enter a valid amount greater than 0" };
4286
+ }
4287
+ if (numericAmount > balance) {
4288
+ return { valid: false, error: `You only have ${balance} ${token}.` };
4289
+ }
4290
+ if (min !== void 0 && numericAmount < min) {
4291
+ return { valid: false, error: `You need to ${action} at least ${min} ${token}.` };
4292
+ }
4293
+ if (max !== void 0 && numericAmount > max) {
4294
+ return { valid: false, error: `You can only ${action} up to ${max} ${token}.` };
4295
+ }
4296
+ return { valid: true };
4297
+ }
4298
+ function isValidAmountInput(value) {
4299
+ return value === "" || /^\d*\.?\d*$/.test(value);
4300
+ }
4301
+
4302
+ exports.DEFAULT_CANCEL_FEE_BPS = DEFAULT_CANCEL_FEE_BPS;
4303
+ exports.DEFAULT_VAULT_ID = DEFAULT_VAULT_ID;
4304
+ exports.EpochNotOpenError = EpochNotOpenError;
4305
+ exports.MaxEpochDepositError = MaxEpochDepositError;
4306
+ exports.MinDepositError = MinDepositError;
4307
+ exports.NoPendingDepositError = NoPendingDepositError;
4308
+ exports.ONE_SHARE = ONE_SHARE;
4309
+ exports.ONE_USDC = ONE_USDC;
4310
+ exports.RpcError = RpcError;
4311
+ exports.RpcTimeoutError = RpcTimeoutError;
4312
+ exports.SHARE_DECIMALS = SHARE_DECIMALS;
4313
+ exports.STATUS_MAP = STATUS_MAP;
4314
+ exports.SharePriceCache = SharePriceCache;
4315
+ exports.SharePriceUnavailableError = SharePriceUnavailableError;
4316
+ exports.TBookVault = TBookVault;
4317
+ exports.TransactionExpiredError = TransactionExpiredError;
4318
+ exports.TransactionFailedError = TransactionFailedError;
4319
+ exports.USDC_DECIMALS = USDC_DECIMALS;
4320
+ exports.UnknownVaultError = UnknownVaultError;
4321
+ exports.UserAccountNotFoundError = UserAccountNotFoundError;
4322
+ exports.VaultNotFoundError = VaultNotFoundError;
4323
+ exports.VaultPausedError = VaultPausedError;
4324
+ exports.VaultSdkError = VaultSdkError;
4325
+ exports.buildCancelDepositTx = buildCancelDepositTx;
4326
+ exports.buildClaimTx = buildClaimTx;
4327
+ exports.buildDepositTx = buildDepositTx;
4328
+ exports.buildRedeemTx = buildRedeemTx;
4329
+ exports.confirmTransactionWithRetry = confirmTransactionWithRetry;
4330
+ exports.explorerUrl = explorerUrl;
4331
+ exports.fetchSharePrice = fetchSharePrice;
4332
+ exports.fetchTransactionHistory = fetchTransactionHistory;
4333
+ exports.fetchUserAccount = fetchUserAccount;
4334
+ exports.fetchVaultInfo = fetchVaultInfo;
4335
+ exports.formatCurrency = formatCurrency;
4336
+ exports.formatNumber = formatNumber;
4337
+ exports.formatPercentage = formatPercentage;
4338
+ exports.formatShares = formatShares;
4339
+ exports.formatTruncated = formatTruncated;
4340
+ exports.formatUsdc = formatUsdc;
4341
+ exports.getDefaultRpcUrl = getDefaultRpcUrl;
4342
+ exports.getDepositEpochPda = getDepositEpochPda;
4343
+ exports.getRedeemEpochPda = getRedeemEpochPda;
4344
+ exports.getUsdcVaultPda = getUsdcVaultPda;
4345
+ exports.getUserPda = getUserPda;
4346
+ exports.getVaultConfig = getVaultConfig;
4347
+ exports.getVaultMirrorPda = getVaultMirrorPda;
4348
+ exports.isValidAmountInput = isValidAmountInput;
4349
+ exports.listBuiltInVaults = listBuiltInVaults;
4350
+ exports.rawToUi = rawToUi;
4351
+ exports.sharePriceCache = sharePriceCache;
4352
+ exports.shortenAddress = shortenAddress;
4353
+ exports.sleep = sleep;
4354
+ exports.truncateNumber = truncateNumber;
4355
+ exports.uiToRaw = uiToRaw;
4356
+ exports.validateAmount = validateAmount;
4357
+ exports.withTimeout = withTimeout;
4358
+ //# sourceMappingURL=index.cjs.map
4359
+ //# sourceMappingURL=index.cjs.map