@pyefi/sdk 0.1.1

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.js ADDED
@@ -0,0 +1,1340 @@
1
+ import {
2
+ ALLOWED_VALIDATORS,
3
+ __spreadValues,
4
+ allTokenAddresses,
5
+ allowedLockups,
6
+ buildMarketLookup,
7
+ buildPtLookup,
8
+ configurePyeSDK,
9
+ createApyStore,
10
+ createBalanceStore,
11
+ createMarketStore,
12
+ createWalletStore,
13
+ fetchBalances,
14
+ fetchBalancesForMints,
15
+ fetchExchangeBalances,
16
+ fetchManifestMarkets,
17
+ fetchUserStakeAccounts,
18
+ getMaturity,
19
+ getPyeConfig,
20
+ lockups,
21
+ lookupBondByVoteAccount,
22
+ maturities,
23
+ maturitiesArray,
24
+ maturityIdsArray,
25
+ parseOrderBook,
26
+ tokenIdsArray,
27
+ tokens,
28
+ validators
29
+ } from "./chunk-5XHGVQ3Z.js";
30
+
31
+ // src/constants/fees.ts
32
+ import { PublicKey } from "@solana/web3.js";
33
+ var PYE_TRADING_FEE_BPS = 50;
34
+ var PYE_TREASURY_WALLET = new PublicKey(
35
+ "D3LKi2CUFmudj4fT8izGeBky84oYPZY7UWwvcLUhh2ch"
36
+ );
37
+ function calculateFeeLamports(expectedSolOut) {
38
+ return BigInt(
39
+ Math.round(expectedSolOut * 1e9 * PYE_TRADING_FEE_BPS / 1e4)
40
+ );
41
+ }
42
+ function applyTradingFee(grossSolOut) {
43
+ return grossSolOut * (1 - PYE_TRADING_FEE_BPS / 1e4);
44
+ }
45
+
46
+ // src/lib/fetch-lockup-metrics.ts
47
+ import { createClient } from "@supabase/supabase-js";
48
+ var LAMPORTS_PER_SOL = 1e9;
49
+ function formatBps(bps) {
50
+ const pct = bps / 100;
51
+ return pct.toLocaleString("en-US", {
52
+ minimumFractionDigits: 0,
53
+ maximumFractionDigits: 2
54
+ }) + "%";
55
+ }
56
+ function formatSol(lamports) {
57
+ const sol = lamports / LAMPORTS_PER_SOL;
58
+ return sol.toLocaleString("en-US", {
59
+ minimumFractionDigits: 2,
60
+ maximumFractionDigits: 4
61
+ }) + " SOL";
62
+ }
63
+ async function fetchLockupMetrics(bondPubkey, opts) {
64
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
65
+ const supabase = (_a = opts == null ? void 0 : opts.supabaseClient) != null ? _a : (() => {
66
+ const config = getPyeConfig();
67
+ return createClient(config.supabaseUrl, config.supabaseAnonKey);
68
+ })();
69
+ const includeCharts = (_b = opts == null ? void 0 : opts.includeChartData) != null ? _b : false;
70
+ const noData = Promise.resolve({ data: null });
71
+ const bondRes = await supabase.from("solo_validator_bonds").select("tvl_cap, inflation_bps, mev_tips_bps, block_rewards_bps, validator_vote_account").eq("pubkey", bondPubkey).single();
72
+ const voteAccount = (_c = bondRes.data) == null ? void 0 : _c.validator_vote_account;
73
+ const [tvlRes, paymentsRes, rewardsRes, tvlHistoryRes, apyRes] = await Promise.all([
74
+ supabase.from("tvl_snapshots").select("sol").eq("bond", bondPubkey).order("created_at", { ascending: false }).limit(1).single(),
75
+ supabase.from("bond_payments").select("epoch, amount").eq("bond_pubkey", bondPubkey).order("epoch", { ascending: true }),
76
+ includeCharts ? supabase.from("bond_rewards").select("epoch, expected_inflation_rewards, expected_mev_rewards, expected_block_rewards").eq("bond_pubkey", bondPubkey).order("epoch", { ascending: true }) : noData,
77
+ includeCharts ? supabase.from("tvl_snapshots").select("created_at, sol").eq("bond", bondPubkey).order("created_at", { ascending: true }) : noData,
78
+ voteAccount ? supabase.from("stakewiz_apy").select("apy").eq("vote_account", voteAccount).order("updated_at", { ascending: false }).limit(1).single() : noData
79
+ ]);
80
+ let depositCap = "No Cap";
81
+ if (((_d = bondRes.data) == null ? void 0 : _d.tvl_cap) && bondRes.data.tvl_cap > 0) {
82
+ const cap = Number(bondRes.data.tvl_cap);
83
+ depositCap = cap.toLocaleString("en-US", {
84
+ minimumFractionDigits: 2,
85
+ maximumFractionDigits: 4
86
+ }) + " SOL";
87
+ }
88
+ let tvl = "\u2014";
89
+ if (((_e = tvlRes.data) == null ? void 0 : _e.sol) != null) {
90
+ const solVal = parseFloat(tvlRes.data.sol);
91
+ tvl = solVal.toLocaleString("en-US", {
92
+ minimumFractionDigits: 2,
93
+ maximumFractionDigits: 4
94
+ }) + " SOL";
95
+ }
96
+ const inflationBps = Number((_g = (_f = bondRes.data) == null ? void 0 : _f.inflation_bps) != null ? _g : 0);
97
+ const mevTipsBps = Number((_i = (_h = bondRes.data) == null ? void 0 : _h.mev_tips_bps) != null ? _i : 0);
98
+ const blockRewardsBps = Number((_k = (_j = bondRes.data) == null ? void 0 : _j.block_rewards_bps) != null ? _k : 0);
99
+ const payments = [];
100
+ let totalPaymentLamports = 0;
101
+ if (paymentsRes.data) {
102
+ for (const row of paymentsRes.data) {
103
+ const amount = Number((_l = row.amount) != null ? _l : 0);
104
+ payments.push({ epoch: Number(row.epoch), amount });
105
+ totalPaymentLamports += amount;
106
+ }
107
+ }
108
+ const rewardBreakdown = [];
109
+ let totalRewardLamports = 0;
110
+ if (rewardsRes.data) {
111
+ for (const row of rewardsRes.data) {
112
+ const inflation = Number((_m = row.expected_inflation_rewards) != null ? _m : 0);
113
+ const mev = Number((_n = row.expected_mev_rewards) != null ? _n : 0);
114
+ const block = Number((_o = row.expected_block_rewards) != null ? _o : 0);
115
+ totalRewardLamports += inflation + mev + block;
116
+ rewardBreakdown.push({
117
+ epoch: Number(row.epoch),
118
+ staking: inflation / LAMPORTS_PER_SOL,
119
+ mev: mev / LAMPORTS_PER_SOL,
120
+ block: block / LAMPORTS_PER_SOL
121
+ });
122
+ }
123
+ }
124
+ const tvlHistory = [];
125
+ if (tvlHistoryRes.data) {
126
+ const byDay = /* @__PURE__ */ new Map();
127
+ for (const row of tvlHistoryRes.data) {
128
+ const date = row.created_at.slice(0, 10);
129
+ byDay.set(date, parseFloat((_p = row.sol) != null ? _p : "0"));
130
+ }
131
+ for (const [date, sol] of byDay) {
132
+ tvlHistory.push({ date, sol });
133
+ }
134
+ }
135
+ const depositCapSol = Number((_r = (_q = bondRes.data) == null ? void 0 : _q.tvl_cap) != null ? _r : 0);
136
+ const tvlSol = parseFloat((_t = (_s = tvlRes.data) == null ? void 0 : _s.sol) != null ? _t : "0");
137
+ let apy90d = null;
138
+ if (((_u = apyRes.data) == null ? void 0 : _u.apy) != null) {
139
+ const pct = Number(apyRes.data.apy);
140
+ apy90d = pct.toFixed(2) + "%";
141
+ }
142
+ return {
143
+ depositCap,
144
+ depositCapSol,
145
+ tvl,
146
+ tvlSol,
147
+ totalRewards: formatSol(totalRewardLamports),
148
+ apy90d,
149
+ inflationRewards: formatBps(1e4 - inflationBps),
150
+ mevRewards: formatBps(1e4 - mevTipsBps),
151
+ blockRewards: formatBps(1e4 - blockRewardsBps),
152
+ payments,
153
+ rewardBreakdown,
154
+ tvlHistory,
155
+ hasChartData: includeCharts,
156
+ fetchedAt: Date.now()
157
+ };
158
+ }
159
+
160
+ // src/lib/liquidity.ts
161
+ function checkBuyLiquidity(asks, orderSizeTokens) {
162
+ if (asks.length === 0 || orderSizeTokens <= 0) {
163
+ return {
164
+ expectedFillPrice: null,
165
+ slippageBps: 0,
166
+ totalAvailableSize: 0,
167
+ isSufficientLiquidity: false
168
+ };
169
+ }
170
+ const sorted = [...asks].sort((a, b) => a.price - b.price);
171
+ const totalAvailableSize = sorted.reduce((sum, o) => sum + o.size, 0);
172
+ let remaining = orderSizeTokens;
173
+ let totalCost = 0;
174
+ const bestPrice = sorted[0].price;
175
+ for (const order of sorted) {
176
+ if (remaining <= 0) break;
177
+ const fillSize = Math.min(remaining, order.size);
178
+ totalCost += fillSize * order.price;
179
+ remaining -= fillSize;
180
+ }
181
+ const isSufficientLiquidity = remaining <= 0;
182
+ const filledSize = orderSizeTokens - Math.max(remaining, 0);
183
+ const expectedFillPrice = filledSize > 0 ? totalCost / filledSize : null;
184
+ const slippageBps = expectedFillPrice && bestPrice > 0 ? Math.round((expectedFillPrice - bestPrice) / bestPrice * 1e4) : 0;
185
+ return {
186
+ expectedFillPrice,
187
+ slippageBps,
188
+ totalAvailableSize,
189
+ isSufficientLiquidity
190
+ };
191
+ }
192
+ function checkSellLiquidity(bids, orderSizeTokens) {
193
+ if (bids.length === 0 || orderSizeTokens <= 0) {
194
+ return {
195
+ expectedFillPrice: null,
196
+ slippageBps: 0,
197
+ totalAvailableSize: 0,
198
+ isSufficientLiquidity: false
199
+ };
200
+ }
201
+ const sorted = [...bids].sort((a, b) => b.price - a.price);
202
+ const totalAvailableSize = sorted.reduce((sum, o) => sum + o.size, 0);
203
+ let remaining = orderSizeTokens;
204
+ let totalRevenue = 0;
205
+ const bestPrice = sorted[0].price;
206
+ for (const order of sorted) {
207
+ if (remaining <= 0) break;
208
+ const fillSize = Math.min(remaining, order.size);
209
+ totalRevenue += fillSize * order.price;
210
+ remaining -= fillSize;
211
+ }
212
+ const isSufficientLiquidity = remaining <= 0;
213
+ const filledSize = orderSizeTokens - Math.max(remaining, 0);
214
+ const expectedFillPrice = filledSize > 0 ? totalRevenue / filledSize : null;
215
+ const slippageBps = expectedFillPrice && bestPrice > 0 ? Math.round((bestPrice - expectedFillPrice) / bestPrice * 1e4) : 0;
216
+ return {
217
+ expectedFillPrice,
218
+ slippageBps,
219
+ totalAvailableSize,
220
+ isSufficientLiquidity
221
+ };
222
+ }
223
+
224
+ // src/lib/estimate-rt.ts
225
+ var DEFAULT_MS_PER_SLOT = 400;
226
+ async function fetchEpochSyncedNowTs(connection) {
227
+ const epochInfo = await connection.getEpochInfo();
228
+ const elapsedSeconds = epochInfo.slotIndex * DEFAULT_MS_PER_SLOT / 1e3;
229
+ return Date.now() / 1e3 - elapsedSeconds;
230
+ }
231
+ function estimateRtFromStake({
232
+ amountSol,
233
+ maturity,
234
+ nowTs
235
+ }) {
236
+ if (amountSol <= 0) return 0;
237
+ const maturityTs = Number(maturity.maturity_timestamp);
238
+ const issuanceStartTs = Number(maturity.issuance_start_timestamp);
239
+ const total = maturityTs - issuanceStartTs;
240
+ if (total <= 0) return 0;
241
+ const remaining = Math.max(maturityTs - nowTs, 0);
242
+ return amountSol * (remaining / total);
243
+ }
244
+
245
+ // src/lib/execute-stake-deposit.ts
246
+ import {
247
+ ComputeBudgetProgram,
248
+ Keypair,
249
+ PublicKey as PublicKey2,
250
+ StakeProgram,
251
+ Transaction,
252
+ TransactionInstruction
253
+ } from "@solana/web3.js";
254
+ import {
255
+ TOKEN_PROGRAM_ID,
256
+ ASSOCIATED_TOKEN_PROGRAM_ID,
257
+ getAssociatedTokenAddressSync,
258
+ createAssociatedTokenAccountIdempotentInstruction
259
+ } from "@solana/spl-token";
260
+ var BONDS_PROGRAM_ID = new PublicKey2(
261
+ "PYEQZ2qYHPQapnw8Ms8MSPMNzoq59NHHfNwAtuV26wx"
262
+ );
263
+ var DEPOSIT_SOL_DISCRIMINATOR = new Uint8Array([
264
+ 253,
265
+ 10,
266
+ 62,
267
+ 175,
268
+ 159,
269
+ 90,
270
+ 55,
271
+ 142
272
+ ]);
273
+ var DEPOSIT_STAKE_DISCRIMINATOR = new Uint8Array([
274
+ 21,
275
+ 14,
276
+ 117,
277
+ 220,
278
+ 1,
279
+ 60,
280
+ 23,
281
+ 13
282
+ ]);
283
+ var SYSVAR_CLOCK = new PublicKey2(
284
+ "SysvarC1ock11111111111111111111111111111111"
285
+ );
286
+ var STAKE_PROGRAM = new PublicKey2(
287
+ "Stake11111111111111111111111111111111111111"
288
+ );
289
+ var SYSVAR_RENT = new PublicKey2(
290
+ "SysvarRent111111111111111111111111111111111"
291
+ );
292
+ var SYSVAR_STAKE_HISTORY = new PublicKey2(
293
+ "SysvarStakeHistory1111111111111111111111111"
294
+ );
295
+ var STAKE_CONFIG = new PublicKey2(
296
+ "StakeConfig11111111111111111111111111111111"
297
+ );
298
+ function deriveGlobalSettings() {
299
+ const [pda] = PublicKey2.findProgramAddressSync(
300
+ [Buffer.from("global_settings")],
301
+ BONDS_PROGRAM_ID
302
+ );
303
+ return pda;
304
+ }
305
+ function deriveStakeAccount(bond) {
306
+ const [pda] = PublicKey2.findProgramAddressSync(
307
+ [Buffer.from("stake"), bond.toBuffer()],
308
+ BONDS_PROGRAM_ID
309
+ );
310
+ return pda;
311
+ }
312
+ async function fetchProtocolFeeWallet(connection, globalSettingsPda) {
313
+ const info = await connection.getAccountInfo(globalSettingsPda);
314
+ if (!info || !info.data) {
315
+ throw new Error("GlobalSettings account not found");
316
+ }
317
+ return new PublicKey2(info.data.subarray(40, 72));
318
+ }
319
+ async function fetchTransientStakeAccount(connection, bond) {
320
+ const info = await connection.getAccountInfo(bond);
321
+ if (!info || !info.data) {
322
+ throw new Error("Bond account not found");
323
+ }
324
+ return new PublicKey2(info.data.subarray(72, 104));
325
+ }
326
+ function encodeDepositData(amountLamports) {
327
+ const buf = new ArrayBuffer(16);
328
+ const bytes = new Uint8Array(buf);
329
+ bytes.set(DEPOSIT_SOL_DISCRIMINATOR, 0);
330
+ new DataView(buf).setBigUint64(8, amountLamports, true);
331
+ return bytes;
332
+ }
333
+ async function executeStakeAccountDeposit({
334
+ connection,
335
+ wallet,
336
+ bondPubkey,
337
+ principalTokenMint,
338
+ yieldTokenMint,
339
+ validatorVoteAccount,
340
+ stakeAccountPubkey,
341
+ amountSol,
342
+ stakeBalanceSol
343
+ }) {
344
+ if (!wallet.publicKey || !wallet.sendTransaction) {
345
+ throw new Error("Wallet not connected");
346
+ }
347
+ const owner = wallet.publicKey;
348
+ const bond = new PublicKey2(bondPubkey);
349
+ const ptMint = new PublicKey2(principalTokenMint);
350
+ const ytMint = new PublicKey2(yieldTokenMint);
351
+ const voteAccount = new PublicKey2(validatorVoteAccount);
352
+ const userStake = new PublicKey2(stakeAccountPubkey);
353
+ const globalSettingsPda = deriveGlobalSettings();
354
+ const stakeAccountPda = deriveStakeAccount(bond);
355
+ const [protocolFeeWallet, transientStakeAccount, rentExemptReserve, latestBlockhash] = await Promise.all([
356
+ fetchProtocolFeeWallet(connection, globalSettingsPda),
357
+ fetchTransientStakeAccount(connection, bond),
358
+ connection.getMinimumBalanceForRentExemption(StakeProgram.space),
359
+ connection.getLatestBlockhash("confirmed")
360
+ ]);
361
+ const ownerPt = getAssociatedTokenAddressSync(ptMint, owner, true);
362
+ const ownerYt = getAssociatedTokenAddressSync(ytMint, owner, true);
363
+ const feeWalletPt = getAssociatedTokenAddressSync(ptMint, protocolFeeWallet, true);
364
+ const feeWalletYt = getAssociatedTokenAddressSync(ytMint, protocolFeeWallet, true);
365
+ const amountLamports = Math.round(amountSol * 1e9);
366
+ const totalLamports = Math.round(stakeBalanceSol * 1e9);
367
+ const isPartial = amountLamports < totalLamports;
368
+ const tx = new Transaction();
369
+ tx.recentBlockhash = latestBlockhash.blockhash;
370
+ tx.feePayer = owner;
371
+ tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 4e5 }));
372
+ tx.add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1e3 }));
373
+ let depositStakeAccount;
374
+ let splitKeypair = null;
375
+ if (isPartial) {
376
+ splitKeypair = Keypair.generate();
377
+ tx.add(
378
+ StakeProgram.split(
379
+ {
380
+ stakePubkey: userStake,
381
+ authorizedPubkey: owner,
382
+ splitStakePubkey: splitKeypair.publicKey,
383
+ lamports: amountLamports
384
+ },
385
+ rentExemptReserve
386
+ )
387
+ );
388
+ depositStakeAccount = splitKeypair.publicKey;
389
+ } else {
390
+ depositStakeAccount = userStake;
391
+ }
392
+ tx.add(
393
+ createAssociatedTokenAccountIdempotentInstruction(owner, ownerPt, owner, ptMint)
394
+ );
395
+ tx.add(
396
+ createAssociatedTokenAccountIdempotentInstruction(owner, ownerYt, owner, ytMint)
397
+ );
398
+ tx.add(
399
+ createAssociatedTokenAccountIdempotentInstruction(owner, feeWalletPt, protocolFeeWallet, ptMint)
400
+ );
401
+ tx.add(
402
+ createAssociatedTokenAccountIdempotentInstruction(owner, feeWalletYt, protocolFeeWallet, ytMint)
403
+ );
404
+ const isTransientSet = !transientStakeAccount.equals(PublicKey2.default);
405
+ const remainingAccounts = isTransientSet ? [{ pubkey: transientStakeAccount, isSigner: false, isWritable: true }] : [];
406
+ const depositIx = new TransactionInstruction({
407
+ programId: BONDS_PROGRAM_ID,
408
+ keys: [
409
+ { pubkey: owner, isSigner: true, isWritable: true },
410
+ { pubkey: depositStakeAccount, isSigner: false, isWritable: true },
411
+ { pubkey: ownerPt, isSigner: false, isWritable: true },
412
+ { pubkey: ownerYt, isSigner: false, isWritable: true },
413
+ { pubkey: bond, isSigner: false, isWritable: false },
414
+ { pubkey: voteAccount, isSigner: false, isWritable: false },
415
+ { pubkey: stakeAccountPda, isSigner: false, isWritable: true },
416
+ { pubkey: ptMint, isSigner: false, isWritable: true },
417
+ { pubkey: ytMint, isSigner: false, isWritable: true },
418
+ { pubkey: globalSettingsPda, isSigner: false, isWritable: false },
419
+ { pubkey: protocolFeeWallet, isSigner: false, isWritable: false },
420
+ { pubkey: feeWalletPt, isSigner: false, isWritable: true },
421
+ { pubkey: feeWalletYt, isSigner: false, isWritable: true },
422
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
423
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
424
+ { pubkey: PublicKey2.default, isSigner: false, isWritable: false },
425
+ { pubkey: SYSVAR_CLOCK, isSigner: false, isWritable: false },
426
+ { pubkey: STAKE_PROGRAM, isSigner: false, isWritable: false },
427
+ { pubkey: SYSVAR_STAKE_HISTORY, isSigner: false, isWritable: false },
428
+ ...remainingAccounts
429
+ ],
430
+ data: Buffer.from(DEPOSIT_STAKE_DISCRIMINATOR)
431
+ });
432
+ tx.add(depositIx);
433
+ const signers = splitKeypair ? [splitKeypair] : [];
434
+ const signature = await wallet.sendTransaction(tx, connection, { signers });
435
+ const confirmation = await connection.confirmTransaction(
436
+ {
437
+ signature,
438
+ blockhash: latestBlockhash.blockhash,
439
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
440
+ },
441
+ "confirmed"
442
+ );
443
+ if (confirmation.value.err) {
444
+ throw new Error(
445
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
446
+ );
447
+ }
448
+ return { signature };
449
+ }
450
+ async function executeStakeDeposit({
451
+ connection,
452
+ wallet,
453
+ bondPubkey,
454
+ principalTokenMint,
455
+ yieldTokenMint,
456
+ validatorVoteAccount,
457
+ amountSol
458
+ }) {
459
+ var _a;
460
+ if (!wallet.publicKey || !wallet.sendTransaction) {
461
+ throw new Error("Wallet not connected");
462
+ }
463
+ const owner = wallet.publicKey;
464
+ const bond = new PublicKey2(bondPubkey);
465
+ const ptMint = new PublicKey2(principalTokenMint);
466
+ const ytMint = new PublicKey2(yieldTokenMint);
467
+ const voteAccount = new PublicKey2(validatorVoteAccount);
468
+ const globalSettingsPda = deriveGlobalSettings();
469
+ const stakeAccountPda = deriveStakeAccount(bond);
470
+ const [protocolFeeWallet, transientStakeAccount, latestBlockhash] = await Promise.all([
471
+ fetchProtocolFeeWallet(connection, globalSettingsPda),
472
+ fetchTransientStakeAccount(connection, bond),
473
+ connection.getLatestBlockhash("confirmed")
474
+ ]);
475
+ const ownerPt = getAssociatedTokenAddressSync(ptMint, owner, true);
476
+ const ownerYt = getAssociatedTokenAddressSync(ytMint, owner, true);
477
+ const feeWalletPt = getAssociatedTokenAddressSync(ptMint, protocolFeeWallet, true);
478
+ const feeWalletYt = getAssociatedTokenAddressSync(ytMint, protocolFeeWallet, true);
479
+ const amountLamports = BigInt(Math.round(amountSol * 1e9));
480
+ const isTransientUninitialized = transientStakeAccount.equals(PublicKey2.default);
481
+ const transientKeypair = isTransientUninitialized ? Keypair.generate() : null;
482
+ const transientPubkey = (_a = transientKeypair == null ? void 0 : transientKeypair.publicKey) != null ? _a : transientStakeAccount;
483
+ const tx = new Transaction();
484
+ tx.recentBlockhash = latestBlockhash.blockhash;
485
+ tx.feePayer = owner;
486
+ tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 285e3 }));
487
+ tx.add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1e3 }));
488
+ tx.add(
489
+ createAssociatedTokenAccountIdempotentInstruction(owner, ownerPt, owner, ptMint)
490
+ );
491
+ tx.add(
492
+ createAssociatedTokenAccountIdempotentInstruction(owner, ownerYt, owner, ytMint)
493
+ );
494
+ tx.add(
495
+ createAssociatedTokenAccountIdempotentInstruction(owner, feeWalletPt, protocolFeeWallet, ptMint)
496
+ );
497
+ tx.add(
498
+ createAssociatedTokenAccountIdempotentInstruction(owner, feeWalletYt, protocolFeeWallet, ytMint)
499
+ );
500
+ const depositIx = new TransactionInstruction({
501
+ programId: BONDS_PROGRAM_ID,
502
+ keys: [
503
+ { pubkey: owner, isSigner: true, isWritable: true },
504
+ { pubkey: ownerPt, isSigner: false, isWritable: true },
505
+ { pubkey: ownerYt, isSigner: false, isWritable: true },
506
+ { pubkey: bond, isSigner: false, isWritable: true },
507
+ { pubkey: voteAccount, isSigner: false, isWritable: false },
508
+ { pubkey: stakeAccountPda, isSigner: false, isWritable: true },
509
+ { pubkey: ptMint, isSigner: false, isWritable: true },
510
+ { pubkey: ytMint, isSigner: false, isWritable: true },
511
+ { pubkey: globalSettingsPda, isSigner: false, isWritable: false },
512
+ { pubkey: protocolFeeWallet, isSigner: false, isWritable: true },
513
+ { pubkey: feeWalletPt, isSigner: false, isWritable: true },
514
+ { pubkey: feeWalletYt, isSigner: false, isWritable: true },
515
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
516
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
517
+ { pubkey: PublicKey2.default, isSigner: false, isWritable: false },
518
+ { pubkey: SYSVAR_CLOCK, isSigner: false, isWritable: false },
519
+ { pubkey: STAKE_PROGRAM, isSigner: false, isWritable: false },
520
+ { pubkey: SYSVAR_RENT, isSigner: false, isWritable: false },
521
+ { pubkey: SYSVAR_STAKE_HISTORY, isSigner: false, isWritable: false },
522
+ { pubkey: STAKE_CONFIG, isSigner: false, isWritable: false },
523
+ { pubkey: transientPubkey, isSigner: !!transientKeypair, isWritable: true },
524
+ { pubkey: BONDS_PROGRAM_ID, isSigner: false, isWritable: false }
525
+ ],
526
+ data: Buffer.from(encodeDepositData(amountLamports))
527
+ });
528
+ tx.add(depositIx);
529
+ const signers = transientKeypair ? [transientKeypair] : [];
530
+ const signature = await wallet.sendTransaction(tx, connection, { signers });
531
+ const confirmation = await connection.confirmTransaction(
532
+ {
533
+ signature,
534
+ blockhash: latestBlockhash.blockhash,
535
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
536
+ },
537
+ "confirmed"
538
+ );
539
+ if (confirmation.value.err) {
540
+ throw new Error(
541
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
542
+ );
543
+ }
544
+ return { signature };
545
+ }
546
+
547
+ // src/lib/execute-deposit-and-sell.ts
548
+ import { ManifestClient } from "@cks-systems/manifest-sdk";
549
+ import {
550
+ ComputeBudgetProgram as ComputeBudgetProgram2,
551
+ Keypair as Keypair2,
552
+ PublicKey as PublicKey3,
553
+ StakeProgram as StakeProgram2,
554
+ TransactionInstruction as TransactionInstruction2,
555
+ TransactionMessage,
556
+ VersionedTransaction
557
+ } from "@solana/web3.js";
558
+ import {
559
+ ASSOCIATED_TOKEN_PROGRAM_ID as ASSOCIATED_TOKEN_PROGRAM_ID2,
560
+ NATIVE_MINT,
561
+ TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID2,
562
+ createAssociatedTokenAccountIdempotentInstruction as createAssociatedTokenAccountIdempotentInstruction2,
563
+ createCloseAccountInstruction,
564
+ createTransferInstruction,
565
+ getAssociatedTokenAddressSync as getAssociatedTokenAddressSync2
566
+ } from "@solana/spl-token";
567
+ var BONDS_PROGRAM_ID2 = new PublicKey3(
568
+ "PYEQZ2qYHPQapnw8Ms8MSPMNzoq59NHHfNwAtuV26wx"
569
+ );
570
+ var DEPOSIT_STAKE_DISCRIMINATOR2 = new Uint8Array([
571
+ 21,
572
+ 14,
573
+ 117,
574
+ 220,
575
+ 1,
576
+ 60,
577
+ 23,
578
+ 13
579
+ ]);
580
+ var SYSVAR_CLOCK2 = new PublicKey3("SysvarC1ock11111111111111111111111111111111");
581
+ var STAKE_PROGRAM2 = new PublicKey3("Stake11111111111111111111111111111111111111");
582
+ var SYSVAR_STAKE_HISTORY2 = new PublicKey3("SysvarStakeHistory1111111111111111111111111");
583
+ function deriveGlobalSettings2() {
584
+ const [pda] = PublicKey3.findProgramAddressSync(
585
+ [Buffer.from("global_settings")],
586
+ BONDS_PROGRAM_ID2
587
+ );
588
+ return pda;
589
+ }
590
+ function deriveStakeAccount2(bond) {
591
+ const [pda] = PublicKey3.findProgramAddressSync(
592
+ [Buffer.from("stake"), bond.toBuffer()],
593
+ BONDS_PROGRAM_ID2
594
+ );
595
+ return pda;
596
+ }
597
+ async function fetchProtocolFeeWallet2(connection, globalSettingsPda) {
598
+ const info = await connection.getAccountInfo(globalSettingsPda);
599
+ if (!(info == null ? void 0 : info.data)) throw new Error("GlobalSettings account not found");
600
+ return new PublicKey3(info.data.subarray(40, 72));
601
+ }
602
+ async function fetchTransientStakeAccount2(connection, bond) {
603
+ const info = await connection.getAccountInfo(bond);
604
+ if (!(info == null ? void 0 : info.data)) throw new Error("Bond account not found");
605
+ return new PublicKey3(info.data.subarray(72, 104));
606
+ }
607
+ async function executeDepositAndSell({
608
+ connection,
609
+ wallet,
610
+ bondPubkey,
611
+ principalTokenMint,
612
+ yieldTokenMint,
613
+ validatorVoteAccount,
614
+ stakeAccountPubkey,
615
+ amountSol,
616
+ stakeBalanceSol,
617
+ marketPubkey,
618
+ rtAmountToSell,
619
+ minReceiveTokens,
620
+ expectedSolOut,
621
+ altPubkey
622
+ }) {
623
+ if (!wallet.publicKey || !wallet.sendTransaction) {
624
+ throw new Error("Wallet not connected");
625
+ }
626
+ const owner = wallet.publicKey;
627
+ const bond = new PublicKey3(bondPubkey);
628
+ const ptMint = new PublicKey3(principalTokenMint);
629
+ const ytMint = new PublicKey3(yieldTokenMint);
630
+ const voteAccount = new PublicKey3(validatorVoteAccount);
631
+ const userStake = new PublicKey3(stakeAccountPubkey);
632
+ const marketPk = new PublicKey3(marketPubkey);
633
+ const globalSettingsPda = deriveGlobalSettings2();
634
+ const stakeAccountPda = deriveStakeAccount2(bond);
635
+ const [
636
+ protocolFeeWallet,
637
+ transientStakeAccount,
638
+ rentExemptReserve,
639
+ latestBlockhash,
640
+ manifestClient,
641
+ altResponse
642
+ ] = await Promise.all([
643
+ fetchProtocolFeeWallet2(connection, globalSettingsPda),
644
+ fetchTransientStakeAccount2(connection, bond),
645
+ connection.getMinimumBalanceForRentExemption(StakeProgram2.space),
646
+ connection.getLatestBlockhash("confirmed"),
647
+ ManifestClient.getClientReadOnly(connection, marketPk),
648
+ connection.getAddressLookupTable(new PublicKey3(altPubkey))
649
+ ]);
650
+ const altAccount = altResponse.value;
651
+ if (!altAccount) {
652
+ throw new Error(
653
+ `Address Lookup Table ${altPubkey} not found on-chain \u2014 it may not be deployed yet.`
654
+ );
655
+ }
656
+ const ownerPt = getAssociatedTokenAddressSync2(ptMint, owner, true);
657
+ const ownerYt = getAssociatedTokenAddressSync2(ytMint, owner, true);
658
+ const feeWalletPt = getAssociatedTokenAddressSync2(ptMint, protocolFeeWallet, true);
659
+ const feeWalletYt = getAssociatedTokenAddressSync2(ytMint, protocolFeeWallet, true);
660
+ const wsolAta = getAssociatedTokenAddressSync2(NATIVE_MINT, owner, true, TOKEN_PROGRAM_ID2);
661
+ const treasuryWsol = getAssociatedTokenAddressSync2(
662
+ NATIVE_MINT,
663
+ PYE_TREASURY_WALLET,
664
+ true,
665
+ TOKEN_PROGRAM_ID2
666
+ );
667
+ const ataInfos = await connection.getMultipleAccountsInfo([
668
+ ownerPt,
669
+ ownerYt,
670
+ feeWalletPt,
671
+ feeWalletYt,
672
+ wsolAta,
673
+ treasuryWsol
674
+ ]);
675
+ const [
676
+ ownerPtExists,
677
+ ownerYtExists,
678
+ feeWalletPtExists,
679
+ feeWalletYtExists,
680
+ wsolAtaExists,
681
+ treasuryWsolExists
682
+ ] = ataInfos.map((info) => info !== null);
683
+ const amountLamports = Math.round(amountSol * 1e9);
684
+ const totalLamports = Math.round(stakeBalanceSol * 1e9);
685
+ const isPartial = amountLamports < totalLamports;
686
+ const baseDecimals = manifestClient.market.baseDecimals();
687
+ const quoteDecimals = manifestClient.market.quoteDecimals();
688
+ const rawInAtoms = Math.floor(rtAmountToSell * 10 ** baseDecimals);
689
+ const safetyBuffer = Math.max(Math.ceil(rawInAtoms * 2e-4), 100);
690
+ const inAtoms = BigInt(Math.max(rawInAtoms - safetyBuffer, 0));
691
+ const outAtoms = BigInt(Math.floor(minReceiveTokens * 10 ** quoteDecimals));
692
+ const instructions = [];
693
+ instructions.push(ComputeBudgetProgram2.setComputeUnitLimit({ units: 55e4 }));
694
+ instructions.push(ComputeBudgetProgram2.setComputeUnitPrice({ microLamports: 1e3 }));
695
+ let depositStakeAccount;
696
+ let splitKeypair = null;
697
+ if (isPartial) {
698
+ splitKeypair = Keypair2.generate();
699
+ instructions.push(
700
+ ...StakeProgram2.split(
701
+ {
702
+ stakePubkey: userStake,
703
+ authorizedPubkey: owner,
704
+ splitStakePubkey: splitKeypair.publicKey,
705
+ lamports: amountLamports
706
+ },
707
+ rentExemptReserve
708
+ ).instructions
709
+ );
710
+ depositStakeAccount = splitKeypair.publicKey;
711
+ } else {
712
+ depositStakeAccount = userStake;
713
+ }
714
+ if (!ownerPtExists) instructions.push(createAssociatedTokenAccountIdempotentInstruction2(owner, ownerPt, owner, ptMint));
715
+ if (!ownerYtExists) instructions.push(createAssociatedTokenAccountIdempotentInstruction2(owner, ownerYt, owner, ytMint));
716
+ if (!feeWalletPtExists) instructions.push(createAssociatedTokenAccountIdempotentInstruction2(owner, feeWalletPt, protocolFeeWallet, ptMint));
717
+ if (!feeWalletYtExists) instructions.push(createAssociatedTokenAccountIdempotentInstruction2(owner, feeWalletYt, protocolFeeWallet, ytMint));
718
+ if (!wsolAtaExists) instructions.push(createAssociatedTokenAccountIdempotentInstruction2(owner, wsolAta, owner, NATIVE_MINT));
719
+ if (!treasuryWsolExists) instructions.push(createAssociatedTokenAccountIdempotentInstruction2(owner, treasuryWsol, PYE_TREASURY_WALLET, NATIVE_MINT));
720
+ const isTransientSet = !transientStakeAccount.equals(PublicKey3.default);
721
+ const remainingAccounts = isTransientSet ? [{ pubkey: transientStakeAccount, isSigner: false, isWritable: true }] : [];
722
+ instructions.push(
723
+ new TransactionInstruction2({
724
+ programId: BONDS_PROGRAM_ID2,
725
+ keys: [
726
+ { pubkey: owner, isSigner: true, isWritable: true },
727
+ { pubkey: depositStakeAccount, isSigner: false, isWritable: true },
728
+ { pubkey: ownerPt, isSigner: false, isWritable: true },
729
+ { pubkey: ownerYt, isSigner: false, isWritable: true },
730
+ { pubkey: bond, isSigner: false, isWritable: false },
731
+ { pubkey: voteAccount, isSigner: false, isWritable: false },
732
+ { pubkey: stakeAccountPda, isSigner: false, isWritable: true },
733
+ { pubkey: ptMint, isSigner: false, isWritable: true },
734
+ { pubkey: ytMint, isSigner: false, isWritable: true },
735
+ { pubkey: globalSettingsPda, isSigner: false, isWritable: false },
736
+ { pubkey: protocolFeeWallet, isSigner: false, isWritable: false },
737
+ { pubkey: feeWalletPt, isSigner: false, isWritable: true },
738
+ { pubkey: feeWalletYt, isSigner: false, isWritable: true },
739
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID2, isSigner: false, isWritable: false },
740
+ { pubkey: TOKEN_PROGRAM_ID2, isSigner: false, isWritable: false },
741
+ { pubkey: PublicKey3.default, isSigner: false, isWritable: false },
742
+ { pubkey: SYSVAR_CLOCK2, isSigner: false, isWritable: false },
743
+ { pubkey: STAKE_PROGRAM2, isSigner: false, isWritable: false },
744
+ { pubkey: SYSVAR_STAKE_HISTORY2, isSigner: false, isWritable: false },
745
+ ...remainingAccounts
746
+ ],
747
+ data: Buffer.from(DEPOSIT_STAKE_DISCRIMINATOR2)
748
+ })
749
+ );
750
+ instructions.push(
751
+ manifestClient.swapIx(owner, {
752
+ inAtoms,
753
+ outAtoms,
754
+ isBaseIn: true,
755
+ isExactIn: true
756
+ })
757
+ );
758
+ const feeLamports = calculateFeeLamports(expectedSolOut);
759
+ if (feeLamports > BigInt(0)) {
760
+ instructions.push(
761
+ createTransferInstruction(wsolAta, treasuryWsol, owner, feeLamports)
762
+ );
763
+ }
764
+ instructions.push(createCloseAccountInstruction(wsolAta, owner, owner));
765
+ const message = new TransactionMessage({
766
+ payerKey: owner,
767
+ recentBlockhash: latestBlockhash.blockhash,
768
+ instructions
769
+ }).compileToV0Message([altAccount]);
770
+ const vtx = new VersionedTransaction(message);
771
+ if (splitKeypair) vtx.sign([splitKeypair]);
772
+ try {
773
+ const serialized = vtx.serialize();
774
+ console.log(
775
+ `[executeDepositAndSell] v0 tx size=${serialized.length}B (limit=1232) alt=${altPubkey.slice(0, 8)}... skipped=[ownerPt:${ownerPtExists},ownerYt:${ownerYtExists},feeWalletPt:${feeWalletPtExists},feeWalletYt:${feeWalletYtExists},wsolAta:${wsolAtaExists},treasuryWsol:${treasuryWsolExists}] feeLamports=${feeLamports}`
776
+ );
777
+ } catch (err) {
778
+ console.warn("[executeDepositAndSell] could not measure tx size:", err);
779
+ }
780
+ const signature = await wallet.sendTransaction(vtx, connection);
781
+ const confirmation = await connection.confirmTransaction(
782
+ {
783
+ signature,
784
+ blockhash: latestBlockhash.blockhash,
785
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
786
+ },
787
+ "confirmed"
788
+ );
789
+ if (confirmation.value.err) {
790
+ throw new Error(
791
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
792
+ );
793
+ }
794
+ return { signature };
795
+ }
796
+
797
+ // src/lib/execute-swap.ts
798
+ import { ManifestClient as ManifestClient2 } from "@cks-systems/manifest-sdk";
799
+ import {
800
+ PublicKey as PublicKey4,
801
+ SystemProgram,
802
+ Transaction as Transaction2
803
+ } from "@solana/web3.js";
804
+ import {
805
+ NATIVE_MINT as NATIVE_MINT2,
806
+ TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID3,
807
+ createAssociatedTokenAccountIdempotentInstruction as createAssociatedTokenAccountIdempotentInstruction3,
808
+ createCloseAccountInstruction as createCloseAccountInstruction2,
809
+ createSyncNativeInstruction,
810
+ getAssociatedTokenAddressSync as getAssociatedTokenAddressSync3
811
+ } from "@solana/spl-token";
812
+ async function executeSwap({
813
+ connection,
814
+ wallet,
815
+ marketPubkey,
816
+ orderSizeTokens,
817
+ maxPayTokens,
818
+ slippageBps
819
+ }) {
820
+ if (!wallet.publicKey || !wallet.sendTransaction) {
821
+ throw new Error("Wallet not connected");
822
+ }
823
+ const payer = wallet.publicKey;
824
+ const marketPk = new PublicKey4(marketPubkey);
825
+ const client = await ManifestClient2.getClientReadOnly(connection, marketPk);
826
+ const baseDecimals = client.market.baseDecimals();
827
+ const quoteDecimals = client.market.quoteDecimals();
828
+ const baseMint = client.market.baseMint();
829
+ const outAtoms = BigInt(Math.round(orderSizeTokens * 10 ** baseDecimals));
830
+ const inAtoms = BigInt(
831
+ Math.round(maxPayTokens * (1 + slippageBps / 1e4) * 10 ** quoteDecimals)
832
+ );
833
+ const baseAta = getAssociatedTokenAddressSync3(baseMint, payer, true, TOKEN_PROGRAM_ID3);
834
+ const wsolAta = getAssociatedTokenAddressSync3(NATIVE_MINT2, payer, true, TOKEN_PROGRAM_ID3);
835
+ const tx = new Transaction2();
836
+ tx.add(
837
+ createAssociatedTokenAccountIdempotentInstruction3(
838
+ payer,
839
+ baseAta,
840
+ payer,
841
+ baseMint
842
+ )
843
+ );
844
+ tx.add(
845
+ createAssociatedTokenAccountIdempotentInstruction3(
846
+ payer,
847
+ wsolAta,
848
+ payer,
849
+ NATIVE_MINT2
850
+ )
851
+ );
852
+ tx.add(
853
+ SystemProgram.transfer({
854
+ fromPubkey: payer,
855
+ toPubkey: wsolAta,
856
+ lamports: inAtoms
857
+ })
858
+ );
859
+ tx.add(createSyncNativeInstruction(wsolAta));
860
+ tx.add(
861
+ client.swapIx(payer, {
862
+ inAtoms,
863
+ outAtoms,
864
+ isBaseIn: false,
865
+ isExactIn: false
866
+ })
867
+ );
868
+ tx.add(createCloseAccountInstruction2(wsolAta, payer, payer));
869
+ const latestBlockhash = await connection.getLatestBlockhash("confirmed");
870
+ tx.recentBlockhash = latestBlockhash.blockhash;
871
+ tx.feePayer = payer;
872
+ const signature = await wallet.sendTransaction(tx, connection);
873
+ const confirmation = await connection.confirmTransaction(
874
+ __spreadValues({ signature }, latestBlockhash),
875
+ "confirmed"
876
+ );
877
+ if (confirmation.value.err) {
878
+ throw new Error(
879
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
880
+ );
881
+ }
882
+ return { signature };
883
+ }
884
+
885
+ // src/lib/execute-rt-sell.ts
886
+ import { ManifestClient as ManifestClient3 } from "@cks-systems/manifest-sdk";
887
+ import {
888
+ PublicKey as PublicKey5,
889
+ Transaction as Transaction3
890
+ } from "@solana/web3.js";
891
+ import {
892
+ NATIVE_MINT as NATIVE_MINT3,
893
+ TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID4,
894
+ createAssociatedTokenAccountIdempotentInstruction as createAssociatedTokenAccountIdempotentInstruction4,
895
+ createCloseAccountInstruction as createCloseAccountInstruction3,
896
+ createTransferInstruction as createTransferInstruction2,
897
+ getAssociatedTokenAddressSync as getAssociatedTokenAddressSync4
898
+ } from "@solana/spl-token";
899
+ async function executeRtSell({
900
+ connection,
901
+ wallet,
902
+ marketPubkey,
903
+ rtMint,
904
+ orderSizeTokens,
905
+ minReceiveTokens,
906
+ expectedSolOut
907
+ }) {
908
+ if (!wallet.publicKey || !wallet.sendTransaction) {
909
+ throw new Error("Wallet not connected");
910
+ }
911
+ const payer = wallet.publicKey;
912
+ const marketPk = new PublicKey5(marketPubkey);
913
+ const rtMintPk = new PublicKey5(rtMint);
914
+ const client = await ManifestClient3.getClientReadOnly(connection, marketPk);
915
+ const baseDecimals = client.market.baseDecimals();
916
+ const quoteDecimals = client.market.quoteDecimals();
917
+ const rawInAtoms = Math.floor(orderSizeTokens * 10 ** baseDecimals);
918
+ const safetyBuffer = Math.max(Math.ceil(rawInAtoms * 2e-4), 100);
919
+ const inAtoms = BigInt(Math.max(rawInAtoms - safetyBuffer, 0));
920
+ const outAtoms = BigInt(Math.floor(minReceiveTokens * 10 ** quoteDecimals));
921
+ const rtAta = getAssociatedTokenAddressSync4(rtMintPk, payer, true, TOKEN_PROGRAM_ID4);
922
+ const wsolAta = getAssociatedTokenAddressSync4(NATIVE_MINT3, payer, true, TOKEN_PROGRAM_ID4);
923
+ const treasuryWsol = getAssociatedTokenAddressSync4(
924
+ NATIVE_MINT3,
925
+ PYE_TREASURY_WALLET,
926
+ true,
927
+ TOKEN_PROGRAM_ID4
928
+ );
929
+ const tx = new Transaction3();
930
+ tx.add(
931
+ createAssociatedTokenAccountIdempotentInstruction4(
932
+ payer,
933
+ rtAta,
934
+ payer,
935
+ rtMintPk
936
+ )
937
+ );
938
+ tx.add(
939
+ createAssociatedTokenAccountIdempotentInstruction4(
940
+ payer,
941
+ wsolAta,
942
+ payer,
943
+ NATIVE_MINT3
944
+ )
945
+ );
946
+ tx.add(
947
+ createAssociatedTokenAccountIdempotentInstruction4(
948
+ payer,
949
+ treasuryWsol,
950
+ PYE_TREASURY_WALLET,
951
+ NATIVE_MINT3
952
+ )
953
+ );
954
+ tx.add(
955
+ client.swapIx(payer, {
956
+ inAtoms,
957
+ outAtoms,
958
+ isBaseIn: true,
959
+ isExactIn: true
960
+ })
961
+ );
962
+ const feeLamports = calculateFeeLamports(expectedSolOut);
963
+ if (feeLamports > BigInt(0)) {
964
+ tx.add(createTransferInstruction2(wsolAta, treasuryWsol, payer, feeLamports));
965
+ }
966
+ tx.add(createCloseAccountInstruction3(wsolAta, payer, payer));
967
+ const latestBlockhash = await connection.getLatestBlockhash("confirmed");
968
+ tx.recentBlockhash = latestBlockhash.blockhash;
969
+ tx.feePayer = payer;
970
+ const signature = await wallet.sendTransaction(tx, connection);
971
+ const confirmation = await connection.confirmTransaction(
972
+ __spreadValues({ signature }, latestBlockhash),
973
+ "confirmed"
974
+ );
975
+ if (confirmation.value.err) {
976
+ throw new Error(
977
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
978
+ );
979
+ }
980
+ return { signature };
981
+ }
982
+
983
+ // src/lib/execute-limit-order.ts
984
+ import { ManifestClient as ManifestClient4, OrderType } from "@cks-systems/manifest-sdk";
985
+ import { PublicKey as PublicKey6, Transaction as Transaction4 } from "@solana/web3.js";
986
+ async function executeLimitOrder({
987
+ connection,
988
+ wallet,
989
+ marketPubkey,
990
+ orderSizeTokens,
991
+ limitPrice
992
+ }) {
993
+ if (!wallet.publicKey || !wallet.sendTransaction) {
994
+ throw new Error("Wallet not connected");
995
+ }
996
+ const payer = wallet.publicKey;
997
+ const marketPk = new PublicKey6(marketPubkey);
998
+ let setupSignature;
999
+ const setupData = await ManifestClient4.getSetupIxs(
1000
+ connection,
1001
+ marketPk,
1002
+ payer
1003
+ );
1004
+ if (setupData.setupNeeded) {
1005
+ const setupTx = new Transaction4();
1006
+ for (const ix of setupData.instructions) {
1007
+ setupTx.add(ix);
1008
+ }
1009
+ const signers = setupData.wrapperKeypair ? [setupData.wrapperKeypair] : [];
1010
+ const setupBlockhash = await connection.getLatestBlockhash("confirmed");
1011
+ setupTx.recentBlockhash = setupBlockhash.blockhash;
1012
+ setupTx.feePayer = payer;
1013
+ setupSignature = await wallet.sendTransaction(setupTx, connection, {
1014
+ signers
1015
+ });
1016
+ const setupConfirmation = await connection.confirmTransaction(
1017
+ __spreadValues({ signature: setupSignature }, setupBlockhash),
1018
+ "confirmed"
1019
+ );
1020
+ if (setupConfirmation.value.err) {
1021
+ throw new Error(
1022
+ `Setup transaction failed on-chain: ${JSON.stringify(setupConfirmation.value.err)}`
1023
+ );
1024
+ }
1025
+ }
1026
+ const client = await ManifestClient4.getClientForMarketNoPrivateKey(
1027
+ connection,
1028
+ marketPk,
1029
+ payer
1030
+ );
1031
+ const orderIxs = await client.placeOrderWithRequiredDepositIxs(payer, {
1032
+ numBaseTokens: orderSizeTokens,
1033
+ tokenPrice: limitPrice,
1034
+ isBid: false,
1035
+ lastValidSlot: 4e9,
1036
+ orderType: OrderType.Limit,
1037
+ clientOrderId: BigInt(Date.now())
1038
+ });
1039
+ const latestBlockhash = await connection.getLatestBlockhash("confirmed");
1040
+ const tx = new Transaction4();
1041
+ tx.recentBlockhash = latestBlockhash.blockhash;
1042
+ tx.feePayer = payer;
1043
+ for (const ix of orderIxs) tx.add(ix);
1044
+ const signature = await wallet.sendTransaction(tx, connection);
1045
+ const confirmation = await connection.confirmTransaction(
1046
+ __spreadValues({ signature }, latestBlockhash),
1047
+ "confirmed"
1048
+ );
1049
+ if (confirmation.value.err) {
1050
+ throw new Error(
1051
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
1052
+ );
1053
+ }
1054
+ return { signature, setupSignature };
1055
+ }
1056
+
1057
+ // src/lib/execute-cancel-order.ts
1058
+ import {
1059
+ Market,
1060
+ createBatchUpdateInstruction,
1061
+ getVaultAddress,
1062
+ getGlobalAddress,
1063
+ getGlobalVaultAddress
1064
+ } from "@cks-systems/manifest-sdk";
1065
+ import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID5 } from "@solana/spl-token";
1066
+ import { PublicKey as PublicKey7, Transaction as Transaction5 } from "@solana/web3.js";
1067
+ async function executeCancelOrder({
1068
+ connection,
1069
+ wallet,
1070
+ marketPubkey,
1071
+ sequenceNumber
1072
+ }) {
1073
+ if (!wallet.publicKey || !wallet.sendTransaction) {
1074
+ throw new Error("Wallet not connected");
1075
+ }
1076
+ const payer = wallet.publicKey;
1077
+ const marketPk = new PublicKey7(marketPubkey);
1078
+ const market = await Market.loadFromAddress({ connection, address: marketPk });
1079
+ const baseMint = market.baseMint();
1080
+ const quoteMint = market.quoteMint();
1081
+ const cancelIx = createBatchUpdateInstruction(
1082
+ {
1083
+ payer,
1084
+ market: marketPk,
1085
+ baseMint,
1086
+ baseGlobal: getGlobalAddress(baseMint),
1087
+ baseGlobalVault: getGlobalVaultAddress(baseMint),
1088
+ baseMarketVault: getVaultAddress(marketPk, baseMint),
1089
+ baseTokenProgram: TOKEN_PROGRAM_ID5,
1090
+ quoteMint,
1091
+ quoteGlobal: getGlobalAddress(quoteMint),
1092
+ quoteGlobalVault: getGlobalVaultAddress(quoteMint),
1093
+ quoteMarketVault: getVaultAddress(marketPk, quoteMint),
1094
+ quoteTokenProgram: TOKEN_PROGRAM_ID5
1095
+ },
1096
+ {
1097
+ params: {
1098
+ cancels: [
1099
+ {
1100
+ orderSequenceNumber: BigInt(sequenceNumber),
1101
+ orderIndexHint: null
1102
+ }
1103
+ ],
1104
+ orders: [],
1105
+ traderIndexHint: null
1106
+ }
1107
+ }
1108
+ );
1109
+ const latestBlockhash = await connection.getLatestBlockhash("confirmed");
1110
+ const tx = new Transaction5();
1111
+ tx.recentBlockhash = latestBlockhash.blockhash;
1112
+ tx.feePayer = payer;
1113
+ tx.add(cancelIx);
1114
+ const signature = await wallet.sendTransaction(tx, connection);
1115
+ const confirmation = await connection.confirmTransaction(
1116
+ __spreadValues({ signature }, latestBlockhash),
1117
+ "confirmed"
1118
+ );
1119
+ if (confirmation.value.err) {
1120
+ throw new Error(
1121
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
1122
+ );
1123
+ }
1124
+ return { signature };
1125
+ }
1126
+
1127
+ // src/lib/execute-redeem.ts
1128
+ import {
1129
+ ComputeBudgetProgram as ComputeBudgetProgram3,
1130
+ Keypair as Keypair3,
1131
+ PublicKey as PublicKey8,
1132
+ Transaction as Transaction6,
1133
+ TransactionInstruction as TransactionInstruction3
1134
+ } from "@solana/web3.js";
1135
+ import {
1136
+ TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID6,
1137
+ getAssociatedTokenAddressSync as getAssociatedTokenAddressSync5
1138
+ } from "@solana/spl-token";
1139
+ var BONDS_PROGRAM_ID3 = new PublicKey8(
1140
+ "PYEQZ2qYHPQapnw8Ms8MSPMNzoq59NHHfNwAtuV26wx"
1141
+ );
1142
+ var HANDLE_MATURITY_DISC = new Uint8Array([127, 154, 109, 164, 119, 21, 34, 149]);
1143
+ var REDEEM_PT_STAKE_DISC = new Uint8Array([131, 241, 170, 225, 20, 53, 106, 95]);
1144
+ var REDEEM_YT_STAKE_DISC = new Uint8Array([143, 45, 75, 247, 229, 60, 80, 179]);
1145
+ var SYSVAR_CLOCK3 = new PublicKey8("SysvarC1ock11111111111111111111111111111111");
1146
+ var STAKE_PROGRAM3 = new PublicKey8("Stake11111111111111111111111111111111111111");
1147
+ var SYSVAR_RENT2 = new PublicKey8("SysvarRent111111111111111111111111111111111");
1148
+ var SYSVAR_STAKE_HISTORY3 = new PublicKey8("SysvarStakeHistory1111111111111111111111111");
1149
+ function deriveGlobalSettings3() {
1150
+ const [pda] = PublicKey8.findProgramAddressSync(
1151
+ [Buffer.from("global_settings")],
1152
+ BONDS_PROGRAM_ID3
1153
+ );
1154
+ return pda;
1155
+ }
1156
+ function deriveStakeAccount3(bond) {
1157
+ const [pda] = PublicKey8.findProgramAddressSync(
1158
+ [Buffer.from("stake"), bond.toBuffer()],
1159
+ BONDS_PROGRAM_ID3
1160
+ );
1161
+ return pda;
1162
+ }
1163
+ async function fetchBondData(connection, bond) {
1164
+ const info = await connection.getAccountInfo(bond);
1165
+ if (!(info == null ? void 0 : info.data)) throw new Error("Bond account not found");
1166
+ return {
1167
+ transientStakeAccount: new PublicKey8(info.data.subarray(72, 104)),
1168
+ maturityHandled: info.data[185] === 1
1169
+ };
1170
+ }
1171
+ function encodeAmount(disc, amount) {
1172
+ const ab = new ArrayBuffer(16);
1173
+ const view = new DataView(ab);
1174
+ for (let i = 0; i < 8; i++) view.setUint8(i, disc[i]);
1175
+ view.setBigUint64(8, amount, true);
1176
+ return Buffer.from(ab);
1177
+ }
1178
+ async function executeRedeem({
1179
+ connection,
1180
+ wallet,
1181
+ bondPubkey,
1182
+ principalTokenMint,
1183
+ yieldTokenMint,
1184
+ ptAmountLamports,
1185
+ rtAmountLamports
1186
+ }) {
1187
+ if (!wallet.publicKey || !wallet.sendTransaction) {
1188
+ throw new Error("Wallet not connected");
1189
+ }
1190
+ const owner = wallet.publicKey;
1191
+ const bond = new PublicKey8(bondPubkey);
1192
+ const ptMint = new PublicKey8(principalTokenMint);
1193
+ const ytMint = new PublicKey8(yieldTokenMint);
1194
+ const globalSettingsPda = deriveGlobalSettings3();
1195
+ const stakeAccountPda = deriveStakeAccount3(bond);
1196
+ const ownerPt = getAssociatedTokenAddressSync5(ptMint, owner, true);
1197
+ const ownerYt = getAssociatedTokenAddressSync5(ytMint, owner, true);
1198
+ const [bondData, latestBlockhash] = await Promise.all([
1199
+ fetchBondData(connection, bond),
1200
+ connection.getLatestBlockhash("confirmed")
1201
+ ]);
1202
+ const tx = new Transaction6();
1203
+ tx.recentBlockhash = latestBlockhash.blockhash;
1204
+ tx.feePayer = owner;
1205
+ tx.add(ComputeBudgetProgram3.setComputeUnitLimit({ units: 5e5 }));
1206
+ tx.add(ComputeBudgetProgram3.setComputeUnitPrice({ microLamports: 1e3 }));
1207
+ if (!bondData.maturityHandled) {
1208
+ const isTransientSet = !bondData.transientStakeAccount.equals(PublicKey8.default);
1209
+ tx.add(
1210
+ new TransactionInstruction3({
1211
+ programId: BONDS_PROGRAM_ID3,
1212
+ keys: [
1213
+ { pubkey: bond, isSigner: false, isWritable: true },
1214
+ { pubkey: stakeAccountPda, isSigner: false, isWritable: true },
1215
+ ...isTransientSet ? [{ pubkey: bondData.transientStakeAccount, isSigner: false, isWritable: true }] : [],
1216
+ { pubkey: ptMint, isSigner: false, isWritable: false },
1217
+ { pubkey: ytMint, isSigner: false, isWritable: false },
1218
+ { pubkey: SYSVAR_CLOCK3, isSigner: false, isWritable: false },
1219
+ { pubkey: STAKE_PROGRAM3, isSigner: false, isWritable: false },
1220
+ { pubkey: SYSVAR_STAKE_HISTORY3, isSigner: false, isWritable: false },
1221
+ { pubkey: globalSettingsPda, isSigner: false, isWritable: false }
1222
+ ],
1223
+ data: Buffer.from(HANDLE_MATURITY_DISC)
1224
+ })
1225
+ );
1226
+ }
1227
+ const signers = [];
1228
+ if (ptAmountLamports > 0) {
1229
+ const newStakeKp = Keypair3.generate();
1230
+ signers.push(newStakeKp);
1231
+ tx.add(
1232
+ new TransactionInstruction3({
1233
+ programId: BONDS_PROGRAM_ID3,
1234
+ keys: [
1235
+ { pubkey: owner, isSigner: true, isWritable: true },
1236
+ { pubkey: newStakeKp.publicKey, isSigner: true, isWritable: true },
1237
+ { pubkey: ownerPt, isSigner: false, isWritable: true },
1238
+ { pubkey: bond, isSigner: false, isWritable: true },
1239
+ { pubkey: stakeAccountPda, isSigner: false, isWritable: true },
1240
+ { pubkey: ptMint, isSigner: false, isWritable: true },
1241
+ { pubkey: TOKEN_PROGRAM_ID6, isSigner: false, isWritable: false },
1242
+ { pubkey: PublicKey8.default, isSigner: false, isWritable: false },
1243
+ { pubkey: SYSVAR_CLOCK3, isSigner: false, isWritable: false },
1244
+ { pubkey: STAKE_PROGRAM3, isSigner: false, isWritable: false },
1245
+ { pubkey: SYSVAR_RENT2, isSigner: false, isWritable: false },
1246
+ { pubkey: SYSVAR_STAKE_HISTORY3, isSigner: false, isWritable: false },
1247
+ { pubkey: globalSettingsPda, isSigner: false, isWritable: false }
1248
+ ],
1249
+ data: encodeAmount(REDEEM_PT_STAKE_DISC, BigInt(ptAmountLamports))
1250
+ })
1251
+ );
1252
+ }
1253
+ if (rtAmountLamports > 0) {
1254
+ const newStakeKp = Keypair3.generate();
1255
+ signers.push(newStakeKp);
1256
+ tx.add(
1257
+ new TransactionInstruction3({
1258
+ programId: BONDS_PROGRAM_ID3,
1259
+ keys: [
1260
+ { pubkey: owner, isSigner: true, isWritable: false },
1261
+ { pubkey: newStakeKp.publicKey, isSigner: true, isWritable: true },
1262
+ { pubkey: ownerYt, isSigner: false, isWritable: true },
1263
+ { pubkey: bond, isSigner: false, isWritable: true },
1264
+ { pubkey: stakeAccountPda, isSigner: false, isWritable: true },
1265
+ { pubkey: ytMint, isSigner: false, isWritable: true },
1266
+ { pubkey: ptMint, isSigner: false, isWritable: false },
1267
+ { pubkey: TOKEN_PROGRAM_ID6, isSigner: false, isWritable: false },
1268
+ { pubkey: PublicKey8.default, isSigner: false, isWritable: false },
1269
+ { pubkey: SYSVAR_CLOCK3, isSigner: false, isWritable: false },
1270
+ { pubkey: STAKE_PROGRAM3, isSigner: false, isWritable: false },
1271
+ { pubkey: SYSVAR_RENT2, isSigner: false, isWritable: false },
1272
+ { pubkey: SYSVAR_STAKE_HISTORY3, isSigner: false, isWritable: false },
1273
+ { pubkey: globalSettingsPda, isSigner: false, isWritable: false }
1274
+ ],
1275
+ data: encodeAmount(REDEEM_YT_STAKE_DISC, BigInt(rtAmountLamports))
1276
+ })
1277
+ );
1278
+ }
1279
+ const signature = await wallet.sendTransaction(tx, connection, { signers });
1280
+ const confirmation = await connection.confirmTransaction(
1281
+ {
1282
+ signature,
1283
+ blockhash: latestBlockhash.blockhash,
1284
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
1285
+ },
1286
+ "confirmed"
1287
+ );
1288
+ if (confirmation.value.err) {
1289
+ throw new Error(
1290
+ `Transaction failed on-chain: ${JSON.stringify(confirmation.value.err)}`
1291
+ );
1292
+ }
1293
+ return { signature };
1294
+ }
1295
+ export {
1296
+ ALLOWED_VALIDATORS,
1297
+ PYE_TRADING_FEE_BPS,
1298
+ PYE_TREASURY_WALLET,
1299
+ allTokenAddresses,
1300
+ allowedLockups,
1301
+ applyTradingFee,
1302
+ buildMarketLookup,
1303
+ buildPtLookup,
1304
+ calculateFeeLamports,
1305
+ checkBuyLiquidity,
1306
+ checkSellLiquidity,
1307
+ configurePyeSDK,
1308
+ createApyStore,
1309
+ createBalanceStore,
1310
+ createMarketStore,
1311
+ createWalletStore,
1312
+ estimateRtFromStake,
1313
+ executeCancelOrder,
1314
+ executeDepositAndSell,
1315
+ executeLimitOrder,
1316
+ executeRedeem,
1317
+ executeRtSell,
1318
+ executeStakeAccountDeposit,
1319
+ executeStakeDeposit,
1320
+ executeSwap,
1321
+ fetchBalances,
1322
+ fetchBalancesForMints,
1323
+ fetchEpochSyncedNowTs,
1324
+ fetchExchangeBalances,
1325
+ fetchLockupMetrics,
1326
+ fetchManifestMarkets,
1327
+ fetchUserStakeAccounts,
1328
+ getMaturity,
1329
+ getPyeConfig,
1330
+ lockups,
1331
+ lookupBondByVoteAccount,
1332
+ maturities,
1333
+ maturitiesArray,
1334
+ maturityIdsArray,
1335
+ parseOrderBook,
1336
+ tokenIdsArray,
1337
+ tokens,
1338
+ validators
1339
+ };
1340
+ //# sourceMappingURL=index.js.map