@elemental-stv-core/sdk 0.9.3 → 0.11.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 +38 -3
  27. package/dist/p-stv-core/accounts.js +93 -2
  28. package/dist/p-stv-core/constants.d.ts +37 -2
  29. package/dist/p-stv-core/constants.js +41 -4
  30. package/dist/p-stv-core/events.js +49 -10
  31. package/dist/p-stv-core/instructions.d.ts +245 -2
  32. package/dist/p-stv-core/instructions.js +226 -13
  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 +74 -4
  38. package/package.json +1 -1
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBaseToBaseSwapIx = createBaseToBaseSwapIx;
4
+ exports.buildBaseToBaseSwapTransaction = buildBaseToBaseSwapTransaction;
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ const spl_token_1 = require("@solana/spl-token");
7
+ const ata_1 = require("../common/ata");
8
+ const constants_1 = require("./constants");
9
+ const pda_1 = require("./pda");
10
+ const accounts_1 = require("./accounts");
11
+ const swap_jlp_1 = require("./swap-jlp");
12
+ // ---------------------------------------------------------------------------
13
+ // Stable-asset detection (mirrors swap-jlp.ts)
14
+ // ---------------------------------------------------------------------------
15
+ // Stablecoin mints use a hardcoded $1 price on-chain — the oracle account is
16
+ // passed but ignored. We pass PublicKey.default as a safe placeholder for them
17
+ // so callers never need to supply or fetch a feed for USDC/JupUSD.
18
+ // ---------------------------------------------------------------------------
19
+ /** Mints that use a hardcoded $1 price on-chain (oracle account ignored). */
20
+ const STABLE_MINTS = new Set(constants_1.JLPD_POOLS.filter((p) => p.name === "USDC" || p.name === "JupUSD").map((p) => p.mint));
21
+ function isStableMint(mint) {
22
+ return STABLE_MINTS.has(mint.toBase58());
23
+ }
24
+ function toBigInt(v) {
25
+ if (typeof v === "bigint")
26
+ return v;
27
+ const bn = v;
28
+ if (typeof bn.toBigInt === "function")
29
+ return bn.toBigInt();
30
+ return BigInt(bn.toString());
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Low-level instruction builder
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Build the on-chain `base_to_base_swap` instruction.
37
+ *
38
+ * Instruction data layout (Anchor Borsh):
39
+ * [8-byte disc, 8-byte amount_in (LE), 8-byte min_out (LE),
40
+ * 4-byte jupiter_data_len (LE), ...jupiter_data_bytes]
41
+ */
42
+ function createBaseToBaseSwapIx(args, programId = constants_1.PROGRAM_ID) {
43
+ const { manager, config, managerRole, strategyStateIn, strategyStateOut, baseInAta, baseOutAta, baseInMint, baseOutMint, tokenProgram, jupiterProgram, priceOracleIn, priceOracleOut, amountIn, minOut, jupiterData, remainingAccounts = [], } = args;
44
+ const amountInBi = toBigInt(amountIn);
45
+ const minOutBi = toBigInt(minOut);
46
+ const jupBytes = Buffer.from(jupiterData);
47
+ const dataLen = 8 + 8 + 8 + 4 + jupBytes.length;
48
+ const data = Buffer.alloc(dataLen);
49
+ constants_1.IX_BASE_TO_BASE_SWAP.copy(data, 0);
50
+ data.writeBigUInt64LE(amountInBi, 8);
51
+ data.writeBigUInt64LE(minOutBi, 16);
52
+ data.writeUInt32LE(jupBytes.length, 24);
53
+ jupBytes.copy(data, 28);
54
+ const keys = [
55
+ { pubkey: manager, isSigner: true, isWritable: false },
56
+ { pubkey: config, isSigner: false, isWritable: false },
57
+ { pubkey: managerRole, isSigner: false, isWritable: false },
58
+ { pubkey: strategyStateIn, isSigner: false, isWritable: true },
59
+ { pubkey: strategyStateOut, isSigner: false, isWritable: true },
60
+ { pubkey: baseInAta, isSigner: false, isWritable: true },
61
+ { pubkey: baseOutAta, isSigner: false, isWritable: true },
62
+ { pubkey: baseInMint, isSigner: false, isWritable: false },
63
+ { pubkey: baseOutMint, isSigner: false, isWritable: false },
64
+ { pubkey: tokenProgram, isSigner: false, isWritable: false },
65
+ { pubkey: jupiterProgram, isSigner: false, isWritable: false },
66
+ { pubkey: priceOracleIn, isSigner: false, isWritable: false },
67
+ { pubkey: priceOracleOut, isSigner: false, isWritable: false },
68
+ ...remainingAccounts,
69
+ ];
70
+ return new web3_js_1.TransactionInstruction({ keys, programId, data });
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // High-level builder (Jupiter quote + ALTs + ix)
74
+ // ---------------------------------------------------------------------------
75
+ /**
76
+ * Build a complete base_to_base_swap transaction:
77
+ * 1. Derive PDAs for both strategies
78
+ * 2. Resolve oracle accounts (from strategy_state.price_oracle on-chain, or overrides)
79
+ * 3. Get Jupiter quote (base_in → base_out)
80
+ * 4. Get Jupiter swap instructions (strategy_state_in PDA signs)
81
+ * 5. Build instruction + return ALTs
82
+ *
83
+ * Oracle resolution:
84
+ * - Stablecoins (USDC/JupUSD): always PublicKey.default (program ignores oracle for $1 assets).
85
+ * - Volatile assets: use caller-supplied override, or fetch strategy_state on-chain
86
+ * to read the stored price_oracle field. To avoid two extra RPC calls, pass
87
+ * priceOracleIn/priceOracleOut when you already have the strategy states.
88
+ */
89
+ async function buildBaseToBaseSwapTransaction(args) {
90
+ const { connection, manager, baseInMint, baseOutMint, amountIn, slippageBps = 50, tokenProgram = spl_token_1.TOKEN_PROGRAM_ID, programId = constants_1.PROGRAM_ID, } = args;
91
+ if (baseInMint.equals(baseOutMint)) {
92
+ throw new Error("base_to_base_swap: baseInMint must differ from baseOutMint");
93
+ }
94
+ // 1. Derive PDAs
95
+ const [config] = (0, pda_1.findJlpdConfigPda)(programId);
96
+ const [managerRole] = (0, pda_1.findJlpdManagerRolePda)(config, manager, programId);
97
+ const [strategyStateIn] = (0, pda_1.findStrategyStatePda)(baseInMint, programId);
98
+ const [strategyStateOut] = (0, pda_1.findStrategyStatePda)(baseOutMint, programId);
99
+ const baseInAta = (0, ata_1.findAta)(baseInMint, strategyStateIn, tokenProgram);
100
+ const baseOutAta = (0, ata_1.findAta)(baseOutMint, strategyStateOut, tokenProgram);
101
+ // 2. Resolve oracle accounts.
102
+ // Stablecoins always get PublicKey.default — on-chain ignores the feed.
103
+ // Volatile assets: use caller override, or fetch strategy state to read price_oracle.
104
+ // The two fetches are issued in parallel when both are needed.
105
+ const needFetchIn = !isStableMint(baseInMint) && args.priceOracleIn === undefined;
106
+ const needFetchOut = !isStableMint(baseOutMint) && args.priceOracleOut === undefined;
107
+ const [fetchedIn, fetchedOut] = await Promise.all([
108
+ needFetchIn ? (0, accounts_1.fetchJlpStrategyState)(connection, baseInMint, programId) : Promise.resolve(null),
109
+ needFetchOut ? (0, accounts_1.fetchJlpStrategyState)(connection, baseOutMint, programId) : Promise.resolve(null),
110
+ ]);
111
+ const priceOracleIn = isStableMint(baseInMint)
112
+ ? web3_js_1.PublicKey.default
113
+ : (args.priceOracleIn ?? fetchedIn.priceOracle);
114
+ const priceOracleOut = isStableMint(baseOutMint)
115
+ ? web3_js_1.PublicKey.default
116
+ : (args.priceOracleOut ?? fetchedOut.priceOracle);
117
+ // 3. Jupiter quote
118
+ const quote = await (0, swap_jlp_1.getJupiterSwapQuote)({
119
+ inputMint: baseInMint,
120
+ outputMint: baseOutMint,
121
+ amount: amountIn,
122
+ slippageBps,
123
+ });
124
+ // 4. Jupiter swap instructions (strategy_state_in PDA signs via CPI seeds).
125
+ // We override destinationTokenAccount to baseOutAta (ATA owned by strategy_state_OUT)
126
+ // because Jupiter defaults destination to userPublicKey's ATA, which for base_to_base
127
+ // would set it to ATA(baseOutMint, strategy_state_IN) — the wrong owner.
128
+ // On-chain: base_to_base_swap validates destination == base_out_ata → InvalidOwner if wrong.
129
+ const jupSwap = await (0, swap_jlp_1.getJupiterSwapInstructions)({
130
+ quoteResponse: quote,
131
+ userPublicKey: strategyStateIn,
132
+ destinationTokenAccount: baseOutAta,
133
+ });
134
+ // Defensive guard: verify the first writable non-signer account in the Jupiter swap
135
+ // instruction's accounts list that matches baseOutAta.
136
+ //
137
+ // NOTE: Jupiter's swap-instructions route account ordering is not guaranteed to be
138
+ // stable across route variants (shared-accounts vs standard-route layout). Reliably
139
+ // identifying the destination-ATA index requires parsing the Jupiter instruction
140
+ // discriminator and routing into variant-specific offset tables — which would
141
+ // duplicate on-chain logic and drift. Instead we do a membership check: confirm
142
+ // baseOutAta appears somewhere in the account list (necessary condition), and rely
143
+ // on the destinationTokenAccount override above to ensure it is wired as destination.
144
+ const baseOutAtaStr = baseOutAta.toBase58();
145
+ const baseInAtaStr = baseInAta.toBase58();
146
+ const routeKeys = jupSwap.remainingAccounts.map((a) => a.pubkey.toBase58());
147
+ if (!routeKeys.includes(baseOutAtaStr)) {
148
+ throw new Error(`base_to_base_swap: Jupiter route does not include baseOutAta (${baseOutAtaStr}). ` +
149
+ `destinationTokenAccount override may not have been honored. ` +
150
+ `Source: ${baseInAtaStr}. Route accounts: ${routeKeys.join(", ")}`);
151
+ }
152
+ if (!routeKeys.includes(baseInAtaStr)) {
153
+ throw new Error(`base_to_base_swap: Jupiter route does not include baseInAta (${baseInAtaStr}). ` +
154
+ `Unexpected route configuration. Route accounts: ${routeKeys.join(", ")}`);
155
+ }
156
+ const minOut = BigInt(quote.otherAmountThreshold);
157
+ // 5. Build ix
158
+ const ix = createBaseToBaseSwapIx({
159
+ manager,
160
+ config,
161
+ managerRole,
162
+ strategyStateIn,
163
+ strategyStateOut,
164
+ baseInAta,
165
+ baseOutAta,
166
+ baseInMint,
167
+ baseOutMint,
168
+ tokenProgram,
169
+ jupiterProgram: constants_1.JUPITER_PROGRAM,
170
+ priceOracleIn,
171
+ priceOracleOut,
172
+ amountIn,
173
+ minOut,
174
+ jupiterData: jupSwap.swapInstructionData,
175
+ remainingAccounts: jupSwap.remainingAccounts,
176
+ }, programId);
177
+ // 6. Resolve ALTs
178
+ const altAddresses = jupSwap.addressLookupTableAddresses;
179
+ const altPubkeys = altAddresses.map((a) => new web3_js_1.PublicKey(a));
180
+ const altInfos = await connection.getMultipleAccountsInfo(altPubkeys);
181
+ const addressLookupTables = [];
182
+ for (let i = 0; i < altInfos.length; i++) {
183
+ const info = altInfos[i];
184
+ if (!info)
185
+ continue;
186
+ addressLookupTables.push(new web3_js_1.AddressLookupTableAccount({
187
+ key: altPubkeys[i],
188
+ state: web3_js_1.AddressLookupTableAccount.deserialize(info.data),
189
+ }));
190
+ }
191
+ return {
192
+ instructions: [ix],
193
+ addressLookupTables,
194
+ quoteInAmount: BigInt(quote.inAmount),
195
+ quoteOutAmount: BigInt(quote.outAmount),
196
+ minOut,
197
+ quote,
198
+ };
199
+ }
@@ -6,11 +6,18 @@ export declare const PROGRAM_ID_DEVNET: PublicKey;
6
6
  export declare const JLP_MINT: PublicKey;
7
7
  /** Jupiter aggregator program (swap routing) */
8
8
  export declare const JUPITER_PROGRAM: PublicKey;
9
- /** Doves oracle: BTC/USD price feed */
9
+ /**
10
+ * Reference/backfill defaults for the Doves price oracle feeds.
11
+ * Pending Jupiter confirmation; runtime feed comes from StrategyState.priceOracle.
12
+ * These constants are NOT used at runtime — swap_jlp, base_to_base_swap, and
13
+ * settle_yield all read the feed from strategy_state.price_oracle on-chain.
14
+ * Use these for backfill scripts, LUT tooling, and admin init calls only.
15
+ */
16
+ /** Doves oracle: BTC/USD price feed (reference/backfill default only) */
10
17
  export declare const DOVES_BTC_USD: PublicKey;
11
- /** Doves oracle: ETH/USD price feed */
18
+ /** Doves oracle: ETH/USD price feed (reference/backfill default only) */
12
19
  export declare const DOVES_ETH_USD: PublicKey;
13
- /** Doves oracle: SOL/USD price feed */
20
+ /** Doves oracle: SOL/USD price feed (reference/backfill default only) */
14
21
  export declare const DOVES_SOL_USD: PublicKey;
15
22
  /** Jupiter Perps Pool account (stores aumUsd for JLP price calculation) */
16
23
  export declare const JLP_POOL_ACCOUNT: PublicKey;
@@ -30,6 +37,7 @@ export declare const IX_DEPOSIT: Buffer<ArrayBuffer>;
30
37
  export declare const IX_WITHDRAW: Buffer<ArrayBuffer>;
31
38
  export declare const IX_UPDATE_AUM: Buffer<ArrayBuffer>;
32
39
  export declare const IX_SWAP_JLP: Buffer<ArrayBuffer>;
40
+ export declare const IX_BASE_TO_BASE_SWAP: Buffer<ArrayBuffer>;
33
41
  export declare const IX_SETTLE_YIELD: Buffer<ArrayBuffer>;
34
42
  export declare const IX_DEPOSIT_TO_ADAPTER: Buffer<ArrayBuffer>;
35
43
  export declare const IX_WITHDRAW_FROM_ADAPTER: Buffer<ArrayBuffer>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JLPD_VAULT_IDS_BY_POOL = exports.JLPD_VAULT_IDS = exports.JLPD_POOLS = exports.BPS_DENOMINATOR = exports.PPS_DECIMALS = exports.MAX_PERF_FEE_BPS = exports.MAX_MGMT_FEE_BPS = exports.NUM_ASSETS = exports.FLAG_TEST_MODE = exports.FLAG_REBALANCE_DISABLED = exports.FLAG_JLP_DISABLED = exports.FLAG_WITHDRAWALS_DISABLED = exports.FLAG_DEPOSITS_DISABLED = exports.FLAG_PAUSED = exports.STV_POSITION_SIZE = exports.STRATEGY_STATE_SIZE = exports.MANAGER_ROLE_SIZE = exports.JLPD_CONFIG_SIZE = exports.IX_REMOVE_MANAGER = exports.IX_ADD_MANAGER = exports.IX_ADAPTER_MANAGE = exports.IX_WITHDRAW_FROM_ADAPTER = exports.IX_DEPOSIT_TO_ADAPTER = exports.IX_SETTLE_YIELD = exports.IX_SWAP_JLP = exports.IX_UPDATE_AUM = exports.IX_WITHDRAW = exports.IX_DEPOSIT = exports.IX_CLOSE_POSITION = exports.IX_INIT_POSITION = exports.IX_INIT_OR_UPDATE_STRATEGY_STATE = exports.IX_INIT_OR_UPDATE_CONFIG = exports.DISC_MANAGER_ROLE = exports.DISC_STV_POSITION = exports.DISC_STRATEGY_STATE = exports.DISC_JLPD_CONFIG = exports.POSITION_SEED = exports.STRATEGY_STATE_SEED = exports.MANAGER_SEED = exports.CONFIG_SEED = exports.JUPITER_PERPS_PROGRAM = exports.JLP_POOL_ACCOUNT = exports.DOVES_SOL_USD = exports.DOVES_ETH_USD = exports.DOVES_BTC_USD = exports.JUPITER_PROGRAM = exports.JLP_MINT = exports.PROGRAM_ID_DEVNET = exports.PROGRAM_ID_MAINNET = exports.PROGRAM_ID = void 0;
4
- exports.JLPD_POOL_DECIMALS = void 0;
3
+ exports.JLPD_VAULT_IDS = exports.JLPD_POOLS = exports.BPS_DENOMINATOR = exports.PPS_DECIMALS = exports.MAX_PERF_FEE_BPS = exports.MAX_MGMT_FEE_BPS = exports.NUM_ASSETS = exports.FLAG_TEST_MODE = exports.FLAG_REBALANCE_DISABLED = exports.FLAG_JLP_DISABLED = exports.FLAG_WITHDRAWALS_DISABLED = exports.FLAG_DEPOSITS_DISABLED = exports.FLAG_PAUSED = exports.STV_POSITION_SIZE = exports.STRATEGY_STATE_SIZE = exports.MANAGER_ROLE_SIZE = exports.JLPD_CONFIG_SIZE = exports.IX_REMOVE_MANAGER = exports.IX_ADD_MANAGER = exports.IX_ADAPTER_MANAGE = exports.IX_WITHDRAW_FROM_ADAPTER = exports.IX_DEPOSIT_TO_ADAPTER = exports.IX_SETTLE_YIELD = exports.IX_BASE_TO_BASE_SWAP = exports.IX_SWAP_JLP = exports.IX_UPDATE_AUM = exports.IX_WITHDRAW = exports.IX_DEPOSIT = exports.IX_CLOSE_POSITION = exports.IX_INIT_POSITION = exports.IX_INIT_OR_UPDATE_STRATEGY_STATE = exports.IX_INIT_OR_UPDATE_CONFIG = exports.DISC_MANAGER_ROLE = exports.DISC_STV_POSITION = exports.DISC_STRATEGY_STATE = exports.DISC_JLPD_CONFIG = exports.POSITION_SEED = exports.STRATEGY_STATE_SEED = exports.MANAGER_SEED = exports.CONFIG_SEED = exports.JUPITER_PERPS_PROGRAM = exports.JLP_POOL_ACCOUNT = exports.DOVES_SOL_USD = exports.DOVES_ETH_USD = exports.DOVES_BTC_USD = exports.JUPITER_PROGRAM = exports.JLP_MINT = exports.PROGRAM_ID_DEVNET = exports.PROGRAM_ID_MAINNET = exports.PROGRAM_ID = void 0;
4
+ exports.JLPD_POOL_DECIMALS = exports.JLPD_VAULT_IDS_BY_POOL = void 0;
5
5
  const web3_js_1 = require("@solana/web3.js");
6
6
  exports.PROGRAM_ID = new web3_js_1.PublicKey("GXqt4ZH2UUBsLWwMNJiZMXza3q7xEGChfW8XjVRjLxr5");
7
7
  exports.PROGRAM_ID_MAINNET = exports.PROGRAM_ID;
@@ -13,12 +13,19 @@ exports.PROGRAM_ID_DEVNET = new web3_js_1.PublicKey("AcVcAihjB9Z3Lg3ZiboWxni2sTz
13
13
  exports.JLP_MINT = new web3_js_1.PublicKey("27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4");
14
14
  /** Jupiter aggregator program (swap routing) */
15
15
  exports.JUPITER_PROGRAM = new web3_js_1.PublicKey("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4");
16
- /** Doves oracle: BTC/USD price feed */
17
- exports.DOVES_BTC_USD = new web3_js_1.PublicKey("4HBbPx9QJdjJ7GUe6bsiJjGybvfpDhQMMPXP1UEa7VT5");
18
- /** Doves oracle: ETH/USD price feed */
19
- exports.DOVES_ETH_USD = new web3_js_1.PublicKey("5URYohbPy32nxK1t3jAHVNfdWY2xTubHiFvLrE3VhXEp");
20
- /** Doves oracle: SOL/USD price feed */
21
- exports.DOVES_SOL_USD = new web3_js_1.PublicKey("39cWjvHrpHNz2SbXv6ME4NPhqBDBd4KsjUYv5JkHEAJU");
16
+ /**
17
+ * Reference/backfill defaults for the Doves price oracle feeds.
18
+ * Pending Jupiter confirmation; runtime feed comes from StrategyState.priceOracle.
19
+ * These constants are NOT used at runtime — swap_jlp, base_to_base_swap, and
20
+ * settle_yield all read the feed from strategy_state.price_oracle on-chain.
21
+ * Use these for backfill scripts, LUT tooling, and admin init calls only.
22
+ */
23
+ /** Doves oracle: BTC/USD price feed (reference/backfill default only) */
24
+ exports.DOVES_BTC_USD = new web3_js_1.PublicKey("FxSvTMvZS9S1jjjixHPh7QEn99WuVWaEHqvw8NqfWmB8");
25
+ /** Doves oracle: ETH/USD price feed (reference/backfill default only) */
26
+ exports.DOVES_ETH_USD = new web3_js_1.PublicKey("9QEL8K51uZrqoqTp6Zfjmr65gYqvivVrd2Yg5bo6joGV");
27
+ /** Doves oracle: SOL/USD price feed (reference/backfill default only) */
28
+ exports.DOVES_SOL_USD = new web3_js_1.PublicKey("A5d4aY4K4BYEtXdAY7WNBHTKxRMeyAA6RYHWVYEW22Fe");
22
29
  /** Jupiter Perps Pool account (stores aumUsd for JLP price calculation) */
23
30
  exports.JLP_POOL_ACCOUNT = new web3_js_1.PublicKey("5BUwFW4nRbftYTDMbgxykoFWqWHPzahFSNAaaaJtVKsq");
24
31
  /** Jupiter Perpetuals Program ID */
@@ -37,14 +44,16 @@ Object.defineProperty(exports, "DISC_STRATEGY_STATE", { enumerable: true, get: f
37
44
  Object.defineProperty(exports, "DISC_STV_POSITION", { enumerable: true, get: function () { return constants_1.DISC_STV_POSITION; } });
38
45
  Object.defineProperty(exports, "DISC_MANAGER_ROLE", { enumerable: true, get: function () { return constants_1.DISC_MANAGER_ROLE; } });
39
46
  // Instruction discriminators (Anchor 8-byte)
40
- exports.IX_INIT_OR_UPDATE_CONFIG = Buffer.from([234, 24, 218, 120, 213, 149, 245, 213]);
41
- exports.IX_INIT_OR_UPDATE_STRATEGY_STATE = Buffer.from([223, 7, 93, 99, 12, 44, 180, 255]);
47
+ exports.IX_INIT_OR_UPDATE_CONFIG = Buffer.from([120, 208, 225, 179, 75, 21, 139, 209]);
48
+ exports.IX_INIT_OR_UPDATE_STRATEGY_STATE = Buffer.from([148, 75, 234, 144, 185, 1, 1, 111]);
42
49
  exports.IX_INIT_POSITION = Buffer.from([197, 20, 10, 1, 97, 160, 177, 91]);
43
50
  exports.IX_CLOSE_POSITION = Buffer.from([123, 134, 81, 0, 49, 68, 98, 98]);
44
51
  exports.IX_DEPOSIT = Buffer.from([242, 35, 198, 137, 82, 225, 242, 182]);
45
52
  exports.IX_WITHDRAW = Buffer.from([183, 18, 70, 156, 148, 109, 161, 34]);
46
53
  exports.IX_UPDATE_AUM = Buffer.from([162, 40, 227, 16, 84, 169, 182, 185]);
47
54
  exports.IX_SWAP_JLP = Buffer.from([190, 44, 224, 191, 169, 243, 146, 127]);
55
+ // sha256("global:base_to_base_swap")[..8]
56
+ exports.IX_BASE_TO_BASE_SWAP = Buffer.from([138, 14, 49, 99, 201, 152, 239, 96]);
48
57
  exports.IX_SETTLE_YIELD = Buffer.from([64, 28, 44, 24, 43, 204, 58, 215]);
49
58
  // sha256("global:deposit_to_adapter")[..8]
50
59
  exports.IX_DEPOSIT_TO_ADAPTER = Buffer.from([123, 167, 9, 180, 75, 80, 195, 219]);
@@ -4,6 +4,7 @@ export * from "./pda";
4
4
  export * from "./accounts";
5
5
  export * from "./instructions";
6
6
  export * from "./swap-jlp";
7
+ export * from "./base-to-base-swap";
7
8
  export * from "./settle-yield";
8
9
  export * from "./jlp-data";
9
10
  export * from "./jlp-borrow";
@@ -20,6 +20,7 @@ __exportStar(require("./pda"), exports);
20
20
  __exportStar(require("./accounts"), exports);
21
21
  __exportStar(require("./instructions"), exports);
22
22
  __exportStar(require("./swap-jlp"), exports);
23
+ __exportStar(require("./base-to-base-swap"), exports);
23
24
  __exportStar(require("./settle-yield"), exports);
24
25
  __exportStar(require("./jlp-data"), exports);
25
26
  __exportStar(require("./jlp-borrow"), exports);
@@ -1,4 +1,53 @@
1
1
  import { PublicKey, TransactionInstruction } from "@solana/web3.js";
2
+ export interface InitOrUpdateStrategyStateArgs {
3
+ /** Admin signer; also the rent payer for the init_if_needed ATAs (writable). */
4
+ admin: PublicKey;
5
+ config: PublicKey;
6
+ strategyState: PublicKey;
7
+ baseMint: PublicKey;
8
+ jlpMint: PublicKey;
9
+ strategyBaseAta: PublicKey;
10
+ strategyJlpAta: PublicKey;
11
+ tokenProgram: PublicKey;
12
+ systemProgram?: PublicKey;
13
+ associatedTokenProgram?: PublicKey;
14
+ rent?: PublicKey;
15
+ /** New admin/authority Pubkey, or null to leave unchanged. */
16
+ authority?: PublicKey | null;
17
+ /** New flags value, or null to leave unchanged. */
18
+ flags?: number | null;
19
+ /**
20
+ * Doves price-feed account to store in strategy_state.price_oracle.
21
+ * Serialized as the THIRD optional field in InitOrUpdateStrategyStateParams.
22
+ * Pass null to leave unchanged.
23
+ */
24
+ priceOracle?: PublicKey | null;
25
+ }
26
+ /**
27
+ * Create an `init_or_update_strategy_state` instruction for the JLPD program.
28
+ *
29
+ * Instruction data: [8-byte disc,
30
+ * Option<Pubkey> authority, (1 tag + 32 bytes if Some)
31
+ * Option<u16> flags, (1 tag + 2 bytes if Some)
32
+ * Option<Pubkey> price_oracle (1 tag + 32 bytes if Some)]
33
+ *
34
+ * Field order matches Rust `InitOrUpdateStrategyStateParams`:
35
+ * authority: Option<Pubkey>, flags: Option<u16>, price_oracle: Option<Pubkey>
36
+ *
37
+ * Accounts (match on-chain InitOrUpdateStrategyState exactly):
38
+ * 0. admin (signer, writable — pays init_if_needed ATA rent)
39
+ * 1. config
40
+ * 2. strategy_state (writable — init_if_needed)
41
+ * 3. base_mint
42
+ * 4. jlp_mint
43
+ * 5. strategy_base_ata (writable — init_if_needed)
44
+ * 6. strategy_jlp_ata (writable — init_if_needed)
45
+ * 7. system_program
46
+ * 8. token_program
47
+ * 9. associated_token_program
48
+ * 10. rent
49
+ */
50
+ export declare function createInitOrUpdateStrategyStateIx(args: InitOrUpdateStrategyStateArgs, programId?: PublicKey): TransactionInstruction;
2
51
  export interface AddManagerArgs {
3
52
  admin: PublicKey;
4
53
  payer: PublicKey;
@@ -1,9 +1,64 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createInitOrUpdateStrategyStateIx = createInitOrUpdateStrategyStateIx;
3
4
  exports.createAddManagerIx = createAddManagerIx;
4
5
  exports.createRemoveManagerIx = createRemoveManagerIx;
5
6
  const web3_js_1 = require("@solana/web3.js");
7
+ const spl_token_1 = require("@solana/spl-token");
8
+ const buffer_1 = require("../common/buffer");
6
9
  const constants_1 = require("./constants");
10
+ /**
11
+ * Create an `init_or_update_strategy_state` instruction for the JLPD program.
12
+ *
13
+ * Instruction data: [8-byte disc,
14
+ * Option<Pubkey> authority, (1 tag + 32 bytes if Some)
15
+ * Option<u16> flags, (1 tag + 2 bytes if Some)
16
+ * Option<Pubkey> price_oracle (1 tag + 32 bytes if Some)]
17
+ *
18
+ * Field order matches Rust `InitOrUpdateStrategyStateParams`:
19
+ * authority: Option<Pubkey>, flags: Option<u16>, price_oracle: Option<Pubkey>
20
+ *
21
+ * Accounts (match on-chain InitOrUpdateStrategyState exactly):
22
+ * 0. admin (signer, writable — pays init_if_needed ATA rent)
23
+ * 1. config
24
+ * 2. strategy_state (writable — init_if_needed)
25
+ * 3. base_mint
26
+ * 4. jlp_mint
27
+ * 5. strategy_base_ata (writable — init_if_needed)
28
+ * 6. strategy_jlp_ata (writable — init_if_needed)
29
+ * 7. system_program
30
+ * 8. token_program
31
+ * 9. associated_token_program
32
+ * 10. rent
33
+ */
34
+ function createInitOrUpdateStrategyStateIx(args, programId = constants_1.PROGRAM_ID) {
35
+ const { admin, config, strategyState, baseMint, jlpMint, strategyBaseAta, strategyJlpAta, tokenProgram, systemProgram = web3_js_1.SystemProgram.programId, associatedTokenProgram = spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, rent = web3_js_1.SYSVAR_RENT_PUBKEY, authority, flags, priceOracle, } = args;
36
+ // Serialize Borsh Option<T> fields in Rust param order:
37
+ // 1. authority: Option<Pubkey>
38
+ // 2. flags: Option<u16>
39
+ // 3. price_oracle: Option<Pubkey>
40
+ const parts = [...constants_1.IX_INIT_OR_UPDATE_STRATEGY_STATE];
41
+ (0, buffer_1.writeOptionalPubkey)(parts, authority ?? null);
42
+ (0, buffer_1.writeOptionalU16)(parts, flags ?? null);
43
+ (0, buffer_1.writeOptionalPubkey)(parts, priceOracle ?? null);
44
+ return new web3_js_1.TransactionInstruction({
45
+ keys: [
46
+ { pubkey: admin, isSigner: true, isWritable: true },
47
+ { pubkey: config, isSigner: false, isWritable: false },
48
+ { pubkey: strategyState, isSigner: false, isWritable: true },
49
+ { pubkey: baseMint, isSigner: false, isWritable: false },
50
+ { pubkey: jlpMint, isSigner: false, isWritable: false },
51
+ { pubkey: strategyBaseAta, isSigner: false, isWritable: true },
52
+ { pubkey: strategyJlpAta, isSigner: false, isWritable: true },
53
+ { pubkey: systemProgram, isSigner: false, isWritable: false },
54
+ { pubkey: tokenProgram, isSigner: false, isWritable: false },
55
+ { pubkey: associatedTokenProgram, isSigner: false, isWritable: false },
56
+ { pubkey: rent, isSigner: false, isWritable: false },
57
+ ],
58
+ programId,
59
+ data: Buffer.from(parts),
60
+ });
61
+ }
7
62
  /**
8
63
  * Create an `add_manager` instruction for the JLPD Strategy program.
9
64
  *
@@ -37,6 +37,17 @@ export interface JlpPoolDetails {
37
37
  jlpPrice: number;
38
38
  jlpSupply: number;
39
39
  }
40
+ /**
41
+ * Reset the price memo. Intended for unit tests that mock global fetch with
42
+ * scenario-specific prices — module-level cache pollutes across tests when
43
+ * TTL has not expired, leading to assertion failures that depend on test
44
+ * ordering.
45
+ *
46
+ * Not part of the public surface for application code; cache TTL handles
47
+ * production. Exported under `__test__*` namespace convention so consumers
48
+ * tree-shake it out and never accidentally rely on cache invalidation.
49
+ */
50
+ export declare function __test__resetPricesCache(): void;
40
51
  /**
41
52
  * Fetch full JLP pool details: fee parameters, per-custody target/current
42
53
  * weights, pool AUM, and JLP price.
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.__test__resetPricesCache = __test__resetPricesCache;
3
4
  exports.fetchJlpPoolDetails = fetchJlpPoolDetails;
4
5
  exports.computeAddLiquidityFee = computeAddLiquidityFee;
5
6
  exports.fetchJlpCustodyData = fetchJlpCustodyData;
@@ -113,6 +114,20 @@ async function fetchAllCustodies(connection) {
113
114
  const PRICES_TTL_MS = 30000;
114
115
  let pricesCache = null;
115
116
  let pricesInFlight = null;
117
+ /**
118
+ * Reset the price memo. Intended for unit tests that mock global fetch with
119
+ * scenario-specific prices — module-level cache pollutes across tests when
120
+ * TTL has not expired, leading to assertion failures that depend on test
121
+ * ordering.
122
+ *
123
+ * Not part of the public surface for application code; cache TTL handles
124
+ * production. Exported under `__test__*` namespace convention so consumers
125
+ * tree-shake it out and never accidentally rely on cache invalidation.
126
+ */
127
+ function __test__resetPricesCache() {
128
+ pricesCache = null;
129
+ pricesInFlight = null;
130
+ }
116
131
  async function fetchPrices() {
117
132
  if (pricesCache && Date.now() - pricesCache.at < PRICES_TTL_MS) {
118
133
  return pricesCache.data;
@@ -1,4 +1,4 @@
1
- import { PublicKey, TransactionInstruction } from "@solana/web3.js";
1
+ import { PublicKey, TransactionInstruction, AccountMeta } from "@solana/web3.js";
2
2
  /** Arguments accepted by `createSettleYieldIx`. */
3
3
  export interface CreateSettleYieldIxArgs {
4
4
  manager: PublicKey;
@@ -7,6 +7,25 @@ export interface CreateSettleYieldIxArgs {
7
7
  jlpMint?: PublicKey;
8
8
  tokenProgram?: PublicKey;
9
9
  programId?: PublicKey;
10
+ /**
11
+ * Adapter accounts for the earn-yield accrual CPI, appended after the 14
12
+ * fixed accounts. REQUIRED whenever `config.jlp_earn_amount > 0` (the program
13
+ * rejects settle with no adapter accounts when JLP is deployed in an adapter).
14
+ * Order: [adapter_state (writable), adapter_program (executable),
15
+ * ...adapter update_yield protocol accounts]. Omit when no earn is active.
16
+ */
17
+ adapterAccounts?: AccountMeta[];
18
+ /**
19
+ * Doves price-feed accounts for BTC/ETH/SOL. These MUST equal the on-chain
20
+ * `strategy_state.price_oracle` of each respective strategy (the program now
21
+ * validates the passed oracle against the stored feed). To stay rotation-proof,
22
+ * read each strategy's `priceOracle` from chain and pass it here. If omitted,
23
+ * falls back to the `DOVES_*_USD` reference constants (correct only while they
24
+ * match the backfilled on-chain value).
25
+ */
26
+ priceOracleBtc?: PublicKey;
27
+ priceOracleEth?: PublicKey;
28
+ priceOracleSol?: PublicKey;
10
29
  }
11
30
  /**
12
31
  * Build a `settle_yield` instruction with automatic PDA derivation.
@@ -29,14 +29,15 @@ const ata_1 = require("../common/ata");
29
29
  * 11: jlp_pool (Jupiter Perps Pool)
30
30
  * 12: jlp_mint_account
31
31
  * 13: manager (signer)
32
+ * 14+: optional adapter accounts (earn accrual CPI; required when earn active)
32
33
  */
33
34
  function buildRawSettleYieldIx(args, programId = constants_1.PROGRAM_ID) {
34
- const { config, managerRole, vaultJlpAta, stv0, stv1, stv2, stv3, stv4, dovesBtcUsd, dovesEthUsd, dovesSolUsd, jlpPool, jlpMintAccount, manager, } = args;
35
+ const { config, managerRole, vaultJlpAta, stv0, stv1, stv2, stv3, stv4, dovesBtcUsd, dovesEthUsd, dovesSolUsd, jlpPool, jlpMintAccount, manager, adapterAccounts = [], } = args;
35
36
  // Instruction data: just the 8-byte discriminator (no params)
36
37
  const data = Buffer.alloc(8);
37
38
  constants_1.IX_SETTLE_YIELD.copy(data, 0);
38
39
  const keys = [
39
- { pubkey: config, isSigner: false, isWritable: false },
40
+ { pubkey: config, isSigner: false, isWritable: true },
40
41
  { pubkey: managerRole, isSigner: false, isWritable: false },
41
42
  { pubkey: vaultJlpAta, isSigner: false, isWritable: false },
42
43
  { pubkey: stv0, isSigner: false, isWritable: true },
@@ -50,6 +51,7 @@ function buildRawSettleYieldIx(args, programId = constants_1.PROGRAM_ID) {
50
51
  { pubkey: jlpPool, isSigner: false, isWritable: false },
51
52
  { pubkey: jlpMintAccount, isSigner: false, isWritable: false },
52
53
  { pubkey: manager, isSigner: true, isWritable: false },
54
+ ...adapterAccounts,
53
55
  ];
54
56
  return new web3_js_1.TransactionInstruction({ keys, programId, data });
55
57
  }
@@ -67,7 +69,7 @@ function buildRawSettleYieldIx(args, programId = constants_1.PROGRAM_ID) {
67
69
  * (if any) are named `build*Transaction`.
68
70
  */
69
71
  function createSettleYieldIx(args) {
70
- const { manager, baseAssetMints, jlpMint = constants_1.JLP_MINT, tokenProgram = spl_token_1.TOKEN_PROGRAM_ID, programId = constants_1.PROGRAM_ID, } = args;
72
+ const { manager, baseAssetMints, jlpMint = constants_1.JLP_MINT, tokenProgram = spl_token_1.TOKEN_PROGRAM_ID, programId = constants_1.PROGRAM_ID, adapterAccounts, priceOracleBtc = constants_1.DOVES_BTC_USD, priceOracleEth = constants_1.DOVES_ETH_USD, priceOracleSol = constants_1.DOVES_SOL_USD, } = args;
71
73
  // Derive PDAs
72
74
  const [config] = (0, pda_1.findJlpdConfigPda)(programId);
73
75
  const [managerRole] = (0, pda_1.findJlpdManagerRolePda)(config, manager, programId);
@@ -88,11 +90,12 @@ function createSettleYieldIx(args) {
88
90
  stv2,
89
91
  stv3,
90
92
  stv4,
91
- dovesBtcUsd: constants_1.DOVES_BTC_USD,
92
- dovesEthUsd: constants_1.DOVES_ETH_USD,
93
- dovesSolUsd: constants_1.DOVES_SOL_USD,
93
+ dovesBtcUsd: priceOracleBtc,
94
+ dovesEthUsd: priceOracleEth,
95
+ dovesSolUsd: priceOracleSol,
94
96
  jlpPool: constants_1.JLP_POOL_ACCOUNT,
95
97
  jlpMintAccount: jlpMint,
96
98
  manager,
99
+ adapterAccounts,
97
100
  }, programId);
98
101
  }
@@ -16,6 +16,16 @@ export interface CreateSwapJlpIxArgs {
16
16
  jlpMint: PublicKey;
17
17
  tokenProgram: PublicKey;
18
18
  jupiterProgram: PublicKey;
19
+ /**
20
+ * Doves price-feed account for this base asset. Must match
21
+ * strategy_state.price_oracle on-chain. Stablecoins (USDC/JupUSD) use
22
+ * PublicKey.default — the program ignores the oracle for $1-pegged assets.
23
+ */
24
+ priceOracle: PublicKey;
25
+ /** Jupiter Perps JLP pool account — must equal the on-chain JLP_POOL_ACCOUNT. */
26
+ jlpPool: PublicKey;
27
+ /** JLP mint account (raw) for pool-price supply read — equals config.jlp_mint. */
28
+ jlpMintAccount: PublicKey;
19
29
  direction: SwapDirection;
20
30
  amount: bigint | BN;
21
31
  minOut: bigint | BN;
@@ -78,10 +88,15 @@ export declare function getJupiterSwapQuote(args: {
78
88
  *
79
89
  * @param quoteResponse The quote from getJupiterSwapQuote
80
90
  * @param userPublicKey The account that signs the swap -- for JLPD this is the strategy_state PDA
91
+ * @param destinationTokenAccount Optional override for the destination token account.
92
+ * For base_to_base_swap: must be base_out_ata (ATA owned by strategy_state_OUT) so
93
+ * Jupiter routes output tokens there instead of to userPublicKey's default ATA.
94
+ * For swap_jlp: omit — Jupiter defaults destination to userPublicKey's ATA which is correct.
81
95
  */
82
96
  export declare function getJupiterSwapInstructions(args: {
83
97
  quoteResponse: JupiterQuote;
84
98
  userPublicKey: PublicKey;
99
+ destinationTokenAccount?: PublicKey;
85
100
  }): Promise<{
86
101
  swapInstructionData: Buffer;
87
102
  remainingAccounts: AccountMeta[];
@@ -107,6 +122,17 @@ export declare function buildSwapJlpTransaction(args: {
107
122
  jlpMint?: PublicKey;
108
123
  tokenProgram?: PublicKey;
109
124
  programId?: PublicKey;
125
+ /**
126
+ * Doves price-feed account for this base asset. Must equal
127
+ * strategy_state.price_oracle on-chain.
128
+ *
129
+ * - For non-stable assets (BTC/ETH/SOL): if omitted the strategy state is
130
+ * fetched from the chain to read the stored feed. Provide this when you
131
+ * already have the strategy state in memory to avoid an extra RPC call.
132
+ * - For stable assets (USDC/JupUSD): pass `PublicKey.default` or omit —
133
+ * the program uses a hardcoded $1 price and ignores the oracle account.
134
+ */
135
+ priceOracle?: PublicKey;
110
136
  }): Promise<{
111
137
  instructions: TransactionInstruction[];
112
138
  addressLookupTables: AddressLookupTableAccount[];