@elmntl/jlpd-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.mjs ADDED
@@ -0,0 +1,1753 @@
1
+ // src/client.ts
2
+ import {
3
+ PublicKey as PublicKey12,
4
+ TransactionMessage,
5
+ VersionedTransaction,
6
+ ComputeBudgetProgram,
7
+ SystemProgram as SystemProgram2,
8
+ SYSVAR_RENT_PUBKEY
9
+ } from "@solana/web3.js";
10
+ import { BN as BN5 } from "@coral-xyz/anchor";
11
+ import {
12
+ TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID2,
13
+ ASSOCIATED_TOKEN_PROGRAM_ID as ASSOCIATED_TOKEN_PROGRAM_ID2,
14
+ getAssociatedTokenAddressSync as getAssociatedTokenAddressSync2
15
+ } from "@solana/spl-token";
16
+
17
+ // src/constants.ts
18
+ import { PublicKey } from "@solana/web3.js";
19
+ import { NATIVE_MINT } from "@solana/spl-token";
20
+ var JLPD_PROGRAM_ID = new PublicKey(
21
+ "ELEM2bAobpZNuysfhyF28XGVjA1aTUwm6rPYyv1JX3oq"
22
+ );
23
+ var JUPITER_LEND_PROGRAM_ID = new PublicKey(
24
+ "jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9"
25
+ );
26
+ var JUPITER_SWAP_PROGRAM_ID = new PublicKey(
27
+ "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
28
+ );
29
+ var SEED_JLP_VAULT = "jlp_vault";
30
+ var SEED_STV = "stv";
31
+ var FLAG_PAUSED = 1;
32
+ var FLAG_DEPOSITS_DISABLED = 2;
33
+ var FLAG_WITHDRAWALS_DISABLED = 4;
34
+ var FLAG_JLP_DISABLED = 8;
35
+ var FLAG_REBALANCE_DISABLED = 16;
36
+ var PPS_DECIMALS = 1e9;
37
+ var EXCHANGE_RATE_PRECISION = 1e12;
38
+ var MINTS = {
39
+ JLP: new PublicKey("27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4"),
40
+ WSOL: NATIVE_MINT,
41
+ USDC: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
42
+ WBTC: new PublicKey("3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh"),
43
+ WETH: new PublicKey("7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"),
44
+ JupUSD: new PublicKey("JuprjznTrTSp2UFa3ZBUFgwdAmtZCq4MQCwysN55USD")
45
+ };
46
+ var STV_INDEX = /* @__PURE__ */ ((STV_INDEX2) => {
47
+ STV_INDEX2[STV_INDEX2["BTC"] = 0] = "BTC";
48
+ STV_INDEX2[STV_INDEX2["ETH"] = 1] = "ETH";
49
+ STV_INDEX2[STV_INDEX2["SOL"] = 2] = "SOL";
50
+ STV_INDEX2[STV_INDEX2["USDC"] = 3] = "USDC";
51
+ STV_INDEX2[STV_INDEX2["JupUSD"] = 4] = "JupUSD";
52
+ return STV_INDEX2;
53
+ })(STV_INDEX || {});
54
+ var ORACLES = {
55
+ // Doves oracles (Jupiter Perps oracle system)
56
+ DOVES_BTC_USD: new PublicKey("4HBbPx9QJdjJ7GUe6bsiJjGybvfpDhQMMPXP1UEa7VT5"),
57
+ DOVES_ETH_USD: new PublicKey("5URYohbPy32nxK1t3jAHVNfdWY2xTubHiFvLrE3VhXEp"),
58
+ DOVES_SOL_USD: new PublicKey("39cWjvHrpHNz2SbXv6ME4NPhqBDBd4KsjUYv5JkHEAJU"),
59
+ // Pyth oracle for JLP price
60
+ PYTH_JLP_USD: new PublicKey("2TTGSRSezqFzeLUH8JwRUbtN66XLLaymfYsWRTMjfiMw")
61
+ };
62
+
63
+ // src/accounts/pdas.ts
64
+ import { PublicKey as PublicKey2 } from "@solana/web3.js";
65
+ var SEED_JLP_VAULT_BUFFER = Buffer.from(SEED_JLP_VAULT);
66
+ var SEED_STV_BUFFER = Buffer.from(SEED_STV);
67
+ var pdaCache = /* @__PURE__ */ new Map();
68
+ function deriveVaultPda(programId) {
69
+ const key = `vault:${programId.toBase58()}`;
70
+ let cached = pdaCache.get(key);
71
+ if (!cached) {
72
+ cached = PublicKey2.findProgramAddressSync(
73
+ [SEED_JLP_VAULT_BUFFER],
74
+ programId
75
+ );
76
+ pdaCache.set(key, cached);
77
+ }
78
+ return cached;
79
+ }
80
+ function deriveStvPda(baseMint, programId) {
81
+ const key = `stv:${baseMint.toBase58()}:${programId.toBase58()}`;
82
+ let cached = pdaCache.get(key);
83
+ if (!cached) {
84
+ cached = PublicKey2.findProgramAddressSync(
85
+ [SEED_STV_BUFFER, baseMint.toBuffer()],
86
+ programId
87
+ );
88
+ pdaCache.set(key, cached);
89
+ }
90
+ return cached;
91
+ }
92
+ function clearPdaCache() {
93
+ pdaCache.clear();
94
+ }
95
+
96
+ // src/accounts/vault.ts
97
+ import { PublicKey as PublicKey3 } from "@solana/web3.js";
98
+ import { BN } from "@coral-xyz/anchor";
99
+ var JLP_VAULT_DATA_SIZE = 464;
100
+ var JLP_VAULT_ACCOUNT_SIZE = 8 + JLP_VAULT_DATA_SIZE;
101
+ var JLP_VAULT_DISCRIMINATOR = Buffer.from([
102
+ 41,
103
+ 108,
104
+ 189,
105
+ 168,
106
+ 199,
107
+ 152,
108
+ 221,
109
+ 119
110
+ ]);
111
+ function parseVault(data) {
112
+ if (data.length < JLP_VAULT_ACCOUNT_SIZE) {
113
+ throw new Error(
114
+ `Invalid JLPVault data size: expected ${JLP_VAULT_ACCOUNT_SIZE}, got ${data.length}`
115
+ );
116
+ }
117
+ const discriminator = data.subarray(0, 8);
118
+ if (!discriminator.equals(JLP_VAULT_DISCRIMINATOR)) {
119
+ throw new Error(
120
+ `Invalid JLPVault discriminator: expected ${JLP_VAULT_DISCRIMINATOR.toString("hex")}, got ${discriminator.toString("hex")}`
121
+ );
122
+ }
123
+ let offset = 8;
124
+ const admin = new PublicKey3(data.subarray(offset, offset + 32));
125
+ offset += 32;
126
+ const manager = new PublicKey3(data.subarray(offset, offset + 32));
127
+ offset += 32;
128
+ const feeReceiver = new PublicKey3(data.subarray(offset, offset + 32));
129
+ offset += 32;
130
+ const jlpMint = new PublicKey3(data.subarray(offset, offset + 32));
131
+ offset += 32;
132
+ const baseAssetMints = [];
133
+ for (let i = 0; i < 5; i++) {
134
+ baseAssetMints.push(new PublicKey3(data.subarray(offset, offset + 32)));
135
+ offset += 32;
136
+ }
137
+ const jlxAssetMints = [];
138
+ for (let i = 0; i < 5; i++) {
139
+ jlxAssetMints.push(new PublicKey3(data.subarray(offset, offset + 32)));
140
+ offset += 32;
141
+ }
142
+ const oracleStalenessThreshold = new BN(data.subarray(offset, offset + 8), "le");
143
+ offset += 8;
144
+ const flags = data.readUInt16LE(offset);
145
+ offset += 2;
146
+ const jlpSlippageBps = data.readUInt16LE(offset);
147
+ offset += 2;
148
+ const version = data.readUInt8(offset);
149
+ offset += 1;
150
+ const bump = data.readUInt8(offset);
151
+ offset += 1;
152
+ return {
153
+ admin,
154
+ manager,
155
+ feeReceiver,
156
+ jlpMint,
157
+ baseAssetMints,
158
+ jlxAssetMints,
159
+ oracleStalenessThreshold,
160
+ flags,
161
+ jlpSlippageBps,
162
+ version,
163
+ bump
164
+ };
165
+ }
166
+
167
+ // src/accounts/stv.ts
168
+ import { PublicKey as PublicKey4 } from "@solana/web3.js";
169
+ import { BN as BN2 } from "@coral-xyz/anchor";
170
+ var STV_DATA_SIZE = 160;
171
+ var STV_ACCOUNT_SIZE = 8 + STV_DATA_SIZE;
172
+ var STV_DISCRIMINATOR = Buffer.from([
173
+ 214,
174
+ 2,
175
+ 96,
176
+ 41,
177
+ 85,
178
+ 163,
179
+ 17,
180
+ 230
181
+ ]);
182
+ function parseStv(data) {
183
+ if (data.length < STV_ACCOUNT_SIZE) {
184
+ throw new Error(
185
+ `Invalid STV data size: expected ${STV_ACCOUNT_SIZE}, got ${data.length}`
186
+ );
187
+ }
188
+ const discriminator = data.subarray(0, 8);
189
+ if (!discriminator.equals(STV_DISCRIMINATOR)) {
190
+ throw new Error(
191
+ `Invalid STV discriminator: expected ${STV_DISCRIMINATOR.toString("hex")}, got ${discriminator.toString("hex")}`
192
+ );
193
+ }
194
+ let offset = 8;
195
+ const baseMint = new PublicKey4(data.subarray(offset, offset + 32));
196
+ offset += 32;
197
+ const jlMint = new PublicKey4(data.subarray(offset, offset + 32));
198
+ offset += 32;
199
+ const jvMint = new PublicKey4(data.subarray(offset, offset + 32));
200
+ offset += 32;
201
+ const pps = new BN2(data.subarray(offset, offset + 8), "le");
202
+ offset += 8;
203
+ const hwm = new BN2(data.subarray(offset, offset + 8), "le");
204
+ offset += 8;
205
+ const lastMgmtFeeTs = new BN2(data.subarray(offset, offset + 8), "le");
206
+ offset += 8;
207
+ const baseLoaned = new BN2(data.subarray(offset, offset + 8), "le");
208
+ offset += 8;
209
+ const accruedFeesJlx = new BN2(data.subarray(offset, offset + 8), "le");
210
+ offset += 8;
211
+ const maxDeposit = new BN2(data.subarray(offset, offset + 8), "le");
212
+ offset += 8;
213
+ const minDeposit = new BN2(data.subarray(offset, offset + 8), "le");
214
+ offset += 8;
215
+ const mgmtFeeBps = data.readUInt16LE(offset);
216
+ offset += 2;
217
+ const perfFeeBps = data.readUInt16LE(offset);
218
+ offset += 2;
219
+ const flags = data.readUInt16LE(offset);
220
+ offset += 2;
221
+ const version = data.readUInt8(offset);
222
+ offset += 1;
223
+ const bump = data.readUInt8(offset);
224
+ offset += 1;
225
+ return {
226
+ baseMint,
227
+ jlMint,
228
+ jvMint,
229
+ pps,
230
+ hwm,
231
+ lastMgmtFeeTs,
232
+ baseLoaned,
233
+ accruedFeesJlx,
234
+ maxDeposit,
235
+ minDeposit,
236
+ mgmtFeeBps,
237
+ perfFeeBps,
238
+ flags,
239
+ version,
240
+ bump
241
+ };
242
+ }
243
+
244
+ // src/utils/ata.ts
245
+ import { getAssociatedTokenAddressSync } from "@solana/spl-token";
246
+ var ataCache = /* @__PURE__ */ new Map();
247
+ function deriveAta(mint, owner, allowPda = false) {
248
+ const key = `${mint.toBase58()}:${owner.toBase58()}:${allowPda}`;
249
+ let cached = ataCache.get(key);
250
+ if (!cached) {
251
+ cached = getAssociatedTokenAddressSync(mint, owner, allowPda);
252
+ ataCache.set(key, cached);
253
+ }
254
+ return cached;
255
+ }
256
+ function deriveUserAtas(baseMint, jvMint, userWallet) {
257
+ return {
258
+ baseAta: deriveAta(baseMint, userWallet, false),
259
+ jvxAta: deriveAta(jvMint, userWallet, false)
260
+ };
261
+ }
262
+ function deriveStvAtas(baseMint, jlxMint, stvPda) {
263
+ return {
264
+ baseAta: deriveAta(baseMint, stvPda, true),
265
+ jlxAta: deriveAta(jlxMint, stvPda, true)
266
+ };
267
+ }
268
+ function deriveVaultAtas(jlxMint, jlpMint, vaultPda) {
269
+ return {
270
+ stagingAta: deriveAta(jlxMint, vaultPda, true),
271
+ jlpAta: deriveAta(jlpMint, vaultPda, true)
272
+ };
273
+ }
274
+ function clearAtaCache() {
275
+ ataCache.clear();
276
+ }
277
+
278
+ // src/utils/math.ts
279
+ import { BN as BN3 } from "@coral-xyz/anchor";
280
+ var PPS_DECIMALS_BN = new BN3(PPS_DECIMALS);
281
+ var EXCHANGE_RATE_PRECISION_BN = new BN3(EXCHANGE_RATE_PRECISION);
282
+ var EXCHANGE_RATE_PRECISION_BI = BigInt(EXCHANGE_RATE_PRECISION);
283
+ var RETURN_PERCENT_PRECISION = EXCHANGE_RATE_PRECISION_BI * 100n;
284
+ var SECONDS_PER_YEAR = BigInt(365 * 24 * 60 * 60);
285
+ var MAX_REWARDS_RATE = 50n * EXCHANGE_RATE_PRECISION_BI;
286
+ function calculateNav(stvBaseBalance, stvJlxBalance, exchangeRate, baseLoaned) {
287
+ const jlxValue = stvJlxBalance.mul(new BN3(exchangeRate.toString())).div(EXCHANGE_RATE_PRECISION_BN);
288
+ return stvBaseBalance.add(jlxValue).add(baseLoaned);
289
+ }
290
+ function calculatePps(nav, jvSupply) {
291
+ if (jvSupply.isZero()) {
292
+ return new BN3(PPS_DECIMALS);
293
+ }
294
+ return nav.mul(PPS_DECIMALS_BN).div(jvSupply);
295
+ }
296
+ function sharesToBase(shares, pps) {
297
+ if (pps.isZero()) {
298
+ throw new Error("Price per share cannot be zero");
299
+ }
300
+ return shares.mul(pps).div(PPS_DECIMALS_BN);
301
+ }
302
+ function baseToShares(base, pps) {
303
+ if (pps.isZero()) {
304
+ throw new Error("Price per share cannot be zero");
305
+ }
306
+ return base.mul(PPS_DECIMALS_BN).div(pps);
307
+ }
308
+ function jlxToBase(jlxAmount, exchangeRate) {
309
+ if (exchangeRate.isZero()) {
310
+ throw new Error("Exchange rate cannot be zero");
311
+ }
312
+ return jlxAmount.mul(exchangeRate).div(EXCHANGE_RATE_PRECISION_BN);
313
+ }
314
+ function baseToJlx(baseAmount, exchangeRate) {
315
+ if (exchangeRate.isZero()) {
316
+ throw new Error("Exchange rate cannot be zero");
317
+ }
318
+ return baseAmount.mul(EXCHANGE_RATE_PRECISION_BN).div(exchangeRate);
319
+ }
320
+ function calculateExchangeRate(storedRate, rewardsRate, currentTimestamp, lastUpdateTimestamp, fTokenTotalSupply) {
321
+ if (fTokenTotalSupply === 0n) {
322
+ return storedRate;
323
+ }
324
+ const totalAssets = storedRate * fTokenTotalSupply / EXCHANGE_RATE_PRECISION_BI;
325
+ if (totalAssets === 0n || rewardsRate === 0n) {
326
+ return storedRate;
327
+ }
328
+ const timeDiff = currentTimestamp - lastUpdateTimestamp;
329
+ if (timeDiff <= 0n) {
330
+ return storedRate;
331
+ }
332
+ const rate = rewardsRate * RETURN_PERCENT_PRECISION / totalAssets;
333
+ const cappedRate = rate > MAX_REWARDS_RATE ? MAX_REWARDS_RATE : rate;
334
+ const priceIncrease = storedRate * cappedRate * timeDiff / RETURN_PERCENT_PRECISION / SECONDS_PER_YEAR;
335
+ return storedRate + priceIncrease;
336
+ }
337
+
338
+ // src/jupiter/pools.ts
339
+ import { PublicKey as PublicKey5 } from "@solana/web3.js";
340
+ import { NATIVE_MINT as NATIVE_MINT2 } from "@solana/spl-token";
341
+ var LENDING_ADMIN = new PublicKey5("5nmGjA4s7ATzpBQXC5RNceRpaJ7pYw2wKsNBWyuSAZV6");
342
+ var LIQUIDITY_PROGRAM_ID = new PublicKey5("jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC");
343
+ var LIQUIDITY_SINGLETON = new PublicKey5("7s1da8DduuBFqGra5bJBjpnvL5E9mGzCuMk1Qkh4or2Z");
344
+ var WSOL_POOL = {
345
+ mint: NATIVE_MINT2,
346
+ name: "SOL",
347
+ lending: new PublicKey5("BeAqbxfrcXmzEYT2Ra62oW2MqkuFDHaCtps47Mzg6Zj3"),
348
+ fTokenMint: new PublicKey5("2uQsyo1fXXQkDtcpXnLofWy88PxcvnfH2L8FPSE62FVU"),
349
+ tokenReservesLiquidity: new PublicKey5("4Y66HtUEqbbbpZdENGtFdVhUMS3tnagffn3M4do59Nfy"),
350
+ supplyPositionOnLiquidity: new PublicKey5("4SkEYxmiRgQ4VYyvh9VB4k39M49BpqazyzDUFDzJhXQm"),
351
+ rewardsRateModel: new PublicKey5("CkeQGDRsgMZcCaU8cZEdC2aFAohia4jLzL36RaLcUDsR"),
352
+ vault: new PublicKey5("BWeWnEbVmYKLmUpcrAXGrvDYxVA7VBS6TEnNc74jTerw"),
353
+ rateModel: new PublicKey5("Acvyi9HBGmqh3Exe1N4PjBVyY8fokq2AdC6fSLqV6KSo"),
354
+ claimAccount: new PublicKey5("6AQGR8zK4KTVZfZ9UZaRzyEL5ynvwVaF5ywVdmtJT24N"),
355
+ decimals: 9,
356
+ stvIndex: 2 /* SOL */,
357
+ hasJupiterLend: true
358
+ };
359
+ var USDC_POOL = {
360
+ mint: MINTS.USDC,
361
+ name: "USDC",
362
+ lending: new PublicKey5("2vVYHYM8VYnvZqQWpTJSj8o8DBf1wM8pVs3bsTgYZiqJ"),
363
+ fTokenMint: new PublicKey5("9BEcn9aPEmhSPbPQeFGjidRiEKki46fVQDyPpSQXPA2D"),
364
+ tokenReservesLiquidity: new PublicKey5("94vK29npVbyRHXH63rRcTiSr26SFhrQTzbpNJuhQEDu"),
365
+ supplyPositionOnLiquidity: new PublicKey5("Hf9gtkM4dpVBahVSzEXSVCAPpKzBsBcns3s8As3z77oF"),
366
+ rewardsRateModel: new PublicKey5("5xSPBiD3TibamAnwHDhZABdB4z4F9dcj5PnbteroBTTd"),
367
+ vault: new PublicKey5("BmkUoKMFYBxNSzWXyUjyMJjMAaVz4d8ZnxwwmhDCUXFB"),
368
+ rateModel: new PublicKey5("5pjzT5dFTsXcwixoab1QDLvZQvpYJxJeBphkyfHGn688"),
369
+ claimAccount: new PublicKey5("HN1r4VfkDn53xQQfeGDYrNuDKFdemAhZsHYRwBrFhsW"),
370
+ decimals: 6,
371
+ stvIndex: 3 /* USDC */,
372
+ hasJupiterLend: true
373
+ };
374
+ var JUPUSD_POOL = {
375
+ mint: MINTS.JupUSD,
376
+ name: "JupUSD",
377
+ lending: new PublicKey5("papYEgeG5uPE4niUWZhihUUzVVotJn1mAWbYo2UBSHi"),
378
+ fTokenMint: new PublicKey5("7GxATsNMnaC88vdwd2t3mwrFuQwwGvmYPrUQ4D6FotXk"),
379
+ tokenReservesLiquidity: new PublicKey5("2tQE8jVR5ezDw3PDa21BNzfyQ14Ug5cTf6n3swJNjkod"),
380
+ supplyPositionOnLiquidity: new PublicKey5("DXFoJruECdEch2KpzLQ2cSpxoBSsyg4bpYPnHYofsbD4"),
381
+ rewardsRateModel: new PublicKey5("E3U32h49TL9Qof3NeLja9qJxTrGYpY1o1NQPtrSLJjcc"),
382
+ vault: new PublicKey5("9kGqd5zsQGaFfFPdUuEgbRM4V7x72Jdt7WTS4uRouAQ7"),
383
+ rateModel: new PublicKey5("2hT44GA9r5PiqsbbmqN5CuF7ymtquoEdokRncAs9CVej"),
384
+ claimAccount: new PublicKey5("6q9vTzAsTMEPUCwuhEdJSJdpRNXnubwKZbi2go1B8nvg"),
385
+ decimals: 6,
386
+ stvIndex: 4 /* JupUSD */,
387
+ hasJupiterLend: true
388
+ };
389
+ var WBTC_POOL = {
390
+ mint: MINTS.WBTC,
391
+ name: "BTC",
392
+ lending: PublicKey5.default,
393
+ fTokenMint: MINTS.WBTC,
394
+ // jlBTC = WBTC (base-only)
395
+ tokenReservesLiquidity: PublicKey5.default,
396
+ supplyPositionOnLiquidity: PublicKey5.default,
397
+ rewardsRateModel: PublicKey5.default,
398
+ vault: PublicKey5.default,
399
+ rateModel: PublicKey5.default,
400
+ claimAccount: PublicKey5.default,
401
+ decimals: 8,
402
+ stvIndex: 0 /* BTC */,
403
+ hasJupiterLend: false
404
+ };
405
+ var WETH_POOL = {
406
+ mint: MINTS.WETH,
407
+ name: "ETH",
408
+ lending: PublicKey5.default,
409
+ fTokenMint: MINTS.WETH,
410
+ // jlETH = WETH (base-only)
411
+ tokenReservesLiquidity: PublicKey5.default,
412
+ supplyPositionOnLiquidity: PublicKey5.default,
413
+ rewardsRateModel: PublicKey5.default,
414
+ vault: PublicKey5.default,
415
+ rateModel: PublicKey5.default,
416
+ claimAccount: PublicKey5.default,
417
+ decimals: 8,
418
+ stvIndex: 1 /* ETH */,
419
+ hasJupiterLend: false
420
+ };
421
+ var POOLS = {
422
+ SOL: WSOL_POOL,
423
+ USDC: USDC_POOL,
424
+ JupUSD: JUPUSD_POOL,
425
+ BTC: WBTC_POOL,
426
+ ETH: WETH_POOL
427
+ };
428
+ var POOLS_BY_MINT = new Map(
429
+ Object.values(POOLS).map((p) => [p.mint.toBase58(), p])
430
+ );
431
+ function getPoolByName(name) {
432
+ return POOLS[name];
433
+ }
434
+ function getPoolByMint(mint) {
435
+ return POOLS_BY_MINT.get(mint.toBase58());
436
+ }
437
+
438
+ // src/jupiter/lend.ts
439
+ import { PublicKey as PublicKey6, SystemProgram } from "@solana/web3.js";
440
+ import { TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token";
441
+ var JUPITER_LEND_PROGRAM_ID2 = new PublicKey6(
442
+ "jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9"
443
+ );
444
+ function buildExchangeRateAccounts(pool) {
445
+ if (!pool.hasJupiterLend) {
446
+ return null;
447
+ }
448
+ return {
449
+ lending: pool.lending,
450
+ rewardsRateModel: pool.rewardsRateModel
451
+ };
452
+ }
453
+ function buildJupEarnDepositAccounts(pool, stvPda, stvBaseAta, stvJlxAta) {
454
+ if (!pool.hasJupiterLend) {
455
+ throw new Error(`Pool ${pool.name} does not support Jupiter Lend`);
456
+ }
457
+ return [
458
+ { pubkey: stvPda, isSigner: false, isWritable: true },
459
+ { pubkey: stvBaseAta, isSigner: false, isWritable: true },
460
+ { pubkey: stvJlxAta, isSigner: false, isWritable: true },
461
+ { pubkey: pool.mint, isSigner: false, isWritable: false },
462
+ { pubkey: LENDING_ADMIN, isSigner: false, isWritable: false },
463
+ { pubkey: pool.lending, isSigner: false, isWritable: true },
464
+ { pubkey: pool.fTokenMint, isSigner: false, isWritable: true },
465
+ { pubkey: pool.tokenReservesLiquidity, isSigner: false, isWritable: true },
466
+ { pubkey: pool.supplyPositionOnLiquidity, isSigner: false, isWritable: true },
467
+ { pubkey: pool.rateModel, isSigner: false, isWritable: false },
468
+ { pubkey: pool.vault, isSigner: false, isWritable: true },
469
+ { pubkey: LIQUIDITY_SINGLETON, isSigner: false, isWritable: true },
470
+ { pubkey: LIQUIDITY_PROGRAM_ID, isSigner: false, isWritable: true },
471
+ { pubkey: pool.rewardsRateModel, isSigner: false, isWritable: false },
472
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
473
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
474
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
475
+ { pubkey: JUPITER_LEND_PROGRAM_ID2, isSigner: false, isWritable: false }
476
+ ];
477
+ }
478
+ function buildJupEarnWithdrawAccounts(pool, stvPda, stvJlxAta, stvBaseAta) {
479
+ if (!pool.hasJupiterLend) {
480
+ throw new Error(`Pool ${pool.name} does not support Jupiter Lend`);
481
+ }
482
+ return [
483
+ { pubkey: stvPda, isSigner: false, isWritable: true },
484
+ { pubkey: stvJlxAta, isSigner: false, isWritable: true },
485
+ { pubkey: stvBaseAta, isSigner: false, isWritable: true },
486
+ { pubkey: LENDING_ADMIN, isSigner: false, isWritable: false },
487
+ { pubkey: pool.lending, isSigner: false, isWritable: true },
488
+ { pubkey: pool.mint, isSigner: false, isWritable: false },
489
+ { pubkey: pool.fTokenMint, isSigner: false, isWritable: true },
490
+ { pubkey: pool.tokenReservesLiquidity, isSigner: false, isWritable: true },
491
+ { pubkey: pool.supplyPositionOnLiquidity, isSigner: false, isWritable: true },
492
+ { pubkey: pool.rateModel, isSigner: false, isWritable: false },
493
+ { pubkey: pool.vault, isSigner: false, isWritable: true },
494
+ { pubkey: pool.claimAccount, isSigner: false, isWritable: true },
495
+ { pubkey: LIQUIDITY_SINGLETON, isSigner: false, isWritable: true },
496
+ { pubkey: LIQUIDITY_PROGRAM_ID, isSigner: false, isWritable: true },
497
+ { pubkey: pool.rewardsRateModel, isSigner: false, isWritable: false },
498
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
499
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
500
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
501
+ { pubkey: JUPITER_LEND_PROGRAM_ID2, isSigner: false, isWritable: false }
502
+ ];
503
+ }
504
+ function parseLendingAccount(data) {
505
+ return {
506
+ mint: new PublicKey6(data.slice(8, 40)),
507
+ fTokenMint: new PublicKey6(data.slice(40, 72)),
508
+ lendingId: data.readUInt16LE(72),
509
+ decimals: data[74],
510
+ rewardsRateModel: new PublicKey6(data.slice(75, 107)),
511
+ liquidityExchangePrice: data.readBigUInt64LE(107),
512
+ tokenExchangePrice: data.readBigUInt64LE(115),
513
+ lastUpdateTimestamp: data.readBigUInt64LE(123),
514
+ tokenReservesLiquidity: new PublicKey6(data.slice(131, 163)),
515
+ supplyPositionOnLiquidity: new PublicKey6(data.slice(163, 195)),
516
+ bump: data[195]
517
+ };
518
+ }
519
+ function parseRewardsRateModel(data) {
520
+ return {
521
+ mint: new PublicKey6(data.slice(8, 40)),
522
+ startTvl: data.readBigUInt64LE(40),
523
+ duration: data.readBigUInt64LE(48),
524
+ startTime: data.readBigUInt64LE(56),
525
+ yearlyReward: data.readBigUInt64LE(64),
526
+ nextDuration: data.readBigUInt64LE(72),
527
+ nextRewardAmount: data.readBigUInt64LE(80),
528
+ bump: data[88]
529
+ };
530
+ }
531
+
532
+ // src/jupiter/swap.ts
533
+ import {
534
+ PublicKey as PublicKey7,
535
+ AddressLookupTableAccount
536
+ } from "@solana/web3.js";
537
+ var JUPITER_API_BASE = "https://lite-api.jup.ag/swap/v1";
538
+ var DEFAULT_TIMEOUT_MS = 3e4;
539
+ var MAX_RETRIES = 3;
540
+ var RETRY_DELAY_MS = 1e3;
541
+ function sleep(ms) {
542
+ return new Promise((resolve) => setTimeout(resolve, ms));
543
+ }
544
+ async function fetchWithRetry(url, options = {}, timeoutMs = DEFAULT_TIMEOUT_MS, retries = MAX_RETRIES) {
545
+ let lastError = null;
546
+ for (let attempt = 0; attempt < retries; attempt++) {
547
+ try {
548
+ const controller = new AbortController();
549
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
550
+ const response = await fetch(url, {
551
+ ...options,
552
+ signal: controller.signal
553
+ });
554
+ clearTimeout(timeoutId);
555
+ if (response.ok) {
556
+ return response;
557
+ }
558
+ if (response.status >= 400 && response.status < 500) {
559
+ const errorText = await response.text();
560
+ throw new Error(`Jupiter API error (${response.status}): ${errorText}`);
561
+ }
562
+ lastError = new Error(`Jupiter API returned ${response.status}`);
563
+ } catch (error) {
564
+ if (error instanceof Error) {
565
+ if (error.name === "AbortError") {
566
+ lastError = new Error(`Request timed out after ${timeoutMs}ms`);
567
+ } else {
568
+ lastError = error;
569
+ }
570
+ }
571
+ }
572
+ if (attempt < retries - 1) {
573
+ await sleep(RETRY_DELAY_MS * (attempt + 1));
574
+ }
575
+ }
576
+ throw lastError ?? new Error("Unknown error during fetch");
577
+ }
578
+ async function getJupiterQuote(inputMint, outputMint, amount, slippageBps = 50, maxAccounts = 40) {
579
+ const params = new URLSearchParams({
580
+ inputMint: inputMint.toBase58(),
581
+ outputMint: outputMint.toBase58(),
582
+ amount: amount.toString(),
583
+ slippageBps: slippageBps.toString(),
584
+ maxAccounts: maxAccounts.toString()
585
+ });
586
+ const url = `${JUPITER_API_BASE}/quote?${params.toString()}`;
587
+ const response = await fetchWithRetry(url);
588
+ const data = await response.json();
589
+ if (data.error) {
590
+ throw new Error(`Jupiter quote error: ${data.error}`);
591
+ }
592
+ return data;
593
+ }
594
+ async function getJupiterSwapInstructions(quote, userPubkey) {
595
+ const url = `${JUPITER_API_BASE}/swap-instructions`;
596
+ const body = {
597
+ quoteResponse: quote,
598
+ userPublicKey: userPubkey.toBase58(),
599
+ wrapAndUnwrapSol: true,
600
+ useSharedAccounts: true,
601
+ dynamicComputeUnitLimit: true,
602
+ skipUserAccountsRpcCalls: false
603
+ };
604
+ const response = await fetchWithRetry(url, {
605
+ method: "POST",
606
+ headers: { "Content-Type": "application/json" },
607
+ body: JSON.stringify(body)
608
+ });
609
+ const data = await response.json();
610
+ if (data.error) {
611
+ throw new Error(`Jupiter swap instructions error: ${data.error}`);
612
+ }
613
+ return data;
614
+ }
615
+ function parseSwapRemainingAccounts(swapInstruction) {
616
+ return swapInstruction.accounts.map((acc) => ({
617
+ pubkey: new PublicKey7(acc.pubkey),
618
+ isSigner: acc.isSigner,
619
+ isWritable: acc.isWritable
620
+ }));
621
+ }
622
+ async function fetchAddressLookupTables(connection, addresses) {
623
+ if (addresses.length === 0) {
624
+ return [];
625
+ }
626
+ const pubkeys = addresses.map((addr) => new PublicKey7(addr));
627
+ const accountInfos = await connection.getMultipleAccountsInfo(pubkeys);
628
+ const tables = [];
629
+ for (let i = 0; i < accountInfos.length; i++) {
630
+ const info = accountInfos[i];
631
+ if (info === null) {
632
+ console.warn(`ALT not found: ${addresses[i]}`);
633
+ continue;
634
+ }
635
+ const table = new AddressLookupTableAccount({
636
+ key: pubkeys[i],
637
+ state: AddressLookupTableAccount.deserialize(info.data)
638
+ });
639
+ tables.push(table);
640
+ }
641
+ return tables;
642
+ }
643
+ async function buildSwapData(connection, inputMint, outputMint, amount, userPubkey, slippageBps = 50, maxAccounts = 40) {
644
+ const quote = await getJupiterQuote(
645
+ inputMint,
646
+ outputMint,
647
+ amount,
648
+ slippageBps,
649
+ maxAccounts
650
+ );
651
+ const instructions = await getJupiterSwapInstructions(quote, userPubkey);
652
+ const remainingAccounts = parseSwapRemainingAccounts(instructions.swapInstruction);
653
+ const addressLookupTables = await fetchAddressLookupTables(
654
+ connection,
655
+ instructions.addressLookupTableAddresses
656
+ );
657
+ return {
658
+ quote,
659
+ instructions,
660
+ remainingAccounts,
661
+ addressLookupTables
662
+ };
663
+ }
664
+
665
+ // src/jupiter/price.ts
666
+ import { BN as BN4 } from "@coral-xyz/anchor";
667
+ var DEFAULT_API_KEY = "9edc77aa-0be8-41cf-9264-907603c44150";
668
+ async function fetchJupiterPriceUsd(mint, apiKey = DEFAULT_API_KEY) {
669
+ const url = `https://api.jup.ag/price/v3?ids=${mint}`;
670
+ try {
671
+ const response = await fetch(url, {
672
+ headers: {
673
+ "x-api-key": apiKey
674
+ }
675
+ });
676
+ if (!response.ok) {
677
+ console.warn(`Jupiter Price API error: ${response.status}`);
678
+ return null;
679
+ }
680
+ const data = await response.json();
681
+ const priceData = data[mint];
682
+ if (!priceData?.usdPrice) {
683
+ console.warn(`No price data for ${mint}`);
684
+ return null;
685
+ }
686
+ return priceData.usdPrice;
687
+ } catch (error) {
688
+ console.warn(`Failed to fetch Jupiter price: ${error.message}`);
689
+ return null;
690
+ }
691
+ }
692
+ async function fetchJlpRate(jlpMint, fallbackPrice = 4.6, apiKey = DEFAULT_API_KEY) {
693
+ const priceUsd = await fetchJupiterPriceUsd(jlpMint, apiKey);
694
+ if (priceUsd === null) {
695
+ console.warn(`Using fallback JLP price: $${fallbackPrice}`);
696
+ return new BN4(Math.round(fallbackPrice * 1e8));
697
+ }
698
+ console.log(`JLP price: $${priceUsd.toFixed(4)} -> ${Math.round(priceUsd * 1e8)} (8 decimals)`);
699
+ return new BN4(Math.round(priceUsd * 1e8));
700
+ }
701
+
702
+ // src/instructions/admin.ts
703
+ import { TransactionInstruction } from "@solana/web3.js";
704
+ var INIT_OR_UPDATE_VAULT_DISCRIMINATOR = Buffer.from([
705
+ 91,
706
+ 101,
707
+ 110,
708
+ 100,
709
+ 105,
710
+ 110,
711
+ 103,
712
+ 93
713
+ ]);
714
+ var INITIALIZE_STV_DISCRIMINATOR = Buffer.from([
715
+ 105,
716
+ 110,
717
+ 105,
718
+ 116,
719
+ 95,
720
+ 115,
721
+ 116,
722
+ 118
723
+ ]);
724
+ var UPDATE_STV_DISCRIMINATOR = Buffer.from([
725
+ 117,
726
+ 112,
727
+ 100,
728
+ 95,
729
+ 115,
730
+ 116,
731
+ 118,
732
+ 0
733
+ ]);
734
+ function serializeOptionPubkey(value) {
735
+ if (value === null) {
736
+ return Buffer.from([0]);
737
+ }
738
+ return Buffer.concat([Buffer.from([1]), value.toBuffer()]);
739
+ }
740
+ function serializeOptionU64(value) {
741
+ if (value === null) {
742
+ return Buffer.from([0]);
743
+ }
744
+ const buf = Buffer.alloc(9);
745
+ buf.writeUInt8(1, 0);
746
+ buf.writeBigUInt64LE(BigInt(value.toString()), 1);
747
+ return buf;
748
+ }
749
+ function serializeU16(value) {
750
+ const buf = Buffer.alloc(2);
751
+ buf.writeUInt16LE(value, 0);
752
+ return buf;
753
+ }
754
+ function serializeU64(value) {
755
+ const buf = Buffer.alloc(8);
756
+ buf.writeBigUInt64LE(BigInt(value.toString()), 0);
757
+ return buf;
758
+ }
759
+ function createInitOrUpdateVaultInstruction(params, accounts, programId = JLPD_PROGRAM_ID) {
760
+ const data = Buffer.concat([
761
+ INIT_OR_UPDATE_VAULT_DISCRIMINATOR,
762
+ serializeOptionPubkey(params.jlpMint),
763
+ // baseAssetMints - Option<[Pubkey; 5]>
764
+ params.baseAssetMints ? Buffer.concat([Buffer.from([1]), ...params.baseAssetMints.map((p) => p.toBuffer())]) : Buffer.from([0]),
765
+ // jlxAssetMints - Option<[Pubkey; 5]>
766
+ params.jlxAssetMints ? Buffer.concat([Buffer.from([1]), ...params.jlxAssetMints.map((p) => p.toBuffer())]) : Buffer.from([0]),
767
+ serializeOptionPubkey(params.newAdmin),
768
+ serializeOptionPubkey(params.manager ?? null),
769
+ serializeOptionPubkey(params.feeReceiver ?? null),
770
+ params.flags !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU16(params.flags)]) : Buffer.from([0]),
771
+ params.jlpSlippageBps !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU16(params.jlpSlippageBps)]) : Buffer.from([0]),
772
+ serializeOptionU64(params.oracleStalenessThreshold)
773
+ ]);
774
+ const keys = [
775
+ { pubkey: accounts.admin, isSigner: true, isWritable: true },
776
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: true },
777
+ { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }
778
+ ];
779
+ return new TransactionInstruction({ keys, programId, data });
780
+ }
781
+ function createInitializeStvInstruction(params, accounts, programId = JLPD_PROGRAM_ID) {
782
+ const data = Buffer.concat([
783
+ INITIALIZE_STV_DISCRIMINATOR,
784
+ serializeU16(params.mgmtFeeBps),
785
+ serializeU16(params.perfFeeBps),
786
+ serializeU64(params.maxDeposit),
787
+ serializeU64(params.minDeposit)
788
+ ]);
789
+ const keys = [
790
+ { pubkey: accounts.admin, isSigner: true, isWritable: true },
791
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
792
+ { pubkey: accounts.stv, isSigner: false, isWritable: true },
793
+ { pubkey: accounts.baseMint, isSigner: false, isWritable: false },
794
+ { pubkey: accounts.jlMint, isSigner: false, isWritable: false },
795
+ { pubkey: accounts.jvMint, isSigner: true, isWritable: true },
796
+ { pubkey: accounts.stvJlxAta, isSigner: false, isWritable: true },
797
+ { pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
798
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
799
+ { pubkey: accounts.associatedTokenProgram, isSigner: false, isWritable: false },
800
+ { pubkey: accounts.rent, isSigner: false, isWritable: false }
801
+ ];
802
+ return new TransactionInstruction({ keys, programId, data });
803
+ }
804
+ function createUpdateStvInstruction(params, accounts, programId = JLPD_PROGRAM_ID) {
805
+ const data = Buffer.concat([
806
+ UPDATE_STV_DISCRIMINATOR,
807
+ params.mgmtFeeBps !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU16(params.mgmtFeeBps)]) : Buffer.from([0]),
808
+ params.perfFeeBps !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU16(params.perfFeeBps)]) : Buffer.from([0]),
809
+ params.flags !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU16(params.flags)]) : Buffer.from([0]),
810
+ params.maxDeposit !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU64(params.maxDeposit)]) : Buffer.from([0]),
811
+ params.minDeposit !== void 0 ? Buffer.concat([Buffer.from([1]), serializeU64(params.minDeposit)]) : Buffer.from([0])
812
+ ]);
813
+ const keys = [
814
+ { pubkey: accounts.admin, isSigner: true, isWritable: false },
815
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
816
+ { pubkey: accounts.stv, isSigner: false, isWritable: true }
817
+ ];
818
+ return new TransactionInstruction({ keys, programId, data });
819
+ }
820
+
821
+ // src/instructions/user.ts
822
+ import { TransactionInstruction as TransactionInstruction2 } from "@solana/web3.js";
823
+ var DEPOSIT_DISCRIMINATOR = Buffer.from([
824
+ 248,
825
+ 198,
826
+ 158,
827
+ 145,
828
+ 225,
829
+ 117,
830
+ 135,
831
+ 200
832
+ ]);
833
+ var WITHDRAW_DISCRIMINATOR = Buffer.from([
834
+ 183,
835
+ 18,
836
+ 70,
837
+ 156,
838
+ 148,
839
+ 109,
840
+ 161,
841
+ 34
842
+ ]);
843
+ function serializeU642(value) {
844
+ const buf = Buffer.alloc(8);
845
+ buf.writeBigUInt64LE(BigInt(value.toString()), 0);
846
+ return buf;
847
+ }
848
+ function createDepositInstruction(amount, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
849
+ const data = Buffer.concat([DEPOSIT_DISCRIMINATOR, serializeU642(amount)]);
850
+ const keys = [
851
+ { pubkey: accounts.user, isSigner: true, isWritable: true },
852
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
853
+ { pubkey: accounts.stv, isSigner: false, isWritable: true },
854
+ { pubkey: accounts.baseMint, isSigner: false, isWritable: false },
855
+ { pubkey: accounts.jlMint, isSigner: false, isWritable: false },
856
+ { pubkey: accounts.jvMint, isSigner: false, isWritable: true },
857
+ { pubkey: accounts.userBaseAta, isSigner: false, isWritable: true },
858
+ { pubkey: accounts.userJvxAta, isSigner: false, isWritable: true },
859
+ { pubkey: accounts.stvBaseAta, isSigner: false, isWritable: true },
860
+ { pubkey: accounts.stvJlxAta, isSigner: false, isWritable: false },
861
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
862
+ ...remainingAccounts
863
+ ];
864
+ return new TransactionInstruction2({ keys, programId, data });
865
+ }
866
+ function createWithdrawInstruction(sharesToBurn, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
867
+ const data = Buffer.concat([WITHDRAW_DISCRIMINATOR, serializeU642(sharesToBurn)]);
868
+ const keys = [
869
+ { pubkey: accounts.user, isSigner: true, isWritable: true },
870
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
871
+ { pubkey: accounts.stv, isSigner: false, isWritable: true },
872
+ { pubkey: accounts.baseMint, isSigner: false, isWritable: false },
873
+ { pubkey: accounts.jlMint, isSigner: false, isWritable: false },
874
+ { pubkey: accounts.jvMint, isSigner: false, isWritable: true },
875
+ { pubkey: accounts.userBaseAta, isSigner: false, isWritable: true },
876
+ { pubkey: accounts.userJvxAta, isSigner: false, isWritable: true },
877
+ { pubkey: accounts.stvBaseAta, isSigner: false, isWritable: true },
878
+ { pubkey: accounts.stvJlxAta, isSigner: false, isWritable: false },
879
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
880
+ ...remainingAccounts
881
+ ];
882
+ return new TransactionInstruction2({ keys, programId, data });
883
+ }
884
+
885
+ // src/instructions/manager.ts
886
+ import { TransactionInstruction as TransactionInstruction3 } from "@solana/web3.js";
887
+ var JUP_EARN_DISCRIMINATOR = Buffer.from([
888
+ 161,
889
+ 178,
890
+ 195,
891
+ 212,
892
+ 229,
893
+ 246,
894
+ 7,
895
+ 24
896
+ ]);
897
+ var MOVE_STV_DISCRIMINATOR = Buffer.from([
898
+ 41,
899
+ 58,
900
+ 75,
901
+ 92,
902
+ 109,
903
+ 126,
904
+ 143,
905
+ 144
906
+ ]);
907
+ var SWAP_JLX_JLX_DISCRIMINATOR = Buffer.from([
908
+ 65,
909
+ 82,
910
+ 99,
911
+ 116,
912
+ 133,
913
+ 150,
914
+ 167,
915
+ 184
916
+ ]);
917
+ var SWAP_JLX_JLP_DISCRIMINATOR = Buffer.from([
918
+ 201,
919
+ 218,
920
+ 235,
921
+ 252,
922
+ 13,
923
+ 30,
924
+ 47,
925
+ 48
926
+ ]);
927
+ var SETTLE_YIELD_DISCRIMINATOR = Buffer.from([
928
+ 81,
929
+ 98,
930
+ 115,
931
+ 132,
932
+ 149,
933
+ 166,
934
+ 183,
935
+ 200
936
+ ]);
937
+ function serializeU8(value) {
938
+ const buf = Buffer.alloc(1);
939
+ buf.writeUInt8(value, 0);
940
+ return buf;
941
+ }
942
+ function serializeU643(value) {
943
+ const buf = Buffer.alloc(8);
944
+ buf.writeBigUInt64LE(BigInt(value.toString()), 0);
945
+ return buf;
946
+ }
947
+ function createJupEarnInstruction(params, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
948
+ const directionByte = params.direction === "Deposit" ? 0 : 1;
949
+ const data = Buffer.concat([
950
+ JUP_EARN_DISCRIMINATOR,
951
+ serializeU8(directionByte),
952
+ serializeU643(params.amount)
953
+ ]);
954
+ const keys = [
955
+ { pubkey: accounts.manager, isSigner: true, isWritable: false },
956
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
957
+ { pubkey: accounts.stv, isSigner: false, isWritable: false },
958
+ { pubkey: accounts.baseMint, isSigner: false, isWritable: false },
959
+ { pubkey: accounts.jlMint, isSigner: false, isWritable: true },
960
+ { pubkey: accounts.stvBaseAta, isSigner: false, isWritable: true },
961
+ { pubkey: accounts.stvJlxAta, isSigner: false, isWritable: true },
962
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
963
+ ...remainingAccounts
964
+ ];
965
+ return new TransactionInstruction3({ keys, programId, data });
966
+ }
967
+ function createMoveJlxInstruction(params, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
968
+ const directionByte = params.direction === "ToVault" ? 0 : 1;
969
+ const data = Buffer.concat([
970
+ MOVE_STV_DISCRIMINATOR,
971
+ serializeU643(params.amountJlx),
972
+ serializeU8(directionByte)
973
+ ]);
974
+ const keys = [
975
+ { pubkey: accounts.manager, isSigner: true, isWritable: false },
976
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
977
+ { pubkey: accounts.stv, isSigner: false, isWritable: true },
978
+ { pubkey: accounts.baseMint, isSigner: false, isWritable: false },
979
+ { pubkey: accounts.jlMint, isSigner: false, isWritable: false },
980
+ { pubkey: accounts.stvJlxAta, isSigner: false, isWritable: true },
981
+ { pubkey: accounts.vaultStagingAta, isSigner: false, isWritable: true },
982
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
983
+ ...remainingAccounts
984
+ ];
985
+ return new TransactionInstruction3({ keys, programId, data });
986
+ }
987
+ function createSwapJlxJlxInstruction(params, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
988
+ const lenBuf = Buffer.alloc(4);
989
+ lenBuf.writeUInt32LE(params.jupiterData.length, 0);
990
+ const data = Buffer.concat([
991
+ SWAP_JLX_JLX_DISCRIMINATOR,
992
+ serializeU8(params.fromIndex),
993
+ serializeU8(params.toIndex),
994
+ serializeU643(params.amountIn),
995
+ serializeU643(params.minOut),
996
+ lenBuf,
997
+ params.jupiterData
998
+ ]);
999
+ const keys = [
1000
+ { pubkey: accounts.manager, isSigner: true, isWritable: false },
1001
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
1002
+ { pubkey: accounts.fromJlxMint, isSigner: false, isWritable: false },
1003
+ { pubkey: accounts.toJlxMint, isSigner: false, isWritable: false },
1004
+ { pubkey: accounts.fromJlxAta, isSigner: false, isWritable: true },
1005
+ { pubkey: accounts.toJlxAta, isSigner: false, isWritable: true },
1006
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
1007
+ { pubkey: accounts.jupiterProgram, isSigner: false, isWritable: false },
1008
+ ...remainingAccounts
1009
+ ];
1010
+ return new TransactionInstruction3({ keys, programId, data });
1011
+ }
1012
+ function createSwapJlxJlpInstruction(params, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
1013
+ const directionByte = params.direction === "JlxToJlp" ? 0 : 1;
1014
+ const lenBuf = Buffer.alloc(4);
1015
+ lenBuf.writeUInt32LE(params.jupiterData.length, 0);
1016
+ const data = Buffer.concat([
1017
+ SWAP_JLX_JLP_DISCRIMINATOR,
1018
+ serializeU8(params.stvIndex),
1019
+ serializeU8(directionByte),
1020
+ serializeU643(params.amountIn),
1021
+ serializeU643(params.expectedAmountOut),
1022
+ lenBuf,
1023
+ params.jupiterData
1024
+ ]);
1025
+ const keys = [
1026
+ { pubkey: accounts.manager, isSigner: true, isWritable: false },
1027
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
1028
+ { pubkey: accounts.vaultJlxAta, isSigner: false, isWritable: true },
1029
+ { pubkey: accounts.vaultJlpAta, isSigner: false, isWritable: true },
1030
+ { pubkey: accounts.jlpMint, isSigner: false, isWritable: false },
1031
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
1032
+ { pubkey: accounts.jupiterProgram, isSigner: false, isWritable: false },
1033
+ ...remainingAccounts
1034
+ ];
1035
+ return new TransactionInstruction3({ keys, programId, data });
1036
+ }
1037
+ function createSettleYieldInstruction(params, accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
1038
+ const data = Buffer.concat([
1039
+ SETTLE_YIELD_DISCRIMINATOR,
1040
+ serializeU643(params.jlpRate)
1041
+ ]);
1042
+ const keys = [
1043
+ { pubkey: accounts.manager, isSigner: true, isWritable: false },
1044
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: true },
1045
+ { pubkey: accounts.vaultJlpAta, isSigner: false, isWritable: false },
1046
+ { pubkey: accounts.jlpMint, isSigner: false, isWritable: false },
1047
+ { pubkey: accounts.stvBtc, isSigner: false, isWritable: true },
1048
+ { pubkey: accounts.stvEth, isSigner: false, isWritable: true },
1049
+ { pubkey: accounts.stvSol, isSigner: false, isWritable: true },
1050
+ { pubkey: accounts.stvUsdc, isSigner: false, isWritable: true },
1051
+ { pubkey: accounts.stvJupusd, isSigner: false, isWritable: true },
1052
+ { pubkey: accounts.stagingBtc, isSigner: false, isWritable: false },
1053
+ { pubkey: accounts.stagingEth, isSigner: false, isWritable: false },
1054
+ { pubkey: accounts.stagingSol, isSigner: false, isWritable: false },
1055
+ { pubkey: accounts.stagingUsdc, isSigner: false, isWritable: false },
1056
+ { pubkey: accounts.stagingJupusd, isSigner: false, isWritable: false },
1057
+ { pubkey: accounts.oracleBtc, isSigner: false, isWritable: false },
1058
+ { pubkey: accounts.oracleEth, isSigner: false, isWritable: false },
1059
+ { pubkey: accounts.oracleSol, isSigner: false, isWritable: false },
1060
+ { pubkey: accounts.oracleJlp, isSigner: false, isWritable: false },
1061
+ ...remainingAccounts
1062
+ ];
1063
+ return new TransactionInstruction3({ keys, programId, data });
1064
+ }
1065
+
1066
+ // src/instructions/fees.ts
1067
+ import { TransactionInstruction as TransactionInstruction4 } from "@solana/web3.js";
1068
+ var CLAIM_FEES_DISCRIMINATOR = Buffer.from([
1069
+ 209,
1070
+ 226,
1071
+ 243,
1072
+ 4,
1073
+ 21,
1074
+ 38,
1075
+ 55,
1076
+ 72
1077
+ ]);
1078
+ function createClaimFeesInstruction(accounts, remainingAccounts = [], programId = JLPD_PROGRAM_ID) {
1079
+ const data = CLAIM_FEES_DISCRIMINATOR;
1080
+ const keys = [
1081
+ { pubkey: accounts.manager, isSigner: true, isWritable: false },
1082
+ { pubkey: accounts.jlpVault, isSigner: false, isWritable: false },
1083
+ { pubkey: accounts.stv, isSigner: false, isWritable: true },
1084
+ { pubkey: accounts.baseMint, isSigner: false, isWritable: false },
1085
+ { pubkey: accounts.jlMint, isSigner: false, isWritable: false },
1086
+ { pubkey: accounts.jvMint, isSigner: false, isWritable: false },
1087
+ { pubkey: accounts.stvBaseAta, isSigner: false, isWritable: false },
1088
+ { pubkey: accounts.stvJlxAta, isSigner: false, isWritable: true },
1089
+ { pubkey: accounts.feeReceiverJlxAta, isSigner: false, isWritable: true },
1090
+ { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
1091
+ ...remainingAccounts
1092
+ ];
1093
+ return new TransactionInstruction4({ keys, programId, data });
1094
+ }
1095
+
1096
+ // src/client.ts
1097
+ var JlpdClientError = class extends Error {
1098
+ constructor(message) {
1099
+ super(message);
1100
+ this.name = "JlpdClientError";
1101
+ }
1102
+ };
1103
+ var JlpdClient = class _JlpdClient {
1104
+ constructor(connection, programId = JLPD_PROGRAM_ID) {
1105
+ // Cache for PoolContext instances (avoids re-deriving PDAs/ATAs)
1106
+ this.poolContextCache = /* @__PURE__ */ new Map();
1107
+ this.connection = connection;
1108
+ this.programId = programId;
1109
+ const [vaultPda, vaultBump] = deriveVaultPda(programId);
1110
+ this.vaultPda = vaultPda;
1111
+ this.vaultBump = vaultBump;
1112
+ }
1113
+ static mainnet(connection) {
1114
+ return new _JlpdClient(connection, JLPD_PROGRAM_ID);
1115
+ }
1116
+ static devnet(connection) {
1117
+ const devnetProgramId = new PublicKey12(
1118
+ "AcVcAihjB9Z3Lg3ZiboWxni2sTzXUrrsF3unGX4ntn6p"
1119
+ );
1120
+ return new _JlpdClient(connection, devnetProgramId);
1121
+ }
1122
+ // Fetch vault account
1123
+ async fetchVault() {
1124
+ const accountInfo = await this.connection.getAccountInfo(this.vaultPda);
1125
+ if (!accountInfo) return null;
1126
+ return parseVault(accountInfo.data);
1127
+ }
1128
+ // Fetch STV by base mint
1129
+ async fetchStv(baseMint) {
1130
+ const [stvPda] = deriveStvPda(baseMint, this.programId);
1131
+ const accountInfo = await this.connection.getAccountInfo(stvPda);
1132
+ if (!accountInfo) return null;
1133
+ return parseStv(accountInfo.data);
1134
+ }
1135
+ // Fetch exchange rate for a pool
1136
+ async fetchExchangeRate(poolName) {
1137
+ const pool = getPoolByName(poolName);
1138
+ if (!pool) throw new JlpdClientError(`Unknown pool: ${poolName}`);
1139
+ if (!pool.hasJupiterLend) {
1140
+ return {
1141
+ rate: 1,
1142
+ rawRate: BigInt(EXCHANGE_RATE_PRECISION),
1143
+ storedRate: 1,
1144
+ staleness: 0,
1145
+ isFresh: true
1146
+ };
1147
+ }
1148
+ const accounts = await this.connection.getMultipleAccountsInfo([
1149
+ pool.lending,
1150
+ pool.rewardsRateModel,
1151
+ pool.fTokenMint
1152
+ ]);
1153
+ const [lendingInfo, rewardsInfo, mintInfo] = accounts;
1154
+ if (!lendingInfo || !rewardsInfo || !mintInfo) {
1155
+ throw new JlpdClientError("Failed to fetch Jupiter Lend accounts");
1156
+ }
1157
+ const lendingData = parseLendingAccount(lendingInfo.data);
1158
+ const rewardsData = parseRewardsRateModel(rewardsInfo.data);
1159
+ const slot = await this.connection.getSlot();
1160
+ const timestamp = await this.connection.getBlockTime(slot);
1161
+ if (!timestamp) throw new JlpdClientError("Failed to get block time");
1162
+ const supply = mintInfo.data.readBigUInt64LE(36);
1163
+ const rawRate = calculateExchangeRate(
1164
+ lendingData.tokenExchangePrice,
1165
+ rewardsData.yearlyReward,
1166
+ BigInt(timestamp),
1167
+ lendingData.lastUpdateTimestamp,
1168
+ supply
1169
+ );
1170
+ const rate = Number(rawRate) / EXCHANGE_RATE_PRECISION;
1171
+ const storedRate = Number(lendingData.tokenExchangePrice) / EXCHANGE_RATE_PRECISION;
1172
+ const staleness = timestamp - Number(lendingData.lastUpdateTimestamp);
1173
+ return {
1174
+ rate,
1175
+ rawRate,
1176
+ storedRate,
1177
+ staleness,
1178
+ isFresh: staleness < 300
1179
+ };
1180
+ }
1181
+ // Get pool context for pool-specific operations (cached)
1182
+ pool(poolNameOrMint) {
1183
+ const key = typeof poolNameOrMint === "string" ? poolNameOrMint : poolNameOrMint.toBase58();
1184
+ let ctx = this.poolContextCache.get(key);
1185
+ if (!ctx) {
1186
+ const pool = typeof poolNameOrMint === "string" ? getPoolByName(poolNameOrMint) : getPoolByMint(poolNameOrMint);
1187
+ if (!pool) throw new JlpdClientError(`Unknown pool: ${key}`);
1188
+ ctx = new PoolContext(this, pool);
1189
+ this.poolContextCache.set(key, ctx);
1190
+ if (typeof poolNameOrMint === "string") {
1191
+ this.poolContextCache.set(pool.mint.toBase58(), ctx);
1192
+ } else {
1193
+ this.poolContextCache.set(pool.name, ctx);
1194
+ }
1195
+ }
1196
+ return ctx;
1197
+ }
1198
+ // Get swap context for swap operations
1199
+ swap() {
1200
+ return new SwapContext(this);
1201
+ }
1202
+ // Get admin context for admin operations
1203
+ admin() {
1204
+ return new AdminContext(this);
1205
+ }
1206
+ // Build a versioned transaction
1207
+ async buildTransaction(payer, ixs, alts = []) {
1208
+ const { blockhash } = await this.connection.getLatestBlockhash("confirmed");
1209
+ const message = new TransactionMessage({
1210
+ payerKey: payer,
1211
+ recentBlockhash: blockhash,
1212
+ instructions: ixs
1213
+ }).compileToV0Message(alts);
1214
+ return new VersionedTransaction(message);
1215
+ }
1216
+ };
1217
+ var PoolContext = class {
1218
+ constructor(client, pool) {
1219
+ this.client = client;
1220
+ this.pool = pool;
1221
+ const [pda, bump] = deriveStvPda(pool.mint, client.programId);
1222
+ this.stvPda = pda;
1223
+ this.stvBump = bump;
1224
+ const vaultAtas = deriveVaultAtas(pool.fTokenMint, MINTS.JLP, client.vaultPda);
1225
+ this.vaultStagingAta = vaultAtas.stagingAta;
1226
+ this.vaultJlpAta = vaultAtas.jlpAta;
1227
+ const stvAtas = deriveStvAtas(pool.mint, pool.fTokenMint, this.stvPda);
1228
+ this.stvBaseAta = stvAtas.baseAta;
1229
+ this.stvJlxAta = stvAtas.jlxAta;
1230
+ }
1231
+ // Deposit base asset and receive jvX shares
1232
+ async deposit(params) {
1233
+ if (params.amount.isZero() || params.amount.isNeg()) {
1234
+ throw new JlpdClientError("Deposit amount must be positive");
1235
+ }
1236
+ const [stv, { blockhash }] = await Promise.all([
1237
+ this.client.fetchStv(this.pool.mint),
1238
+ this.client.connection.getLatestBlockhash("confirmed")
1239
+ ]);
1240
+ if (!stv) throw new JlpdClientError("STV not found");
1241
+ const userAtas = deriveUserAtas(this.pool.mint, stv.jvMint, params.user);
1242
+ const erAccounts = this.pool.hasJupiterLend ? buildExchangeRateAccounts(this.pool) : null;
1243
+ const ix = createDepositInstruction(
1244
+ params.amount,
1245
+ {
1246
+ user: params.user,
1247
+ jlpVault: this.client.vaultPda,
1248
+ stv: this.stvPda,
1249
+ baseMint: this.pool.mint,
1250
+ jlMint: this.pool.fTokenMint,
1251
+ jvMint: stv.jvMint,
1252
+ userBaseAta: userAtas.baseAta,
1253
+ userJvxAta: userAtas.jvxAta,
1254
+ stvBaseAta: this.stvBaseAta,
1255
+ stvJlxAta: this.stvJlxAta,
1256
+ tokenProgram: TOKEN_PROGRAM_ID2
1257
+ },
1258
+ erAccounts ? [
1259
+ { pubkey: erAccounts.lending, isSigner: false, isWritable: false },
1260
+ { pubkey: erAccounts.rewardsRateModel, isSigner: false, isWritable: false }
1261
+ ] : [],
1262
+ this.client.programId
1263
+ );
1264
+ const message = new TransactionMessage({
1265
+ payerKey: params.user,
1266
+ recentBlockhash: blockhash,
1267
+ instructions: [ix]
1268
+ }).compileToV0Message();
1269
+ return new VersionedTransaction(message);
1270
+ }
1271
+ // Burn jvX shares and withdraw base asset
1272
+ async withdraw(params) {
1273
+ if (params.shares.isZero() || params.shares.isNeg()) {
1274
+ throw new JlpdClientError("Withdraw shares must be positive");
1275
+ }
1276
+ const [stv, { blockhash }] = await Promise.all([
1277
+ this.client.fetchStv(this.pool.mint),
1278
+ this.client.connection.getLatestBlockhash("confirmed")
1279
+ ]);
1280
+ if (!stv) throw new JlpdClientError("STV not found");
1281
+ const userAtas = deriveUserAtas(this.pool.mint, stv.jvMint, params.user);
1282
+ const erAccounts = this.pool.hasJupiterLend ? buildExchangeRateAccounts(this.pool) : null;
1283
+ const ix = createWithdrawInstruction(
1284
+ params.shares,
1285
+ {
1286
+ user: params.user,
1287
+ jlpVault: this.client.vaultPda,
1288
+ stv: this.stvPda,
1289
+ baseMint: this.pool.mint,
1290
+ jlMint: this.pool.fTokenMint,
1291
+ jvMint: stv.jvMint,
1292
+ userBaseAta: userAtas.baseAta,
1293
+ userJvxAta: userAtas.jvxAta,
1294
+ stvBaseAta: this.stvBaseAta,
1295
+ stvJlxAta: this.stvJlxAta,
1296
+ tokenProgram: TOKEN_PROGRAM_ID2
1297
+ },
1298
+ erAccounts ? [
1299
+ { pubkey: erAccounts.lending, isSigner: false, isWritable: false },
1300
+ { pubkey: erAccounts.rewardsRateModel, isSigner: false, isWritable: false }
1301
+ ] : [],
1302
+ this.client.programId
1303
+ );
1304
+ const message = new TransactionMessage({
1305
+ payerKey: params.user,
1306
+ recentBlockhash: blockhash,
1307
+ instructions: [ix]
1308
+ }).compileToV0Message();
1309
+ return new VersionedTransaction(message);
1310
+ }
1311
+ // Jupiter Earn deposit/withdraw
1312
+ async jupEarn(params) {
1313
+ if (!this.pool.hasJupiterLend) {
1314
+ throw new JlpdClientError(`Pool ${this.pool.name} does not support Jupiter Earn`);
1315
+ }
1316
+ const remainingAccounts = params.direction === "Deposit" ? buildJupEarnDepositAccounts(this.pool, this.stvPda, this.stvBaseAta, this.stvJlxAta) : buildJupEarnWithdrawAccounts(this.pool, this.stvPda, this.stvJlxAta, this.stvBaseAta);
1317
+ const ix = createJupEarnInstruction(
1318
+ { direction: params.direction, amount: params.amount },
1319
+ {
1320
+ manager: params.manager,
1321
+ jlpVault: this.client.vaultPda,
1322
+ stv: this.stvPda,
1323
+ baseMint: this.pool.mint,
1324
+ jlMint: this.pool.fTokenMint,
1325
+ stvBaseAta: this.stvBaseAta,
1326
+ stvJlxAta: this.stvJlxAta,
1327
+ tokenProgram: TOKEN_PROGRAM_ID2
1328
+ },
1329
+ remainingAccounts,
1330
+ this.client.programId
1331
+ );
1332
+ return this.client.buildTransaction(params.manager, [ix]);
1333
+ }
1334
+ // Move jlX between STV and vault
1335
+ async moveJlx(params) {
1336
+ const erAccounts = this.pool.hasJupiterLend ? buildExchangeRateAccounts(this.pool) : null;
1337
+ const ix = createMoveJlxInstruction(
1338
+ { amountJlx: params.jlxAmount, direction: params.direction },
1339
+ {
1340
+ manager: params.manager,
1341
+ jlpVault: this.client.vaultPda,
1342
+ stv: this.stvPda,
1343
+ baseMint: this.pool.mint,
1344
+ jlMint: this.pool.fTokenMint,
1345
+ stvJlxAta: this.stvJlxAta,
1346
+ vaultStagingAta: this.vaultStagingAta,
1347
+ tokenProgram: TOKEN_PROGRAM_ID2
1348
+ },
1349
+ erAccounts ? [
1350
+ { pubkey: erAccounts.lending, isSigner: false, isWritable: false },
1351
+ { pubkey: erAccounts.rewardsRateModel, isSigner: false, isWritable: false }
1352
+ ] : [],
1353
+ this.client.programId
1354
+ );
1355
+ return this.client.buildTransaction(params.manager, [ix]);
1356
+ }
1357
+ // Claim fees
1358
+ async claimFees(params) {
1359
+ const [vault, stv] = await Promise.all([
1360
+ this.client.fetchVault(),
1361
+ this.client.fetchStv(this.pool.mint)
1362
+ ]);
1363
+ if (!vault) throw new JlpdClientError("Vault not found");
1364
+ if (!stv) throw new JlpdClientError("STV not found");
1365
+ const feeReceiverJlxAta = getAssociatedTokenAddressSync2(
1366
+ this.pool.fTokenMint,
1367
+ vault.feeReceiver,
1368
+ true
1369
+ );
1370
+ const erAccounts = this.pool.hasJupiterLend ? buildExchangeRateAccounts(this.pool) : null;
1371
+ const ix = createClaimFeesInstruction(
1372
+ {
1373
+ manager: params.manager,
1374
+ jlpVault: this.client.vaultPda,
1375
+ stv: this.stvPda,
1376
+ baseMint: this.pool.mint,
1377
+ jlMint: this.pool.fTokenMint,
1378
+ jvMint: stv.jvMint,
1379
+ stvBaseAta: this.stvBaseAta,
1380
+ stvJlxAta: this.stvJlxAta,
1381
+ feeReceiverJlxAta,
1382
+ tokenProgram: TOKEN_PROGRAM_ID2
1383
+ },
1384
+ erAccounts ? [
1385
+ { pubkey: erAccounts.lending, isSigner: false, isWritable: false },
1386
+ { pubkey: erAccounts.rewardsRateModel, isSigner: false, isWritable: false }
1387
+ ] : [],
1388
+ this.client.programId
1389
+ );
1390
+ return this.client.buildTransaction(params.manager, [ix]);
1391
+ }
1392
+ // Update STV parameters (admin only)
1393
+ async updateStv(params) {
1394
+ const ix = createUpdateStvInstruction(
1395
+ {
1396
+ mgmtFeeBps: params.mgmtFeeBps,
1397
+ perfFeeBps: params.perfFeeBps,
1398
+ flags: params.flags,
1399
+ maxDeposit: params.maxDeposit,
1400
+ minDeposit: params.minDeposit
1401
+ },
1402
+ {
1403
+ admin: params.admin,
1404
+ jlpVault: this.client.vaultPda,
1405
+ stv: this.stvPda
1406
+ },
1407
+ this.client.programId
1408
+ );
1409
+ return this.client.buildTransaction(params.admin, [ix]);
1410
+ }
1411
+ };
1412
+ var SwapContext = class {
1413
+ constructor(client) {
1414
+ this.client = client;
1415
+ }
1416
+ // Get a quote for jlX <-> JLP swap
1417
+ async quoteJlxJlp(params) {
1418
+ const poolConfig = getPoolByName(params.pool);
1419
+ if (!poolConfig) throw new JlpdClientError(`Unknown pool: ${params.pool}`);
1420
+ const inputMint = params.direction === "JlxToJlp" ? poolConfig.fTokenMint : MINTS.JLP;
1421
+ const outputMint = params.direction === "JlxToJlp" ? MINTS.JLP : poolConfig.fTokenMint;
1422
+ const quote = await getJupiterQuote(
1423
+ inputMint,
1424
+ outputMint,
1425
+ BigInt(params.amountIn.toString()),
1426
+ params.slippageBps ?? 30
1427
+ );
1428
+ const swapIxs = await getJupiterSwapInstructions(quote, this.client.vaultPda);
1429
+ const remainingAccounts = parseSwapRemainingAccounts(swapIxs.swapInstruction);
1430
+ const alts = await fetchAddressLookupTables(
1431
+ this.client.connection,
1432
+ swapIxs.addressLookupTableAddresses
1433
+ );
1434
+ return {
1435
+ inputMint,
1436
+ outputMint,
1437
+ inAmount: new BN5(quote.inAmount),
1438
+ outAmount: new BN5(quote.outAmount),
1439
+ minOutAmount: new BN5(quote.otherAmountThreshold),
1440
+ priceImpactPct: parseFloat(quote.priceImpactPct),
1441
+ route: quote.routePlan.map((r) => r.swapInfo.label || "unknown"),
1442
+ jupiterData: Buffer.from(swapIxs.swapInstruction.data, "base64"),
1443
+ remainingAccounts,
1444
+ addressLookupTables: alts,
1445
+ computeUnitLimit: swapIxs.computeUnitLimit ?? 6e5
1446
+ };
1447
+ }
1448
+ // Build jlX <-> JLP swap transaction
1449
+ async swapJlxJlp(params) {
1450
+ const poolConfig = getPoolByName(params.pool);
1451
+ if (!poolConfig) throw new JlpdClientError(`Unknown pool: ${params.pool}`);
1452
+ const poolCtx = this.client.pool(params.pool);
1453
+ const computeIx = ComputeBudgetProgram.setComputeUnitLimit({
1454
+ units: params.quote.computeUnitLimit
1455
+ });
1456
+ const jupiterProgram = params.quote.remainingAccounts[0]?.pubkey ?? PublicKey12.default;
1457
+ const swapIx = createSwapJlxJlpInstruction(
1458
+ {
1459
+ stvIndex: poolConfig.stvIndex,
1460
+ direction: params.direction,
1461
+ amountIn: params.amountIn,
1462
+ expectedAmountOut: params.expectedOut,
1463
+ jupiterData: params.quote.jupiterData
1464
+ },
1465
+ {
1466
+ manager: params.manager,
1467
+ jlpVault: this.client.vaultPda,
1468
+ vaultJlxAta: poolCtx.vaultStagingAta,
1469
+ vaultJlpAta: poolCtx.vaultJlpAta,
1470
+ jlpMint: MINTS.JLP,
1471
+ tokenProgram: TOKEN_PROGRAM_ID2,
1472
+ jupiterProgram
1473
+ },
1474
+ params.quote.remainingAccounts,
1475
+ this.client.programId
1476
+ );
1477
+ const { blockhash } = await this.client.connection.getLatestBlockhash("confirmed");
1478
+ const message = new TransactionMessage({
1479
+ payerKey: params.manager,
1480
+ recentBlockhash: blockhash,
1481
+ instructions: [computeIx, swapIx]
1482
+ }).compileToV0Message(params.quote.addressLookupTables);
1483
+ return new VersionedTransaction(message);
1484
+ }
1485
+ // Get a quote for jlX <-> jlX swap
1486
+ async quoteJlxJlx(params) {
1487
+ const fromPoolConfig = getPoolByName(params.fromPool);
1488
+ const toPoolConfig = getPoolByName(params.toPool);
1489
+ if (!fromPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.fromPool}`);
1490
+ if (!toPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.toPool}`);
1491
+ const inputMint = fromPoolConfig.fTokenMint;
1492
+ const outputMint = toPoolConfig.fTokenMint;
1493
+ const quote = await getJupiterQuote(
1494
+ inputMint,
1495
+ outputMint,
1496
+ BigInt(params.amountIn.toString()),
1497
+ params.slippageBps ?? 30
1498
+ );
1499
+ const swapIxs = await getJupiterSwapInstructions(quote, this.client.vaultPda);
1500
+ const remainingAccounts = parseSwapRemainingAccounts(swapIxs.swapInstruction);
1501
+ const alts = await fetchAddressLookupTables(
1502
+ this.client.connection,
1503
+ swapIxs.addressLookupTableAddresses
1504
+ );
1505
+ return {
1506
+ inputMint,
1507
+ outputMint,
1508
+ inAmount: new BN5(quote.inAmount),
1509
+ outAmount: new BN5(quote.outAmount),
1510
+ minOutAmount: new BN5(quote.otherAmountThreshold),
1511
+ priceImpactPct: parseFloat(quote.priceImpactPct),
1512
+ route: quote.routePlan.map((r) => r.swapInfo.label || "unknown"),
1513
+ jupiterData: Buffer.from(swapIxs.swapInstruction.data, "base64"),
1514
+ remainingAccounts,
1515
+ addressLookupTables: alts,
1516
+ computeUnitLimit: swapIxs.computeUnitLimit ?? 6e5
1517
+ };
1518
+ }
1519
+ // Build jlX <-> jlX swap transaction
1520
+ async swapJlxJlx(params) {
1521
+ const fromPoolConfig = getPoolByName(params.fromPool);
1522
+ const toPoolConfig = getPoolByName(params.toPool);
1523
+ if (!fromPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.fromPool}`);
1524
+ if (!toPoolConfig) throw new JlpdClientError(`Unknown pool: ${params.toPool}`);
1525
+ const fromPoolCtx = this.client.pool(params.fromPool);
1526
+ const toPoolCtx = this.client.pool(params.toPool);
1527
+ const computeIx = ComputeBudgetProgram.setComputeUnitLimit({
1528
+ units: params.quote.computeUnitLimit
1529
+ });
1530
+ const jupiterProgram = params.quote.remainingAccounts[0]?.pubkey ?? PublicKey12.default;
1531
+ const swapIx = createSwapJlxJlxInstruction(
1532
+ {
1533
+ fromIndex: fromPoolConfig.stvIndex,
1534
+ toIndex: toPoolConfig.stvIndex,
1535
+ amountIn: params.amountIn,
1536
+ minOut: params.minOut,
1537
+ jupiterData: params.quote.jupiterData
1538
+ },
1539
+ {
1540
+ manager: params.manager,
1541
+ jlpVault: this.client.vaultPda,
1542
+ fromJlxMint: fromPoolConfig.fTokenMint,
1543
+ toJlxMint: toPoolConfig.fTokenMint,
1544
+ fromJlxAta: fromPoolCtx.vaultStagingAta,
1545
+ toJlxAta: toPoolCtx.vaultStagingAta,
1546
+ tokenProgram: TOKEN_PROGRAM_ID2,
1547
+ jupiterProgram
1548
+ },
1549
+ params.quote.remainingAccounts,
1550
+ this.client.programId
1551
+ );
1552
+ const { blockhash } = await this.client.connection.getLatestBlockhash("confirmed");
1553
+ const message = new TransactionMessage({
1554
+ payerKey: params.manager,
1555
+ recentBlockhash: blockhash,
1556
+ instructions: [computeIx, swapIx]
1557
+ }).compileToV0Message(params.quote.addressLookupTables);
1558
+ return new VersionedTransaction(message);
1559
+ }
1560
+ };
1561
+ var AdminContext = class {
1562
+ constructor(client) {
1563
+ this.client = client;
1564
+ }
1565
+ // Initialize or update vault
1566
+ async initOrUpdateVault(params) {
1567
+ const ix = createInitOrUpdateVaultInstruction(
1568
+ {
1569
+ jlpMint: params.jlpMint ?? null,
1570
+ baseAssetMints: params.baseAssetMints ?? null,
1571
+ jlxAssetMints: params.jlxAssetMints ?? null,
1572
+ newAdmin: params.newAdmin ?? null,
1573
+ manager: params.manager,
1574
+ feeReceiver: params.feeReceiver,
1575
+ flags: params.flags,
1576
+ jlpSlippageBps: params.jlpSlippageBps,
1577
+ oracleStalenessThreshold: params.oracleStalenessThreshold ?? null
1578
+ },
1579
+ {
1580
+ admin: params.admin,
1581
+ jlpVault: this.client.vaultPda,
1582
+ systemProgram: SystemProgram2.programId
1583
+ },
1584
+ this.client.programId
1585
+ );
1586
+ return this.client.buildTransaction(params.admin, [ix]);
1587
+ }
1588
+ // Initialize STV
1589
+ async initializeStv(params, jvMintKeypair) {
1590
+ const pool = getPoolByName(params.poolName);
1591
+ if (!pool) throw new JlpdClientError(`Unknown pool: ${params.poolName}`);
1592
+ const [stvPda] = deriveStvPda(pool.mint, this.client.programId);
1593
+ const stvJlxAta = getAssociatedTokenAddressSync2(pool.fTokenMint, stvPda, true);
1594
+ const ix = createInitializeStvInstruction(
1595
+ {
1596
+ mgmtFeeBps: params.mgmtFeeBps,
1597
+ perfFeeBps: params.perfFeeBps,
1598
+ maxDeposit: params.maxDeposit,
1599
+ minDeposit: params.minDeposit
1600
+ },
1601
+ {
1602
+ admin: params.admin,
1603
+ jlpVault: this.client.vaultPda,
1604
+ stv: stvPda,
1605
+ baseMint: pool.mint,
1606
+ jlMint: pool.fTokenMint,
1607
+ jvMint: jvMintKeypair,
1608
+ stvJlxAta,
1609
+ systemProgram: SystemProgram2.programId,
1610
+ tokenProgram: TOKEN_PROGRAM_ID2,
1611
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID2,
1612
+ rent: SYSVAR_RENT_PUBKEY
1613
+ },
1614
+ this.client.programId
1615
+ );
1616
+ return this.client.buildTransaction(params.admin, [ix]);
1617
+ }
1618
+ // Settle yield across all STVs
1619
+ async settleYield(params) {
1620
+ const poolNames = ["BTC", "ETH", "SOL", "USDC", "JupUSD"];
1621
+ const pools = poolNames.map((name) => {
1622
+ const pool = getPoolByName(name);
1623
+ if (!pool) throw new JlpdClientError(`Unknown pool: ${name}`);
1624
+ return pool;
1625
+ });
1626
+ const stvPdas = pools.map((p) => deriveStvPda(p.mint, this.client.programId)[0]);
1627
+ const stagingAtas = pools.map(
1628
+ (p) => getAssociatedTokenAddressSync2(p.fTokenMint, this.client.vaultPda, true)
1629
+ );
1630
+ const lendingAccounts = pools.map((p) => ({
1631
+ pubkey: p.hasJupiterLend ? p.lending : PublicKey12.default,
1632
+ isSigner: false,
1633
+ isWritable: false
1634
+ }));
1635
+ const rewardsAccounts = pools.map((p) => ({
1636
+ pubkey: p.hasJupiterLend ? p.rewardsRateModel : PublicKey12.default,
1637
+ isSigner: false,
1638
+ isWritable: false
1639
+ }));
1640
+ const mintAccounts = pools.map((p) => ({
1641
+ pubkey: p.fTokenMint,
1642
+ isSigner: false,
1643
+ isWritable: false
1644
+ }));
1645
+ const remainingAccounts = [...lendingAccounts, ...rewardsAccounts, ...mintAccounts];
1646
+ const ix = createSettleYieldInstruction(
1647
+ { jlpRate: params.jlpRate },
1648
+ {
1649
+ manager: params.manager,
1650
+ jlpVault: this.client.vaultPda,
1651
+ vaultJlpAta: getAssociatedTokenAddressSync2(MINTS.JLP, this.client.vaultPda, true),
1652
+ jlpMint: MINTS.JLP,
1653
+ stvBtc: stvPdas[0],
1654
+ stvEth: stvPdas[1],
1655
+ stvSol: stvPdas[2],
1656
+ stvUsdc: stvPdas[3],
1657
+ stvJupusd: stvPdas[4],
1658
+ stagingBtc: stagingAtas[0],
1659
+ stagingEth: stagingAtas[1],
1660
+ stagingSol: stagingAtas[2],
1661
+ stagingUsdc: stagingAtas[3],
1662
+ stagingJupusd: stagingAtas[4],
1663
+ oracleBtc: ORACLES.DOVES_BTC_USD,
1664
+ oracleEth: ORACLES.DOVES_ETH_USD,
1665
+ oracleSol: ORACLES.DOVES_SOL_USD,
1666
+ oracleJlp: ORACLES.PYTH_JLP_USD
1667
+ },
1668
+ remainingAccounts,
1669
+ this.client.programId
1670
+ );
1671
+ return this.client.buildTransaction(params.manager, [ix]);
1672
+ }
1673
+ };
1674
+ export {
1675
+ AdminContext,
1676
+ EXCHANGE_RATE_PRECISION,
1677
+ FLAG_DEPOSITS_DISABLED,
1678
+ FLAG_JLP_DISABLED,
1679
+ FLAG_PAUSED,
1680
+ FLAG_REBALANCE_DISABLED,
1681
+ FLAG_WITHDRAWALS_DISABLED,
1682
+ JLPD_PROGRAM_ID,
1683
+ JLP_VAULT_ACCOUNT_SIZE,
1684
+ JLP_VAULT_DATA_SIZE,
1685
+ JLP_VAULT_DISCRIMINATOR,
1686
+ JUPITER_LEND_PROGRAM_ID,
1687
+ JUPITER_SWAP_PROGRAM_ID,
1688
+ JUPUSD_POOL,
1689
+ JUPITER_LEND_PROGRAM_ID2 as JUP_LEND_PROGRAM_ID,
1690
+ JlpdClient,
1691
+ JlpdClientError,
1692
+ LENDING_ADMIN,
1693
+ LIQUIDITY_PROGRAM_ID,
1694
+ LIQUIDITY_SINGLETON,
1695
+ MINTS,
1696
+ ORACLES,
1697
+ POOLS,
1698
+ PPS_DECIMALS,
1699
+ PoolContext,
1700
+ SEED_JLP_VAULT,
1701
+ SEED_STV,
1702
+ STV_ACCOUNT_SIZE,
1703
+ STV_DATA_SIZE,
1704
+ STV_DISCRIMINATOR,
1705
+ STV_INDEX,
1706
+ SwapContext,
1707
+ USDC_POOL,
1708
+ WBTC_POOL,
1709
+ WETH_POOL,
1710
+ WSOL_POOL,
1711
+ baseToJlx,
1712
+ baseToShares,
1713
+ buildExchangeRateAccounts,
1714
+ buildJupEarnDepositAccounts,
1715
+ buildJupEarnWithdrawAccounts,
1716
+ buildSwapData,
1717
+ calculateExchangeRate,
1718
+ calculateNav,
1719
+ calculatePps,
1720
+ clearAtaCache,
1721
+ clearPdaCache,
1722
+ createClaimFeesInstruction,
1723
+ createDepositInstruction,
1724
+ createInitOrUpdateVaultInstruction,
1725
+ createInitializeStvInstruction,
1726
+ createJupEarnInstruction,
1727
+ createMoveJlxInstruction,
1728
+ createSettleYieldInstruction,
1729
+ createSwapJlxJlpInstruction,
1730
+ createSwapJlxJlxInstruction,
1731
+ createUpdateStvInstruction,
1732
+ createWithdrawInstruction,
1733
+ deriveAta,
1734
+ deriveStvAtas,
1735
+ deriveStvPda,
1736
+ deriveUserAtas,
1737
+ deriveVaultAtas,
1738
+ deriveVaultPda,
1739
+ fetchAddressLookupTables,
1740
+ fetchJlpRate,
1741
+ fetchJupiterPriceUsd,
1742
+ getJupiterQuote,
1743
+ getJupiterSwapInstructions,
1744
+ getPoolByMint,
1745
+ getPoolByName,
1746
+ jlxToBase,
1747
+ parseLendingAccount,
1748
+ parseRewardsRateModel,
1749
+ parseStv,
1750
+ parseSwapRemainingAccounts,
1751
+ parseVault,
1752
+ sharesToBase
1753
+ };