@0dotxyz/p0-ts-sdk 2.2.0-beta.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -118,10 +118,9 @@ function getConfig(environment = "production", overrides) {
118
118
 
119
119
  // src/errors/transaction-building.errors.ts
120
120
  var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCode2) => {
121
- TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_REPAY"] = "JUPITER_SWAP_SIZE_EXCEEDED_REPAY";
122
- TransactionBuildingErrorCode2["JUPITER_SWAP_SIZE_EXCEEDED_LOOP"] = "JUPITER_SWAP_SIZE_EXCEEDED_LOOP";
123
121
  TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_LOOP"] = "SWAP_SIZE_EXCEEDED_LOOP";
124
122
  TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_REPAY"] = "SWAP_SIZE_EXCEEDED_REPAY";
123
+ TransactionBuildingErrorCode2["SWAP_SIZE_EXCEEDED_POSITION_SWAP"] = "SWAP_SIZE_EXCEEDED_POSITION_SWAP";
125
124
  TransactionBuildingErrorCode2["ORACLE_CRANK_FAILED"] = "ORACLE_CRANK_FAILED";
126
125
  TransactionBuildingErrorCode2["KAMINO_RESERVE_NOT_FOUND"] = "KAMINO_RESERVE_NOT_FOUND";
127
126
  TransactionBuildingErrorCode2["DRIFT_STATE_NOT_FOUND"] = "DRIFT_STATE_NOT_FOUND";
@@ -142,23 +141,6 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
142
141
  Error.captureStackTrace(this, _TransactionBuildingError);
143
142
  }
144
143
  }
145
- /**
146
- * Jupiter swap instruction size exceeds available transaction size
147
- */
148
- static jupiterSwapSizeExceededLoop(bytes, accountKeys) {
149
- return new _TransactionBuildingError(
150
- "JUPITER_SWAP_SIZE_EXCEEDED_LOOP" /* JUPITER_SWAP_SIZE_EXCEEDED_LOOP */,
151
- "Jupiter swap instruction size exceeds available transaction size",
152
- { bytes, accountKeys }
153
- );
154
- }
155
- static jupiterSwapSizeExceededRepay(bytes, accountKeys) {
156
- return new _TransactionBuildingError(
157
- "JUPITER_SWAP_SIZE_EXCEEDED_REPAY" /* JUPITER_SWAP_SIZE_EXCEEDED_REPAY */,
158
- "Jupiter swap instruction size exceeds available transaction size",
159
- { bytes, accountKeys }
160
- );
161
- }
162
144
  static swapSizeExceededLoop(bytes, accountKeys, provider) {
163
145
  return new _TransactionBuildingError(
164
146
  "SWAP_SIZE_EXCEEDED_LOOP" /* SWAP_SIZE_EXCEEDED_LOOP */,
@@ -173,6 +155,13 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
173
155
  { bytes, accountKeys, provider }
174
156
  );
175
157
  }
158
+ static swapSizeExceededPositionSwap(bytes, accountKeys, provider) {
159
+ return new _TransactionBuildingError(
160
+ "SWAP_SIZE_EXCEEDED_POSITION_SWAP" /* SWAP_SIZE_EXCEEDED_POSITION_SWAP */,
161
+ `${provider ?? "Swap"} instruction size exceeds available transaction size`,
162
+ { bytes, accountKeys, provider }
163
+ );
164
+ }
176
165
  /**
177
166
  * Failed to crank oracles for one or more banks
178
167
  */
@@ -15163,9 +15152,48 @@ var MintLayout = bufferLayout.struct([
15163
15152
  bufferLayoutUtils.publicKey("freezeAuthority")
15164
15153
  ]);
15165
15154
  MintLayout.span;
15155
+ var approveInstructionData = bufferLayout.struct([
15156
+ bufferLayout.u8("instruction"),
15157
+ bufferLayoutUtils.u64("amount")
15158
+ ]);
15159
+ function createApproveInstruction(account, delegate, owner, amount, multiSigners = [], programId = TOKEN_PROGRAM_ID) {
15160
+ const keys = addSigners(
15161
+ [
15162
+ { pubkey: account, isSigner: false, isWritable: true },
15163
+ { pubkey: delegate, isSigner: false, isWritable: false }
15164
+ ],
15165
+ owner,
15166
+ multiSigners
15167
+ );
15168
+ const data = buffer.Buffer.alloc(approveInstructionData.span);
15169
+ approveInstructionData.encode(
15170
+ {
15171
+ instruction: 4 /* Approve */,
15172
+ amount: BigInt(amount)
15173
+ },
15174
+ data
15175
+ );
15176
+ return new web3_js.TransactionInstruction({ keys, programId, data });
15177
+ }
15166
15178
  bufferLayout.struct([
15167
15179
  bufferLayout.u8("instruction")
15168
15180
  ]);
15181
+ function createAssociatedTokenAccountInstruction(payer, associatedToken, owner, mint, programId = TOKEN_PROGRAM_ID, associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID) {
15182
+ const keys = [
15183
+ { pubkey: payer, isSigner: true, isWritable: true },
15184
+ { pubkey: associatedToken, isSigner: false, isWritable: true },
15185
+ { pubkey: owner, isSigner: false, isWritable: false },
15186
+ { pubkey: mint, isSigner: false, isWritable: false },
15187
+ { pubkey: web3_js.SystemProgram.programId, isSigner: false, isWritable: false },
15188
+ { pubkey: programId, isSigner: false, isWritable: false },
15189
+ { pubkey: web3_js.SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }
15190
+ ];
15191
+ return new web3_js.TransactionInstruction({
15192
+ keys,
15193
+ programId: associatedTokenProgramId,
15194
+ data: buffer.Buffer.alloc(0)
15195
+ });
15196
+ }
15169
15197
  function createAssociatedTokenAccountIdempotentInstruction(payer, associatedToken, owner, mint, programId = TOKEN_PROGRAM_ID, associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID) {
15170
15198
  return buildAssociatedTokenAccountInstruction(
15171
15199
  payer,
@@ -43378,6 +43406,173 @@ new Fraction(new BN11__default.default(0));
43378
43406
  function roundNearest(decimal) {
43379
43407
  return decimal.toDecimalPlaces(0, Decimal3__default.default.ROUND_HALF_CEIL);
43380
43408
  }
43409
+ var SinglePoolInstruction = {
43410
+ initializePool: (voteAccount) => {
43411
+ const pool = findPoolAddress(voteAccount);
43412
+ const stake = findPoolStakeAddress(pool);
43413
+ const mint = findPoolMintAddress(pool);
43414
+ const stakeAuthority = findPoolStakeAuthorityAddress(pool);
43415
+ const mintAuthority = findPoolMintAuthorityAddress(pool);
43416
+ return createTransactionInstruction(
43417
+ SINGLE_POOL_PROGRAM_ID,
43418
+ [
43419
+ { pubkey: voteAccount, isSigner: false, isWritable: false },
43420
+ { pubkey: pool, isSigner: false, isWritable: true },
43421
+ { pubkey: stake, isSigner: false, isWritable: true },
43422
+ { pubkey: mint, isSigner: false, isWritable: true },
43423
+ { pubkey: stakeAuthority, isSigner: false, isWritable: false },
43424
+ { pubkey: mintAuthority, isSigner: false, isWritable: false },
43425
+ { pubkey: SYSVAR_RENT_ID, isSigner: false, isWritable: false },
43426
+ { pubkey: SYSVAR_CLOCK_ID, isSigner: false, isWritable: false },
43427
+ { pubkey: SYSVAR_STAKE_HISTORY_ID, isSigner: false, isWritable: false },
43428
+ { pubkey: web3_js.STAKE_CONFIG_ID, isSigner: false, isWritable: false },
43429
+ { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
43430
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
43431
+ { pubkey: STAKE_PROGRAM_ID, isSigner: false, isWritable: false }
43432
+ ],
43433
+ Buffer.from([0 /* InitializePool */])
43434
+ );
43435
+ },
43436
+ initializeOnRamp: (pool) => {
43437
+ const onRamp = findPoolOnRampAddress(pool);
43438
+ const stakeAuthority = findPoolStakeAuthorityAddress(pool);
43439
+ return createTransactionInstruction(
43440
+ SINGLE_POOL_PROGRAM_ID,
43441
+ [
43442
+ { pubkey: pool, isSigner: false, isWritable: false },
43443
+ { pubkey: onRamp, isSigner: false, isWritable: true },
43444
+ { pubkey: stakeAuthority, isSigner: false, isWritable: false },
43445
+ { pubkey: SYSVAR_RENT_ID, isSigner: false, isWritable: false },
43446
+ { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false },
43447
+ { pubkey: STAKE_PROGRAM_ID, isSigner: false, isWritable: false }
43448
+ ],
43449
+ Buffer.from([6 /* InitializeOnRamp */])
43450
+ );
43451
+ },
43452
+ depositStake: async (pool, userStakeAccount, userTokenAccount, userLamportAccount) => {
43453
+ const stake = findPoolStakeAddress(pool);
43454
+ const onRamp = findPoolOnRampAddress(pool);
43455
+ const mint = findPoolMintAddress(pool);
43456
+ const stakeAuthority = findPoolStakeAuthorityAddress(pool);
43457
+ const mintAuthority = findPoolMintAuthorityAddress(pool);
43458
+ return createTransactionInstruction(
43459
+ SINGLE_POOL_PROGRAM_ID,
43460
+ [
43461
+ { pubkey: pool, isSigner: false, isWritable: false },
43462
+ { pubkey: stake, isSigner: false, isWritable: true },
43463
+ { pubkey: onRamp, isSigner: false, isWritable: false },
43464
+ { pubkey: mint, isSigner: false, isWritable: true },
43465
+ { pubkey: stakeAuthority, isSigner: false, isWritable: false },
43466
+ { pubkey: mintAuthority, isSigner: false, isWritable: false },
43467
+ { pubkey: userStakeAccount, isSigner: false, isWritable: true },
43468
+ { pubkey: userTokenAccount, isSigner: false, isWritable: true },
43469
+ { pubkey: userLamportAccount, isSigner: false, isWritable: true },
43470
+ { pubkey: SYSVAR_CLOCK_ID, isSigner: false, isWritable: false },
43471
+ { pubkey: SYSVAR_STAKE_HISTORY_ID, isSigner: false, isWritable: false },
43472
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
43473
+ { pubkey: STAKE_PROGRAM_ID, isSigner: false, isWritable: false }
43474
+ ],
43475
+ Buffer.from([2 /* DepositStake */])
43476
+ );
43477
+ },
43478
+ withdrawStake: async (pool, userStakeAccount, userStakeAuthority, userTokenAccount, tokenAmount) => {
43479
+ const stake = findPoolStakeAddress(pool);
43480
+ const onRamp = findPoolOnRampAddress(pool);
43481
+ const mint = findPoolMintAddress(pool);
43482
+ const stakeAuthority = findPoolStakeAuthorityAddress(pool);
43483
+ const mintAuthority = findPoolMintAuthorityAddress(pool);
43484
+ const rawAmount = BigInt(tokenAmount.multipliedBy(1e9).toString());
43485
+ const data = Buffer.concat([
43486
+ Buffer.from([3 /* WithdrawStake */]),
43487
+ userStakeAuthority.toBuffer(),
43488
+ Buffer.from(new BN11.BN(rawAmount.toString()).toArray("le", 8))
43489
+ ]);
43490
+ return createTransactionInstruction(
43491
+ SINGLE_POOL_PROGRAM_ID,
43492
+ [
43493
+ { pubkey: pool, isSigner: false, isWritable: false },
43494
+ { pubkey: stake, isSigner: false, isWritable: true },
43495
+ { pubkey: onRamp, isSigner: false, isWritable: false },
43496
+ { pubkey: mint, isSigner: false, isWritable: true },
43497
+ { pubkey: stakeAuthority, isSigner: false, isWritable: false },
43498
+ { pubkey: mintAuthority, isSigner: false, isWritable: false },
43499
+ { pubkey: userStakeAccount, isSigner: false, isWritable: true },
43500
+ { pubkey: userTokenAccount, isSigner: false, isWritable: true },
43501
+ { pubkey: SYSVAR_CLOCK_ID, isSigner: false, isWritable: false },
43502
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
43503
+ { pubkey: STAKE_PROGRAM_ID, isSigner: false, isWritable: false }
43504
+ ],
43505
+ data
43506
+ );
43507
+ },
43508
+ createTokenMetadata: async (pool, payer) => {
43509
+ const mint = findPoolMintAddress(pool);
43510
+ const [mintAuthority, mplAuthority, mplMetadata] = await Promise.all([
43511
+ findPoolMintAuthorityAddress(pool),
43512
+ findPoolMplAuthorityAddress(pool),
43513
+ findMplMetadataAddress(mint)
43514
+ ]);
43515
+ return createTransactionInstruction(
43516
+ SINGLE_POOL_PROGRAM_ID,
43517
+ [
43518
+ { pubkey: pool, isSigner: false, isWritable: false },
43519
+ { pubkey: mint, isSigner: false, isWritable: false },
43520
+ { pubkey: mintAuthority, isSigner: false, isWritable: false },
43521
+ { pubkey: mplAuthority, isSigner: false, isWritable: false },
43522
+ { pubkey: payer, isSigner: true, isWritable: true },
43523
+ { pubkey: mplMetadata, isSigner: false, isWritable: true },
43524
+ { pubkey: MPL_METADATA_PROGRAM_ID, isSigner: false, isWritable: false },
43525
+ { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false }
43526
+ ],
43527
+ Buffer.from([4 /* CreateTokenMetadata */])
43528
+ );
43529
+ },
43530
+ updateTokenMetadata: async (voteAccount, authorizedWithdrawer, tokenName, tokenSymbol, tokenUri = "") => {
43531
+ if (tokenName.length > 32) {
43532
+ throw new Error("maximum token name length is 32 characters");
43533
+ }
43534
+ if (tokenSymbol.length > 10) {
43535
+ throw new Error("maximum token symbol length is 10 characters");
43536
+ }
43537
+ if (tokenUri.length > 200) {
43538
+ throw new Error("maximum token uri length is 200 characters");
43539
+ }
43540
+ const pool = findPoolAddress(voteAccount);
43541
+ const [mint, mplAuthority] = await Promise.all([
43542
+ findPoolMintAddress(pool),
43543
+ findPoolMplAuthorityAddress(pool)
43544
+ ]);
43545
+ const mplMetadata = await findMplMetadataAddress(mint);
43546
+ const data = Buffer.concat([
43547
+ Buffer.from([5 /* UpdateTokenMetadata */]),
43548
+ Buffer.from(new Uint32Array([tokenName.length]).buffer),
43549
+ Buffer.from(tokenName),
43550
+ Buffer.from(new Uint32Array([tokenSymbol.length]).buffer),
43551
+ Buffer.from(tokenSymbol),
43552
+ Buffer.from(new Uint32Array([tokenUri.length]).buffer),
43553
+ Buffer.from(tokenUri)
43554
+ ]);
43555
+ return createTransactionInstruction(
43556
+ SINGLE_POOL_PROGRAM_ID,
43557
+ [
43558
+ { pubkey: voteAccount, isSigner: false, isWritable: false },
43559
+ { pubkey: pool, isSigner: false, isWritable: false },
43560
+ { pubkey: mplAuthority, isSigner: false, isWritable: false },
43561
+ { pubkey: authorizedWithdrawer, isSigner: true, isWritable: false },
43562
+ { pubkey: mplMetadata, isSigner: false, isWritable: true },
43563
+ { pubkey: MPL_METADATA_PROGRAM_ID, isSigner: false, isWritable: false }
43564
+ ],
43565
+ data
43566
+ );
43567
+ }
43568
+ };
43569
+ var createTransactionInstruction = (programId, keys, data) => {
43570
+ return {
43571
+ programId,
43572
+ keys,
43573
+ data
43574
+ };
43575
+ };
43381
43576
  var findPda = (baseAddress, prefix, programId = SINGLE_POOL_PROGRAM_ID) => {
43382
43577
  const [pda] = web3_js.PublicKey.findProgramAddressSync(
43383
43578
  [Buffer.from(prefix), baseAddress.toBuffer()],
@@ -43388,7 +43583,17 @@ var findPda = (baseAddress, prefix, programId = SINGLE_POOL_PROGRAM_ID) => {
43388
43583
  var findPoolAddress = (voteAccountAddress) => findPda(voteAccountAddress, "pool");
43389
43584
  var findPoolMintAddress = (poolAddress) => findPda(poolAddress, "mint");
43390
43585
  var findPoolStakeAddress = (poolAddress) => findPda(poolAddress, "stake");
43586
+ var findPoolStakeAuthorityAddress = (poolAddress) => findPda(poolAddress, "stake_authority");
43587
+ var findPoolMintAuthorityAddress = (poolAddress) => findPda(poolAddress, "mint_authority");
43588
+ var findPoolMplAuthorityAddress = (poolAddress) => findPda(poolAddress, "mpl_authority");
43391
43589
  var findPoolOnRampAddress = (poolAddress) => findPda(poolAddress, "onramp");
43590
+ var findMplMetadataAddress = async (poolMintAddress) => {
43591
+ const [pda] = web3_js.PublicKey.findProgramAddressSync(
43592
+ [Buffer.from("metadata"), MPL_METADATA_PROGRAM_ID.toBuffer(), poolMintAddress.toBuffer()],
43593
+ MPL_METADATA_PROGRAM_ID
43594
+ );
43595
+ return pda;
43596
+ };
43392
43597
  BigInt(33);
43393
43598
  BigInt(200);
43394
43599
  BigInt(82);
@@ -44169,12 +44374,28 @@ var V1Client = class _V1Client {
44169
44374
  return new Promise((resolve, reject) => {
44170
44375
  const ws = new WebSocket__default.default(url, [SUBPROTOCOL]);
44171
44376
  ws.binaryType = "arraybuffer";
44172
- ws.on("open", () => {
44377
+ const onOpen = () => {
44378
+ ws.off("error", onError);
44379
+ ws.off("close", onClose);
44173
44380
  resolve(new _V1Client(ws));
44174
- });
44175
- ws.on("error", (err) => {
44381
+ };
44382
+ const onError = (err) => {
44383
+ ws.off("open", onOpen);
44384
+ ws.off("close", onClose);
44176
44385
  reject(err);
44177
- });
44386
+ };
44387
+ const onClose = (code, reason) => {
44388
+ ws.off("open", onOpen);
44389
+ ws.off("error", onError);
44390
+ reject(
44391
+ new Error(
44392
+ `WebSocket closed before open (code=${code}${reason.length ? `, reason=${reason.toString()}` : ""})`
44393
+ )
44394
+ );
44395
+ };
44396
+ ws.once("open", onOpen);
44397
+ ws.once("error", onError);
44398
+ ws.once("close", onClose);
44178
44399
  });
44179
44400
  }
44180
44401
  // --- Constructor ---
@@ -46175,10 +46396,11 @@ async function makeBorrowIx3({
46175
46396
  );
46176
46397
  borrowIxs.push(createAtaIdempotentIx);
46177
46398
  }
46399
+ const mandatoryBanks = [bank.address, ...opts.additionalHealthCheckBanks ?? []];
46178
46400
  const healthAccounts = computeHealthCheckAccounts(
46179
46401
  marginfiAccount.balances,
46180
46402
  bankMap,
46181
- [bank.address],
46403
+ mandatoryBanks,
46182
46404
  []
46183
46405
  );
46184
46406
  const remainingAccounts = [];
@@ -46713,81 +46935,116 @@ async function makeJuplendDepositTx(params) {
46713
46935
  });
46714
46936
  return solanaTx;
46715
46937
  }
46716
- async function makeRepayIx3({
46717
- program,
46718
- bank,
46719
- tokenProgram,
46720
- amount,
46721
- authority,
46722
- accountAddress,
46723
- repayAll = false,
46724
- isSync = false,
46725
- opts = {}
46726
- }) {
46727
- const wrapAndUnwrapSol = opts.wrapAndUnwrapSol ?? true;
46728
- const wSolBalanceUi = opts.wSolBalanceUi ?? 0;
46729
- const repayIxs = [];
46730
- const userAta = getAssociatedTokenAddressSync(bank.mint, authority, true, tokenProgram);
46731
- const remainingAccounts = tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? [{ pubkey: bank.mint, isSigner: false, isWritable: false }] : [];
46732
- if (bank.mint.equals(NATIVE_MINT) && wrapAndUnwrapSol) {
46733
- repayIxs.push(...makeWrapSolIxs(authority, new BigNumber3.BigNumber(amount).minus(wSolBalanceUi)));
46734
- }
46735
- const repayIx = !isSync || !opts.overrideInferAccounts?.group ? await instructions_default.makeRepayIx(
46938
+ async function makeBeginFlashLoanIx3(program, marginfiAccountPk, endIndex, authority, isSync) {
46939
+ const ix = isSync && authority ? sync_instructions_default.makeBeginFlashLoanIx(
46940
+ program.programId,
46941
+ {
46942
+ marginfiAccount: marginfiAccountPk,
46943
+ authority
46944
+ },
46945
+ { endIndex: new BN11__default.default(endIndex) }
46946
+ ) : await instructions_default.makeBeginFlashLoanIx(
46736
46947
  program,
46737
46948
  {
46738
- marginfiAccount: accountAddress,
46739
- signerTokenAccount: userAta,
46740
- bank: bank.address,
46741
- tokenProgram,
46742
- authority: opts.overrideInferAccounts?.authority ?? authority,
46743
- group: opts.overrideInferAccounts?.group,
46744
- liquidityVault: opts.overrideInferAccounts?.liquidityVault
46949
+ marginfiAccount: marginfiAccountPk,
46950
+ authority
46745
46951
  },
46746
- { amount: uiToNative(amount, bank.mintDecimals), repayAll },
46747
- remainingAccounts
46748
- ) : sync_instructions_default.makeRepayIx(
46952
+ { endIndex: new BN11__default.default(endIndex) }
46953
+ );
46954
+ return { instructions: [ix], keys: [] };
46955
+ }
46956
+ async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
46957
+ const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
46958
+ const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
46749
46959
  program.programId,
46750
46960
  {
46751
- marginfiAccount: accountAddress,
46752
- signerTokenAccount: userAta,
46753
- bank: bank.address,
46754
- tokenProgram,
46755
- authority: opts.overrideInferAccounts?.authority ?? authority,
46756
- group: opts.overrideInferAccounts?.group
46961
+ marginfiAccount: marginfiAccountPk,
46962
+ authority
46757
46963
  },
46758
- { amount: uiToNative(amount, bank.mintDecimals), repayAll },
46759
- remainingAccounts
46964
+ remainingAccounts.map((account) => ({
46965
+ pubkey: account,
46966
+ isSigner: false,
46967
+ isWritable: false
46968
+ }))
46969
+ ) : await instructions_default.makeEndFlashLoanIx(
46970
+ program,
46971
+ {
46972
+ marginfiAccount: marginfiAccountPk,
46973
+ authority
46974
+ },
46975
+ remainingAccounts.map((account) => ({
46976
+ pubkey: account,
46977
+ isSigner: false,
46978
+ isWritable: false
46979
+ }))
46760
46980
  );
46761
- repayIxs.push(repayIx);
46762
- return {
46763
- instructions: repayIxs,
46764
- keys: []
46765
- };
46981
+ return { instructions: [ix], keys: [] };
46766
46982
  }
46767
- async function makeRepayTx(params) {
46768
- const { luts, ...depositIxParams } = params;
46769
- const ixs = await makeRepayIx3(depositIxParams);
46770
- const tx = new web3_js.Transaction().add(...ixs.instructions);
46771
- tx.feePayer = params.authority;
46772
- const solanaTx = addTransactionMetadata(tx, {
46773
- type: "REPAY" /* REPAY */,
46774
- signers: ixs.keys,
46775
- addressLookupTables: luts
46983
+ async function makeFlashLoanTx({
46984
+ program,
46985
+ marginfiAccount,
46986
+ ixs,
46987
+ bankMap,
46988
+ blockhash,
46989
+ addressLookupTableAccounts,
46990
+ signers,
46991
+ isSync
46992
+ }) {
46993
+ const endIndex = ixs.length + 1;
46994
+ const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
46995
+ marginfiAccount.balances,
46996
+ ixs,
46997
+ program
46998
+ );
46999
+ const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
47000
+ const b = bankMap.get(account.toBase58());
47001
+ if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
47002
+ return b;
46776
47003
  });
46777
- return solanaTx;
47004
+ const beginFlashLoanIx = await makeBeginFlashLoanIx3(
47005
+ program,
47006
+ marginfiAccount.address,
47007
+ endIndex,
47008
+ marginfiAccount.authority,
47009
+ isSync
47010
+ );
47011
+ const endFlashLoanIx = await makeEndFlashLoanIx3(
47012
+ program,
47013
+ marginfiAccount.address,
47014
+ projectedActiveBanks,
47015
+ marginfiAccount.authority,
47016
+ isSync
47017
+ );
47018
+ const message = new web3_js.TransactionMessage({
47019
+ payerKey: marginfiAccount.authority,
47020
+ recentBlockhash: blockhash,
47021
+ instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
47022
+ }).compileToV0Message(addressLookupTableAccounts);
47023
+ const tx = addTransactionMetadata(new web3_js.VersionedTransaction(message), {
47024
+ addressLookupTables: addressLookupTableAccounts,
47025
+ type: "FLASHLOAN" /* FLASHLOAN */,
47026
+ signers
47027
+ });
47028
+ if (signers) {
47029
+ tx.sign(signers);
47030
+ }
47031
+ return tx;
46778
47032
  }
46779
- async function makeRepayWithCollatTx(params) {
47033
+
47034
+ // src/services/account/actions/loop.ts
47035
+ async function makeLoopTx(params) {
46780
47036
  const {
46781
47037
  program,
46782
47038
  marginfiAccount,
46783
47039
  bankMap,
46784
- withdrawOpts,
46785
- repayOpts,
47040
+ depositOpts,
47041
+ borrowOpts,
46786
47042
  bankMetadataMap,
46787
47043
  addressLookupTableAccounts,
46788
47044
  connection,
46789
47045
  oraclePrices,
46790
- crossbarUrl
47046
+ crossbarUrl,
47047
+ additionalIxs = []
46791
47048
  } = params;
46792
47049
  const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
46793
47050
  const setupIxs = await makeSetupIx({
@@ -46795,34 +47052,34 @@ async function makeRepayWithCollatTx(params) {
46795
47052
  authority: marginfiAccount.authority,
46796
47053
  tokens: [
46797
47054
  {
46798
- mint: repayOpts.repayBank.mint,
46799
- tokenProgram: repayOpts.tokenProgram
47055
+ mint: borrowOpts.borrowBank.mint,
47056
+ tokenProgram: borrowOpts.tokenProgram
46800
47057
  },
46801
47058
  {
46802
- mint: withdrawOpts.withdrawBank.mint,
46803
- tokenProgram: withdrawOpts.tokenProgram
47059
+ mint: depositOpts.depositBank.mint,
47060
+ tokenProgram: depositOpts.tokenProgram
46804
47061
  }
46805
47062
  ]
46806
47063
  });
46807
- const updateJuplendMarketIxs = makeUpdateJupLendRateIxs(
46808
- marginfiAccount,
46809
- bankMap,
46810
- [withdrawOpts.withdrawBank.address],
46811
- bankMetadataMap
47064
+ const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
47065
+ params.marginfiAccount,
47066
+ params.bankMap,
47067
+ [depositOpts.depositBank.address],
47068
+ params.bankMetadataMap
46812
47069
  );
46813
47070
  const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
46814
- marginfiAccount,
46815
- bankMap,
46816
- [withdrawOpts.withdrawBank.address],
46817
- bankMetadataMap
47071
+ params.marginfiAccount,
47072
+ params.bankMap,
47073
+ [depositOpts.depositBank.address],
47074
+ params.bankMetadataMap
46818
47075
  );
46819
47076
  const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
46820
47077
  marginfiAccount,
46821
47078
  bankMap,
46822
- [withdrawOpts.withdrawBank.address, repayOpts.repayBank.address],
47079
+ [borrowOpts.borrowBank.address, depositOpts.depositBank.address],
46823
47080
  bankMetadataMap
46824
47081
  );
46825
- const { flashloanTx, setupInstructions, swapQuote, amountToRepay, withdrawIxs, repayIxs } = await buildRepayWithCollatFlashloanTx({
47082
+ const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
46826
47083
  ...params,
46827
47084
  blockhash
46828
47085
  });
@@ -46832,7 +47089,7 @@ async function makeRepayWithCollatTx(params) {
46832
47089
  }
46833
47090
  if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
46834
47091
  const mintKey = ix.keys[3]?.pubkey;
46835
- if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(repayOpts.repayBank.mint)) {
47092
+ if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
46836
47093
  return false;
46837
47094
  }
46838
47095
  }
@@ -46844,18 +47101,24 @@ async function makeRepayWithCollatTx(params) {
46844
47101
  bankMap,
46845
47102
  oraclePrices,
46846
47103
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
46847
- instructions: [...withdrawIxs.instructions, ...repayIxs.instructions],
47104
+ instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
46848
47105
  program,
46849
47106
  connection,
46850
47107
  crossbarUrl
46851
47108
  });
46852
47109
  let additionalTxs = [];
46853
- if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJuplendMarketIxs.instructions.length > 0) {
47110
+ if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
47111
+ setupIxs.push(
47112
+ ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber3.BigNumber(depositOpts.inputDepositAmount))
47113
+ );
47114
+ }
47115
+ if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
46854
47116
  const ixs = [
47117
+ ...additionalIxs,
46855
47118
  ...setupIxs,
46856
47119
  ...kaminoRefreshIxs.instructions,
46857
47120
  ...updateDriftMarketIxs.instructions,
46858
- ...updateJuplendMarketIxs.instructions
47121
+ ...updateJupLendRateIxs.instructions
46859
47122
  ];
46860
47123
  const txs = splitInstructionsToFitTransactions([], ixs, {
46861
47124
  blockhash,
@@ -46885,16 +47148,19 @@ async function makeRepayWithCollatTx(params) {
46885
47148
  );
46886
47149
  }
46887
47150
  const transactions = [...additionalTxs, flashloanTx];
46888
- return { transactions, swapQuote, amountToRepay };
47151
+ return {
47152
+ transactions,
47153
+ actionTxIndex: transactions.length - 1,
47154
+ quoteResponse: swapQuote
47155
+ };
46889
47156
  }
46890
- async function buildRepayWithCollatFlashloanTx({
47157
+ async function buildLoopFlashloanTx({
46891
47158
  program,
46892
47159
  marginfiAccount,
46893
47160
  bankMap,
46894
- withdrawOpts,
46895
- repayOpts,
47161
+ borrowOpts,
47162
+ depositOpts,
46896
47163
  bankMetadataMap,
46897
- assetShareValueMultiplierByBank,
46898
47164
  addressLookupTableAccounts,
46899
47165
  connection,
46900
47166
  swapOpts,
@@ -46905,20 +47171,20 @@ async function buildRepayWithCollatFlashloanTx({
46905
47171
  web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
46906
47172
  web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
46907
47173
  ];
46908
- let amountToRepay;
47174
+ let amountToDeposit;
46909
47175
  let swapInstructions = [];
46910
47176
  let setupInstructions = [];
46911
47177
  let swapLookupTables = [];
46912
47178
  let swapQuote;
46913
47179
  let sizeConstraintUsed = 0;
46914
- if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
46915
- amountToRepay = withdrawOpts.withdrawAmount;
47180
+ if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
47181
+ amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
46916
47182
  } else {
46917
47183
  const destinationTokenAccount = getAssociatedTokenAddressSync(
46918
- new web3_js.PublicKey(repayOpts.repayBank.mint),
47184
+ new web3_js.PublicKey(depositOpts.depositBank.mint),
46919
47185
  marginfiAccount.authority,
46920
47186
  true,
46921
- repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47187
+ depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
46922
47188
  );
46923
47189
  const swapConstraints = await computeFlashloanSwapConstraints({
46924
47190
  program,
@@ -46927,24 +47193,21 @@ async function buildRepayWithCollatFlashloanTx({
46927
47193
  bankMetadataMap,
46928
47194
  addressLookupTableAccounts: addressLookupTableAccounts ?? [],
46929
47195
  primaryIx: {
46930
- type: "withdraw",
46931
- bank: withdrawOpts.withdrawBank,
46932
- tokenProgram: withdrawOpts.tokenProgram
47196
+ type: "borrow",
47197
+ bank: borrowOpts.borrowBank,
47198
+ tokenProgram: borrowOpts.tokenProgram
46933
47199
  },
46934
47200
  secondaryIx: {
46935
- type: "repay",
46936
- bank: repayOpts.repayBank,
46937
- tokenProgram: repayOpts.tokenProgram
47201
+ type: "deposit",
47202
+ bank: depositOpts.depositBank,
47203
+ tokenProgram: depositOpts.tokenProgram
46938
47204
  },
46939
47205
  overrideInferAccounts
46940
47206
  });
46941
47207
  const swapResponse = await getSwapIxsForFlashloan({
46942
- inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
46943
- outputMint: repayOpts.repayBank.mint.toBase58(),
46944
- amount: uiToNative(
46945
- withdrawOpts.withdrawAmount,
46946
- withdrawOpts.withdrawBank.mintDecimals
46947
- ).toNumber(),
47208
+ inputMint: borrowOpts.borrowBank.mint.toBase58(),
47209
+ outputMint: depositOpts.depositBank.mint.toBase58(),
47210
+ amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
46948
47211
  swapMode: "ExactIn",
46949
47212
  authority: marginfiAccount.authority,
46950
47213
  connection,
@@ -46954,50 +47217,52 @@ async function buildRepayWithCollatFlashloanTx({
46954
47217
  maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
46955
47218
  });
46956
47219
  sizeConstraintUsed = swapConstraints.sizeConstraint;
46957
- const { quoteResponse } = swapResponse;
46958
- const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
46959
47220
  const outAmountThreshold = nativeToUi(
46960
- quoteResponse.otherAmountThreshold,
46961
- repayOpts.repayBank.mintDecimals
47221
+ swapResponse.quoteResponse.otherAmountThreshold,
47222
+ depositOpts.depositBank.mintDecimals
46962
47223
  );
46963
- amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
47224
+ amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
46964
47225
  swapInstructions = swapResponse.swapInstructions;
47226
+ setupInstructions = swapResponse.setupInstructions;
46965
47227
  swapLookupTables = swapResponse.addressLookupTableAddresses;
46966
- swapQuote = quoteResponse;
47228
+ swapQuote = swapResponse.quoteResponse;
46967
47229
  }
46968
- let withdrawIxs;
46969
- switch (withdrawOpts.withdrawBank.config.assetTag) {
47230
+ const borrowIxs = await makeBorrowIx3({
47231
+ program,
47232
+ bank: borrowOpts.borrowBank,
47233
+ bankMap,
47234
+ tokenProgram: borrowOpts.tokenProgram,
47235
+ amount: borrowOpts.borrowAmount,
47236
+ marginfiAccount,
47237
+ authority: marginfiAccount.authority,
47238
+ isSync: false,
47239
+ opts: {
47240
+ createAtas: false,
47241
+ wrapAndUnwrapSol: false,
47242
+ overrideInferAccounts
47243
+ }
47244
+ });
47245
+ let depositIxs;
47246
+ switch (depositOpts.depositBank.config.assetTag) {
46970
47247
  case 3 /* KAMINO */: {
46971
- const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
47248
+ const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
46972
47249
  if (!reserve) {
46973
47250
  throw TransactionBuildingError.kaminoReserveNotFound(
46974
- withdrawOpts.withdrawBank.address.toBase58(),
46975
- withdrawOpts.withdrawBank.mint.toBase58(),
46976
- withdrawOpts.withdrawBank.tokenSymbol
47251
+ depositOpts.depositBank.address.toBase58(),
47252
+ depositOpts.depositBank.mint.toBase58(),
47253
+ depositOpts.depositBank.tokenSymbol
46977
47254
  );
46978
47255
  }
46979
- const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber3.BigNumber(1);
46980
- const adjustedAmount = new BigNumber3.BigNumber(withdrawOpts.withdrawAmount).div(multiplier).times(1.0001).toNumber();
46981
- withdrawIxs = await makeKaminoWithdrawIx3({
47256
+ depositIxs = await makeKaminoDepositIx3({
46982
47257
  program,
46983
- bank: withdrawOpts.withdrawBank,
46984
- bankMap,
46985
- tokenProgram: withdrawOpts.tokenProgram,
46986
- cTokenAmount: adjustedAmount,
46987
- marginfiAccount,
47258
+ bank: depositOpts.depositBank,
47259
+ tokenProgram: depositOpts.tokenProgram,
47260
+ amount: amountToDeposit,
47261
+ accountAddress: marginfiAccount.address,
46988
47262
  authority: marginfiAccount.authority,
47263
+ group: marginfiAccount.group,
46989
47264
  reserve,
46990
- withdrawAll: isWholePosition(
46991
- {
46992
- amount: withdrawOpts.totalPositionAmount,
46993
- isLending: true
46994
- },
46995
- withdrawOpts.withdrawAmount,
46996
- withdrawOpts.withdrawBank.mintDecimals
46997
- ),
46998
- isSync: false,
46999
47265
  opts: {
47000
- createAtas: false,
47001
47266
  wrapAndUnwrapSol: false,
47002
47267
  overrideInferAccounts
47003
47268
  }
@@ -47005,35 +47270,27 @@ async function buildRepayWithCollatFlashloanTx({
47005
47270
  break;
47006
47271
  }
47007
47272
  case 4 /* DRIFT */: {
47008
- const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
47273
+ const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
47009
47274
  if (!driftState) {
47010
47275
  throw TransactionBuildingError.driftStateNotFound(
47011
- withdrawOpts.withdrawBank.address.toBase58(),
47012
- withdrawOpts.withdrawBank.mint.toBase58(),
47013
- withdrawOpts.withdrawBank.tokenSymbol
47276
+ depositOpts.depositBank.address.toBase58(),
47277
+ depositOpts.depositBank.mint.toBase58(),
47278
+ depositOpts.depositBank.tokenSymbol
47014
47279
  );
47015
47280
  }
47016
- withdrawIxs = await makeDriftWithdrawIx3({
47281
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
47282
+ const driftOracle = driftState.spotMarketState.oracle;
47283
+ depositIxs = await makeDriftDepositIx3({
47017
47284
  program,
47018
- bank: withdrawOpts.withdrawBank,
47019
- bankMap,
47020
- tokenProgram: withdrawOpts.tokenProgram,
47021
- amount: withdrawOpts.withdrawAmount,
47022
- marginfiAccount,
47285
+ bank: depositOpts.depositBank,
47286
+ tokenProgram: depositOpts.tokenProgram,
47287
+ amount: amountToDeposit,
47288
+ accountAddress: marginfiAccount.address,
47023
47289
  authority: marginfiAccount.authority,
47024
- driftSpotMarket: driftState.spotMarketState,
47025
- userRewards: driftState.userRewards,
47026
- withdrawAll: isWholePosition(
47027
- {
47028
- amount: withdrawOpts.totalPositionAmount,
47029
- isLending: true
47030
- },
47031
- withdrawOpts.withdrawAmount,
47032
- withdrawOpts.withdrawBank.mintDecimals
47033
- ),
47034
- isSync: false,
47290
+ group: marginfiAccount.group,
47291
+ driftMarketIndex,
47292
+ driftOracle,
47035
47293
  opts: {
47036
- createAtas: false,
47037
47294
  wrapAndUnwrapSol: false,
47038
47295
  overrideInferAccounts
47039
47296
  }
@@ -47041,33 +47298,15 @@ async function buildRepayWithCollatFlashloanTx({
47041
47298
  break;
47042
47299
  }
47043
47300
  case 6 /* JUPLEND */: {
47044
- const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
47045
- if (!jupLendState) {
47046
- throw TransactionBuildingError.jupLendStateNotFound(
47047
- withdrawOpts.withdrawBank.address.toBase58(),
47048
- withdrawOpts.withdrawBank.mint.toBase58(),
47049
- withdrawOpts.withdrawBank.tokenSymbol
47050
- );
47051
- }
47052
- withdrawIxs = await makeJuplendWithdrawIx2({
47301
+ depositIxs = await makeJuplendDepositIx2({
47053
47302
  program,
47054
- bank: withdrawOpts.withdrawBank,
47055
- bankMap,
47056
- tokenProgram: withdrawOpts.tokenProgram,
47057
- amount: withdrawOpts.withdrawAmount,
47058
- marginfiAccount,
47303
+ bank: depositOpts.depositBank,
47304
+ tokenProgram: depositOpts.tokenProgram,
47305
+ amount: amountToDeposit,
47306
+ accountAddress: marginfiAccount.address,
47059
47307
  authority: marginfiAccount.authority,
47060
- jupLendingState: jupLendState.jupLendingState,
47061
- withdrawAll: isWholePosition(
47062
- {
47063
- amount: withdrawOpts.totalPositionAmount,
47064
- isLending: true
47065
- },
47066
- withdrawOpts.withdrawAmount,
47067
- withdrawOpts.withdrawBank.mintDecimals
47068
- ),
47308
+ group: marginfiAccount.group,
47069
47309
  opts: {
47070
- createAtas: false,
47071
47310
  wrapAndUnwrapSol: false,
47072
47311
  overrideInferAccounts
47073
47312
  }
@@ -47075,645 +47314,140 @@ async function buildRepayWithCollatFlashloanTx({
47075
47314
  break;
47076
47315
  }
47077
47316
  default: {
47078
- withdrawIxs = await makeWithdrawIx3({
47079
- program,
47080
- bank: withdrawOpts.withdrawBank,
47081
- bankMap,
47082
- tokenProgram: withdrawOpts.tokenProgram,
47083
- amount: withdrawOpts.withdrawAmount,
47084
- marginfiAccount,
47085
- authority: marginfiAccount.authority,
47086
- withdrawAll: isWholePosition(
47087
- {
47088
- amount: withdrawOpts.totalPositionAmount,
47089
- isLending: true
47090
- },
47091
- withdrawOpts.withdrawAmount,
47092
- withdrawOpts.withdrawBank.mintDecimals
47093
- ),
47094
- isSync: false,
47095
- opts: {
47096
- createAtas: false,
47097
- wrapAndUnwrapSol: false,
47098
- overrideInferAccounts
47099
- }
47100
- });
47101
- break;
47102
- }
47103
- }
47104
- const repayIxs = await makeRepayIx3({
47105
- program,
47106
- bank: repayOpts.repayBank,
47107
- tokenProgram: repayOpts.tokenProgram,
47108
- amount: amountToRepay,
47109
- accountAddress: marginfiAccount.address,
47110
- authority: marginfiAccount.authority,
47111
- repayAll: isWholePosition(
47112
- {
47113
- amount: repayOpts.totalPositionAmount,
47114
- isLending: true
47115
- },
47116
- amountToRepay,
47117
- repayOpts.repayBank.mintDecimals
47118
- ),
47119
- isSync: false,
47120
- opts: {
47121
- wrapAndUnwrapSol: false,
47122
- overrideInferAccounts
47123
- }
47124
- });
47125
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47126
- const allNonFlIxs = [
47127
- ...cuRequestIxs,
47128
- ...withdrawIxs.instructions,
47129
- ...swapInstructions,
47130
- ...repayIxs.instructions
47131
- ];
47132
- if (swapInstructions.length > 0) {
47133
- compileFlashloanPrecheck({
47134
- allIxs: allNonFlIxs,
47135
- payer: marginfiAccount.authority,
47136
- luts,
47137
- sizeConstraint: sizeConstraintUsed,
47138
- swapIxCount: swapInstructions.length,
47139
- swapLutCount: swapLookupTables.length
47140
- });
47141
- }
47142
- const flashloanTx = await makeFlashLoanTx({
47143
- program,
47144
- marginfiAccount,
47145
- bankMap,
47146
- addressLookupTableAccounts: luts,
47147
- blockhash,
47148
- ixs: allNonFlIxs,
47149
- isSync: true
47150
- });
47151
- const txSize = getTxSize(flashloanTx);
47152
- const totalKeys = getTotalAccountKeys(flashloanTx);
47153
- if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
47154
- throw TransactionBuildingError.swapSizeExceededRepay(
47155
- txSize,
47156
- totalKeys,
47157
- swapOpts.swapConfig?.provider
47158
- );
47159
- }
47160
- return {
47161
- flashloanTx,
47162
- setupInstructions,
47163
- swapQuote,
47164
- withdrawIxs,
47165
- repayIxs,
47166
- amountToRepay
47167
- };
47168
- }
47169
-
47170
- // src/services/account/utils/flashloan-size.utils.ts
47171
- var SWAP_MERGE_OVERHEAD = 150;
47172
- var FL_IX_OVERHEAD = 52;
47173
- function compactU16Size(n) {
47174
- return n < 128 ? 1 : n < 16384 ? 2 : 3;
47175
- }
47176
- function computeV0TxSize(ixs, payerKey, luts) {
47177
- const keyMap = /* @__PURE__ */ new Map();
47178
- const payerStr = payerKey.toBase58();
47179
- keyMap.set(payerStr, { isSigner: true, isWritable: true });
47180
- const programIds = /* @__PURE__ */ new Set();
47181
- for (const ix of ixs) {
47182
- const progStr = ix.programId.toBase58();
47183
- programIds.add(progStr);
47184
- if (!keyMap.has(progStr)) {
47185
- keyMap.set(progStr, { isSigner: false, isWritable: false });
47186
- }
47187
- for (const meta of ix.keys) {
47188
- const keyStr = meta.pubkey.toBase58();
47189
- const existing = keyMap.get(keyStr);
47190
- if (existing) {
47191
- existing.isSigner = existing.isSigner || meta.isSigner;
47192
- existing.isWritable = existing.isWritable || meta.isWritable;
47193
- } else {
47194
- keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
47195
- }
47196
- }
47197
- }
47198
- const lutLookup = /* @__PURE__ */ new Map();
47199
- for (let li = 0; li < luts.length; li++) {
47200
- const addresses = luts[li].state.addresses;
47201
- for (let ai = 0; ai < addresses.length; ai++) {
47202
- const addrStr = addresses[ai].toBase58();
47203
- if (!lutLookup.has(addrStr)) {
47204
- lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
47205
- }
47206
- }
47207
- }
47208
- let numStaticKeys = 0;
47209
- let numWritableStaticKeys = 0;
47210
- const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
47211
- const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
47212
- for (const [keyStr, props] of keyMap) {
47213
- if (props.isSigner || programIds.has(keyStr)) {
47214
- numStaticKeys++;
47215
- if (props.isWritable) numWritableStaticKeys++;
47216
- continue;
47217
- }
47218
- const lutEntry = lutLookup.get(keyStr);
47219
- if (lutEntry) {
47220
- if (props.isWritable) {
47221
- lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
47222
- } else {
47223
- lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
47224
- }
47225
- } else {
47226
- numStaticKeys++;
47227
- if (props.isWritable) numWritableStaticKeys++;
47228
- }
47229
- }
47230
- const fixedOverhead = 101;
47231
- const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
47232
- let ixSection = compactU16Size(ixs.length);
47233
- for (const ix of ixs) {
47234
- const numAccounts = ix.keys.length;
47235
- ixSection += 1 + // programId index
47236
- compactU16Size(numAccounts) + numAccounts + // account key indexes
47237
- compactU16Size(ix.data.length) + ix.data.length;
47238
- }
47239
- let numUsedLuts = 0;
47240
- let lutSection = 0;
47241
- for (let li = 0; li < luts.length; li++) {
47242
- const wCount = lutWritableIdxs[li].size;
47243
- const rCount = lutReadonlyIdxs[li].size;
47244
- if (wCount === 0 && rCount === 0) continue;
47245
- numUsedLuts++;
47246
- lutSection += 32 + // LUT address
47247
- compactU16Size(wCount) + wCount + // writable indexes
47248
- compactU16Size(rCount) + rCount;
47249
- }
47250
- lutSection += compactU16Size(numUsedLuts);
47251
- let totalLutKeys = 0;
47252
- for (let li = 0; li < luts.length; li++) {
47253
- totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
47254
- }
47255
- const accountCount = numStaticKeys + totalLutKeys;
47256
- let totalLutWritableKeys = 0;
47257
- for (let li = 0; li < luts.length; li++) {
47258
- totalLutWritableKeys += lutWritableIdxs[li].size;
47259
- }
47260
- const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
47261
- const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
47262
- return { size, accountCount, writableAccountCount };
47263
- }
47264
- function computeFlashLoanNonSwapBudget({
47265
- program,
47266
- marginfiAccount,
47267
- ixs,
47268
- bankMap,
47269
- addressLookupTableAccounts
47270
- }) {
47271
- const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
47272
- marginfiAccount.balances,
47273
- ixs,
47274
- program
47275
- );
47276
- const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
47277
- const b = bankMap.get(key.toBase58());
47278
- if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
47279
- return b;
47280
- });
47281
- const endIndex = ixs.length + 1;
47282
- const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
47283
- program.programId,
47284
- { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
47285
- { endIndex: new BN11__default.default(endIndex) }
47286
- );
47287
- const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
47288
- const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
47289
- program.programId,
47290
- { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
47291
- endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
47292
- );
47293
- const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
47294
- const nonSwapMsg = new web3_js.TransactionMessage({
47295
- payerKey: marginfiAccount.authority,
47296
- recentBlockhash: web3_js.PublicKey.default.toBase58(),
47297
- instructions: allNonSwapIxs
47298
- }).compileToV0Message(addressLookupTableAccounts);
47299
- const nonSwapSize = new web3_js.VersionedTransaction(nonSwapMsg).serialize().length;
47300
- const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
47301
- const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
47302
- (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
47303
- 0
47304
- );
47305
- const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
47306
- const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
47307
- console.log("[flashloan-budget]", {
47308
- method: "compiled",
47309
- nonSwapSize,
47310
- nonSwapTotal,
47311
- sizeConstraint,
47312
- maxSwapTotalAccounts
47313
- });
47314
- return { sizeConstraint, maxSwapTotalAccounts };
47315
- }
47316
- function compileFlashloanPrecheck({
47317
- allIxs,
47318
- payer,
47319
- luts,
47320
- sizeConstraint,
47321
- swapIxCount,
47322
- swapLutCount
47323
- }) {
47324
- const msg = new web3_js.TransactionMessage({
47325
- payerKey: payer,
47326
- recentBlockhash: web3_js.PublicKey.default.toBase58(),
47327
- instructions: allIxs
47328
- }).compileToV0Message(luts);
47329
- const rawSize = new web3_js.VersionedTransaction(msg).serialize().length;
47330
- const fullTxSize = rawSize + FL_IX_OVERHEAD;
47331
- const overshoot = fullTxSize - MAX_TX_SIZE;
47332
- const { header, staticAccountKeys, addressTableLookups } = msg;
47333
- const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
47334
- const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
47335
- const writableAccounts = writableStatic + writableLut;
47336
- const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
47337
- (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
47338
- 0
47339
- );
47340
- console.log("[flashloan-precheck]", {
47341
- fullTxSize,
47342
- overshoot,
47343
- sizeConstraint,
47344
- writableAccounts,
47345
- totalAccounts,
47346
- staticKeys: staticAccountKeys.length,
47347
- numLuts: addressTableLookups.length,
47348
- swapIxCount,
47349
- swapLutCount
47350
- });
47351
- return { fullTxSize, overshoot, writableAccounts, totalAccounts };
47352
- }
47353
- async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
47354
- const { bank, tokenProgram } = config;
47355
- switch (config.type) {
47356
- case "borrow":
47357
- return makeBorrowIx3({
47358
- program,
47359
- bank,
47360
- bankMap,
47361
- tokenProgram,
47362
- amount: 1,
47363
- marginfiAccount,
47364
- authority: marginfiAccount.authority,
47365
- isSync: true,
47366
- opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
47367
- });
47368
- case "repay":
47369
- return makeRepayIx3({
47370
- program,
47371
- bank,
47372
- tokenProgram,
47373
- amount: 1,
47374
- accountAddress: marginfiAccount.address,
47375
- authority: marginfiAccount.authority,
47376
- repayAll: false,
47377
- isSync: true,
47378
- opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
47379
- });
47380
- case "deposit":
47381
- return buildDepositBudgetIx(
47382
- config,
47383
- program,
47384
- marginfiAccount,
47385
- bankMetadataMap,
47386
- overrideInferAccounts
47387
- );
47388
- case "withdraw":
47389
- return buildWithdrawBudgetIx(
47390
- config,
47391
- program,
47392
- marginfiAccount,
47393
- bankMap,
47394
- bankMetadataMap,
47395
- overrideInferAccounts
47396
- );
47397
- }
47398
- }
47399
- async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
47400
- const { bank, tokenProgram } = config;
47401
- const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
47402
- switch (bank.config.assetTag) {
47403
- case 3 /* KAMINO */: {
47404
- const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
47405
- if (!reserve) {
47406
- throw TransactionBuildingError.kaminoReserveNotFound(
47407
- bank.address.toBase58(),
47408
- bank.mint.toBase58(),
47409
- bank.tokenSymbol
47410
- );
47411
- }
47412
- return makeKaminoDepositIx3({
47413
- program,
47414
- bank,
47415
- tokenProgram,
47416
- amount: 1,
47417
- accountAddress: marginfiAccount.address,
47418
- authority: marginfiAccount.authority,
47419
- group: marginfiAccount.group,
47420
- reserve,
47421
- isSync: true,
47422
- opts
47423
- });
47424
- }
47425
- case 4 /* DRIFT */: {
47426
- const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
47427
- if (!driftState) {
47428
- throw TransactionBuildingError.driftStateNotFound(
47429
- bank.address.toBase58(),
47430
- bank.mint.toBase58(),
47431
- bank.tokenSymbol
47432
- );
47433
- }
47434
- return makeDriftDepositIx3({
47435
- program,
47436
- bank,
47437
- tokenProgram,
47438
- amount: 1,
47439
- accountAddress: marginfiAccount.address,
47440
- authority: marginfiAccount.authority,
47441
- group: marginfiAccount.group,
47442
- driftMarketIndex: driftState.spotMarketState.marketIndex,
47443
- driftOracle: driftState.spotMarketState.oracle,
47444
- isSync: true,
47445
- opts
47446
- });
47447
- }
47448
- case 6 /* JUPLEND */: {
47449
- return makeJuplendDepositIx2({
47450
- program,
47451
- bank,
47452
- tokenProgram,
47453
- amount: 1,
47454
- accountAddress: marginfiAccount.address,
47455
- authority: marginfiAccount.authority,
47456
- group: marginfiAccount.group,
47457
- isSync: true,
47458
- opts
47459
- });
47460
- }
47461
- default: {
47462
- return makeDepositIx3({
47463
- program,
47464
- bank,
47465
- tokenProgram,
47466
- amount: 1,
47467
- accountAddress: marginfiAccount.address,
47468
- authority: marginfiAccount.authority,
47469
- group: marginfiAccount.group,
47470
- isSync: true,
47471
- opts
47472
- });
47473
- }
47474
- }
47475
- }
47476
- async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
47477
- const { bank, tokenProgram } = config;
47478
- const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
47479
- switch (bank.config.assetTag) {
47480
- case 3 /* KAMINO */: {
47481
- const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
47482
- if (!reserve) {
47483
- throw TransactionBuildingError.kaminoReserveNotFound(
47484
- bank.address.toBase58(),
47485
- bank.mint.toBase58(),
47486
- bank.tokenSymbol
47487
- );
47488
- }
47489
- return makeKaminoWithdrawIx3({
47490
- program,
47491
- bank,
47492
- bankMap,
47493
- tokenProgram,
47494
- cTokenAmount: 1,
47495
- marginfiAccount,
47496
- authority: marginfiAccount.authority,
47497
- reserve,
47498
- withdrawAll: false,
47499
- isSync: true,
47500
- opts
47501
- });
47502
- }
47503
- case 4 /* DRIFT */: {
47504
- const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
47505
- if (!driftState) {
47506
- throw TransactionBuildingError.driftStateNotFound(
47507
- bank.address.toBase58(),
47508
- bank.mint.toBase58(),
47509
- bank.tokenSymbol
47510
- );
47511
- }
47512
- return makeDriftWithdrawIx3({
47513
- program,
47514
- bank,
47515
- bankMap,
47516
- tokenProgram,
47517
- amount: 1,
47518
- marginfiAccount,
47519
- authority: marginfiAccount.authority,
47520
- driftSpotMarket: driftState.spotMarketState,
47521
- userRewards: driftState.userRewards,
47522
- withdrawAll: false,
47523
- isSync: true,
47524
- opts
47525
- });
47526
- }
47527
- case 6 /* JUPLEND */: {
47528
- const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
47529
- if (!jupLendState) {
47530
- throw TransactionBuildingError.jupLendStateNotFound(
47531
- bank.address.toBase58(),
47532
- bank.mint.toBase58(),
47533
- bank.tokenSymbol
47534
- );
47535
- }
47536
- return makeJuplendWithdrawIx2({
47537
- program,
47538
- bank,
47539
- bankMap,
47540
- tokenProgram,
47541
- amount: 1,
47542
- marginfiAccount,
47543
- authority: marginfiAccount.authority,
47544
- jupLendingState: jupLendState.jupLendingState,
47545
- withdrawAll: false,
47546
- opts
47547
- });
47548
- }
47549
- default: {
47550
- return makeWithdrawIx3({
47551
- program,
47552
- bank,
47553
- bankMap,
47554
- tokenProgram,
47555
- amount: 1,
47556
- marginfiAccount,
47317
+ depositIxs = await makeDepositIx3({
47318
+ program,
47319
+ bank: depositOpts.depositBank,
47320
+ tokenProgram: depositOpts.tokenProgram,
47321
+ amount: amountToDeposit,
47322
+ accountAddress: marginfiAccount.address,
47557
47323
  authority: marginfiAccount.authority,
47558
- withdrawAll: false,
47559
- isSync: true,
47560
- opts
47324
+ group: marginfiAccount.group,
47325
+ opts: {
47326
+ wrapAndUnwrapSol: false,
47327
+ overrideInferAccounts
47328
+ }
47561
47329
  });
47330
+ break;
47562
47331
  }
47563
47332
  }
47564
- }
47565
- async function computeFlashloanSwapConstraints({
47566
- program,
47567
- marginfiAccount,
47568
- bankMap,
47569
- addressLookupTableAccounts,
47570
- bankMetadataMap,
47571
- primaryIx,
47572
- secondaryIx,
47573
- overrideInferAccounts
47574
- }) {
47575
- const cuRequestIxs = [
47576
- web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47577
- web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47333
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47334
+ const allNonFlIxs = [
47335
+ ...cuRequestIxs,
47336
+ ...borrowIxs.instructions,
47337
+ ...swapInstructions,
47338
+ ...depositIxs.instructions
47578
47339
  ];
47579
- const [primaryResult, secondaryResult] = await Promise.all([
47580
- buildBudgetIx(
47581
- primaryIx,
47582
- program,
47583
- marginfiAccount,
47584
- bankMap,
47585
- bankMetadataMap,
47586
- overrideInferAccounts
47587
- ),
47588
- buildBudgetIx(
47589
- secondaryIx,
47590
- program,
47591
- marginfiAccount,
47592
- bankMap,
47593
- bankMetadataMap,
47594
- overrideInferAccounts
47595
- )
47596
- ]);
47597
- return computeFlashLoanNonSwapBudget({
47340
+ if (swapInstructions.length > 0) {
47341
+ compileFlashloanPrecheck({
47342
+ allIxs: allNonFlIxs,
47343
+ payer: marginfiAccount.authority,
47344
+ luts,
47345
+ sizeConstraint: sizeConstraintUsed,
47346
+ swapIxCount: swapInstructions.length,
47347
+ swapLutCount: swapLookupTables.length
47348
+ });
47349
+ }
47350
+ const flashloanTx = await makeFlashLoanTx({
47598
47351
  program,
47599
47352
  marginfiAccount,
47600
47353
  bankMap,
47601
- addressLookupTableAccounts,
47602
- ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
47354
+ addressLookupTableAccounts: luts,
47355
+ blockhash,
47356
+ ixs: allNonFlIxs
47603
47357
  });
47358
+ const txSize = getTxSize(flashloanTx);
47359
+ const totalKeys = getTotalAccountKeys(flashloanTx);
47360
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
47361
+ throw TransactionBuildingError.swapSizeExceededLoop(
47362
+ txSize,
47363
+ totalKeys,
47364
+ swapOpts.swapConfig?.provider
47365
+ );
47366
+ }
47367
+ return {
47368
+ flashloanTx,
47369
+ setupInstructions,
47370
+ swapQuote,
47371
+ borrowIxs,
47372
+ depositIxs,
47373
+ amountToDeposit
47374
+ };
47604
47375
  }
47605
-
47606
- // src/services/account/actions/flash-loan.ts
47607
- async function makeBeginFlashLoanIx3(program, marginfiAccountPk, endIndex, authority, isSync) {
47608
- const ix = isSync && authority ? sync_instructions_default.makeBeginFlashLoanIx(
47609
- program.programId,
47610
- {
47611
- marginfiAccount: marginfiAccountPk,
47612
- authority
47613
- },
47614
- { endIndex: new BN11__default.default(endIndex) }
47615
- ) : await instructions_default.makeBeginFlashLoanIx(
47376
+ async function makeRepayIx3({
47377
+ program,
47378
+ bank,
47379
+ tokenProgram,
47380
+ amount,
47381
+ authority,
47382
+ accountAddress,
47383
+ repayAll = false,
47384
+ isSync = false,
47385
+ opts = {}
47386
+ }) {
47387
+ const wrapAndUnwrapSol = opts.wrapAndUnwrapSol ?? true;
47388
+ const wSolBalanceUi = opts.wSolBalanceUi ?? 0;
47389
+ const repayIxs = [];
47390
+ const userAta = getAssociatedTokenAddressSync(bank.mint, authority, true, tokenProgram);
47391
+ const remainingAccounts = tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? [{ pubkey: bank.mint, isSigner: false, isWritable: false }] : [];
47392
+ if (bank.mint.equals(NATIVE_MINT) && wrapAndUnwrapSol) {
47393
+ repayIxs.push(...makeWrapSolIxs(authority, new BigNumber3.BigNumber(amount).minus(wSolBalanceUi)));
47394
+ }
47395
+ const repayIx = !isSync || !opts.overrideInferAccounts?.group ? await instructions_default.makeRepayIx(
47616
47396
  program,
47617
47397
  {
47618
- marginfiAccount: marginfiAccountPk,
47619
- authority
47398
+ marginfiAccount: accountAddress,
47399
+ signerTokenAccount: userAta,
47400
+ bank: bank.address,
47401
+ tokenProgram,
47402
+ authority: opts.overrideInferAccounts?.authority ?? authority,
47403
+ group: opts.overrideInferAccounts?.group,
47404
+ liquidityVault: opts.overrideInferAccounts?.liquidityVault
47620
47405
  },
47621
- { endIndex: new BN11__default.default(endIndex) }
47622
- );
47623
- return { instructions: [ix], keys: [] };
47624
- }
47625
- async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
47626
- const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
47627
- const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
47406
+ { amount: uiToNative(amount, bank.mintDecimals), repayAll },
47407
+ remainingAccounts
47408
+ ) : sync_instructions_default.makeRepayIx(
47628
47409
  program.programId,
47629
47410
  {
47630
- marginfiAccount: marginfiAccountPk,
47631
- authority
47632
- },
47633
- remainingAccounts.map((account) => ({
47634
- pubkey: account,
47635
- isSigner: false,
47636
- isWritable: false
47637
- }))
47638
- ) : await instructions_default.makeEndFlashLoanIx(
47639
- program,
47640
- {
47641
- marginfiAccount: marginfiAccountPk,
47642
- authority
47411
+ marginfiAccount: accountAddress,
47412
+ signerTokenAccount: userAta,
47413
+ bank: bank.address,
47414
+ tokenProgram,
47415
+ authority: opts.overrideInferAccounts?.authority ?? authority,
47416
+ group: opts.overrideInferAccounts?.group
47643
47417
  },
47644
- remainingAccounts.map((account) => ({
47645
- pubkey: account,
47646
- isSigner: false,
47647
- isWritable: false
47648
- }))
47418
+ { amount: uiToNative(amount, bank.mintDecimals), repayAll },
47419
+ remainingAccounts
47649
47420
  );
47650
- return { instructions: [ix], keys: [] };
47421
+ repayIxs.push(repayIx);
47422
+ return {
47423
+ instructions: repayIxs,
47424
+ keys: []
47425
+ };
47651
47426
  }
47652
- async function makeFlashLoanTx({
47653
- program,
47654
- marginfiAccount,
47655
- ixs,
47656
- bankMap,
47657
- blockhash,
47658
- addressLookupTableAccounts,
47659
- signers,
47660
- isSync
47661
- }) {
47662
- const endIndex = ixs.length + 1;
47663
- const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
47664
- marginfiAccount.balances,
47665
- ixs,
47666
- program
47667
- );
47668
- const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
47669
- const b = bankMap.get(account.toBase58());
47670
- if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
47671
- return b;
47672
- });
47673
- const beginFlashLoanIx = await makeBeginFlashLoanIx3(
47674
- program,
47675
- marginfiAccount.address,
47676
- endIndex,
47677
- marginfiAccount.authority,
47678
- isSync
47679
- );
47680
- const endFlashLoanIx = await makeEndFlashLoanIx3(
47681
- program,
47682
- marginfiAccount.address,
47683
- projectedActiveBanks,
47684
- marginfiAccount.authority,
47685
- isSync
47686
- );
47687
- const message = new web3_js.TransactionMessage({
47688
- payerKey: marginfiAccount.authority,
47689
- recentBlockhash: blockhash,
47690
- instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
47691
- }).compileToV0Message(addressLookupTableAccounts);
47692
- const tx = addTransactionMetadata(new web3_js.VersionedTransaction(message), {
47693
- addressLookupTables: addressLookupTableAccounts,
47694
- type: "FLASHLOAN" /* FLASHLOAN */,
47695
- signers
47427
+ async function makeRepayTx(params) {
47428
+ const { luts, ...depositIxParams } = params;
47429
+ const ixs = await makeRepayIx3(depositIxParams);
47430
+ const tx = new web3_js.Transaction().add(...ixs.instructions);
47431
+ tx.feePayer = params.authority;
47432
+ const solanaTx = addTransactionMetadata(tx, {
47433
+ type: "REPAY" /* REPAY */,
47434
+ signers: ixs.keys,
47435
+ addressLookupTables: luts
47696
47436
  });
47697
- if (signers) {
47698
- tx.sign(signers);
47699
- }
47700
- return tx;
47437
+ return solanaTx;
47701
47438
  }
47702
-
47703
- // src/services/account/actions/loop.ts
47704
- async function makeLoopTx(params) {
47439
+ async function makeRepayWithCollatTx(params) {
47705
47440
  const {
47706
47441
  program,
47707
47442
  marginfiAccount,
47708
47443
  bankMap,
47709
- depositOpts,
47710
- borrowOpts,
47444
+ withdrawOpts,
47445
+ repayOpts,
47711
47446
  bankMetadataMap,
47712
47447
  addressLookupTableAccounts,
47713
47448
  connection,
47714
47449
  oraclePrices,
47715
- crossbarUrl,
47716
- additionalIxs = []
47450
+ crossbarUrl
47717
47451
  } = params;
47718
47452
  const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
47719
47453
  const setupIxs = await makeSetupIx({
@@ -47721,34 +47455,34 @@ async function makeLoopTx(params) {
47721
47455
  authority: marginfiAccount.authority,
47722
47456
  tokens: [
47723
47457
  {
47724
- mint: borrowOpts.borrowBank.mint,
47725
- tokenProgram: borrowOpts.tokenProgram
47458
+ mint: repayOpts.repayBank.mint,
47459
+ tokenProgram: repayOpts.tokenProgram
47726
47460
  },
47727
47461
  {
47728
- mint: depositOpts.depositBank.mint,
47729
- tokenProgram: depositOpts.tokenProgram
47462
+ mint: withdrawOpts.withdrawBank.mint,
47463
+ tokenProgram: withdrawOpts.tokenProgram
47730
47464
  }
47731
47465
  ]
47732
47466
  });
47733
- const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
47734
- params.marginfiAccount,
47735
- params.bankMap,
47736
- [depositOpts.depositBank.address],
47737
- params.bankMetadataMap
47467
+ const updateJuplendMarketIxs = makeUpdateJupLendRateIxs(
47468
+ marginfiAccount,
47469
+ bankMap,
47470
+ [withdrawOpts.withdrawBank.address],
47471
+ bankMetadataMap
47738
47472
  );
47739
47473
  const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
47740
- params.marginfiAccount,
47741
- params.bankMap,
47742
- [depositOpts.depositBank.address],
47743
- params.bankMetadataMap
47474
+ marginfiAccount,
47475
+ bankMap,
47476
+ [withdrawOpts.withdrawBank.address],
47477
+ bankMetadataMap
47744
47478
  );
47745
47479
  const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
47746
47480
  marginfiAccount,
47747
47481
  bankMap,
47748
- [borrowOpts.borrowBank.address, depositOpts.depositBank.address],
47482
+ [withdrawOpts.withdrawBank.address, repayOpts.repayBank.address],
47749
47483
  bankMetadataMap
47750
47484
  );
47751
- const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
47485
+ const { flashloanTx, setupInstructions, swapQuote, amountToRepay, withdrawIxs, repayIxs } = await buildRepayWithCollatFlashloanTx({
47752
47486
  ...params,
47753
47487
  blockhash
47754
47488
  });
@@ -47758,7 +47492,7 @@ async function makeLoopTx(params) {
47758
47492
  }
47759
47493
  if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
47760
47494
  const mintKey = ix.keys[3]?.pubkey;
47761
- if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
47495
+ if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(repayOpts.repayBank.mint)) {
47762
47496
  return false;
47763
47497
  }
47764
47498
  }
@@ -47770,24 +47504,18 @@ async function makeLoopTx(params) {
47770
47504
  bankMap,
47771
47505
  oraclePrices,
47772
47506
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
47773
- instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
47507
+ instructions: [...withdrawIxs.instructions, ...repayIxs.instructions],
47774
47508
  program,
47775
47509
  connection,
47776
47510
  crossbarUrl
47777
47511
  });
47778
47512
  let additionalTxs = [];
47779
- if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
47780
- setupIxs.push(
47781
- ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber3.BigNumber(depositOpts.inputDepositAmount))
47782
- );
47783
- }
47784
- if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
47513
+ if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJuplendMarketIxs.instructions.length > 0) {
47785
47514
  const ixs = [
47786
- ...additionalIxs,
47787
47515
  ...setupIxs,
47788
47516
  ...kaminoRefreshIxs.instructions,
47789
47517
  ...updateDriftMarketIxs.instructions,
47790
- ...updateJupLendRateIxs.instructions
47518
+ ...updateJuplendMarketIxs.instructions
47791
47519
  ];
47792
47520
  const txs = splitInstructionsToFitTransactions([], ixs, {
47793
47521
  blockhash,
@@ -47817,19 +47545,16 @@ async function makeLoopTx(params) {
47817
47545
  );
47818
47546
  }
47819
47547
  const transactions = [...additionalTxs, flashloanTx];
47820
- return {
47821
- transactions,
47822
- actionTxIndex: transactions.length - 1,
47823
- quoteResponse: swapQuote
47824
- };
47548
+ return { transactions, swapQuote, amountToRepay };
47825
47549
  }
47826
- async function buildLoopFlashloanTx({
47550
+ async function buildRepayWithCollatFlashloanTx({
47827
47551
  program,
47828
47552
  marginfiAccount,
47829
47553
  bankMap,
47830
- borrowOpts,
47831
- depositOpts,
47554
+ withdrawOpts,
47555
+ repayOpts,
47832
47556
  bankMetadataMap,
47557
+ assetShareValueMultiplierByBank,
47833
47558
  addressLookupTableAccounts,
47834
47559
  connection,
47835
47560
  swapOpts,
@@ -47840,20 +47565,20 @@ async function buildLoopFlashloanTx({
47840
47565
  web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47841
47566
  web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47842
47567
  ];
47843
- let amountToDeposit;
47568
+ let amountToRepay;
47844
47569
  let swapInstructions = [];
47845
47570
  let setupInstructions = [];
47846
47571
  let swapLookupTables = [];
47847
47572
  let swapQuote;
47848
47573
  let sizeConstraintUsed = 0;
47849
- if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
47850
- amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
47574
+ if (repayOpts.repayBank.mint.equals(withdrawOpts.withdrawBank.mint)) {
47575
+ amountToRepay = withdrawOpts.withdrawAmount;
47851
47576
  } else {
47852
47577
  const destinationTokenAccount = getAssociatedTokenAddressSync(
47853
- new web3_js.PublicKey(depositOpts.depositBank.mint),
47578
+ new web3_js.PublicKey(repayOpts.repayBank.mint),
47854
47579
  marginfiAccount.authority,
47855
47580
  true,
47856
- depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47581
+ repayOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47857
47582
  );
47858
47583
  const swapConstraints = await computeFlashloanSwapConstraints({
47859
47584
  program,
@@ -47862,21 +47587,24 @@ async function buildLoopFlashloanTx({
47862
47587
  bankMetadataMap,
47863
47588
  addressLookupTableAccounts: addressLookupTableAccounts ?? [],
47864
47589
  primaryIx: {
47865
- type: "borrow",
47866
- bank: borrowOpts.borrowBank,
47867
- tokenProgram: borrowOpts.tokenProgram
47590
+ type: "withdraw",
47591
+ bank: withdrawOpts.withdrawBank,
47592
+ tokenProgram: withdrawOpts.tokenProgram
47868
47593
  },
47869
47594
  secondaryIx: {
47870
- type: "deposit",
47871
- bank: depositOpts.depositBank,
47872
- tokenProgram: depositOpts.tokenProgram
47595
+ type: "repay",
47596
+ bank: repayOpts.repayBank,
47597
+ tokenProgram: repayOpts.tokenProgram
47873
47598
  },
47874
47599
  overrideInferAccounts
47875
47600
  });
47876
47601
  const swapResponse = await getSwapIxsForFlashloan({
47877
- inputMint: borrowOpts.borrowBank.mint.toBase58(),
47878
- outputMint: depositOpts.depositBank.mint.toBase58(),
47879
- amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
47602
+ inputMint: withdrawOpts.withdrawBank.mint.toBase58(),
47603
+ outputMint: repayOpts.repayBank.mint.toBase58(),
47604
+ amount: uiToNative(
47605
+ withdrawOpts.withdrawAmount,
47606
+ withdrawOpts.withdrawBank.mintDecimals
47607
+ ).toNumber(),
47880
47608
  swapMode: "ExactIn",
47881
47609
  authority: marginfiAccount.authority,
47882
47610
  connection,
@@ -47886,52 +47614,50 @@ async function buildLoopFlashloanTx({
47886
47614
  maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47887
47615
  });
47888
47616
  sizeConstraintUsed = swapConstraints.sizeConstraint;
47617
+ const { quoteResponse } = swapResponse;
47618
+ const outAmount = nativeToUi(quoteResponse.outAmount, repayOpts.repayBank.mintDecimals);
47889
47619
  const outAmountThreshold = nativeToUi(
47890
- swapResponse.quoteResponse.otherAmountThreshold,
47891
- depositOpts.depositBank.mintDecimals
47620
+ quoteResponse.otherAmountThreshold,
47621
+ repayOpts.repayBank.mintDecimals
47892
47622
  );
47893
- amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
47623
+ amountToRepay = outAmount > repayOpts.totalPositionAmount ? repayOpts.totalPositionAmount : outAmountThreshold;
47894
47624
  swapInstructions = swapResponse.swapInstructions;
47895
- setupInstructions = swapResponse.setupInstructions;
47896
47625
  swapLookupTables = swapResponse.addressLookupTableAddresses;
47897
- swapQuote = swapResponse.quoteResponse;
47626
+ swapQuote = quoteResponse;
47898
47627
  }
47899
- const borrowIxs = await makeBorrowIx3({
47900
- program,
47901
- bank: borrowOpts.borrowBank,
47902
- bankMap,
47903
- tokenProgram: borrowOpts.tokenProgram,
47904
- amount: borrowOpts.borrowAmount,
47905
- marginfiAccount,
47906
- authority: marginfiAccount.authority,
47907
- isSync: false,
47908
- opts: {
47909
- createAtas: false,
47910
- wrapAndUnwrapSol: false,
47911
- overrideInferAccounts
47912
- }
47913
- });
47914
- let depositIxs;
47915
- switch (depositOpts.depositBank.config.assetTag) {
47628
+ let withdrawIxs;
47629
+ switch (withdrawOpts.withdrawBank.config.assetTag) {
47916
47630
  case 3 /* KAMINO */: {
47917
- const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
47631
+ const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
47918
47632
  if (!reserve) {
47919
47633
  throw TransactionBuildingError.kaminoReserveNotFound(
47920
- depositOpts.depositBank.address.toBase58(),
47921
- depositOpts.depositBank.mint.toBase58(),
47922
- depositOpts.depositBank.tokenSymbol
47634
+ withdrawOpts.withdrawBank.address.toBase58(),
47635
+ withdrawOpts.withdrawBank.mint.toBase58(),
47636
+ withdrawOpts.withdrawBank.tokenSymbol
47923
47637
  );
47924
47638
  }
47925
- depositIxs = await makeKaminoDepositIx3({
47639
+ const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber3.BigNumber(1);
47640
+ const adjustedAmount = new BigNumber3.BigNumber(withdrawOpts.withdrawAmount).div(multiplier).times(1.0001).toNumber();
47641
+ withdrawIxs = await makeKaminoWithdrawIx3({
47926
47642
  program,
47927
- bank: depositOpts.depositBank,
47928
- tokenProgram: depositOpts.tokenProgram,
47929
- amount: amountToDeposit,
47930
- accountAddress: marginfiAccount.address,
47643
+ bank: withdrawOpts.withdrawBank,
47644
+ bankMap,
47645
+ tokenProgram: withdrawOpts.tokenProgram,
47646
+ cTokenAmount: adjustedAmount,
47647
+ marginfiAccount,
47931
47648
  authority: marginfiAccount.authority,
47932
- group: marginfiAccount.group,
47933
47649
  reserve,
47650
+ withdrawAll: isWholePosition(
47651
+ {
47652
+ amount: withdrawOpts.totalPositionAmount,
47653
+ isLending: true
47654
+ },
47655
+ withdrawOpts.withdrawAmount,
47656
+ withdrawOpts.withdrawBank.mintDecimals
47657
+ ),
47658
+ isSync: false,
47934
47659
  opts: {
47660
+ createAtas: false,
47935
47661
  wrapAndUnwrapSol: false,
47936
47662
  overrideInferAccounts
47937
47663
  }
@@ -47939,27 +47665,35 @@ async function buildLoopFlashloanTx({
47939
47665
  break;
47940
47666
  }
47941
47667
  case 4 /* DRIFT */: {
47942
- const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
47668
+ const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
47943
47669
  if (!driftState) {
47944
47670
  throw TransactionBuildingError.driftStateNotFound(
47945
- depositOpts.depositBank.address.toBase58(),
47946
- depositOpts.depositBank.mint.toBase58(),
47947
- depositOpts.depositBank.tokenSymbol
47671
+ withdrawOpts.withdrawBank.address.toBase58(),
47672
+ withdrawOpts.withdrawBank.mint.toBase58(),
47673
+ withdrawOpts.withdrawBank.tokenSymbol
47948
47674
  );
47949
47675
  }
47950
- const driftMarketIndex = driftState.spotMarketState.marketIndex;
47951
- const driftOracle = driftState.spotMarketState.oracle;
47952
- depositIxs = await makeDriftDepositIx3({
47676
+ withdrawIxs = await makeDriftWithdrawIx3({
47953
47677
  program,
47954
- bank: depositOpts.depositBank,
47955
- tokenProgram: depositOpts.tokenProgram,
47956
- amount: amountToDeposit,
47957
- accountAddress: marginfiAccount.address,
47678
+ bank: withdrawOpts.withdrawBank,
47679
+ bankMap,
47680
+ tokenProgram: withdrawOpts.tokenProgram,
47681
+ amount: withdrawOpts.withdrawAmount,
47682
+ marginfiAccount,
47958
47683
  authority: marginfiAccount.authority,
47959
- group: marginfiAccount.group,
47960
- driftMarketIndex,
47961
- driftOracle,
47684
+ driftSpotMarket: driftState.spotMarketState,
47685
+ userRewards: driftState.userRewards,
47686
+ withdrawAll: isWholePosition(
47687
+ {
47688
+ amount: withdrawOpts.totalPositionAmount,
47689
+ isLending: true
47690
+ },
47691
+ withdrawOpts.withdrawAmount,
47692
+ withdrawOpts.withdrawBank.mintDecimals
47693
+ ),
47694
+ isSync: false,
47962
47695
  opts: {
47696
+ createAtas: false,
47963
47697
  wrapAndUnwrapSol: false,
47964
47698
  overrideInferAccounts
47965
47699
  }
@@ -47967,15 +47701,33 @@ async function buildLoopFlashloanTx({
47967
47701
  break;
47968
47702
  }
47969
47703
  case 6 /* JUPLEND */: {
47970
- depositIxs = await makeJuplendDepositIx2({
47704
+ const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
47705
+ if (!jupLendState) {
47706
+ throw TransactionBuildingError.jupLendStateNotFound(
47707
+ withdrawOpts.withdrawBank.address.toBase58(),
47708
+ withdrawOpts.withdrawBank.mint.toBase58(),
47709
+ withdrawOpts.withdrawBank.tokenSymbol
47710
+ );
47711
+ }
47712
+ withdrawIxs = await makeJuplendWithdrawIx2({
47971
47713
  program,
47972
- bank: depositOpts.depositBank,
47973
- tokenProgram: depositOpts.tokenProgram,
47974
- amount: amountToDeposit,
47975
- accountAddress: marginfiAccount.address,
47714
+ bank: withdrawOpts.withdrawBank,
47715
+ bankMap,
47716
+ tokenProgram: withdrawOpts.tokenProgram,
47717
+ amount: withdrawOpts.withdrawAmount,
47718
+ marginfiAccount,
47976
47719
  authority: marginfiAccount.authority,
47977
- group: marginfiAccount.group,
47720
+ jupLendingState: jupLendState.jupLendingState,
47721
+ withdrawAll: isWholePosition(
47722
+ {
47723
+ amount: withdrawOpts.totalPositionAmount,
47724
+ isLending: true
47725
+ },
47726
+ withdrawOpts.withdrawAmount,
47727
+ withdrawOpts.withdrawBank.mintDecimals
47728
+ ),
47978
47729
  opts: {
47730
+ createAtas: false,
47979
47731
  wrapAndUnwrapSol: false,
47980
47732
  overrideInferAccounts
47981
47733
  }
@@ -47983,15 +47735,25 @@ async function buildLoopFlashloanTx({
47983
47735
  break;
47984
47736
  }
47985
47737
  default: {
47986
- depositIxs = await makeDepositIx3({
47738
+ withdrawIxs = await makeWithdrawIx3({
47987
47739
  program,
47988
- bank: depositOpts.depositBank,
47989
- tokenProgram: depositOpts.tokenProgram,
47990
- amount: amountToDeposit,
47991
- accountAddress: marginfiAccount.address,
47740
+ bank: withdrawOpts.withdrawBank,
47741
+ bankMap,
47742
+ tokenProgram: withdrawOpts.tokenProgram,
47743
+ amount: withdrawOpts.withdrawAmount,
47744
+ marginfiAccount,
47992
47745
  authority: marginfiAccount.authority,
47993
- group: marginfiAccount.group,
47746
+ withdrawAll: isWholePosition(
47747
+ {
47748
+ amount: withdrawOpts.totalPositionAmount,
47749
+ isLending: true
47750
+ },
47751
+ withdrawOpts.withdrawAmount,
47752
+ withdrawOpts.withdrawBank.mintDecimals
47753
+ ),
47754
+ isSync: false,
47994
47755
  opts: {
47756
+ createAtas: false,
47995
47757
  wrapAndUnwrapSol: false,
47996
47758
  overrideInferAccounts
47997
47759
  }
@@ -47999,12 +47761,33 @@ async function buildLoopFlashloanTx({
47999
47761
  break;
48000
47762
  }
48001
47763
  }
47764
+ const repayIxs = await makeRepayIx3({
47765
+ program,
47766
+ bank: repayOpts.repayBank,
47767
+ tokenProgram: repayOpts.tokenProgram,
47768
+ amount: amountToRepay,
47769
+ accountAddress: marginfiAccount.address,
47770
+ authority: marginfiAccount.authority,
47771
+ repayAll: isWholePosition(
47772
+ {
47773
+ amount: repayOpts.totalPositionAmount,
47774
+ isLending: true
47775
+ },
47776
+ amountToRepay,
47777
+ repayOpts.repayBank.mintDecimals
47778
+ ),
47779
+ isSync: false,
47780
+ opts: {
47781
+ wrapAndUnwrapSol: false,
47782
+ overrideInferAccounts
47783
+ }
47784
+ });
48002
47785
  const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
48003
47786
  const allNonFlIxs = [
48004
47787
  ...cuRequestIxs,
48005
- ...borrowIxs.instructions,
47788
+ ...withdrawIxs.instructions,
48006
47789
  ...swapInstructions,
48007
- ...depositIxs.instructions
47790
+ ...repayIxs.instructions
48008
47791
  ];
48009
47792
  if (swapInstructions.length > 0) {
48010
47793
  compileFlashloanPrecheck({
@@ -48022,12 +47805,13 @@ async function buildLoopFlashloanTx({
48022
47805
  bankMap,
48023
47806
  addressLookupTableAccounts: luts,
48024
47807
  blockhash,
48025
- ixs: allNonFlIxs
47808
+ ixs: allNonFlIxs,
47809
+ isSync: true
48026
47810
  });
48027
47811
  const txSize = getTxSize(flashloanTx);
48028
47812
  const totalKeys = getTotalAccountKeys(flashloanTx);
48029
47813
  if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48030
- throw TransactionBuildingError.swapSizeExceededLoop(
47814
+ throw TransactionBuildingError.swapSizeExceededRepay(
48031
47815
  txSize,
48032
47816
  totalKeys,
48033
47817
  swapOpts.swapConfig?.provider
@@ -48037,9 +47821,9 @@ async function buildLoopFlashloanTx({
48037
47821
  flashloanTx,
48038
47822
  setupInstructions,
48039
47823
  swapQuote,
48040
- borrowIxs,
48041
- depositIxs,
48042
- amountToDeposit
47824
+ withdrawIxs,
47825
+ repayIxs,
47826
+ amountToRepay
48043
47827
  };
48044
47828
  }
48045
47829
 
@@ -48470,7 +48254,7 @@ async function buildSwapCollateralFlashloanTx({
48470
48254
  const txSize = getTxSize(flashloanTx);
48471
48255
  const totalKeys = getTotalAccountKeys(flashloanTx);
48472
48256
  if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48473
- throw TransactionBuildingError.swapSizeExceededLoop(
48257
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
48474
48258
  txSize,
48475
48259
  totalKeys,
48476
48260
  swapOpts.swapConfig?.provider
@@ -48731,7 +48515,7 @@ async function buildSwapDebtFlashloanTx({
48731
48515
  const txSize = getTxSize(flashloanTx);
48732
48516
  const totalKeys = getTotalAccountKeys(flashloanTx);
48733
48517
  if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48734
- throw TransactionBuildingError.swapSizeExceededLoop(
48518
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
48735
48519
  txSize,
48736
48520
  totalKeys,
48737
48521
  swapOpts.swapConfig?.provider
@@ -49401,23 +49185,27 @@ var getTitanSwapIxsForFlashloan = async ({
49401
49185
  quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint
49402
49186
  );
49403
49187
  const { feeAccount, hasFeeAccount } = await checkTitanFeeAccount(connection, feeMint);
49188
+ const useFeeAccount = hasFeeAccount && !!quoteParams.platformFeeBps;
49404
49189
  let finalQuoteParams = quoteParams;
49405
- if (!hasFeeAccount) {
49406
- console.warn("Warning: Titan fee account ATA does not exist, disabling platform fee");
49190
+ if (!useFeeAccount) {
49191
+ if (!hasFeeAccount) {
49192
+ console.warn("Warning: Titan fee account ATA does not exist, disabling platform fee");
49193
+ }
49407
49194
  finalQuoteParams = {
49408
49195
  ...quoteParams,
49409
49196
  platformFeeBps: void 0
49410
49197
  };
49411
49198
  }
49199
+ const effectiveFeeAccount = useFeeAccount ? feeAccount : void 0;
49412
49200
  if (basePath.startsWith("wss://") || basePath.startsWith("ws://")) {
49413
49201
  return getTitanSwapIxsViaWebSocket(
49414
49202
  { quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
49415
- hasFeeAccount ? feeAccount : void 0
49203
+ effectiveFeeAccount
49416
49204
  );
49417
49205
  } else {
49418
49206
  return getTitanSwapIxsViaHttpProxy(
49419
49207
  { quoteParams: finalQuoteParams, authority, connection, destinationTokenAccount, apiConfig },
49420
- hasFeeAccount ? feeAccount : void 0
49208
+ effectiveFeeAccount
49421
49209
  );
49422
49210
  }
49423
49211
  };
@@ -49593,7 +49381,7 @@ async function getTitanExactOutViaWebSocket(params) {
49593
49381
  inputMint: new web3_js.PublicKey(inputMint).toBytes(),
49594
49382
  outputMint: new web3_js.PublicKey(outputMint).toBytes(),
49595
49383
  amount,
49596
- swapMode: "ExactOut",
49384
+ swapMode: "ExactOut" /* ExactOut */,
49597
49385
  slippageBps
49598
49386
  },
49599
49387
  transaction: {
@@ -49813,178 +49601,616 @@ var getSwapIxsForFlashloan = async (params) => {
49813
49601
  lastError = err;
49814
49602
  console.warn(`[swap] ${attemptProvider} failed:`, err instanceof Error ? err.message : err);
49815
49603
  }
49816
- }
49817
- const firstProvider = attempts[0]?.provider ?? "Swap";
49818
- throw TransactionBuildingError.swapQuoteFailed(
49819
- firstProvider,
49820
- inputMint,
49821
- outputMint,
49822
- lastError?.message ?? "No swap route available"
49823
- );
49824
- };
49825
- var getExactOutEstimate = async (params) => {
49826
- const { inputMint, outputMint, amount, swapOpts, connection } = params;
49827
- const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
49828
- const attempts = [
49829
- { provider, apiConfig: swapOpts.swapConfig?.apiConfig },
49830
- ...swapOpts.swapConfig?.fallbackProviders ?? []
49831
- ];
49832
- let lastError;
49833
- for (const { provider: attemptProvider, apiConfig } of attempts) {
49834
- const fn = getExactOutProviderFn({
49835
- attemptProvider,
49836
- inputMint,
49837
- outputMint,
49838
- amount,
49839
- swapOpts,
49840
- apiConfig
49841
- });
49842
- if (!fn) continue;
49843
- try {
49844
- return await fn(apiConfig);
49845
- } catch (err) {
49846
- if (err instanceof TransactionBuildingError) throw err;
49847
- lastError = err;
49848
- console.warn(
49849
- `[exactout] ${attemptProvider} failed:`,
49850
- err instanceof Error ? err.message : err
49851
- );
49604
+ }
49605
+ const firstProvider = attempts[0]?.provider ?? "Swap";
49606
+ throw TransactionBuildingError.swapQuoteFailed(
49607
+ firstProvider,
49608
+ inputMint,
49609
+ outputMint,
49610
+ lastError?.message ?? "No swap route available"
49611
+ );
49612
+ };
49613
+ var getExactOutEstimate = async (params) => {
49614
+ const { inputMint, outputMint, amount, swapOpts, connection } = params;
49615
+ const provider = swapOpts.swapConfig?.provider ?? "JUPITER" /* JUPITER */;
49616
+ const attempts = [
49617
+ { provider, apiConfig: swapOpts.swapConfig?.apiConfig },
49618
+ ...swapOpts.swapConfig?.fallbackProviders ?? []
49619
+ ];
49620
+ let lastError;
49621
+ for (const { provider: attemptProvider, apiConfig } of attempts) {
49622
+ const fn = getExactOutProviderFn({
49623
+ attemptProvider,
49624
+ inputMint,
49625
+ outputMint,
49626
+ amount,
49627
+ swapOpts,
49628
+ apiConfig
49629
+ });
49630
+ if (!fn) continue;
49631
+ try {
49632
+ return await fn(apiConfig);
49633
+ } catch (err) {
49634
+ if (err instanceof TransactionBuildingError) throw err;
49635
+ lastError = err;
49636
+ console.warn(
49637
+ `[exactout] ${attemptProvider} failed:`,
49638
+ err instanceof Error ? err.message : err
49639
+ );
49640
+ }
49641
+ }
49642
+ const firstProvider = attempts[0]?.provider ?? "Swap";
49643
+ throw TransactionBuildingError.swapQuoteFailed(
49644
+ firstProvider,
49645
+ inputMint,
49646
+ outputMint,
49647
+ lastError?.message ?? "No swap route available"
49648
+ );
49649
+ };
49650
+ function mapJupiterQuoteToSwapQuoteResult(quote) {
49651
+ return {
49652
+ inAmount: quote.inAmount,
49653
+ outAmount: quote.outAmount,
49654
+ otherAmountThreshold: quote.otherAmountThreshold,
49655
+ slippageBps: quote.slippageBps,
49656
+ platformFee: quote.platformFee ? {
49657
+ amount: quote.platformFee.amount ?? "0",
49658
+ feeBps: quote.platformFee.feeBps ?? 0
49659
+ } : void 0,
49660
+ priceImpactPct: quote.priceImpactPct,
49661
+ contextSlot: quote.contextSlot,
49662
+ timeTaken: quote.timeTaken,
49663
+ provider: "JUPITER" /* JUPITER */
49664
+ };
49665
+ }
49666
+
49667
+ // src/services/account/utils/jupiter.utils.ts
49668
+ var REFERRAL_PROGRAM_ID = new web3_js.PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
49669
+ var REFERRAL_ACCOUNT_PUBKEY = new web3_js.PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
49670
+ var getFeeAccount = (mint) => {
49671
+ const [feeAccount] = web3_js.PublicKey.findProgramAddressSync(
49672
+ [Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
49673
+ REFERRAL_PROGRAM_ID
49674
+ );
49675
+ return feeAccount.toBase58();
49676
+ };
49677
+ var checkFeeAccount = async (connection, mint) => {
49678
+ const feeAccount = getFeeAccount(mint);
49679
+ const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
49680
+ return { feeAccount, hasFeeAccount };
49681
+ };
49682
+ function deserializeJupiterInstruction(instruction) {
49683
+ return new web3_js.TransactionInstruction({
49684
+ programId: new web3_js.PublicKey(instruction.programId),
49685
+ keys: instruction.accounts.map((key) => ({
49686
+ pubkey: new web3_js.PublicKey(key.pubkey),
49687
+ isSigner: key.isSigner,
49688
+ isWritable: key.isWritable
49689
+ })),
49690
+ data: Buffer.from(instruction.data, "base64")
49691
+ });
49692
+ }
49693
+ function toJupiterConfig(apiConfig) {
49694
+ if (!apiConfig) return void 0;
49695
+ return {
49696
+ basePath: apiConfig.basePath,
49697
+ apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
49698
+ headers: apiConfig.headers
49699
+ };
49700
+ }
49701
+ var getJupiterSwapIxsForFlashloan = async ({
49702
+ quoteParams,
49703
+ authority,
49704
+ connection,
49705
+ destinationTokenAccount,
49706
+ apiConfig,
49707
+ maxSwapAccounts
49708
+ }) => {
49709
+ const configParams = toJupiterConfig(apiConfig);
49710
+ const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
49711
+ const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
49712
+ const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new web3_js.PublicKey(feeMint));
49713
+ const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
49714
+ const useFeeAccount = hasFeeAccount && !!quoteParams.platformFeeBps;
49715
+ let finalQuoteParams = quoteParams;
49716
+ if (!useFeeAccount) {
49717
+ if (!hasFeeAccount) {
49718
+ console.warn("Warning: feeAccountInfo is undefined");
49719
+ }
49720
+ finalQuoteParams = {
49721
+ ...quoteParams,
49722
+ platformFeeBps: void 0
49723
+ };
49724
+ }
49725
+ const JUPITER_MAX_ACCOUNTS_MARGIN = 4;
49726
+ const maxAccounts = maxSwapAccounts !== void 0 ? maxSwapAccounts - JUPITER_MAX_ACCOUNTS_MARGIN : 40;
49727
+ const swapQuote = await jupiterApiClient.quoteGet({
49728
+ ...finalQuoteParams,
49729
+ maxAccounts
49730
+ });
49731
+ const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
49732
+ swapRequest: {
49733
+ quoteResponse: swapQuote,
49734
+ userPublicKey: authority.toBase58(),
49735
+ feeAccount: useFeeAccount ? feeAccount : void 0,
49736
+ wrapAndUnwrapSol: false,
49737
+ destinationTokenAccount: destinationTokenAccount.toBase58()
49738
+ }
49739
+ });
49740
+ const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
49741
+ const lutAccountsRaw = await connection.getMultipleAccountsInfo(
49742
+ lutAddresses.map((address) => new web3_js.PublicKey(address))
49743
+ );
49744
+ const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
49745
+ const addressLookupTableAddress = lutAddresses[index];
49746
+ if (!accountInfo || !addressLookupTableAddress) {
49747
+ return null;
49748
+ }
49749
+ return new web3_js.AddressLookupTableAccount({
49750
+ key: new web3_js.PublicKey(addressLookupTableAddress),
49751
+ state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
49752
+ });
49753
+ }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
49754
+ const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
49755
+ const setupInstructions = swapInstructionResponse.setupInstructions.map(
49756
+ deserializeJupiterInstruction
49757
+ );
49758
+ return {
49759
+ swapInstructions: [instruction],
49760
+ setupInstructions,
49761
+ addressLookupTableAddresses: addressLookupTableAccounts,
49762
+ quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
49763
+ };
49764
+ };
49765
+
49766
+ // src/services/account/utils/misc.utils.ts
49767
+ function floor(value, decimals) {
49768
+ return Math.floor(value * 10 ** decimals) / 10 ** decimals;
49769
+ }
49770
+ function ceil(value, decimals) {
49771
+ return Math.ceil(value * 10 ** decimals) / 10 ** decimals;
49772
+ }
49773
+ function computeClosePositionTokenAmount(position, mintDecimals) {
49774
+ const closePositionTokenAmount = position.isLending ? floor(position.amount, mintDecimals) : ceil(position.amount, mintDecimals);
49775
+ return closePositionTokenAmount;
49776
+ }
49777
+ function isWholePosition(position, amount, mintDecimals) {
49778
+ const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
49779
+ return amount >= closePositionTokenAmount;
49780
+ }
49781
+ var SWAP_MERGE_OVERHEAD = 150;
49782
+ var FL_IX_OVERHEAD = 52;
49783
+ function compactU16Size(n) {
49784
+ return n < 128 ? 1 : n < 16384 ? 2 : 3;
49785
+ }
49786
+ function computeV0TxSize(ixs, payerKey, luts) {
49787
+ const keyMap = /* @__PURE__ */ new Map();
49788
+ const payerStr = payerKey.toBase58();
49789
+ keyMap.set(payerStr, { isSigner: true, isWritable: true });
49790
+ const programIds = /* @__PURE__ */ new Set();
49791
+ for (const ix of ixs) {
49792
+ const progStr = ix.programId.toBase58();
49793
+ programIds.add(progStr);
49794
+ if (!keyMap.has(progStr)) {
49795
+ keyMap.set(progStr, { isSigner: false, isWritable: false });
49796
+ }
49797
+ for (const meta of ix.keys) {
49798
+ const keyStr = meta.pubkey.toBase58();
49799
+ const existing = keyMap.get(keyStr);
49800
+ if (existing) {
49801
+ existing.isSigner = existing.isSigner || meta.isSigner;
49802
+ existing.isWritable = existing.isWritable || meta.isWritable;
49803
+ } else {
49804
+ keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
49805
+ }
49806
+ }
49807
+ }
49808
+ const lutLookup = /* @__PURE__ */ new Map();
49809
+ for (let li = 0; li < luts.length; li++) {
49810
+ const addresses = luts[li].state.addresses;
49811
+ for (let ai = 0; ai < addresses.length; ai++) {
49812
+ const addrStr = addresses[ai].toBase58();
49813
+ if (!lutLookup.has(addrStr)) {
49814
+ lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
49815
+ }
49816
+ }
49817
+ }
49818
+ let numStaticKeys = 0;
49819
+ let numWritableStaticKeys = 0;
49820
+ const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
49821
+ const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
49822
+ for (const [keyStr, props] of keyMap) {
49823
+ if (props.isSigner || programIds.has(keyStr)) {
49824
+ numStaticKeys++;
49825
+ if (props.isWritable) numWritableStaticKeys++;
49826
+ continue;
49827
+ }
49828
+ const lutEntry = lutLookup.get(keyStr);
49829
+ if (lutEntry) {
49830
+ if (props.isWritable) {
49831
+ lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
49832
+ } else {
49833
+ lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
49834
+ }
49835
+ } else {
49836
+ numStaticKeys++;
49837
+ if (props.isWritable) numWritableStaticKeys++;
49838
+ }
49839
+ }
49840
+ const fixedOverhead = 101;
49841
+ const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
49842
+ let ixSection = compactU16Size(ixs.length);
49843
+ for (const ix of ixs) {
49844
+ const numAccounts = ix.keys.length;
49845
+ ixSection += 1 + // programId index
49846
+ compactU16Size(numAccounts) + numAccounts + // account key indexes
49847
+ compactU16Size(ix.data.length) + ix.data.length;
49848
+ }
49849
+ let numUsedLuts = 0;
49850
+ let lutSection = 0;
49851
+ for (let li = 0; li < luts.length; li++) {
49852
+ const wCount = lutWritableIdxs[li].size;
49853
+ const rCount = lutReadonlyIdxs[li].size;
49854
+ if (wCount === 0 && rCount === 0) continue;
49855
+ numUsedLuts++;
49856
+ lutSection += 32 + // LUT address
49857
+ compactU16Size(wCount) + wCount + // writable indexes
49858
+ compactU16Size(rCount) + rCount;
49859
+ }
49860
+ lutSection += compactU16Size(numUsedLuts);
49861
+ let totalLutKeys = 0;
49862
+ for (let li = 0; li < luts.length; li++) {
49863
+ totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
49864
+ }
49865
+ const accountCount = numStaticKeys + totalLutKeys;
49866
+ let totalLutWritableKeys = 0;
49867
+ for (let li = 0; li < luts.length; li++) {
49868
+ totalLutWritableKeys += lutWritableIdxs[li].size;
49869
+ }
49870
+ const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
49871
+ const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
49872
+ return { size, accountCount, writableAccountCount };
49873
+ }
49874
+ function computeFlashLoanNonSwapBudget({
49875
+ program,
49876
+ marginfiAccount,
49877
+ ixs,
49878
+ bankMap,
49879
+ addressLookupTableAccounts
49880
+ }) {
49881
+ const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
49882
+ marginfiAccount.balances,
49883
+ ixs,
49884
+ program
49885
+ );
49886
+ const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
49887
+ const b = bankMap.get(key.toBase58());
49888
+ if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
49889
+ return b;
49890
+ });
49891
+ const endIndex = ixs.length + 1;
49892
+ const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
49893
+ program.programId,
49894
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
49895
+ { endIndex: new BN11__default.default(endIndex) }
49896
+ );
49897
+ const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
49898
+ const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
49899
+ program.programId,
49900
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
49901
+ endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
49902
+ );
49903
+ const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
49904
+ const nonSwapMsg = new web3_js.TransactionMessage({
49905
+ payerKey: marginfiAccount.authority,
49906
+ recentBlockhash: web3_js.PublicKey.default.toBase58(),
49907
+ instructions: allNonSwapIxs
49908
+ }).compileToV0Message(addressLookupTableAccounts);
49909
+ const nonSwapSize = new web3_js.VersionedTransaction(nonSwapMsg).serialize().length;
49910
+ const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
49911
+ const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
49912
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
49913
+ 0
49914
+ );
49915
+ const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
49916
+ const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
49917
+ console.log("[flashloan-budget]", {
49918
+ method: "compiled",
49919
+ nonSwapSize,
49920
+ nonSwapTotal,
49921
+ sizeConstraint,
49922
+ maxSwapTotalAccounts
49923
+ });
49924
+ return { sizeConstraint, maxSwapTotalAccounts };
49925
+ }
49926
+ function compileFlashloanPrecheck({
49927
+ allIxs,
49928
+ payer,
49929
+ luts,
49930
+ sizeConstraint,
49931
+ swapIxCount,
49932
+ swapLutCount
49933
+ }) {
49934
+ const msg = new web3_js.TransactionMessage({
49935
+ payerKey: payer,
49936
+ recentBlockhash: web3_js.PublicKey.default.toBase58(),
49937
+ instructions: allIxs
49938
+ }).compileToV0Message(luts);
49939
+ const rawSize = new web3_js.VersionedTransaction(msg).serialize().length;
49940
+ const fullTxSize = rawSize + FL_IX_OVERHEAD;
49941
+ const overshoot = fullTxSize - MAX_TX_SIZE;
49942
+ const { header, staticAccountKeys, addressTableLookups } = msg;
49943
+ const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
49944
+ const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
49945
+ const writableAccounts = writableStatic + writableLut;
49946
+ const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
49947
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
49948
+ 0
49949
+ );
49950
+ console.log("[flashloan-precheck]", {
49951
+ fullTxSize,
49952
+ overshoot,
49953
+ sizeConstraint,
49954
+ writableAccounts,
49955
+ totalAccounts,
49956
+ staticKeys: staticAccountKeys.length,
49957
+ numLuts: addressTableLookups.length,
49958
+ swapIxCount,
49959
+ swapLutCount
49960
+ });
49961
+ return { fullTxSize, overshoot, writableAccounts, totalAccounts };
49962
+ }
49963
+ async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
49964
+ const { bank, tokenProgram } = config;
49965
+ switch (config.type) {
49966
+ case "borrow":
49967
+ return makeBorrowIx3({
49968
+ program,
49969
+ bank,
49970
+ bankMap,
49971
+ tokenProgram,
49972
+ amount: 1,
49973
+ marginfiAccount,
49974
+ authority: marginfiAccount.authority,
49975
+ isSync: true,
49976
+ opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
49977
+ });
49978
+ case "repay":
49979
+ return makeRepayIx3({
49980
+ program,
49981
+ bank,
49982
+ tokenProgram,
49983
+ amount: 1,
49984
+ accountAddress: marginfiAccount.address,
49985
+ authority: marginfiAccount.authority,
49986
+ repayAll: false,
49987
+ isSync: true,
49988
+ opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
49989
+ });
49990
+ case "deposit":
49991
+ return buildDepositBudgetIx(
49992
+ config,
49993
+ program,
49994
+ marginfiAccount,
49995
+ bankMetadataMap,
49996
+ overrideInferAccounts
49997
+ );
49998
+ case "withdraw":
49999
+ return buildWithdrawBudgetIx(
50000
+ config,
50001
+ program,
50002
+ marginfiAccount,
50003
+ bankMap,
50004
+ bankMetadataMap,
50005
+ overrideInferAccounts
50006
+ );
50007
+ }
50008
+ }
50009
+ async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
50010
+ const { bank, tokenProgram } = config;
50011
+ const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
50012
+ switch (bank.config.assetTag) {
50013
+ case 3 /* KAMINO */: {
50014
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
50015
+ if (!reserve) {
50016
+ throw TransactionBuildingError.kaminoReserveNotFound(
50017
+ bank.address.toBase58(),
50018
+ bank.mint.toBase58(),
50019
+ bank.tokenSymbol
50020
+ );
50021
+ }
50022
+ return makeKaminoDepositIx3({
50023
+ program,
50024
+ bank,
50025
+ tokenProgram,
50026
+ amount: 1,
50027
+ accountAddress: marginfiAccount.address,
50028
+ authority: marginfiAccount.authority,
50029
+ group: marginfiAccount.group,
50030
+ reserve,
50031
+ isSync: true,
50032
+ opts
50033
+ });
50034
+ }
50035
+ case 4 /* DRIFT */: {
50036
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
50037
+ if (!driftState) {
50038
+ throw TransactionBuildingError.driftStateNotFound(
50039
+ bank.address.toBase58(),
50040
+ bank.mint.toBase58(),
50041
+ bank.tokenSymbol
50042
+ );
50043
+ }
50044
+ return makeDriftDepositIx3({
50045
+ program,
50046
+ bank,
50047
+ tokenProgram,
50048
+ amount: 1,
50049
+ accountAddress: marginfiAccount.address,
50050
+ authority: marginfiAccount.authority,
50051
+ group: marginfiAccount.group,
50052
+ driftMarketIndex: driftState.spotMarketState.marketIndex,
50053
+ driftOracle: driftState.spotMarketState.oracle,
50054
+ isSync: true,
50055
+ opts
50056
+ });
50057
+ }
50058
+ case 6 /* JUPLEND */: {
50059
+ return makeJuplendDepositIx2({
50060
+ program,
50061
+ bank,
50062
+ tokenProgram,
50063
+ amount: 1,
50064
+ accountAddress: marginfiAccount.address,
50065
+ authority: marginfiAccount.authority,
50066
+ group: marginfiAccount.group,
50067
+ isSync: true,
50068
+ opts
50069
+ });
50070
+ }
50071
+ default: {
50072
+ return makeDepositIx3({
50073
+ program,
50074
+ bank,
50075
+ tokenProgram,
50076
+ amount: 1,
50077
+ accountAddress: marginfiAccount.address,
50078
+ authority: marginfiAccount.authority,
50079
+ group: marginfiAccount.group,
50080
+ isSync: true,
50081
+ opts
50082
+ });
49852
50083
  }
49853
50084
  }
49854
- const firstProvider = attempts[0]?.provider ?? "Swap";
49855
- throw TransactionBuildingError.swapQuoteFailed(
49856
- firstProvider,
49857
- inputMint,
49858
- outputMint,
49859
- lastError?.message ?? "No swap route available"
49860
- );
49861
- };
49862
- function mapJupiterQuoteToSwapQuoteResult(quote) {
49863
- return {
49864
- inAmount: quote.inAmount,
49865
- outAmount: quote.outAmount,
49866
- otherAmountThreshold: quote.otherAmountThreshold,
49867
- slippageBps: quote.slippageBps,
49868
- platformFee: quote.platformFee ? {
49869
- amount: quote.platformFee.amount ?? "0",
49870
- feeBps: quote.platformFee.feeBps ?? 0
49871
- } : void 0,
49872
- priceImpactPct: quote.priceImpactPct,
49873
- contextSlot: quote.contextSlot,
49874
- timeTaken: quote.timeTaken,
49875
- provider: "JUPITER" /* JUPITER */
49876
- };
49877
- }
49878
-
49879
- // src/services/account/utils/jupiter.utils.ts
49880
- var REFERRAL_PROGRAM_ID = new web3_js.PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
49881
- var REFERRAL_ACCOUNT_PUBKEY = new web3_js.PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
49882
- var getFeeAccount = (mint) => {
49883
- const [feeAccount] = web3_js.PublicKey.findProgramAddressSync(
49884
- [Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
49885
- REFERRAL_PROGRAM_ID
49886
- );
49887
- return feeAccount.toBase58();
49888
- };
49889
- var checkFeeAccount = async (connection, mint) => {
49890
- const feeAccount = getFeeAccount(mint);
49891
- const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
49892
- return { feeAccount, hasFeeAccount };
49893
- };
49894
- function deserializeJupiterInstruction(instruction) {
49895
- return new web3_js.TransactionInstruction({
49896
- programId: new web3_js.PublicKey(instruction.programId),
49897
- keys: instruction.accounts.map((key) => ({
49898
- pubkey: new web3_js.PublicKey(key.pubkey),
49899
- isSigner: key.isSigner,
49900
- isWritable: key.isWritable
49901
- })),
49902
- data: Buffer.from(instruction.data, "base64")
49903
- });
49904
- }
49905
- function toJupiterConfig(apiConfig) {
49906
- if (!apiConfig) return void 0;
49907
- return {
49908
- basePath: apiConfig.basePath,
49909
- apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
49910
- headers: apiConfig.headers
49911
- };
49912
50085
  }
49913
- var getJupiterSwapIxsForFlashloan = async ({
49914
- quoteParams,
49915
- authority,
49916
- connection,
49917
- destinationTokenAccount,
49918
- apiConfig,
49919
- maxSwapAccounts
49920
- }) => {
49921
- const configParams = toJupiterConfig(apiConfig);
49922
- const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
49923
- const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
49924
- const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new web3_js.PublicKey(feeMint));
49925
- const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
49926
- let finalQuoteParams = quoteParams;
49927
- if (!hasFeeAccount) {
49928
- console.warn("Warning: feeAccountInfo is undefined");
49929
- finalQuoteParams = {
49930
- ...quoteParams,
49931
- platformFeeBps: void 0
49932
- };
49933
- }
49934
- const maxAccounts = maxSwapAccounts ?? 40;
49935
- const swapQuote = await jupiterApiClient.quoteGet({
49936
- ...finalQuoteParams,
49937
- maxAccounts
49938
- });
49939
- const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
49940
- swapRequest: {
49941
- quoteResponse: swapQuote,
49942
- userPublicKey: authority.toBase58(),
49943
- feeAccount: hasFeeAccount ? feeAccount : void 0,
49944
- wrapAndUnwrapSol: false,
49945
- destinationTokenAccount: destinationTokenAccount.toBase58()
50086
+ async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
50087
+ const { bank, tokenProgram } = config;
50088
+ const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
50089
+ switch (bank.config.assetTag) {
50090
+ case 3 /* KAMINO */: {
50091
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
50092
+ if (!reserve) {
50093
+ throw TransactionBuildingError.kaminoReserveNotFound(
50094
+ bank.address.toBase58(),
50095
+ bank.mint.toBase58(),
50096
+ bank.tokenSymbol
50097
+ );
50098
+ }
50099
+ return makeKaminoWithdrawIx3({
50100
+ program,
50101
+ bank,
50102
+ bankMap,
50103
+ tokenProgram,
50104
+ cTokenAmount: 1,
50105
+ marginfiAccount,
50106
+ authority: marginfiAccount.authority,
50107
+ reserve,
50108
+ withdrawAll: false,
50109
+ isSync: true,
50110
+ opts
50111
+ });
49946
50112
  }
49947
- });
49948
- const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
49949
- const lutAccountsRaw = await connection.getMultipleAccountsInfo(
49950
- lutAddresses.map((address) => new web3_js.PublicKey(address))
49951
- );
49952
- const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
49953
- const addressLookupTableAddress = lutAddresses[index];
49954
- if (!accountInfo || !addressLookupTableAddress) {
49955
- return null;
50113
+ case 4 /* DRIFT */: {
50114
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
50115
+ if (!driftState) {
50116
+ throw TransactionBuildingError.driftStateNotFound(
50117
+ bank.address.toBase58(),
50118
+ bank.mint.toBase58(),
50119
+ bank.tokenSymbol
50120
+ );
50121
+ }
50122
+ return makeDriftWithdrawIx3({
50123
+ program,
50124
+ bank,
50125
+ bankMap,
50126
+ tokenProgram,
50127
+ amount: 1,
50128
+ marginfiAccount,
50129
+ authority: marginfiAccount.authority,
50130
+ driftSpotMarket: driftState.spotMarketState,
50131
+ userRewards: driftState.userRewards,
50132
+ withdrawAll: false,
50133
+ isSync: true,
50134
+ opts
50135
+ });
49956
50136
  }
49957
- return new web3_js.AddressLookupTableAccount({
49958
- key: new web3_js.PublicKey(addressLookupTableAddress),
49959
- state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
49960
- });
49961
- }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
49962
- const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
49963
- const setupInstructions = swapInstructionResponse.setupInstructions.map(
49964
- deserializeJupiterInstruction
49965
- );
49966
- return {
49967
- swapInstructions: [instruction],
49968
- setupInstructions,
49969
- addressLookupTableAddresses: addressLookupTableAccounts,
49970
- quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
49971
- };
49972
- };
49973
-
49974
- // src/services/account/utils/misc.utils.ts
49975
- function floor(value, decimals) {
49976
- return Math.floor(value * 10 ** decimals) / 10 ** decimals;
49977
- }
49978
- function ceil(value, decimals) {
49979
- return Math.ceil(value * 10 ** decimals) / 10 ** decimals;
49980
- }
49981
- function computeClosePositionTokenAmount(position, mintDecimals) {
49982
- const closePositionTokenAmount = position.isLending ? floor(position.amount, mintDecimals) : ceil(position.amount, mintDecimals);
49983
- return closePositionTokenAmount;
50137
+ case 6 /* JUPLEND */: {
50138
+ const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
50139
+ if (!jupLendState) {
50140
+ throw TransactionBuildingError.jupLendStateNotFound(
50141
+ bank.address.toBase58(),
50142
+ bank.mint.toBase58(),
50143
+ bank.tokenSymbol
50144
+ );
50145
+ }
50146
+ return makeJuplendWithdrawIx2({
50147
+ program,
50148
+ bank,
50149
+ bankMap,
50150
+ tokenProgram,
50151
+ amount: 1,
50152
+ marginfiAccount,
50153
+ authority: marginfiAccount.authority,
50154
+ jupLendingState: jupLendState.jupLendingState,
50155
+ withdrawAll: false,
50156
+ opts
50157
+ });
50158
+ }
50159
+ default: {
50160
+ return makeWithdrawIx3({
50161
+ program,
50162
+ bank,
50163
+ bankMap,
50164
+ tokenProgram,
50165
+ amount: 1,
50166
+ marginfiAccount,
50167
+ authority: marginfiAccount.authority,
50168
+ withdrawAll: false,
50169
+ isSync: true,
50170
+ opts
50171
+ });
50172
+ }
50173
+ }
49984
50174
  }
49985
- function isWholePosition(position, amount, mintDecimals) {
49986
- const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
49987
- return amount >= closePositionTokenAmount;
50175
+ async function computeFlashloanSwapConstraints({
50176
+ program,
50177
+ marginfiAccount,
50178
+ bankMap,
50179
+ addressLookupTableAccounts,
50180
+ bankMetadataMap,
50181
+ primaryIx,
50182
+ secondaryIx,
50183
+ overrideInferAccounts
50184
+ }) {
50185
+ const cuRequestIxs = [
50186
+ web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
50187
+ web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
50188
+ ];
50189
+ const [primaryResult, secondaryResult] = await Promise.all([
50190
+ buildBudgetIx(
50191
+ primaryIx,
50192
+ program,
50193
+ marginfiAccount,
50194
+ bankMap,
50195
+ bankMetadataMap,
50196
+ overrideInferAccounts
50197
+ ),
50198
+ buildBudgetIx(
50199
+ secondaryIx,
50200
+ program,
50201
+ marginfiAccount,
50202
+ bankMap,
50203
+ bankMetadataMap,
50204
+ overrideInferAccounts
50205
+ )
50206
+ ]);
50207
+ return computeFlashLoanNonSwapBudget({
50208
+ program,
50209
+ marginfiAccount,
50210
+ bankMap,
50211
+ addressLookupTableAccounts,
50212
+ ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
50213
+ });
49988
50214
  }
49989
50215
 
49990
50216
  // src/services/price/utils/smart-crank.utils.ts
@@ -50652,18 +50878,15 @@ var fetchPythOracleData = async (banks, opts) => {
50652
50878
  bankOraclePriceMap: /* @__PURE__ */ new Map()
50653
50879
  };
50654
50880
  }
50655
- pythStakedCollateralBanks.map((bank) => [
50656
- opts.validatorVoteAccountByBank?.[bank.address.toBase58()] ?? "",
50657
- bank.mint.toBase58()
50658
- ]);
50659
- const priceCoeffByBank = {};
50660
50881
  const combinedPythBanks = [
50661
50882
  ...pythPushBanks,
50883
+ ...pythStakedCollateralBanks,
50662
50884
  ...pythPushKaminosBanks,
50663
50885
  ...driftPythPullBanks,
50664
50886
  ...solendPythPullBanks,
50665
50887
  ...juplendPythPullBanks
50666
50888
  ];
50889
+ const priceCoeffByBank = {};
50667
50890
  const pythOracleKeys = extractPythOracleKeys(combinedPythBanks);
50668
50891
  const uniquePythOracleKeys = Array.from(new Set(pythOracleKeys));
50669
50892
  let oraclePrices;
@@ -51467,6 +51690,78 @@ function computeRemainingCapacity(bank) {
51467
51690
  };
51468
51691
  }
51469
51692
 
51693
+ // src/services/bank/utils/bank-metrics.utils.ts
51694
+ function computeBankTotalDeposits(bank, assetShareValueMultiplier) {
51695
+ const totalAssets = getTotalAssetQuantity(bank).times(
51696
+ assetShareValueMultiplier ?? 1
51697
+ );
51698
+ return nativeToUi(totalAssets, bank.mintDecimals);
51699
+ }
51700
+ function computeBankTotalBorrows(bank) {
51701
+ return nativeToUi(getTotalLiabilityQuantity(bank), bank.mintDecimals);
51702
+ }
51703
+ function computeBankTotalDepositsUsd(bank, oraclePrice, assetShareValueMultiplier) {
51704
+ return computeUsdValue({
51705
+ bank,
51706
+ oraclePrice,
51707
+ quantity: getTotalAssetQuantity(bank),
51708
+ priceBias: 1 /* None */,
51709
+ isWeightedPrice: false,
51710
+ assetShareValueMultiplier
51711
+ }).toNumber();
51712
+ }
51713
+ function computeBankTotalBorrowsUsd(bank, oraclePrice) {
51714
+ return computeUsdValue({
51715
+ bank,
51716
+ oraclePrice,
51717
+ quantity: getTotalLiabilityQuantity(bank),
51718
+ priceBias: 1 /* None */,
51719
+ isWeightedPrice: false
51720
+ }).toNumber();
51721
+ }
51722
+ function computeBankPoolSize(bank, assetShareValueMultiplier) {
51723
+ const totalDeposits = computeBankTotalDeposits(bank, assetShareValueMultiplier);
51724
+ const totalBorrows = computeBankTotalBorrows(bank);
51725
+ const borrowCap = nativeToUi(bank.config.borrowLimit, bank.mintDecimals);
51726
+ return Math.max(0, Math.min(totalDeposits, borrowCap) - totalBorrows);
51727
+ }
51728
+ function computeBankDepositCapRemaining(bank) {
51729
+ const { depositCapacity } = computeRemainingCapacity(bank);
51730
+ return Math.max(0, nativeToUi(depositCapacity, bank.mintDecimals));
51731
+ }
51732
+ function computeBankBorrowCapRemaining(bank) {
51733
+ const { borrowCapacity } = computeRemainingCapacity(bank);
51734
+ return Math.max(0, nativeToUi(borrowCapacity, bank.mintDecimals));
51735
+ }
51736
+ function computeBankSupplyApy(bank) {
51737
+ return aprToApy(computeInterestRates(bank).lendingRate.toNumber());
51738
+ }
51739
+ function computeBankBorrowApy(bank) {
51740
+ return aprToApy(computeInterestRates(bank).borrowingRate.toNumber());
51741
+ }
51742
+ function computeBankMetrics(params) {
51743
+ const { bank, oraclePrice, assetShareValueMultiplier, symbol = "" } = params;
51744
+ return {
51745
+ symbol,
51746
+ totalDeposits: computeBankTotalDeposits(bank, assetShareValueMultiplier),
51747
+ totalBorrows: computeBankTotalBorrows(bank),
51748
+ totalDepositsUsd: computeBankTotalDepositsUsd(
51749
+ bank,
51750
+ oraclePrice,
51751
+ assetShareValueMultiplier
51752
+ ),
51753
+ totalBorrowsUsd: computeBankTotalBorrowsUsd(bank, oraclePrice),
51754
+ utilizationRate: computeUtilizationRate(bank).toNumber(),
51755
+ poolSize: computeBankPoolSize(bank, assetShareValueMultiplier),
51756
+ depositCap: nativeToUi(bank.config.depositLimit, bank.mintDecimals),
51757
+ borrowCap: nativeToUi(bank.config.borrowLimit, bank.mintDecimals),
51758
+ depositCapRemaining: computeBankDepositCapRemaining(bank),
51759
+ borrowCapRemaining: computeBankBorrowCapRemaining(bank),
51760
+ supplyApy: computeBankSupplyApy(bank),
51761
+ borrowApy: computeBankBorrowApy(bank)
51762
+ };
51763
+ }
51764
+
51470
51765
  // src/services/bank/bank.service.ts
51471
51766
  async function freezeBankConfigIx(program, bankAddress, bankConfigOpt) {
51472
51767
  let bankConfigRaw;
@@ -51868,6 +52163,613 @@ function dtoToValidatorStakeGroup(validatorStakeGroupDto) {
51868
52163
  }))
51869
52164
  };
51870
52165
  }
52166
+
52167
+ // src/services/native-stake/utils/metadata.data.ts
52168
+ var STAKED_BANK_METADATA_JSON = [
52169
+ {
52170
+ bankAddress: "8g5qG6PVygcVSXV1cJnjXaD1yhrDwcWAMQCY2wR9VuAf",
52171
+ validatorVoteAccount: "CooLbbZy5Xmdt7DiHPQ3ss2uRXawnTXXVgpMS8E8jDzr",
52172
+ tokenAddress: "BADo3D6nMtGnsAaTv3iEes8mMcq92TuFoBWebFe8kzeA",
52173
+ tokenName: "Cavey Cool",
52174
+ tokenSymbol: "COOL"
52175
+ },
52176
+ {
52177
+ bankAddress: "BuCckNm1djpp3vZVhvh1CrrniirY6sr2hwUmeP5kTcGz",
52178
+ validatorVoteAccount: "mrgn4t2JabSgvGnrCaHXMvz8ocr4F52scsxJnkQMQsQ",
52179
+ tokenAddress: "FUyAyVbYrMfiaN1QEQYFZTuBNzW5EJf3jWzjjymGqKLv",
52180
+ tokenName: "Project 0 Meridian",
52181
+ tokenSymbol: "MERIDIAN"
52182
+ },
52183
+ {
52184
+ bankAddress: "Hco1P3dGRXz3ZGFvMkbDgghZQy47Tp7vp7koSYRvP6nm",
52185
+ validatorVoteAccount: "mrgn6ETrBDM8mjjYN8rbVwFqVwF8z6rtmvGLbdGuVUU",
52186
+ tokenAddress: "A4B5MGQvcZCUqeiUEAB4ckZ2tvH2UmEg31vF7TiERDkH",
52187
+ tokenName: "MRGN 3",
52188
+ tokenSymbol: "MRGN3"
52189
+ },
52190
+ {
52191
+ bankAddress: "EPh2abWP8DusPH8myWnECAAeQUZgAz927aMbmwXt3eRY",
52192
+ validatorVoteAccount: "mrgn2vsZ5EJ8YEfAMNPXmRux7th9cNfBasQ1JJvVwPn",
52193
+ tokenAddress: "6Mt7tBWLUJfDxqCFTsjoRXF9wD55g4Lhs5nAyYp244pX",
52194
+ tokenName: "Project 0 Horizon",
52195
+ tokenSymbol: "HORIZON"
52196
+ },
52197
+ {
52198
+ bankAddress: "6wjAwhnxTMEzHk8NNHVXgkx1jSrb6TX1bC17j3S56FfB",
52199
+ validatorVoteAccount: "3N7s9zXMZ4QqvHQR15t5GNHyqc89KduzMP7423eWiD5g",
52200
+ tokenAddress: "DKPvRV4dxUejjGpr2XwFmzZbbbTD7vx9Jmt1kk43n4d5",
52201
+ tokenName: "Binance",
52202
+ tokenSymbol: "BINANCE"
52203
+ },
52204
+ {
52205
+ bankAddress: "J9tksvZEDSwtNtZ6yxYjWDDkzhPbwDMnihU61NkFG9FE",
52206
+ validatorVoteAccount: "he1iusunGwqrNtafDtLdhsUQDFvo13z9sUa36PauBtk",
52207
+ tokenAddress: "2k79y8CApbU9jAvWhLS2j6uRbaVjpLJTUzstBTho9vGq",
52208
+ tokenName: "Helius",
52209
+ tokenSymbol: "HELIUS"
52210
+ },
52211
+ {
52212
+ bankAddress: "Dfr6Sf44ftecaJaoJMzFQABdkt3CEHfBwut1WyacRzaE",
52213
+ validatorVoteAccount: "SLaYv7tCwetrFGbPCRnqpHswG5qqKino78EYpbGF7xY",
52214
+ tokenAddress: "Vsw4JT33S7bLbhjySMMyrP3JKvTAcNi9WG5Doekrmgg",
52215
+ tokenName: "Solayer",
52216
+ tokenSymbol: "SOLAYER"
52217
+ },
52218
+ {
52219
+ bankAddress: "BZAm4qGscR8gg5bmWrEq6BTofgaZPbg7Fwfa7rFghEXL",
52220
+ validatorVoteAccount: "J1to3PQfXidUUhprQWgdKkQAMWPJAEqSJ7amkBDE9qhF",
52221
+ tokenAddress: "6B8hZSupE5mcACmjzozP6C1DR2uaCCtmrGqcYWC6SBCc",
52222
+ tokenName: "Bonk",
52223
+ tokenSymbol: "BONK"
52224
+ },
52225
+ {
52226
+ bankAddress: "3UrMZ26NRKu2y6c2dPE7gZVHwEmhpwKLcWACg3tjCVEt",
52227
+ validatorVoteAccount: "J2nUHEAgZFRyuJbFjdqPrAa9gyWDuc7hErtDQHPhsYRp",
52228
+ tokenAddress: "9M7oMo4oL6RDPG7WbAX3Zz4dPzbMgpiCzwrQPMwG4Wgq",
52229
+ tokenName: "Phantom",
52230
+ tokenSymbol: "PHANTOM"
52231
+ },
52232
+ {
52233
+ bankAddress: "8c269gkonvATm93nviuYiriCQ829f7ypx3aScYDR1YoQ",
52234
+ validatorVoteAccount: "D3QPJm7BDzzPeRG51YZSEz3LfV7GvFNu9NkcibzURxuj",
52235
+ tokenAddress: "8hXCCQmYFcDhU5Mkuvyixp2Q11sbyQComkceSSh3GY4a",
52236
+ tokenName: "Starke Finance",
52237
+ tokenSymbol: "STARKE"
52238
+ },
52239
+ {
52240
+ bankAddress: "37tiA2NTF6YCt85XzCidPo9ZVpuqkkmfVJCYQ5Yx5Uhs",
52241
+ validatorVoteAccount: "SBLZib4npE7svxFA7AsD3ytdQAfYNb39c8zsU82AA2E",
52242
+ tokenAddress: "96rXgCFy1Er49169XoKHkeLiKC2k4bTy1641q1TVrMm2",
52243
+ tokenName: "SolBlaze Validator",
52244
+ tokenSymbol: "SOLBLAZE"
52245
+ },
52246
+ {
52247
+ bankAddress: "J9trpcrVdFjVNg6VFrdF1XPGgjftQKZhbbWsxertdv9V",
52248
+ validatorVoteAccount: "FACqsS19VScz8oo2YhdMg35EsAy6xsCZ9Y58eJXGv8QJ",
52249
+ tokenAddress: "AH6fxpHS2gtMtJgBy8y8pEAPkqyop2pSugF6REs9NaTp",
52250
+ tokenName: "Lantern",
52251
+ tokenSymbol: "LNTRN"
52252
+ },
52253
+ {
52254
+ bankAddress: "EGTfrYiuWpPPZ4yfY9tCxnK6QMkY7pzVie9DxK772iGe",
52255
+ validatorVoteAccount: "EfnywDKqArxK6N6FS9ctsuzNdxfx3pzfXEQE5EevQ1SV",
52256
+ tokenAddress: "FcXEwHku68ZquqtSj1eSWS1SVWkhAZSyb4usfpiuEJAL",
52257
+ tokenName: "PROJECT SUPER",
52258
+ tokenSymbol: "SUPER"
52259
+ },
52260
+ {
52261
+ bankAddress: "A5e7UTE3g11ZfKgftqRCvxAgcDuFGyeDjMka96zJWSWe",
52262
+ validatorVoteAccount: "3ZUQekqiZoybB57y49eqtvSaoonqDwuNbeqEGwN88JkQ",
52263
+ tokenAddress: "F1XPjtpsEy23Q7po4JkWjp1jkDZcvFYSrqD8TR1YL3EF",
52264
+ tokenName: "Paws",
52265
+ tokenSymbol: "PAWS"
52266
+ },
52267
+ {
52268
+ bankAddress: "91jkdp4cF8vCDhjwude3SGSGrmVWFk5vTAtR6fsGVAfy",
52269
+ validatorVoteAccount: "gangtRyGPTvYWb8K3xS2feJQaCks4iJ7rytFUPtVqSY",
52270
+ tokenAddress: "6ZS7ZVDw91BVAC8gsz3SZBSeVeF2GtXtL2BHK31Kvyjm",
52271
+ tokenName: "Lotus Validator",
52272
+ tokenSymbol: "LOTUS"
52273
+ },
52274
+ {
52275
+ bankAddress: "72BS34HkCgq8RWQR7kuVVmiJMtKqSxG4CHX6ZXpSCwg7",
52276
+ validatorVoteAccount: "oRAnGeU5h8h2UkvbfnE5cjXnnAa4rBoaxmS4kbFymSe",
52277
+ tokenAddress: "9yF8pXctzicum2P73uuk4Dhqf2MVz6tzRAe8THGXCJcp",
52278
+ tokenName: "Orangefin Ventures",
52279
+ tokenSymbol: "ORANGEFIN"
52280
+ },
52281
+ {
52282
+ bankAddress: "8F4DsU3NMFunUxBZkWrpYR8zwhAfoAt7QuiEPMtyhWvX",
52283
+ validatorVoteAccount: "3xjfK9C9YNcta8MvK1US4sQ3bc6DEjoJoR3qLExGf9xE",
52284
+ tokenAddress: "Akib1NYJzzh9HkiDH41S2LUefUmR1bKsk65xgqUcW5C5",
52285
+ tokenName: "pico\u{1F644}.sol",
52286
+ tokenSymbol: "PICO"
52287
+ },
52288
+ {
52289
+ bankAddress: "GdtggomQth6cxuYPdiVhBbcX7VC9rnDDwLMfxipxE2Po",
52290
+ validatorVoteAccount: "oPaLTmyvoUhW26QCMwLA5JNUeBYy72PDpFoXQF8SeX4",
52291
+ tokenAddress: "C71A3W7g5XALUNwTDWTwHX3qhfypaYZ41aNZjBpcaC9D",
52292
+ tokenName: "Temporal Opal",
52293
+ tokenSymbol: "OPAL"
52294
+ },
52295
+ {
52296
+ bankAddress: "5sJCKePwAhyD3mzrzLRDM2PkFMc85nnvvarxHLsvWvpg",
52297
+ validatorVoteAccount: "9jYFwBfbjYmvasFbJyES9apLJDTkwtbgSDRWanHEvcRw",
52298
+ tokenAddress: "Hj69K1WbnfZFipLbrzdxgGhDqCR47q48bN5nUHt6xQZo",
52299
+ tokenName: "WATCHTOWER",
52300
+ tokenSymbol: "WATCHTOWER"
52301
+ },
52302
+ {
52303
+ bankAddress: "3F3QXT3BtkegaBfFjn2odKLurFYLHJHJ99xKV2TRTvrk",
52304
+ validatorVoteAccount: "6JfBwvcz5QUKQJ37BMKTLrf968DDJBtwoZLw19aHwFtQ",
52305
+ tokenAddress: "8FqX86cQofBHReetZgxrxxvzN4iqMVsj2hbiv7pj2h73",
52306
+ tokenName: "Spectrum Staking",
52307
+ tokenSymbol: "SPECTRUM"
52308
+ },
52309
+ {
52310
+ bankAddress: "CFmvdtEPQJPVqS1QRkeRcdQm2itAPk6k8hSJbmt88Sjc",
52311
+ validatorVoteAccount: "Haz7b47sZBpxh9SwggGndN3fAyNQ1S949BPdxWXS3ab6",
52312
+ tokenAddress: "38ZUTefZnKSUJU3wxpUe3xpiw2j5WQPnmzSTNbS1JqLA",
52313
+ tokenName: "Temporal Emerald",
52314
+ tokenSymbol: "EMERALD"
52315
+ },
52316
+ {
52317
+ bankAddress: "CmBDHSVuodmUnanbBVFvY9cauLeosbdFQn9bJANMVYUG",
52318
+ validatorVoteAccount: "mintrNtxN3PhAB45Pt41XqyKghTTpqcoBkQTZqh96iR",
52319
+ tokenAddress: "GxGmv7s7s2co3pLZukns946fr5zmR8c5buWRD9prGd6v",
52320
+ tokenName: "Hanabi Staking",
52321
+ tokenSymbol: "haSOLmrgn"
52322
+ },
52323
+ {
52324
+ bankAddress: "7bLfrb4fWVYkVpZ9rg7dBUwKRAqLyiivCW4ahMMGcKyS",
52325
+ validatorVoteAccount: "76DafWkJ6pGK2hoD41HjrM4xTBhfKqrDYDazv13n5ir1",
52326
+ tokenAddress: "GT7n9uZbYzHv52YqDBowtZ5ZVW91umaBQTNPFQNeLUpR",
52327
+ tokenName: "Solana Japan Validator",
52328
+ tokenSymbol: "SolJAPAn"
52329
+ },
52330
+ {
52331
+ bankAddress: "6q5DB86DhCBQt5bqzZwgopV8EA96aCnngu5ebR1ooDFq",
52332
+ validatorVoteAccount: "Cue647T8jgwpRSDUb8ttTYx7NiEfJCRZNiiw1qmchXsG",
52333
+ tokenAddress: "EAR6LenhNstHxR9289rWakm82WgLJYvHD7NawfXtuyUx",
52334
+ tokenName: "KIWAMI",
52335
+ tokenSymbol: "KIWAMI"
52336
+ },
52337
+ {
52338
+ bankAddress: "GLSCJ39N82Xo21621jMheinvjQLrBrkG7gzo2C5L1y6y",
52339
+ validatorVoteAccount: "7emL18Bnve7wbYE9Az7vYJjikxN6YPU81igf6rVU5FN8",
52340
+ tokenAddress: "EQuMUgLZArKwWUk6uGPmTGYUgNbfgJrbBaNR7CQyZ5uf",
52341
+ tokenName: "Temporal Topaz",
52342
+ tokenSymbol: "TOPAZ"
52343
+ },
52344
+ {
52345
+ bankAddress: "4irzCCsU53ffh9XB7NxGzbbHjvSR7FTfPbn6KoXkt7kX",
52346
+ validatorVoteAccount: "2iWXwF2Q5W6o7yntV2mkbxncB4rYHnX61y3NU8a8EFMJ",
52347
+ tokenAddress: "14Pets6QpE9iXKkXg8Ri4GcDazRMfWR3guM6LZXnFChc",
52348
+ tokenName: "Bull Moose SOL",
52349
+ tokenSymbol: "bmsSOL"
52350
+ },
52351
+ {
52352
+ bankAddress: "C96do7nkEaaFjHq8jHzPpyPTdJSea5xEGwxDzDSepCzf",
52353
+ validatorVoteAccount: "voteRnv6PBzmiGP8NicWtQiqEJTwKKq2SxtqtdLUJjd",
52354
+ tokenAddress: "3YEDiJ4r4xRGNhq6nudRnkwrdKHG7PAtDim24CjTMtBH",
52355
+ tokenName: "diman",
52356
+ tokenSymbol: "DIMAN"
52357
+ },
52358
+ {
52359
+ bankAddress: "9dZiyG51FBR4BWpAs69XbDpr7GfVAEB1ZB89v38maV36",
52360
+ validatorVoteAccount: "Simpj3KyRQmpRkXuBvCQFS7DBBG6vqw93SkZb9UD1hp",
52361
+ tokenAddress: "77YLpVLQXr2KU66GM2JykbT9g5du7LarWgehbWD3CJaB",
52362
+ tokenName: "SIMPDIGIT",
52363
+ tokenSymbol: "SIMPDIGIT"
52364
+ },
52365
+ {
52366
+ bankAddress: "2foqT8wWzWRduyV37uRdj81DijkNMKzYD3D6JPfir7La",
52367
+ validatorVoteAccount: "48oxpSHQkM4sdXUY9NQ8KnEtebzZbyk8uUT7JRdVQNuf",
52368
+ tokenAddress: "42m7Ygk5VxREdKfcFrsH1HnuoqCke8BcVcxNeywMCfp2",
52369
+ tokenName: "Infinite Lux",
52370
+ tokenSymbol: "LUX"
52371
+ },
52372
+ {
52373
+ bankAddress: "FsdWEJzHXkUXejWnb7c1p9UJtF69hVWQNNoakjoXyRCJ",
52374
+ validatorVoteAccount: "4AUED4uj6nSTuANzaAUnGBPJQRmhpDYDwoWJNkoUUBBW",
52375
+ tokenAddress: "CiyQTfHJ9PbTwC7TGf4pXZk8szcWGJ8TeFhhCuUwybqi",
52376
+ tokenName: "Anagram",
52377
+ tokenSymbol: "ANAGRAM"
52378
+ },
52379
+ {
52380
+ bankAddress: "2hs1pHAzDWGqnn1d8VQkc8bZRfQ45grYvzfau8dnWFUk",
52381
+ validatorVoteAccount: "2NxEEbhqqj1Qptq5LXLbDTP5tLa9f7PqkU8zNgxbGU9P",
52382
+ tokenAddress: "9yQLxEzusZ7QiZNafDNdzbEaTCPuJToGjMhLRJtZbgsd",
52383
+ tokenName: "NANSEN",
52384
+ tokenSymbol: "NANSEN"
52385
+ },
52386
+ {
52387
+ bankAddress: "FCi8unSVCwJd3QkrhTtv6LTTjw1c4zV65D5cG5N1rAG6",
52388
+ validatorVoteAccount: "Va1idkzkB6LEmVFmxWbWU8Ao9qehC62Tjmf68L3uYKj",
52389
+ tokenAddress: "AExKb8oJ6mGPYJUyfiX49DMMi226h2AnWeG1G6neQBEz",
52390
+ tokenName: "VALIDATOR",
52391
+ tokenSymbol: "VALID"
52392
+ },
52393
+ {
52394
+ bankAddress: "HzS8RqaQ5syk6EHbVi7h9rFYN48PpxykUXEs6w9wNfNP",
52395
+ validatorVoteAccount: "sTach38ebT8jnGH8i2D1g8NDAS6An19whVMnSSWPXt4",
52396
+ tokenAddress: "AFDVYBqxADagPfN9DdbrNrf9zZqugub7CV4kUJEUrK6J",
52397
+ tokenName: "Stache Node",
52398
+ tokenSymbol: "STACHE"
52399
+ },
52400
+ {
52401
+ bankAddress: "9Hs4E6ACNw6Hmwjvm1duXzbaWmvXxSxN11agw4updEn1",
52402
+ validatorVoteAccount: "EtMSc3MvcDXUr6ChK5GxyFVwTxYA3zqP5XzjE9jwKvSV",
52403
+ tokenAddress: "ENKFyZQZHzNNSxcKYoaVsNLi2xoGPoStZH4A9xxezjbC",
52404
+ tokenName: "Mad Lads CN",
52405
+ tokenSymbol: "MadLadsCN"
52406
+ },
52407
+ {
52408
+ bankAddress: "4watsWcjTBAwsrZpArwQbnNX4bQ1yeHBxgdbrGT4eMu9",
52409
+ validatorVoteAccount: "EARNynHRWg6GfyJCmrrizcZxARB3HVzcaasvNa8kBS72",
52410
+ tokenAddress: "8fhkWcm2n28JuadzY7mRR8FFDZZfnaPfWgw7pLNVZCbE",
52411
+ tokenName: "Solana Compass Stake",
52412
+ tokenSymbol: "compaStake"
52413
+ },
52414
+ {
52415
+ bankAddress: "9d7MTvcz1VMB1rK6H73quMxkR26dLPz5HDaac2eGRjQx",
52416
+ validatorVoteAccount: "nymsndUdAZyUPpWYz5VEg8Ghj9cFvwTRgciLogpmYaQ",
52417
+ tokenAddress: "FWFeaqpkgDr3ejVSY3HjiUmUg3u9fcr5d66HvimnDLWE",
52418
+ tokenName: "Hypo Nyms",
52419
+ tokenSymbol: "NYMS"
52420
+ },
52421
+ {
52422
+ bankAddress: "6V4vCK3n3JVncfpS16mW8ceLoNPatvu61pKxFmWx8adi",
52423
+ validatorVoteAccount: "BT8LZUvQVwFHRGw2Dwv7UeqDUq7btfjegLpuz5bwgziD",
52424
+ tokenAddress: "9YRS7Stf9dVibTT1M4uVEAuRMcoS4MH1QxqXy9Lssrab",
52425
+ tokenName: "private",
52426
+ tokenSymbol: "private"
52427
+ },
52428
+ {
52429
+ bankAddress: "CK8qRAcmvkDXaqX2S5GkgTCZT5pCz34me1neQhpJYe1Z",
52430
+ validatorVoteAccount: "Ac1beBKixfNdrTAac7GRaTsJTxLyvgGvJjvy4qQfvyfc",
52431
+ tokenAddress: "DLTAbTL5NXhbqX6LX3ie3tf52pdtGpxe2DrZUr1RhgY6",
52432
+ tokenName: "Stronghold",
52433
+ tokenSymbol: "Stronghold"
52434
+ },
52435
+ {
52436
+ bankAddress: "H6CT1aiCgSNw9S6aq38npEhdoN2UPhSKe8Lj9fQqqjuu",
52437
+ validatorVoteAccount: "FREEL1BCzmPpNneC7FHCtBqzeWYrHRbtisFvi4N8XUP9",
52438
+ tokenAddress: "AKFuMoM5rjSpQSL4p6TBoc7D4dmEem9QrHhuSDCBYyZ8",
52439
+ tokenName: "Ross",
52440
+ tokenSymbol: "Ross"
52441
+ },
52442
+ {
52443
+ bankAddress: "G46aHuakgStymbE2WsLbja61mH5UXBPdSdpwf6Ci3saG",
52444
+ validatorVoteAccount: "mnvkHm47ZmRKoSWuQZAfXLRiDPiKCq8PWkMWrp1Wwqe",
52445
+ tokenAddress: "Cq9S5UB9BviPn5yoGkEDk3m7neQag4KJnhPWGyuev9W8",
52446
+ tokenName: "gripto staked sol",
52447
+ tokenSymbol: "GRIPTO"
52448
+ },
52449
+ {
52450
+ bankAddress: "75UmeEMdqVnGn3JHx8yVZEn7viybJ73XYSjhYCYfyhp2",
52451
+ validatorVoteAccount: "4m1PbxzwLdUnEwog3T9UKxgjktgriHgE1CfAhMqDw7Xx",
52452
+ tokenAddress: "432SogPNunjZMneDV6goZ8ZcCQz282GxoSJ4rwqx95pT",
52453
+ tokenName: "kumasol",
52454
+ tokenSymbol: "kumasol"
52455
+ },
52456
+ {
52457
+ bankAddress: "3zk6EmXANYQK12bwy9dySRAM4cT2vT5cDcAB79j8G33B",
52458
+ validatorVoteAccount: "HvsD9L5t62MGv3QBD2K7xjkipGYr9UZN7BtsW8NuSPpg",
52459
+ tokenAddress: "5vmwd6JHDCmX9W2XT1n2QpvYGA2kk4Xf7qWSayDU6caT",
52460
+ tokenName: "ArgenTerraSOL",
52461
+ tokenSymbol: "atSOL"
52462
+ },
52463
+ {
52464
+ bankAddress: "4C2vPweGNpiE6kTEbYvcbUBHNWxrn4ErQYaqWm5zDexx",
52465
+ validatorVoteAccount: "FnAPJkzf19s87sm24Qhv6bHZMZvZ43gjNUBRgjwXpD4v",
52466
+ tokenAddress: "6q4kVnwUpkE3i7W32dqaX6V12pbsrCnMqZ7TWz9yp1m5",
52467
+ tokenName: "BLOCKPORT",
52468
+ tokenSymbol: "BPT"
52469
+ },
52470
+ {
52471
+ bankAddress: "E5hZu5QQ1pRmGvyS4JHGXVQwzdUPaYM4yEiNKr64YzyG",
52472
+ validatorVoteAccount: "nfGcSJkP35SkPa5475iBChmq1UNcj7JE1uQHrrasymm",
52473
+ tokenAddress: "AQpQoJ3tJKGH9Yn8GSzoUsVcHPJjj3xYfQFp9XVr74F6",
52474
+ tokenName: "Test01",
52475
+ tokenSymbol: "TEST01"
52476
+ },
52477
+ {
52478
+ bankAddress: "3VCkXWAmE5DSwYRpqGFnkUz7vvD2RKbhFvrhzLuE8msu",
52479
+ validatorVoteAccount: "abc1zP7ihWsgQW8z5YmfQNqMckJE5Dfx8fwUNMNVNkY",
52480
+ tokenAddress: "BNisp3omkr6Rg5nHESWafjUbeCpGPy6MYq1iRJRgSAsh",
52481
+ tokenName: "ALGO STAKE",
52482
+ tokenSymbol: "ALGO"
52483
+ },
52484
+ {
52485
+ bankAddress: "7BHHMWw3P1AyebLhX9A8wnDeeGy8jgFXqqHuEZt7BVmW",
52486
+ validatorVoteAccount: "8Pep3GmYiijRALqrMKpez92cxvF4YPTzoZg83uXh14pW",
52487
+ tokenAddress: "zBH13AzXYCqHZKS8NGa4KR8zQhWiyvFdDY15nmfrHgS",
52488
+ tokenName: "8Pep",
52489
+ tokenSymbol: "8Pep"
52490
+ },
52491
+ {
52492
+ bankAddress: "9QWUatjtJtc98yts4ufWnmNeaWQRmaaLjFwbK3iMdS47",
52493
+ validatorVoteAccount: "CatzoSMUkTRidT5DwBxAC2pEtnwMBTpkCepHkFgZDiqb",
52494
+ tokenAddress: "98B1NMLYaNJQNxiQGr53vbjNFMNTYFmDqoCgj7qD9Vhm",
52495
+ tokenName: "JUPITER ",
52496
+ tokenSymbol: "JUPITER"
52497
+ },
52498
+ {
52499
+ bankAddress: "5q1wJkGqqRh6mSBtjG8sfjBsgJSGdA2QoXTWv4UQbHGk",
52500
+ validatorVoteAccount: "shft7Fry1js37Hm9wq4dfwcZSp2DyKszeWMvEpjYCQ1",
52501
+ tokenAddress: "C1KwBJZNwUaodUcP5kXqD52NCuZzThNAG2cw3vt5H6iE",
52502
+ tokenName: "BLUESHIFT",
52503
+ tokenSymbol: "SHIFT"
52504
+ },
52505
+ {
52506
+ bankAddress: "FZaHyfg9hmNMKpfUJ474wNKPaPdXMpnJouasKnndECiZ",
52507
+ validatorVoteAccount: "DdCNGDpP7qMgoAy6paFzhhak2EeyCZcgjH7ak5u5v28m",
52508
+ tokenAddress: "PhxXAYTkFZS23ZWvFcz6H6Uq4VnVBMa6hniiAyudjaW",
52509
+ tokenName: "KILN1",
52510
+ tokenSymbol: "KILN1"
52511
+ },
52512
+ {
52513
+ bankAddress: "5CBocarwfJeWGNozGemWktRYSz6kPikRPdfH8ZHSFrsg",
52514
+ validatorVoteAccount: "8zuMRTXThoPTTPLLvaiKiJshLLCqGMt9BdRjjCL19xBc",
52515
+ tokenAddress: "BDsEuxFWznAP5cUCannnfjyjDtTwqN57CkGfDbjx2nNZ",
52516
+ tokenName: "DawnLabs",
52517
+ tokenSymbol: "DawnLabs"
52518
+ },
52519
+ {
52520
+ bankAddress: "9ivswG37QpCUmkPkLMpRZT7PMyP64V9dDpZdteM254ec",
52521
+ validatorVoteAccount: "gaToR246dheK1DGAMEqxMdBJZwU4qFyt7DzhSwAHFWF",
52522
+ tokenAddress: "TjA2rtxoUFzyPVAw35VQGEQnNXiwcmNjKSk29nmkq1P",
52523
+ tokenName: "Valigator Open",
52524
+ tokenSymbol: "Valigator"
52525
+ }
52526
+ ];
52527
+
52528
+ // src/services/native-stake/utils/metadata.utils.ts
52529
+ var _metadataMap = null;
52530
+ var _voteAccountByBank = null;
52531
+ function getStakedBankMetadataMap() {
52532
+ if (!_metadataMap) {
52533
+ _metadataMap = /* @__PURE__ */ new Map();
52534
+ for (const entry of STAKED_BANK_METADATA_JSON) {
52535
+ _metadataMap.set(entry.bankAddress, entry);
52536
+ }
52537
+ }
52538
+ return _metadataMap;
52539
+ }
52540
+ function getValidatorVoteAccountByBank() {
52541
+ if (!_voteAccountByBank) {
52542
+ _voteAccountByBank = {};
52543
+ for (const entry of STAKED_BANK_METADATA_JSON) {
52544
+ _voteAccountByBank[entry.bankAddress] = entry.validatorVoteAccount;
52545
+ }
52546
+ }
52547
+ return _voteAccountByBank;
52548
+ }
52549
+ async function computeStakedBankMultipliers(stakedBanks, connection) {
52550
+ const multiplierByBank = /* @__PURE__ */ new Map();
52551
+ if (stakedBanks.length === 0) {
52552
+ return multiplierByBank;
52553
+ }
52554
+ const metadataMap = getStakedBankMetadataMap();
52555
+ const stakedBankAddresses = [];
52556
+ const poolStakeAddresses = [];
52557
+ const lstMintAddresses = [];
52558
+ for (const bank of stakedBanks) {
52559
+ const metadata = metadataMap.get(bank.address.toBase58());
52560
+ if (!metadata) {
52561
+ multiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
52562
+ continue;
52563
+ }
52564
+ const pool = findPoolAddress(new web3_js.PublicKey(metadata.validatorVoteAccount));
52565
+ stakedBankAddresses.push(bank.address.toBase58());
52566
+ poolStakeAddresses.push(findPoolStakeAddress(pool));
52567
+ lstMintAddresses.push(findPoolMintAddress(pool));
52568
+ }
52569
+ if (stakedBankAddresses.length === 0) {
52570
+ return multiplierByBank;
52571
+ }
52572
+ const allAddresses = [
52573
+ ...poolStakeAddresses.map((a) => a.toBase58()),
52574
+ ...lstMintAddresses.map((a) => a.toBase58())
52575
+ ];
52576
+ const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(connection, allAddresses);
52577
+ const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
52578
+ const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
52579
+ for (let i = 0; i < stakedBankAddresses.length; i++) {
52580
+ const bankAddr = stakedBankAddresses[i];
52581
+ const poolStakeInfo = poolStakeInfos[i];
52582
+ const lstMintInfo = lstMintInfos[i];
52583
+ if (!poolStakeInfo || !lstMintInfo) {
52584
+ multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
52585
+ continue;
52586
+ }
52587
+ const stakeLamports = poolStakeInfo.lamports;
52588
+ const supplyBuffer = lstMintInfo.data.slice(36, 44);
52589
+ const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
52590
+ if (lstMintSupply === 0) {
52591
+ multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
52592
+ continue;
52593
+ }
52594
+ const adjustedStake = Math.max(stakeLamports - web3_js.LAMPORTS_PER_SOL, 0);
52595
+ const multiplier = new BigNumber3__default.default(adjustedStake).dividedBy(lstMintSupply);
52596
+ multiplierByBank.set(bankAddr, multiplier);
52597
+ }
52598
+ return multiplierByBank;
52599
+ }
52600
+ var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
52601
+ async function makeMintStakedLstIx(params) {
52602
+ const { amount, authority, stakeAccountPk, validator, connection } = params;
52603
+ const pool = findPoolAddress(validator);
52604
+ const lstMint = findPoolMintAddress(pool);
52605
+ const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
52606
+ const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
52607
+ const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
52608
+ connection.getAccountInfo(lstAta),
52609
+ connection.getParsedAccountInfo(stakeAccountPk),
52610
+ connection.getMinimumBalanceForRentExemption(web3_js.StakeProgram.space)
52611
+ ]);
52612
+ const stakeAccParsed = stakeAccInfoParsed?.value?.data;
52613
+ const amountLamports = Math.round(Number(amount) * web3_js.LAMPORTS_PER_SOL);
52614
+ const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
52615
+ const isFullStake = amountLamports >= stakeAccLamports;
52616
+ const instructions2 = [];
52617
+ const signers = [];
52618
+ if (!lstAccInfo) {
52619
+ instructions2.push(
52620
+ createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
52621
+ );
52622
+ }
52623
+ let targetStakePubkey;
52624
+ if (!isFullStake) {
52625
+ const splitStakeAccount = web3_js.Keypair.generate();
52626
+ signers.push(splitStakeAccount);
52627
+ targetStakePubkey = splitStakeAccount.publicKey;
52628
+ instructions2.push(
52629
+ ...web3_js.StakeProgram.split(
52630
+ {
52631
+ stakePubkey: stakeAccountPk,
52632
+ authorizedPubkey: authority,
52633
+ splitStakePubkey: splitStakeAccount.publicKey,
52634
+ lamports: amountLamports
52635
+ },
52636
+ rentExemptReserve
52637
+ ).instructions
52638
+ );
52639
+ } else {
52640
+ targetStakePubkey = stakeAccountPk;
52641
+ }
52642
+ const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
52643
+ web3_js.StakeProgram.authorize({
52644
+ stakePubkey: targetStakePubkey,
52645
+ authorizedPubkey: authority,
52646
+ newAuthorizedPubkey: poolStakeAuth,
52647
+ stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Staker
52648
+ }).instructions,
52649
+ web3_js.StakeProgram.authorize({
52650
+ stakePubkey: targetStakePubkey,
52651
+ authorizedPubkey: authority,
52652
+ newAuthorizedPubkey: poolStakeAuth,
52653
+ stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Withdrawer
52654
+ }).instructions
52655
+ ]);
52656
+ [authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
52657
+ if (ix) {
52658
+ ix.keys = ix.keys.map((key) => ({
52659
+ ...key,
52660
+ isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
52661
+ }));
52662
+ }
52663
+ });
52664
+ instructions2.push(...authorizeStakerIx, ...authorizeWithdrawIx);
52665
+ const depositStakeIx = await SinglePoolInstruction.depositStake(
52666
+ pool,
52667
+ targetStakePubkey,
52668
+ lstAta,
52669
+ authority
52670
+ );
52671
+ instructions2.push(depositStakeIx);
52672
+ return { instructions: instructions2, keys: signers };
52673
+ }
52674
+ async function makeMintStakedLstTx(params) {
52675
+ const { connection, luts, blockhash: providedBlockhash } = params;
52676
+ const { instructions: instructions2, keys } = await makeMintStakedLstIx(params);
52677
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52678
+ const message = new web3_js.TransactionMessage({
52679
+ payerKey: params.authority,
52680
+ recentBlockhash: blockhash,
52681
+ instructions: instructions2
52682
+ }).compileToV0Message(luts);
52683
+ const tx = new web3_js.VersionedTransaction(message);
52684
+ return addTransactionMetadata(tx, {
52685
+ signers: keys,
52686
+ addressLookupTables: luts,
52687
+ type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
52688
+ });
52689
+ }
52690
+ async function makeRedeemStakedLstIx(params) {
52691
+ const { amount, authority, validator, connection } = params;
52692
+ const pool = findPoolAddress(validator);
52693
+ const lstMint = findPoolMintAddress(pool);
52694
+ const mintAuthority = findPoolMintAuthorityAddress(pool);
52695
+ const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
52696
+ const rentExemption = await connection.getMinimumBalanceForRentExemption(
52697
+ web3_js.StakeProgram.space
52698
+ );
52699
+ const stakeAmount = new BigNumber3__default.default(new BigNumber3__default.default(amount).toString());
52700
+ const instructions2 = [];
52701
+ const signers = [];
52702
+ const stakeAccount = web3_js.Keypair.generate();
52703
+ signers.push(stakeAccount);
52704
+ instructions2.push(
52705
+ web3_js.SystemProgram.createAccount({
52706
+ fromPubkey: authority,
52707
+ newAccountPubkey: stakeAccount.publicKey,
52708
+ lamports: rentExemption,
52709
+ space: web3_js.StakeProgram.space,
52710
+ programId: web3_js.StakeProgram.programId
52711
+ })
52712
+ );
52713
+ instructions2.push(
52714
+ createApproveInstruction(
52715
+ lstAta,
52716
+ mintAuthority,
52717
+ authority,
52718
+ BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
52719
+ )
52720
+ );
52721
+ const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
52722
+ pool,
52723
+ stakeAccount.publicKey,
52724
+ authority,
52725
+ lstAta,
52726
+ stakeAmount
52727
+ );
52728
+ instructions2.push(withdrawStakeIx);
52729
+ return { instructions: instructions2, keys: signers };
52730
+ }
52731
+ async function makeRedeemStakedLstTx(params) {
52732
+ const { connection, luts, blockhash: providedBlockhash } = params;
52733
+ const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
52734
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52735
+ const message = new web3_js.TransactionMessage({
52736
+ payerKey: params.authority,
52737
+ recentBlockhash: blockhash,
52738
+ instructions: instructions2
52739
+ }).compileToV0Message(luts);
52740
+ const tx = new web3_js.VersionedTransaction(message);
52741
+ return addTransactionMetadata(tx, {
52742
+ signers: keys,
52743
+ addressLookupTables: luts,
52744
+ type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
52745
+ });
52746
+ }
52747
+ async function makeMergeStakeAccountsTx(params) {
52748
+ const {
52749
+ authority,
52750
+ sourceStakeAccount,
52751
+ destinationStakeAccount,
52752
+ connection,
52753
+ luts,
52754
+ blockhash: providedBlockhash
52755
+ } = params;
52756
+ const mergeIx = web3_js.StakeProgram.merge({
52757
+ stakePubkey: destinationStakeAccount,
52758
+ sourceStakePubKey: sourceStakeAccount,
52759
+ authorizedPubkey: authority
52760
+ }).instructions;
52761
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52762
+ const message = new web3_js.TransactionMessage({
52763
+ payerKey: authority,
52764
+ recentBlockhash: blockhash,
52765
+ instructions: mergeIx
52766
+ }).compileToV0Message(luts);
52767
+ const tx = new web3_js.VersionedTransaction(message);
52768
+ return addTransactionMetadata(tx, {
52769
+ addressLookupTables: luts,
52770
+ type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
52771
+ });
52772
+ }
51871
52773
  async function getKaminoMetadata(options) {
51872
52774
  const kaminoBanks = options.banks.filter((b) => b.config.assetTag === 3 /* KAMINO */);
51873
52775
  const DEFAULT_PUBKEY = web3_js.PublicKey.default;
@@ -54565,7 +55467,6 @@ var Project0Client = class _Project0Client {
54565
55467
  assetShareMultiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
54566
55468
  break;
54567
55469
  case 2 /* STAKED */:
54568
- assetShareMultiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
54569
55470
  break;
54570
55471
  case 0 /* DEFAULT */:
54571
55472
  case 1 /* SOL */:
@@ -54574,6 +55475,11 @@ var Project0Client = class _Project0Client {
54574
55475
  break;
54575
55476
  }
54576
55477
  });
55478
+ const stakedMultipliers = await computeStakedBankMultipliers(
55479
+ banksArray.filter((b) => b.config.assetTag === 2 /* STAKED */),
55480
+ connection
55481
+ );
55482
+ stakedMultipliers.forEach((v, k) => assetShareMultiplierByBank.set(k, v));
54577
55483
  const emodePairs = getEmodePairs(banksArray);
54578
55484
  return new _Project0Client(
54579
55485
  program,
@@ -54725,6 +55631,16 @@ exports.computeActiveEmodePairs = computeActiveEmodePairs;
54725
55631
  exports.computeAssetHealthComponent = computeAssetHealthComponent;
54726
55632
  exports.computeAssetUsdValue = computeAssetUsdValue;
54727
55633
  exports.computeBalanceUsdValue = computeBalanceUsdValue;
55634
+ exports.computeBankBorrowApy = computeBankBorrowApy;
55635
+ exports.computeBankBorrowCapRemaining = computeBankBorrowCapRemaining;
55636
+ exports.computeBankDepositCapRemaining = computeBankDepositCapRemaining;
55637
+ exports.computeBankMetrics = computeBankMetrics;
55638
+ exports.computeBankPoolSize = computeBankPoolSize;
55639
+ exports.computeBankSupplyApy = computeBankSupplyApy;
55640
+ exports.computeBankTotalBorrows = computeBankTotalBorrows;
55641
+ exports.computeBankTotalBorrowsUsd = computeBankTotalBorrowsUsd;
55642
+ exports.computeBankTotalDeposits = computeBankTotalDeposits;
55643
+ exports.computeBankTotalDepositsUsd = computeBankTotalDepositsUsd;
54728
55644
  exports.computeBaseInterestRate = computeBaseInterestRate;
54729
55645
  exports.computeClaimedEmissions = computeClaimedEmissions;
54730
55646
  exports.computeClosePositionTokenAmount = computeClosePositionTokenAmount;
@@ -54755,6 +55671,7 @@ exports.computeQuantity = computeQuantity;
54755
55671
  exports.computeQuantityUi = computeQuantityUi;
54756
55672
  exports.computeRemainingCapacity = computeRemainingCapacity;
54757
55673
  exports.computeSmartCrank = computeSmartCrank;
55674
+ exports.computeStakedBankMultipliers = computeStakedBankMultipliers;
54758
55675
  exports.computeTotalOutstandingEmissions = computeTotalOutstandingEmissions;
54759
55676
  exports.computeTvl = computeTvl;
54760
55677
  exports.computeUsdValue = computeUsdValue;
@@ -54815,6 +55732,7 @@ exports.fetchSwbOraclePricesFromAPI = fetchSwbOraclePricesFromAPI;
54815
55732
  exports.fetchSwbOraclePricesFromCrossbar = fetchSwbOraclePricesFromCrossbar;
54816
55733
  exports.findRandomAvailableAccountIndex = findRandomAvailableAccountIndex;
54817
55734
  exports.freezeBankConfigIx = freezeBankConfigIx;
55735
+ exports.generateDummyAccount = generateDummyAccount;
54818
55736
  exports.getAccountKeys = getAccountKeys;
54819
55737
  exports.getActiveAccountFlags = getActiveAccountFlags;
54820
55738
  exports.getActiveBalances = getActiveBalances;
@@ -54853,6 +55771,7 @@ exports.getOracleSourceFromOracleSetup = getOracleSourceFromOracleSetup;
54853
55771
  exports.getOracleSourceNameFromKey = getOracleSourceNameFromKey;
54854
55772
  exports.getPrice = getPrice;
54855
55773
  exports.getPriceWithConfidence = getPriceWithConfidence;
55774
+ exports.getStakedBankMetadataMap = getStakedBankMetadataMap;
54856
55775
  exports.getSwapIxsForFlashloan = getSwapIxsForFlashloan;
54857
55776
  exports.getTitanExactOutEstimate = getTitanExactOutEstimate;
54858
55777
  exports.getTitanSwapIxsForFlashloan = getTitanSwapIxsForFlashloan;
@@ -54860,6 +55779,7 @@ exports.getTotalAccountKeys = getTotalAccountKeys;
54860
55779
  exports.getTotalAssetQuantity = getTotalAssetQuantity;
54861
55780
  exports.getTotalLiabilityQuantity = getTotalLiabilityQuantity;
54862
55781
  exports.getTxSize = getTxSize;
55782
+ exports.getValidatorVoteAccountByBank = getValidatorVoteAccountByBank;
54863
55783
  exports.getWritableAccountKeys = getWritableAccountKeys;
54864
55784
  exports.groupToDto = groupToDto;
54865
55785
  exports.hasAccountFlag = hasAccountFlag;
@@ -54901,11 +55821,16 @@ exports.makeKaminoDepositTx = makeKaminoDepositTx;
54901
55821
  exports.makeKaminoWithdrawIx = makeKaminoWithdrawIx3;
54902
55822
  exports.makeKaminoWithdrawTx = makeKaminoWithdrawTx;
54903
55823
  exports.makeLoopTx = makeLoopTx;
55824
+ exports.makeMergeStakeAccountsTx = makeMergeStakeAccountsTx;
55825
+ exports.makeMintStakedLstIx = makeMintStakedLstIx;
55826
+ exports.makeMintStakedLstTx = makeMintStakedLstTx;
54904
55827
  exports.makePoolAddBankIx = makePoolAddBankIx3;
54905
55828
  exports.makePoolConfigureBankIx = makePoolConfigureBankIx3;
54906
55829
  exports.makePriorityFeeIx = makePriorityFeeIx;
54907
55830
  exports.makePriorityFeeMicroIx = makePriorityFeeMicroIx;
54908
55831
  exports.makePulseHealthIx = makePulseHealthIx2;
55832
+ exports.makeRedeemStakedLstIx = makeRedeemStakedLstIx;
55833
+ exports.makeRedeemStakedLstTx = makeRedeemStakedLstTx;
54909
55834
  exports.makeRefreshKaminoBanksIxs = makeRefreshKaminoBanksIxs;
54910
55835
  exports.makeRepayIx = makeRepayIx3;
54911
55836
  exports.makeRepayTx = makeRepayTx;