@elemental-stv-core/sdk 0.9.3 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/common/buffer.d.ts +3 -0
  2. package/dist/common/buffer.js +19 -0
  3. package/dist/elemental-lend/instructions.d.ts +14 -0
  4. package/dist/elemental-lend/instructions.js +18 -6
  5. package/dist/elemental-lend/protocol-actions.d.ts +6 -0
  6. package/dist/elemental-lend/protocol-actions.js +21 -10
  7. package/dist/jlpd-strategy/accounts.d.ts +4 -1
  8. package/dist/jlpd-strategy/accounts.js +6 -1
  9. package/dist/jlpd-strategy/adapter.d.ts +16 -6
  10. package/dist/jlpd-strategy/adapter.js +21 -9
  11. package/dist/jlpd-strategy/base-to-base-swap.d.ts +74 -0
  12. package/dist/jlpd-strategy/base-to-base-swap.js +199 -0
  13. package/dist/jlpd-strategy/constants.d.ts +11 -3
  14. package/dist/jlpd-strategy/constants.js +19 -10
  15. package/dist/jlpd-strategy/index.d.ts +1 -0
  16. package/dist/jlpd-strategy/index.js +1 -0
  17. package/dist/jlpd-strategy/instructions.d.ts +49 -0
  18. package/dist/jlpd-strategy/instructions.js +55 -0
  19. package/dist/jlpd-strategy/jlp-data.d.ts +11 -0
  20. package/dist/jlpd-strategy/jlp-data.js +15 -0
  21. package/dist/jlpd-strategy/settle-yield.d.ts +20 -1
  22. package/dist/jlpd-strategy/settle-yield.js +9 -6
  23. package/dist/jlpd-strategy/swap-jlp.d.ts +26 -0
  24. package/dist/jlpd-strategy/swap-jlp.js +74 -10
  25. package/dist/jlpd-strategy/types.d.ts +3 -1
  26. package/dist/p-stv-core/accounts.d.ts +74 -34
  27. package/dist/p-stv-core/accounts.js +163 -56
  28. package/dist/p-stv-core/constants.d.ts +49 -4
  29. package/dist/p-stv-core/constants.js +52 -5
  30. package/dist/p-stv-core/events.js +63 -9
  31. package/dist/p-stv-core/instructions.d.ts +302 -3
  32. package/dist/p-stv-core/instructions.js +277 -15
  33. package/dist/p-stv-core/pda.d.ts +15 -0
  34. package/dist/p-stv-core/pda.js +25 -0
  35. package/dist/p-stv-core/remaining-accounts.d.ts +4 -1
  36. package/dist/p-stv-core/remaining-accounts.js +17 -2
  37. package/dist/p-stv-core/types.d.ts +104 -4
  38. package/package.json +1 -1
@@ -23,6 +23,7 @@ const constants_2 = require("../p-stv-core/constants");
23
23
  const pda_3 = require("../elemental-lend/pda");
24
24
  const jupiter_lend_1 = require("../elemental-lend/jupiter-lend");
25
25
  const instructions_2 = require("../elemental-lend/instructions");
26
+ const accounts_3 = require("../elemental-lend/accounts");
26
27
  // ---------------------------------------------------------------------------
27
28
  // Helpers
28
29
  // ---------------------------------------------------------------------------
@@ -33,7 +34,7 @@ const JUPITER_API_BASE = "https://api.jup.ag/swap/v1";
33
34
  * limits. Read once instead of per-call so the env var is consistent across
34
35
  * the lifetime of the process.
35
36
  */
36
- const JUPITER_API_KEY = process.env.NEXT_PUBLIC_JUPITER_API_KEY;
37
+ const JUPITER_API_KEY = process.env.NEXT_PUBLIC_JUPITER_API_KEY ?? process.env.JUPITER_API_KEY;
37
38
  function toBigInt(v) {
38
39
  if (typeof v === "bigint")
39
40
  return v;
@@ -53,7 +54,7 @@ function toBigInt(v) {
53
54
  * 4-byte jupiter_data_len (LE), ...jupiter_data_bytes]
54
55
  */
55
56
  function createSwapJlpIx(args, programId = constants_1.PROGRAM_ID) {
56
- const { manager, config, managerRole, strategyState, strategyBaseAta, strategyJlpAta, vaultJlpAta, baseMint, jlpMint, tokenProgram, jupiterProgram, direction, amount, minOut, jupiterData, remainingAccounts = [], } = args;
57
+ const { manager, config, managerRole, strategyState, strategyBaseAta, strategyJlpAta, vaultJlpAta, baseMint, jlpMint, tokenProgram, jupiterProgram, priceOracle, jlpPool, jlpMintAccount, direction, amount, minOut, jupiterData, remainingAccounts = [], } = args;
57
58
  const amountBi = toBigInt(amount);
58
59
  const minOutBi = toBigInt(minOut);
59
60
  // Serialize instruction data
@@ -83,11 +84,22 @@ function createSwapJlpIx(args, programId = constants_1.PROGRAM_ID) {
83
84
  { pubkey: jlpMint, isSigner: false, isWritable: false },
84
85
  { pubkey: tokenProgram, isSigner: false, isWritable: false },
85
86
  { pubkey: jupiterProgram, isSigner: false, isWritable: false },
87
+ { pubkey: priceOracle, isSigner: false, isWritable: false },
88
+ { pubkey: jlpPool, isSigner: false, isWritable: false },
89
+ { pubkey: jlpMintAccount, isSigner: false, isWritable: false },
86
90
  ...remainingAccounts,
87
91
  ];
88
92
  return new web3_js_1.TransactionInstruction({ keys, programId, data });
89
93
  }
90
94
  // ---------------------------------------------------------------------------
95
+ // Stable-asset detection
96
+ // ---------------------------------------------------------------------------
97
+ /** Mints that use a hardcoded $1 price on-chain (oracle account ignored). */
98
+ const STABLE_MINTS = new Set(constants_1.JLPD_POOLS.filter((p) => p.name === "USDC" || p.name === "JupUSD").map((p) => p.mint));
99
+ function isStableMint(mint) {
100
+ return STABLE_MINTS.has(mint.toBase58());
101
+ }
102
+ // ---------------------------------------------------------------------------
91
103
  // Jupiter API helpers
92
104
  // ---------------------------------------------------------------------------
93
105
  /**
@@ -123,9 +135,13 @@ async function getJupiterSwapQuote(args) {
123
135
  *
124
136
  * @param quoteResponse The quote from getJupiterSwapQuote
125
137
  * @param userPublicKey The account that signs the swap -- for JLPD this is the strategy_state PDA
138
+ * @param destinationTokenAccount Optional override for the destination token account.
139
+ * For base_to_base_swap: must be base_out_ata (ATA owned by strategy_state_OUT) so
140
+ * Jupiter routes output tokens there instead of to userPublicKey's default ATA.
141
+ * For swap_jlp: omit — Jupiter defaults destination to userPublicKey's ATA which is correct.
126
142
  */
127
143
  async function getJupiterSwapInstructions(args) {
128
- const { quoteResponse, userPublicKey } = args;
144
+ const { quoteResponse, userPublicKey, destinationTokenAccount } = args;
129
145
  const url = `${JUPITER_API_BASE}/swap-instructions`;
130
146
  const body = {
131
147
  quoteResponse,
@@ -134,6 +150,9 @@ async function getJupiterSwapInstructions(args) {
134
150
  dynamicComputeUnitLimit: true,
135
151
  skipUserAccountsRpcCalls: true,
136
152
  };
153
+ if (destinationTokenAccount !== undefined) {
154
+ body["destinationTokenAccount"] = destinationTokenAccount.toBase58();
155
+ }
137
156
  const headers = {
138
157
  "Content-Type": "application/json",
139
158
  };
@@ -214,22 +233,53 @@ async function buildSwapJlpTransaction(args) {
214
233
  const strategyBaseAta = (0, ata_1.findAta)(baseMint, strategyState, tokenProgram);
215
234
  const strategyJlpAta = (0, ata_1.findAta)(jlpMint, strategyState, tokenProgram);
216
235
  const vaultJlpAta = (0, ata_1.findAta)(jlpMint, config, tokenProgram);
217
- // 2. Determine input/output mints for the Jupiter quote
236
+ // 2. Resolve oracle + pending swap_arb. Fetch the strategy state once if we need
237
+ // the stored price_oracle (volatile asset, no override) OR swap_arb (BaseToJlp).
238
+ const needOracleFetch = !isStableMint(baseMint) && args.priceOracle === undefined;
239
+ const needArb = direction === "BaseToJlp";
240
+ const state = needOracleFetch || needArb
241
+ ? await (0, accounts_1.fetchJlpStrategyState)(connection, baseMint, programId)
242
+ : null;
243
+ let priceOracle;
244
+ if (isStableMint(baseMint)) {
245
+ priceOracle = web3_js_1.PublicKey.default;
246
+ }
247
+ else if (args.priceOracle !== undefined) {
248
+ priceOracle = args.priceOracle;
249
+ }
250
+ else {
251
+ priceOracle = state.priceOracle;
252
+ }
253
+ // 3. BaseToJlp folds pending swap_arb into the Jupiter input:
254
+ // total_in = amount + swap_arb (signed; an unfavorable b2b banked a negative
255
+ // deficit that reduces it). The on-chain handler pins base-spent == total_in,
256
+ // so the Jupiter route MUST be quoted for total_in. The instruction `amount`
257
+ // stays = principal (the program credits base_loaned with principal only).
258
+ let quoteAmount = amount;
259
+ if (direction === "BaseToJlp" && state) {
260
+ const arb = BigInt(state.swapArb.toString()); // signed i64
261
+ const totalIn = amount + arb;
262
+ if (totalIn <= 0n) {
263
+ throw new Error(`swap_arb deficit (${arb}) cancels principal (${amount}); cannot Base->JLP — wait for a settle or larger amount.`);
264
+ }
265
+ quoteAmount = totalIn;
266
+ }
267
+ // 4. Determine input/output mints for the Jupiter quote
218
268
  const inputMint = direction === "BaseToJlp" ? baseMint : jlpMint;
219
269
  const outputMint = direction === "BaseToJlp" ? jlpMint : baseMint;
220
- // 3. Get Jupiter quote
270
+ // 5. Get Jupiter quote (for total_in on BaseToJlp; principal otherwise)
221
271
  const quote = await getJupiterSwapQuote({
222
272
  inputMint,
223
273
  outputMint,
224
- amount,
274
+ amount: quoteAmount,
225
275
  slippageBps,
226
276
  });
227
- // 4. Get Jupiter swap instructions (strategy_state PDA signs via CPI)
277
+ // 5. Get Jupiter swap instructions (strategy_state PDA signs via CPI)
228
278
  const jupSwap = await getJupiterSwapInstructions({
229
279
  quoteResponse: quote,
230
280
  userPublicKey: strategyState,
231
281
  });
232
- // 5. Build the swap_jlp instruction
282
+ // 6. Build the swap_jlp instruction
233
283
  const minOut = BigInt(quote.otherAmountThreshold);
234
284
  const swapJlpIx = createSwapJlpIx({
235
285
  manager,
@@ -243,13 +293,16 @@ async function buildSwapJlpTransaction(args) {
243
293
  jlpMint,
244
294
  tokenProgram,
245
295
  jupiterProgram: constants_1.JUPITER_PROGRAM,
296
+ priceOracle,
297
+ jlpPool: constants_1.JLP_POOL_ACCOUNT,
298
+ jlpMintAccount: jlpMint,
246
299
  direction,
247
300
  amount,
248
301
  minOut,
249
302
  jupiterData: jupSwap.swapInstructionData,
250
303
  remainingAccounts: jupSwap.remainingAccounts,
251
304
  }, programId);
252
- // 6. Fetch ALTs
305
+ // 7. Fetch ALTs
253
306
  const addressLookupTables = await fetchAddressLookupTables(connection, jupSwap.addressLookupTableAddresses);
254
307
  return {
255
308
  instructions: [swapJlpIx],
@@ -401,8 +454,12 @@ async function buildJlpToBaseRebalance(args) {
401
454
  const [jlpdStvPosition] = (0, pda_1.findStvPositionPda)(stvAddress, programId);
402
455
  const strategyBaseAta = (0, ata_1.findAta)(baseMint, strategyState, tokenProgram);
403
456
  const vaultAta = (0, ata_1.findAta)(baseMint, stvAddress, tokenProgram);
404
- // Build lend remaining_accounts for auto-sweep after withdraw
457
+ // Build lend remaining_accounts for auto-sweep after withdraw:
458
+ // [4 fixed lend, protocolAumCount protocol-AUM accounts]
459
+ // The protocol-AUM accounts feed the pre-sweep update_aum refresh; on-chain lend
460
+ // rejects an incomplete tail, so we must cover the strategy's full protocol set.
405
461
  const lendAccounts = [];
462
+ let lendProtocolAumCount = 0;
406
463
  const DEFAULT_PUBKEY = web3_js_1.PublicKey.default;
407
464
  if (!stv.lendProgram.equals(DEFAULT_PUBKEY)) {
408
465
  const [lendStrategyState] = (0, pda_3.findStrategyStatePda)(baseMint, stv.lendProgram);
@@ -414,6 +471,12 @@ async function buildJlpToBaseRebalance(args) {
414
471
  lendStvPosition: lendPosition,
415
472
  lendBaseAta,
416
473
  }));
474
+ const lendState = await (0, accounts_3.fetchLendStrategyState)(connection, baseMint, stv.lendProgram).catch(() => null);
475
+ if (lendState) {
476
+ const protocolAumAccounts = await (0, accounts_3.buildProtocolAccountsForAum)(connection, lendState, lendStrategyState, tokenProgram);
477
+ lendProtocolAumCount = protocolAumAccounts.length;
478
+ lendAccounts.push(...protocolAumAccounts);
479
+ }
417
480
  }
418
481
  const [configPda] = (0, pda_2.findConfigPda)(pStvProgramId);
419
482
  const withdrawIx = (0, instructions_1.createWithdrawFromStrategyIx)({
@@ -429,6 +492,7 @@ async function buildJlpToBaseRebalance(args) {
429
492
  strategyBaseAta,
430
493
  tokenProgram,
431
494
  shares: new bn_js_1.default(sharesToWithdraw.toString()),
495
+ protocolAumCount: lendProtocolAumCount,
432
496
  remainingAccounts: lendAccounts,
433
497
  }, pStvProgramId);
434
498
  // Build Jupiter Lend deposit instruction to route funds from Elemental Lend → Jupiter Lend.
@@ -22,9 +22,11 @@ export interface ManagerRole {
22
22
  manager: PublicKey;
23
23
  bump: number;
24
24
  }
25
- /** JLP StrategyState (160 bytes) — extends standard 104-byte header */
25
+ /** JLP StrategyState (224 bytes) — extends standard 104-byte header */
26
26
  export interface JlpStrategyState extends StrategyStateHeader {
27
27
  baseLoaned: BN;
28
+ swapArb: BN;
29
+ priceOracle: PublicKey;
28
30
  }
29
31
  export type { StvPosition } from "../common/strategy-interface";
30
32
  export interface ConfigInitializedEvent {
@@ -1,7 +1,7 @@
1
1
  import { PublicKey } from "@solana/web3.js";
2
2
  import BN from "bn.js";
3
3
  import type { SolanaConnection } from "../common/connection";
4
- import { GlobalConfig, Stv, WithdrawRequest, ManagerRole } from "./types";
4
+ import { GlobalConfig, Stv, WithdrawRequest, DelayedDepositRequest, ManagerRole } from "./types";
5
5
  /**
6
6
  * GlobalConfig — singleton protocol registry. Total 56 bytes.
7
7
  *
@@ -18,39 +18,51 @@ export declare function deserializeGlobalConfig(data: Buffer): GlobalConfig;
18
18
  /**
19
19
  * STV — per-vault state. Total 664 bytes (v2 layout).
20
20
  *
21
- * Layout (offsets include the 8-byte discriminator):
21
+ * v2 layout (offsets include the 8-byte Anchor-compatible discriminator).
22
+ * All compile-time asserts in p-stv-core/programs/p-stv-core/src/state/stv.rs
23
+ * are the canonical source of truth; offsets here are copied from those asserts.
24
+ *
22
25
  * [ 0.. 8] discriminator (sha256("account:Stv")[..8])
23
- * [ 8.. 40] baseMint Pubkey
24
- * [ 40.. 72] evMint Pubkey
25
- * [ 72..104] strategy Pubkey (immutable strategy program)
26
- * [104..136] feeReceiver Pubkey
27
- * [136..168] lendProgram Pubkey (zero pubkey if lend not opted-in)
28
- * [168..200] vaultAta Pubkey (canonical ATA for stv_pda+base_mint+token_program)
29
- * [200..248] childVaults[6] [u64; 6] (allocator child vault IDs)
30
- * [248..256] vaultId u64
31
- * [256..264] reservedBase u64 (base reserved for pending claims)
32
- * [264..272] requestedShares u64 (shares pending in escrow — multiply × PPS to estimate base)
33
- * [272..280] vaultCapacity u64 (0 = uncapped)
34
- * [280..288] minDeposit u64
35
- * [288..296] hwm u64 (high-water mark for perf fees)
36
- * [296..304] lastFeeTs u64 (last fee crystallization timestamp)
37
- * [304..312] epochPps u64 (locked PPS for current epoch claims)
38
- * [312..320] lastNav u64 (snapshot for the rate-limit window)
39
- * [320..328] dailyWithdrawnBase u64 (rate-limit accumulator)
40
- * [328..332] nextEpochTs u32
41
- * [332..336] epochSec u32
42
- * [336..340] currentEpochId u32
43
- * [340..344] pendingWithdrawals u32
44
- * [344..348] withdrawWindowStart u32
45
- * [348..350] mgmtFeeBps u16
46
- * [350..352] perfFeeBps u16
47
- * [352..354] flags u16 (FLAG_PAUSED / DEPOSITS_DISABLED / …)
48
- * [354..356] dailyWithdrawLimitBps u16
49
- * [356..357] childVaultCount u8
50
- * [357..358] version u8
51
- * [358..359] bump u8
52
- * [359..360] _padding [u8; 1]
53
- * [360..664] _reserved [u8; 304]
26
+ * [ 8.. 40] baseMint Pubkey (_OFFSET_BASE_MINT == 8)
27
+ * [ 40.. 72] evMint Pubkey (_OFFSET_EV_MINT == 40)
28
+ * [ 72..104] strategy Pubkey (_OFFSET_STRATEGY == 72; immutable)
29
+ * [104..136] feeReceiver Pubkey (_OFFSET_FEE_RECEIVER == 104)
30
+ * [136..168] lendProgram Pubkey (_OFFSET_LEND_PROGRAM == 136; zero = inactive)
31
+ * [168..200] vaultAta Pubkey (_OFFSET_VAULT_ATA == 168; canonical ATA)
32
+ * [200..232] admin Pubkey (_OFFSET_ADMIN == 200; per-vault admin, never zero on v2)
33
+ * [232..264] pendingAdmin Pubkey (_OFFSET_PENDING_ADMIN == 232; zero = no rotation in progress)
34
+ * [264..296] childVaults[4] [u64; 4] (_OFFSET_CHILD_VAULTS == 264; MAX_CHILD_VAULTS = 4)
35
+ * [296..304] vaultId u64 (_OFFSET_VAULT_ID == 296)
36
+ * [304..312] reservedBase u64
37
+ * [312..320] requestedShares u64 (shares pending in escrow)
38
+ * [320..328] vaultCapacity u64 (0 = uncapped)
39
+ * [328..336] minDeposit u64
40
+ * [336..344] hwm u64 (high-water mark for perf fees)
41
+ * [344..352] lastFeeTs u64
42
+ * [352..360] epochPps u64 (locked PPS for current epoch claims)
43
+ * [360..368] lastNav u64 (snapshot for rate-limit window)
44
+ * [368..376] dailyWithdrawnBase u64 (rate-limit accumulator)
45
+ * [376..380] nextEpochTs u32
46
+ * [380..384] epochSec u32
47
+ * [384..388] currentEpochId u32
48
+ * [388..392] pendingWithdrawals u32
49
+ * [392..396] withdrawWindowStart u32
50
+ * [396..398] mgmtFeeBps u16
51
+ * [398..400] perfFeeBps u16
52
+ * [400..402] flags u16
53
+ * [402..404] dailyWithdrawLimitBps u16
54
+ * [404..405] childVaultCount u8
55
+ * [405..406] version u8 (== 2 for v2 accounts)
56
+ * [406..407] bump u8
57
+ * [407..408] _padding [u8; 1]
58
+ * [408..410] depositFeeBps u16 (_OFFSET_DEPOSIT_FEE_BPS == 408)
59
+ * [410..412] withdrawalFeeBps u16 (_OFFSET_WITHDRAWAL_FEE_BPS == 410)
60
+ * [412..416] pendingDepositCount u32 (_OFFSET_PENDING_DEPOSIT_COUNT == 412)
61
+ * [416..424] pendingDepositBase u64 (_OFFSET_PENDING_DEPOSIT_BASE == 416)
62
+ * [424..456] feeReceiverEvAta Pubkey (_OFFSET_FEE_RECEIVER_EV_ATA == 424)
63
+ * [456..464] lockedSeedShares u64 (_OFFSET_LOCKED_SEED_SHARES == 456)
64
+ * [464..465] withdrawalMode u8 (_OFFSET_WITHDRAWAL_MODE == 464; 0=instant, 1=X, 2=X+1)
65
+ * [465..664] _reserved [u8; 199] (_OFFSET_RESERVED == 465)
54
66
  */
55
67
  export declare function deserializeStv(data: Buffer): Stv;
56
68
  /**
@@ -65,9 +77,34 @@ export declare function deserializeStv(data: Buffer): Stv;
65
77
  * [ 88.. 92] epochId u32
66
78
  * [ 92.. 96] claimAvailableAfter u32 (unix seconds)
67
79
  * [ 96.. 97] bump u8
68
- * [ 97..168] _reserved [u8; 71]
80
+ * [ 97.. 98] version u8
81
+ * [ 98.. 99] requestFlags u8 (bit0 WR_FLAG_MIGRATE: 0=withdraw, 1=migrate)
82
+ * [ 99..104] _padding [u8; 5]
83
+ * [104..112] destVaultId u64 (migrate: dest STV vault_id; withdraw: 0)
84
+ * [112..120] minDestShares u64 (migrate: slippage floor; withdraw: 0)
85
+ * [120..168] _reserved0 [u8; 48]
69
86
  */
70
87
  export declare function deserializeWithdrawRequest(data: Buffer): WithdrawRequest;
88
+ /**
89
+ * WithdrawRequest kind from `requestFlags` bit 0.
90
+ * Returns `"migrate"` when WR_FLAG_MIGRATE (0x01) is set, else `"withdraw"`.
91
+ */
92
+ export declare function withdrawRequestKind(wr: WithdrawRequest): "withdraw" | "migrate";
93
+ /**
94
+ * DelayedDepositRequest — per-(STV, user, epoch) pending deposit. Total 152 bytes.
95
+ *
96
+ * Layout (offsets include the 8-byte discriminator):
97
+ * [ 0.. 8] discriminator (sha256("account:DelayedDepositRequest")[..8])
98
+ * [ 8.. 40] stv Pubkey
99
+ * [ 40.. 72] user Pubkey
100
+ * [ 72.. 80] amount u64
101
+ * [ 80.. 84] epochId u32 (offset_of == 80, asserted on-chain)
102
+ * [ 84.. 85] bump u8
103
+ * [ 85.. 86] version u8
104
+ * [ 86.. 88] _padding [u8; 2]
105
+ * [ 88..152] _reserved [u8; 64]
106
+ */
107
+ export declare function deserializeDelayedDepositRequest(data: Buffer): DelayedDepositRequest;
71
108
  /**
72
109
  * ManagerRole — per-(STV, manager) authorization record. Total 80 bytes.
73
110
  *
@@ -85,7 +122,10 @@ export declare function fetchStv(connection: SolanaConnection, vaultId: number |
85
122
  export declare function fetchStvByAddress(connection: SolanaConnection, address: PublicKey): Promise<Stv>;
86
123
  export declare function fetchWithdrawRequest(connection: SolanaConnection, stv: PublicKey, user: PublicKey, epochId: number, programId?: PublicKey): Promise<WithdrawRequest>;
87
124
  export declare function fetchWithdrawRequestByAddress(connection: SolanaConnection, address: PublicKey): Promise<WithdrawRequest>;
125
+ export declare function fetchDelayedDepositRequest(connection: SolanaConnection, stv: PublicKey, user: PublicKey, epochId: number, programId?: PublicKey): Promise<DelayedDepositRequest>;
126
+ export declare function fetchDelayedDepositRequestByAddress(connection: SolanaConnection, address: PublicKey): Promise<DelayedDepositRequest>;
88
127
  export declare function fetchAllStvs(connection: SolanaConnection, programId?: PublicKey): Promise<[PublicKey, Stv][]>;
89
128
  export declare function fetchPendingWithdrawRequests(connection: SolanaConnection, stv: PublicKey, epochId: number, programId?: PublicKey): Promise<[PublicKey, WithdrawRequest][]>;
129
+ export declare function fetchPendingDelayedDepositRequests(connection: SolanaConnection, stv: PublicKey, epochId: number, programId?: PublicKey): Promise<[PublicKey, DelayedDepositRequest][]>;
90
130
  export declare function fetchManagerRole(connection: SolanaConnection, stv: PublicKey, manager: PublicKey, programId?: PublicKey): Promise<ManagerRole | null>;
91
131
  export declare function fetchManagersForStv(connection: SolanaConnection, stv: PublicKey, programId?: PublicKey): Promise<[PublicKey, ManagerRole][]>;
@@ -3,14 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deserializeGlobalConfig = deserializeGlobalConfig;
4
4
  exports.deserializeStv = deserializeStv;
5
5
  exports.deserializeWithdrawRequest = deserializeWithdrawRequest;
6
+ exports.withdrawRequestKind = withdrawRequestKind;
7
+ exports.deserializeDelayedDepositRequest = deserializeDelayedDepositRequest;
6
8
  exports.deserializeManagerRole = deserializeManagerRole;
7
9
  exports.fetchGlobalConfig = fetchGlobalConfig;
8
10
  exports.fetchStv = fetchStv;
9
11
  exports.fetchStvByAddress = fetchStvByAddress;
10
12
  exports.fetchWithdrawRequest = fetchWithdrawRequest;
11
13
  exports.fetchWithdrawRequestByAddress = fetchWithdrawRequestByAddress;
14
+ exports.fetchDelayedDepositRequest = fetchDelayedDepositRequest;
15
+ exports.fetchDelayedDepositRequestByAddress = fetchDelayedDepositRequestByAddress;
12
16
  exports.fetchAllStvs = fetchAllStvs;
13
17
  exports.fetchPendingWithdrawRequests = fetchPendingWithdrawRequests;
18
+ exports.fetchPendingDelayedDepositRequests = fetchPendingDelayedDepositRequests;
14
19
  exports.fetchManagerRole = fetchManagerRole;
15
20
  exports.fetchManagersForStv = fetchManagersForStv;
16
21
  const buffer_1 = require("../common/buffer");
@@ -56,39 +61,51 @@ function deserializeGlobalConfig(data) {
56
61
  /**
57
62
  * STV — per-vault state. Total 664 bytes (v2 layout).
58
63
  *
59
- * Layout (offsets include the 8-byte discriminator):
64
+ * v2 layout (offsets include the 8-byte Anchor-compatible discriminator).
65
+ * All compile-time asserts in p-stv-core/programs/p-stv-core/src/state/stv.rs
66
+ * are the canonical source of truth; offsets here are copied from those asserts.
67
+ *
60
68
  * [ 0.. 8] discriminator (sha256("account:Stv")[..8])
61
- * [ 8.. 40] baseMint Pubkey
62
- * [ 40.. 72] evMint Pubkey
63
- * [ 72..104] strategy Pubkey (immutable strategy program)
64
- * [104..136] feeReceiver Pubkey
65
- * [136..168] lendProgram Pubkey (zero pubkey if lend not opted-in)
66
- * [168..200] vaultAta Pubkey (canonical ATA for stv_pda+base_mint+token_program)
67
- * [200..248] childVaults[6] [u64; 6] (allocator child vault IDs)
68
- * [248..256] vaultId u64
69
- * [256..264] reservedBase u64 (base reserved for pending claims)
70
- * [264..272] requestedShares u64 (shares pending in escrow — multiply × PPS to estimate base)
71
- * [272..280] vaultCapacity u64 (0 = uncapped)
72
- * [280..288] minDeposit u64
73
- * [288..296] hwm u64 (high-water mark for perf fees)
74
- * [296..304] lastFeeTs u64 (last fee crystallization timestamp)
75
- * [304..312] epochPps u64 (locked PPS for current epoch claims)
76
- * [312..320] lastNav u64 (snapshot for the rate-limit window)
77
- * [320..328] dailyWithdrawnBase u64 (rate-limit accumulator)
78
- * [328..332] nextEpochTs u32
79
- * [332..336] epochSec u32
80
- * [336..340] currentEpochId u32
81
- * [340..344] pendingWithdrawals u32
82
- * [344..348] withdrawWindowStart u32
83
- * [348..350] mgmtFeeBps u16
84
- * [350..352] perfFeeBps u16
85
- * [352..354] flags u16 (FLAG_PAUSED / DEPOSITS_DISABLED / …)
86
- * [354..356] dailyWithdrawLimitBps u16
87
- * [356..357] childVaultCount u8
88
- * [357..358] version u8
89
- * [358..359] bump u8
90
- * [359..360] _padding [u8; 1]
91
- * [360..664] _reserved [u8; 304]
69
+ * [ 8.. 40] baseMint Pubkey (_OFFSET_BASE_MINT == 8)
70
+ * [ 40.. 72] evMint Pubkey (_OFFSET_EV_MINT == 40)
71
+ * [ 72..104] strategy Pubkey (_OFFSET_STRATEGY == 72; immutable)
72
+ * [104..136] feeReceiver Pubkey (_OFFSET_FEE_RECEIVER == 104)
73
+ * [136..168] lendProgram Pubkey (_OFFSET_LEND_PROGRAM == 136; zero = inactive)
74
+ * [168..200] vaultAta Pubkey (_OFFSET_VAULT_ATA == 168; canonical ATA)
75
+ * [200..232] admin Pubkey (_OFFSET_ADMIN == 200; per-vault admin, never zero on v2)
76
+ * [232..264] pendingAdmin Pubkey (_OFFSET_PENDING_ADMIN == 232; zero = no rotation in progress)
77
+ * [264..296] childVaults[4] [u64; 4] (_OFFSET_CHILD_VAULTS == 264; MAX_CHILD_VAULTS = 4)
78
+ * [296..304] vaultId u64 (_OFFSET_VAULT_ID == 296)
79
+ * [304..312] reservedBase u64
80
+ * [312..320] requestedShares u64 (shares pending in escrow)
81
+ * [320..328] vaultCapacity u64 (0 = uncapped)
82
+ * [328..336] minDeposit u64
83
+ * [336..344] hwm u64 (high-water mark for perf fees)
84
+ * [344..352] lastFeeTs u64
85
+ * [352..360] epochPps u64 (locked PPS for current epoch claims)
86
+ * [360..368] lastNav u64 (snapshot for rate-limit window)
87
+ * [368..376] dailyWithdrawnBase u64 (rate-limit accumulator)
88
+ * [376..380] nextEpochTs u32
89
+ * [380..384] epochSec u32
90
+ * [384..388] currentEpochId u32
91
+ * [388..392] pendingWithdrawals u32
92
+ * [392..396] withdrawWindowStart u32
93
+ * [396..398] mgmtFeeBps u16
94
+ * [398..400] perfFeeBps u16
95
+ * [400..402] flags u16
96
+ * [402..404] dailyWithdrawLimitBps u16
97
+ * [404..405] childVaultCount u8
98
+ * [405..406] version u8 (== 2 for v2 accounts)
99
+ * [406..407] bump u8
100
+ * [407..408] _padding [u8; 1]
101
+ * [408..410] depositFeeBps u16 (_OFFSET_DEPOSIT_FEE_BPS == 408)
102
+ * [410..412] withdrawalFeeBps u16 (_OFFSET_WITHDRAWAL_FEE_BPS == 410)
103
+ * [412..416] pendingDepositCount u32 (_OFFSET_PENDING_DEPOSIT_COUNT == 412)
104
+ * [416..424] pendingDepositBase u64 (_OFFSET_PENDING_DEPOSIT_BASE == 416)
105
+ * [424..456] feeReceiverEvAta Pubkey (_OFFSET_FEE_RECEIVER_EV_ATA == 424)
106
+ * [456..464] lockedSeedShares u64 (_OFFSET_LOCKED_SEED_SHARES == 456)
107
+ * [464..465] withdrawalMode u8 (_OFFSET_WITHDRAWAL_MODE == 464; 0=instant, 1=X, 2=X+1)
108
+ * [465..664] _reserved [u8; 199] (_OFFSET_RESERVED == 465)
92
109
  */
93
110
  function deserializeStv(data) {
94
111
  if (data.length < constants_1.STV_SIZE) {
@@ -98,9 +115,18 @@ function deserializeStv(data) {
98
115
  if (!disc.equals(constants_1.DISC_STV)) {
99
116
  throw new Error(`Invalid Stv discriminator`);
100
117
  }
118
+ // v2 freeze gate: version must be 2 AND admin must be nonzero.
119
+ // (mirrors the combined gate in Stv::from_account in stv.rs)
120
+ const version = (0, buffer_1.readU8)(data, 405);
121
+ const adminBytes = data.subarray(200, 232);
122
+ const adminIsZero = adminBytes.every((b) => b === 0);
123
+ if (version !== 2 || adminIsZero) {
124
+ throw new Error(`Stv account is not v2-migrated: version=${version}, admin=${adminIsZero ? "zero" : "nonzero"}`);
125
+ }
126
+ // childVaults: [u64; 4] at offset 264, MAX_CHILD_VAULTS = 4
101
127
  const childVaults = [];
102
128
  for (let i = 0; i < constants_1.MAX_STRATEGIES; i++) {
103
- childVaults.push((0, buffer_1.readU64)(data, 200 + i * 8));
129
+ childVaults.push((0, buffer_1.readU64)(data, 264 + i * 8));
104
130
  }
105
131
  return {
106
132
  baseMint: (0, buffer_1.readPubkey)(data, 8),
@@ -109,29 +135,38 @@ function deserializeStv(data) {
109
135
  feeReceiver: (0, buffer_1.readPubkey)(data, 104),
110
136
  lendProgram: (0, buffer_1.readPubkey)(data, 136),
111
137
  vaultAta: (0, buffer_1.readPubkey)(data, 168),
138
+ admin: (0, buffer_1.readPubkey)(data, 200),
139
+ pendingAdmin: (0, buffer_1.readPubkey)(data, 232),
112
140
  childVaults,
113
- vaultId: (0, buffer_1.readU64)(data, 248),
114
- reservedBase: (0, buffer_1.readU64)(data, 256),
115
- requestedShares: (0, buffer_1.readU64)(data, 264),
116
- vaultCapacity: (0, buffer_1.readU64)(data, 272),
117
- minDeposit: (0, buffer_1.readU64)(data, 280),
118
- hwm: (0, buffer_1.readU64)(data, 288),
119
- lastFeeTs: (0, buffer_1.readU64)(data, 296),
120
- epochPps: (0, buffer_1.readU64)(data, 304),
121
- lastNav: (0, buffer_1.readU64)(data, 312),
122
- dailyWithdrawnBase: (0, buffer_1.readU64)(data, 320),
123
- nextEpochTs: (0, buffer_1.readU32)(data, 328),
124
- epochSec: (0, buffer_1.readU32)(data, 332),
125
- currentEpochId: (0, buffer_1.readU32)(data, 336),
126
- pendingWithdrawals: (0, buffer_1.readU32)(data, 340),
127
- withdrawWindowStart: (0, buffer_1.readU32)(data, 344),
128
- mgmtFeeBps: (0, buffer_1.readU16)(data, 348),
129
- perfFeeBps: (0, buffer_1.readU16)(data, 350),
130
- flags: (0, buffer_1.readU16)(data, 352),
131
- dailyWithdrawLimitBps: (0, buffer_1.readU16)(data, 354),
132
- childVaultCount: (0, buffer_1.readU8)(data, 356),
133
- version: (0, buffer_1.readU8)(data, 357),
134
- bump: (0, buffer_1.readU8)(data, 358),
141
+ vaultId: (0, buffer_1.readU64)(data, 296),
142
+ reservedBase: (0, buffer_1.readU64)(data, 304),
143
+ requestedShares: (0, buffer_1.readU64)(data, 312),
144
+ vaultCapacity: (0, buffer_1.readU64)(data, 320),
145
+ minDeposit: (0, buffer_1.readU64)(data, 328),
146
+ hwm: (0, buffer_1.readU64)(data, 336),
147
+ lastFeeTs: (0, buffer_1.readU64)(data, 344),
148
+ epochPps: (0, buffer_1.readU64)(data, 352),
149
+ lastNav: (0, buffer_1.readU64)(data, 360),
150
+ dailyWithdrawnBase: (0, buffer_1.readU64)(data, 368),
151
+ nextEpochTs: (0, buffer_1.readU32)(data, 376),
152
+ epochSec: (0, buffer_1.readU32)(data, 380),
153
+ currentEpochId: (0, buffer_1.readU32)(data, 384),
154
+ pendingWithdrawals: (0, buffer_1.readU32)(data, 388),
155
+ withdrawWindowStart: (0, buffer_1.readU32)(data, 392),
156
+ mgmtFeeBps: (0, buffer_1.readU16)(data, 396),
157
+ perfFeeBps: (0, buffer_1.readU16)(data, 398),
158
+ flags: (0, buffer_1.readU16)(data, 400),
159
+ dailyWithdrawLimitBps: (0, buffer_1.readU16)(data, 402),
160
+ childVaultCount: (0, buffer_1.readU8)(data, 404),
161
+ version,
162
+ bump: (0, buffer_1.readU8)(data, 406),
163
+ depositFeeBps: (0, buffer_1.readU16)(data, 408),
164
+ withdrawalFeeBps: (0, buffer_1.readU16)(data, 410),
165
+ pendingDepositCount: (0, buffer_1.readU32)(data, 412),
166
+ pendingDepositBase: (0, buffer_1.readU64)(data, 416),
167
+ feeReceiverEvAta: (0, buffer_1.readPubkey)(data, 424),
168
+ lockedSeedShares: (0, buffer_1.readU64)(data, 456),
169
+ withdrawalMode: (0, buffer_1.readU8)(data, 464),
135
170
  };
136
171
  }
137
172
  /**
@@ -146,7 +181,12 @@ function deserializeStv(data) {
146
181
  * [ 88.. 92] epochId u32
147
182
  * [ 92.. 96] claimAvailableAfter u32 (unix seconds)
148
183
  * [ 96.. 97] bump u8
149
- * [ 97..168] _reserved [u8; 71]
184
+ * [ 97.. 98] version u8
185
+ * [ 98.. 99] requestFlags u8 (bit0 WR_FLAG_MIGRATE: 0=withdraw, 1=migrate)
186
+ * [ 99..104] _padding [u8; 5]
187
+ * [104..112] destVaultId u64 (migrate: dest STV vault_id; withdraw: 0)
188
+ * [112..120] minDestShares u64 (migrate: slippage floor; withdraw: 0)
189
+ * [120..168] _reserved0 [u8; 48]
150
190
  */
151
191
  function deserializeWithdrawRequest(data) {
152
192
  if (data.length < constants_1.WITHDRAW_REQUEST_SIZE) {
@@ -164,6 +204,47 @@ function deserializeWithdrawRequest(data) {
164
204
  epochId: (0, buffer_1.readU32)(data, 88),
165
205
  claimAvailableAfter: (0, buffer_1.readU32)(data, 92),
166
206
  bump: (0, buffer_1.readU8)(data, 96),
207
+ requestFlags: (0, buffer_1.readU8)(data, 98),
208
+ destVaultId: (0, buffer_1.readU64)(data, 104),
209
+ minDestShares: (0, buffer_1.readU64)(data, 112),
210
+ };
211
+ }
212
+ /**
213
+ * WithdrawRequest kind from `requestFlags` bit 0.
214
+ * Returns `"migrate"` when WR_FLAG_MIGRATE (0x01) is set, else `"withdraw"`.
215
+ */
216
+ function withdrawRequestKind(wr) {
217
+ return (wr.requestFlags & 0x01) !== 0 ? "migrate" : "withdraw";
218
+ }
219
+ /**
220
+ * DelayedDepositRequest — per-(STV, user, epoch) pending deposit. Total 152 bytes.
221
+ *
222
+ * Layout (offsets include the 8-byte discriminator):
223
+ * [ 0.. 8] discriminator (sha256("account:DelayedDepositRequest")[..8])
224
+ * [ 8.. 40] stv Pubkey
225
+ * [ 40.. 72] user Pubkey
226
+ * [ 72.. 80] amount u64
227
+ * [ 80.. 84] epochId u32 (offset_of == 80, asserted on-chain)
228
+ * [ 84.. 85] bump u8
229
+ * [ 85.. 86] version u8
230
+ * [ 86.. 88] _padding [u8; 2]
231
+ * [ 88..152] _reserved [u8; 64]
232
+ */
233
+ function deserializeDelayedDepositRequest(data) {
234
+ if (data.length < constants_1.DELAYED_DEPOSIT_REQUEST_SIZE) {
235
+ throw new Error(`DelayedDepositRequest data too short: ${data.length} < ${constants_1.DELAYED_DEPOSIT_REQUEST_SIZE}`);
236
+ }
237
+ const disc = data.subarray(0, 8);
238
+ if (!disc.equals(constants_1.DISC_DELAYED_DEPOSIT_REQUEST)) {
239
+ throw new Error(`Invalid DelayedDepositRequest discriminator`);
240
+ }
241
+ return {
242
+ stv: (0, buffer_1.readPubkey)(data, 8),
243
+ user: (0, buffer_1.readPubkey)(data, 40),
244
+ amount: (0, buffer_1.readU64)(data, 72),
245
+ epochId: (0, buffer_1.readU32)(data, 80),
246
+ bump: (0, buffer_1.readU8)(data, 84),
247
+ version: (0, buffer_1.readU8)(data, 85),
167
248
  };
168
249
  }
169
250
  /**
@@ -227,6 +308,19 @@ async function fetchWithdrawRequestByAddress(connection, address) {
227
308
  throw new Error(`WithdrawRequest not found at ${address.toBase58()}`);
228
309
  return deserializeWithdrawRequest(info.data);
229
310
  }
311
+ async function fetchDelayedDepositRequest(connection, stv, user, epochId, programId = constants_1.PROGRAM_ID) {
312
+ const [pda] = (0, pda_1.findDelayedDepositRequestPda)(stv, user, epochId, programId);
313
+ const info = await connection.getAccountInfo(pda);
314
+ if (!info)
315
+ throw new Error("DelayedDepositRequest account not found");
316
+ return deserializeDelayedDepositRequest(info.data);
317
+ }
318
+ async function fetchDelayedDepositRequestByAddress(connection, address) {
319
+ const info = await connection.getAccountInfo(address);
320
+ if (!info)
321
+ throw new Error(`DelayedDepositRequest not found at ${address.toBase58()}`);
322
+ return deserializeDelayedDepositRequest(info.data);
323
+ }
230
324
  // ---------------------------------------------------------------------------
231
325
  // GPA Helpers
232
326
  // ---------------------------------------------------------------------------
@@ -252,6 +346,19 @@ async function fetchPendingWithdrawRequests(connection, stv, epochId, programId
252
346
  });
253
347
  return accounts.map((a) => [a.pubkey, deserializeWithdrawRequest(a.account.data)]);
254
348
  }
349
+ async function fetchPendingDelayedDepositRequests(connection, stv, epochId, programId = constants_1.PROGRAM_ID) {
350
+ const epochBuf = Buffer.alloc(4);
351
+ epochBuf.writeUInt32LE(epochId, 0);
352
+ const accounts = await connection.getProgramAccounts(programId, {
353
+ filters: [
354
+ { dataSize: constants_1.DELAYED_DEPOSIT_REQUEST_SIZE },
355
+ { memcmp: { offset: 0, bytes: constants_1.DISC_DELAYED_DEPOSIT_REQUEST.toString("base64"), encoding: "base64" } },
356
+ { memcmp: { offset: 8, bytes: stv.toBuffer().toString("base64"), encoding: "base64" } },
357
+ { memcmp: { offset: 80, bytes: epochBuf.toString("base64"), encoding: "base64" } },
358
+ ],
359
+ });
360
+ return accounts.map((a) => [a.pubkey, deserializeDelayedDepositRequest(a.account.data)]);
361
+ }
255
362
  async function fetchManagerRole(connection, stv, manager, programId = constants_1.PROGRAM_ID) {
256
363
  const [pda] = (0, pda_1.findStvManagerRolePda)(stv, manager, programId);
257
364
  const info = await connection.getAccountInfo(pda);