@0dotxyz/p0-ts-sdk 2.2.0-alpha.5 → 2.2.0-alpha.6

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
  */
@@ -44385,12 +44374,28 @@ var V1Client = class _V1Client {
44385
44374
  return new Promise((resolve, reject) => {
44386
44375
  const ws = new WebSocket__default.default(url, [SUBPROTOCOL]);
44387
44376
  ws.binaryType = "arraybuffer";
44388
- ws.on("open", () => {
44377
+ const onOpen = () => {
44378
+ ws.off("error", onError);
44379
+ ws.off("close", onClose);
44389
44380
  resolve(new _V1Client(ws));
44390
- });
44391
- ws.on("error", (err) => {
44381
+ };
44382
+ const onError = (err) => {
44383
+ ws.off("open", onOpen);
44384
+ ws.off("close", onClose);
44392
44385
  reject(err);
44393
- });
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);
44394
44399
  });
44395
44400
  }
44396
44401
  // --- Constructor ---
@@ -46930,6 +46935,444 @@ async function makeJuplendDepositTx(params) {
46930
46935
  });
46931
46936
  return solanaTx;
46932
46937
  }
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(
46947
+ program,
46948
+ {
46949
+ marginfiAccount: marginfiAccountPk,
46950
+ authority
46951
+ },
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(
46959
+ program.programId,
46960
+ {
46961
+ marginfiAccount: marginfiAccountPk,
46962
+ authority
46963
+ },
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
+ }))
46980
+ );
46981
+ return { instructions: [ix], keys: [] };
46982
+ }
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;
47003
+ });
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;
47032
+ }
47033
+
47034
+ // src/services/account/actions/loop.ts
47035
+ async function makeLoopTx(params) {
47036
+ const {
47037
+ program,
47038
+ marginfiAccount,
47039
+ bankMap,
47040
+ depositOpts,
47041
+ borrowOpts,
47042
+ bankMetadataMap,
47043
+ addressLookupTableAccounts,
47044
+ connection,
47045
+ oraclePrices,
47046
+ crossbarUrl,
47047
+ additionalIxs = []
47048
+ } = params;
47049
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
47050
+ const setupIxs = await makeSetupIx({
47051
+ connection,
47052
+ authority: marginfiAccount.authority,
47053
+ tokens: [
47054
+ {
47055
+ mint: borrowOpts.borrowBank.mint,
47056
+ tokenProgram: borrowOpts.tokenProgram
47057
+ },
47058
+ {
47059
+ mint: depositOpts.depositBank.mint,
47060
+ tokenProgram: depositOpts.tokenProgram
47061
+ }
47062
+ ]
47063
+ });
47064
+ const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
47065
+ params.marginfiAccount,
47066
+ params.bankMap,
47067
+ [depositOpts.depositBank.address],
47068
+ params.bankMetadataMap
47069
+ );
47070
+ const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
47071
+ params.marginfiAccount,
47072
+ params.bankMap,
47073
+ [depositOpts.depositBank.address],
47074
+ params.bankMetadataMap
47075
+ );
47076
+ const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
47077
+ marginfiAccount,
47078
+ bankMap,
47079
+ [borrowOpts.borrowBank.address, depositOpts.depositBank.address],
47080
+ bankMetadataMap
47081
+ );
47082
+ const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
47083
+ ...params,
47084
+ blockhash
47085
+ });
47086
+ const jupiterSetupInstructions = setupInstructions.filter((ix) => {
47087
+ if (ix.programId.equals(web3_js.ComputeBudgetProgram.programId)) {
47088
+ return false;
47089
+ }
47090
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
47091
+ const mintKey = ix.keys[3]?.pubkey;
47092
+ if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
47093
+ return false;
47094
+ }
47095
+ }
47096
+ return true;
47097
+ });
47098
+ setupIxs.push(...jupiterSetupInstructions);
47099
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
47100
+ marginfiAccount,
47101
+ bankMap,
47102
+ oraclePrices,
47103
+ assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
47104
+ instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
47105
+ program,
47106
+ connection,
47107
+ crossbarUrl
47108
+ });
47109
+ let additionalTxs = [];
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) {
47116
+ const ixs = [
47117
+ ...additionalIxs,
47118
+ ...setupIxs,
47119
+ ...kaminoRefreshIxs.instructions,
47120
+ ...updateDriftMarketIxs.instructions,
47121
+ ...updateJupLendRateIxs.instructions
47122
+ ];
47123
+ const txs = splitInstructionsToFitTransactions([], ixs, {
47124
+ blockhash,
47125
+ payerKey: marginfiAccount.authority,
47126
+ luts: addressLookupTableAccounts ?? []
47127
+ });
47128
+ additionalTxs.push(
47129
+ ...txs.map(
47130
+ (tx) => addTransactionMetadata(tx, {
47131
+ type: "CREATE_ATA" /* CREATE_ATA */,
47132
+ addressLookupTables: addressLookupTableAccounts
47133
+ })
47134
+ )
47135
+ );
47136
+ }
47137
+ if (updateFeedIxs.length > 0) {
47138
+ const message = new web3_js.TransactionMessage({
47139
+ payerKey: marginfiAccount.authority,
47140
+ recentBlockhash: blockhash,
47141
+ instructions: updateFeedIxs
47142
+ }).compileToV0Message(feedLuts);
47143
+ additionalTxs.push(
47144
+ addTransactionMetadata(new web3_js.VersionedTransaction(message), {
47145
+ addressLookupTables: feedLuts,
47146
+ type: "CRANK" /* CRANK */
47147
+ })
47148
+ );
47149
+ }
47150
+ const transactions = [...additionalTxs, flashloanTx];
47151
+ return {
47152
+ transactions,
47153
+ actionTxIndex: transactions.length - 1,
47154
+ quoteResponse: swapQuote
47155
+ };
47156
+ }
47157
+ async function buildLoopFlashloanTx({
47158
+ program,
47159
+ marginfiAccount,
47160
+ bankMap,
47161
+ borrowOpts,
47162
+ depositOpts,
47163
+ bankMetadataMap,
47164
+ addressLookupTableAccounts,
47165
+ connection,
47166
+ swapOpts,
47167
+ overrideInferAccounts,
47168
+ blockhash
47169
+ }) {
47170
+ const cuRequestIxs = [
47171
+ web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47172
+ web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47173
+ ];
47174
+ let amountToDeposit;
47175
+ let swapInstructions = [];
47176
+ let setupInstructions = [];
47177
+ let swapLookupTables = [];
47178
+ let swapQuote;
47179
+ let sizeConstraintUsed = 0;
47180
+ if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
47181
+ amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
47182
+ } else {
47183
+ const destinationTokenAccount = getAssociatedTokenAddressSync(
47184
+ new web3_js.PublicKey(depositOpts.depositBank.mint),
47185
+ marginfiAccount.authority,
47186
+ true,
47187
+ depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
47188
+ );
47189
+ const swapConstraints = await computeFlashloanSwapConstraints({
47190
+ program,
47191
+ marginfiAccount,
47192
+ bankMap,
47193
+ bankMetadataMap,
47194
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
47195
+ primaryIx: {
47196
+ type: "borrow",
47197
+ bank: borrowOpts.borrowBank,
47198
+ tokenProgram: borrowOpts.tokenProgram
47199
+ },
47200
+ secondaryIx: {
47201
+ type: "deposit",
47202
+ bank: depositOpts.depositBank,
47203
+ tokenProgram: depositOpts.tokenProgram
47204
+ },
47205
+ overrideInferAccounts
47206
+ });
47207
+ const swapResponse = await getSwapIxsForFlashloan({
47208
+ inputMint: borrowOpts.borrowBank.mint.toBase58(),
47209
+ outputMint: depositOpts.depositBank.mint.toBase58(),
47210
+ amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
47211
+ swapMode: "ExactIn",
47212
+ authority: marginfiAccount.authority,
47213
+ connection,
47214
+ destinationTokenAccount,
47215
+ swapOpts,
47216
+ sizeConstraint: swapConstraints.sizeConstraint,
47217
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
47218
+ });
47219
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
47220
+ const outAmountThreshold = nativeToUi(
47221
+ swapResponse.quoteResponse.otherAmountThreshold,
47222
+ depositOpts.depositBank.mintDecimals
47223
+ );
47224
+ amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
47225
+ swapInstructions = swapResponse.swapInstructions;
47226
+ setupInstructions = swapResponse.setupInstructions;
47227
+ swapLookupTables = swapResponse.addressLookupTableAddresses;
47228
+ swapQuote = swapResponse.quoteResponse;
47229
+ }
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) {
47247
+ case 3 /* KAMINO */: {
47248
+ const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
47249
+ if (!reserve) {
47250
+ throw TransactionBuildingError.kaminoReserveNotFound(
47251
+ depositOpts.depositBank.address.toBase58(),
47252
+ depositOpts.depositBank.mint.toBase58(),
47253
+ depositOpts.depositBank.tokenSymbol
47254
+ );
47255
+ }
47256
+ depositIxs = await makeKaminoDepositIx3({
47257
+ program,
47258
+ bank: depositOpts.depositBank,
47259
+ tokenProgram: depositOpts.tokenProgram,
47260
+ amount: amountToDeposit,
47261
+ accountAddress: marginfiAccount.address,
47262
+ authority: marginfiAccount.authority,
47263
+ group: marginfiAccount.group,
47264
+ reserve,
47265
+ opts: {
47266
+ wrapAndUnwrapSol: false,
47267
+ overrideInferAccounts
47268
+ }
47269
+ });
47270
+ break;
47271
+ }
47272
+ case 4 /* DRIFT */: {
47273
+ const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
47274
+ if (!driftState) {
47275
+ throw TransactionBuildingError.driftStateNotFound(
47276
+ depositOpts.depositBank.address.toBase58(),
47277
+ depositOpts.depositBank.mint.toBase58(),
47278
+ depositOpts.depositBank.tokenSymbol
47279
+ );
47280
+ }
47281
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
47282
+ const driftOracle = driftState.spotMarketState.oracle;
47283
+ depositIxs = await makeDriftDepositIx3({
47284
+ program,
47285
+ bank: depositOpts.depositBank,
47286
+ tokenProgram: depositOpts.tokenProgram,
47287
+ amount: amountToDeposit,
47288
+ accountAddress: marginfiAccount.address,
47289
+ authority: marginfiAccount.authority,
47290
+ group: marginfiAccount.group,
47291
+ driftMarketIndex,
47292
+ driftOracle,
47293
+ opts: {
47294
+ wrapAndUnwrapSol: false,
47295
+ overrideInferAccounts
47296
+ }
47297
+ });
47298
+ break;
47299
+ }
47300
+ case 6 /* JUPLEND */: {
47301
+ depositIxs = await makeJuplendDepositIx2({
47302
+ program,
47303
+ bank: depositOpts.depositBank,
47304
+ tokenProgram: depositOpts.tokenProgram,
47305
+ amount: amountToDeposit,
47306
+ accountAddress: marginfiAccount.address,
47307
+ authority: marginfiAccount.authority,
47308
+ group: marginfiAccount.group,
47309
+ opts: {
47310
+ wrapAndUnwrapSol: false,
47311
+ overrideInferAccounts
47312
+ }
47313
+ });
47314
+ break;
47315
+ }
47316
+ default: {
47317
+ depositIxs = await makeDepositIx3({
47318
+ program,
47319
+ bank: depositOpts.depositBank,
47320
+ tokenProgram: depositOpts.tokenProgram,
47321
+ amount: amountToDeposit,
47322
+ accountAddress: marginfiAccount.address,
47323
+ authority: marginfiAccount.authority,
47324
+ group: marginfiAccount.group,
47325
+ opts: {
47326
+ wrapAndUnwrapSol: false,
47327
+ overrideInferAccounts
47328
+ }
47329
+ });
47330
+ break;
47331
+ }
47332
+ }
47333
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
47334
+ const allNonFlIxs = [
47335
+ ...cuRequestIxs,
47336
+ ...borrowIxs.instructions,
47337
+ ...swapInstructions,
47338
+ ...depositIxs.instructions
47339
+ ];
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({
47351
+ program,
47352
+ marginfiAccount,
47353
+ bankMap,
47354
+ addressLookupTableAccounts: luts,
47355
+ blockhash,
47356
+ ixs: allNonFlIxs
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
+ };
47375
+ }
46933
47376
  async function makeRepayIx3({
46934
47377
  program,
46935
47378
  bank,
@@ -47384,882 +47827,6 @@ async function buildRepayWithCollatFlashloanTx({
47384
47827
  };
47385
47828
  }
47386
47829
 
47387
- // src/services/account/utils/flashloan-size.utils.ts
47388
- var SWAP_MERGE_OVERHEAD = 150;
47389
- var FL_IX_OVERHEAD = 52;
47390
- function compactU16Size(n) {
47391
- return n < 128 ? 1 : n < 16384 ? 2 : 3;
47392
- }
47393
- function computeV0TxSize(ixs, payerKey, luts) {
47394
- const keyMap = /* @__PURE__ */ new Map();
47395
- const payerStr = payerKey.toBase58();
47396
- keyMap.set(payerStr, { isSigner: true, isWritable: true });
47397
- const programIds = /* @__PURE__ */ new Set();
47398
- for (const ix of ixs) {
47399
- const progStr = ix.programId.toBase58();
47400
- programIds.add(progStr);
47401
- if (!keyMap.has(progStr)) {
47402
- keyMap.set(progStr, { isSigner: false, isWritable: false });
47403
- }
47404
- for (const meta of ix.keys) {
47405
- const keyStr = meta.pubkey.toBase58();
47406
- const existing = keyMap.get(keyStr);
47407
- if (existing) {
47408
- existing.isSigner = existing.isSigner || meta.isSigner;
47409
- existing.isWritable = existing.isWritable || meta.isWritable;
47410
- } else {
47411
- keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
47412
- }
47413
- }
47414
- }
47415
- const lutLookup = /* @__PURE__ */ new Map();
47416
- for (let li = 0; li < luts.length; li++) {
47417
- const addresses = luts[li].state.addresses;
47418
- for (let ai = 0; ai < addresses.length; ai++) {
47419
- const addrStr = addresses[ai].toBase58();
47420
- if (!lutLookup.has(addrStr)) {
47421
- lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
47422
- }
47423
- }
47424
- }
47425
- let numStaticKeys = 0;
47426
- let numWritableStaticKeys = 0;
47427
- const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
47428
- const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
47429
- for (const [keyStr, props] of keyMap) {
47430
- if (props.isSigner || programIds.has(keyStr)) {
47431
- numStaticKeys++;
47432
- if (props.isWritable) numWritableStaticKeys++;
47433
- continue;
47434
- }
47435
- const lutEntry = lutLookup.get(keyStr);
47436
- if (lutEntry) {
47437
- if (props.isWritable) {
47438
- lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
47439
- } else {
47440
- lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
47441
- }
47442
- } else {
47443
- numStaticKeys++;
47444
- if (props.isWritable) numWritableStaticKeys++;
47445
- }
47446
- }
47447
- const fixedOverhead = 101;
47448
- const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
47449
- let ixSection = compactU16Size(ixs.length);
47450
- for (const ix of ixs) {
47451
- const numAccounts = ix.keys.length;
47452
- ixSection += 1 + // programId index
47453
- compactU16Size(numAccounts) + numAccounts + // account key indexes
47454
- compactU16Size(ix.data.length) + ix.data.length;
47455
- }
47456
- let numUsedLuts = 0;
47457
- let lutSection = 0;
47458
- for (let li = 0; li < luts.length; li++) {
47459
- const wCount = lutWritableIdxs[li].size;
47460
- const rCount = lutReadonlyIdxs[li].size;
47461
- if (wCount === 0 && rCount === 0) continue;
47462
- numUsedLuts++;
47463
- lutSection += 32 + // LUT address
47464
- compactU16Size(wCount) + wCount + // writable indexes
47465
- compactU16Size(rCount) + rCount;
47466
- }
47467
- lutSection += compactU16Size(numUsedLuts);
47468
- let totalLutKeys = 0;
47469
- for (let li = 0; li < luts.length; li++) {
47470
- totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
47471
- }
47472
- const accountCount = numStaticKeys + totalLutKeys;
47473
- let totalLutWritableKeys = 0;
47474
- for (let li = 0; li < luts.length; li++) {
47475
- totalLutWritableKeys += lutWritableIdxs[li].size;
47476
- }
47477
- const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
47478
- const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
47479
- return { size, accountCount, writableAccountCount };
47480
- }
47481
- function computeFlashLoanNonSwapBudget({
47482
- program,
47483
- marginfiAccount,
47484
- ixs,
47485
- bankMap,
47486
- addressLookupTableAccounts
47487
- }) {
47488
- const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
47489
- marginfiAccount.balances,
47490
- ixs,
47491
- program
47492
- );
47493
- const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
47494
- const b = bankMap.get(key.toBase58());
47495
- if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
47496
- return b;
47497
- });
47498
- const endIndex = ixs.length + 1;
47499
- const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
47500
- program.programId,
47501
- { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
47502
- { endIndex: new BN11__default.default(endIndex) }
47503
- );
47504
- const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
47505
- const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
47506
- program.programId,
47507
- { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
47508
- endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
47509
- );
47510
- const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
47511
- const nonSwapMsg = new web3_js.TransactionMessage({
47512
- payerKey: marginfiAccount.authority,
47513
- recentBlockhash: web3_js.PublicKey.default.toBase58(),
47514
- instructions: allNonSwapIxs
47515
- }).compileToV0Message(addressLookupTableAccounts);
47516
- const nonSwapSize = new web3_js.VersionedTransaction(nonSwapMsg).serialize().length;
47517
- const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
47518
- const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
47519
- (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
47520
- 0
47521
- );
47522
- const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
47523
- const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
47524
- console.log("[flashloan-budget]", {
47525
- method: "compiled",
47526
- nonSwapSize,
47527
- nonSwapTotal,
47528
- sizeConstraint,
47529
- maxSwapTotalAccounts
47530
- });
47531
- return { sizeConstraint, maxSwapTotalAccounts };
47532
- }
47533
- function compileFlashloanPrecheck({
47534
- allIxs,
47535
- payer,
47536
- luts,
47537
- sizeConstraint,
47538
- swapIxCount,
47539
- swapLutCount
47540
- }) {
47541
- const msg = new web3_js.TransactionMessage({
47542
- payerKey: payer,
47543
- recentBlockhash: web3_js.PublicKey.default.toBase58(),
47544
- instructions: allIxs
47545
- }).compileToV0Message(luts);
47546
- const rawSize = new web3_js.VersionedTransaction(msg).serialize().length;
47547
- const fullTxSize = rawSize + FL_IX_OVERHEAD;
47548
- const overshoot = fullTxSize - MAX_TX_SIZE;
47549
- const { header, staticAccountKeys, addressTableLookups } = msg;
47550
- const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
47551
- const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
47552
- const writableAccounts = writableStatic + writableLut;
47553
- const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
47554
- (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
47555
- 0
47556
- );
47557
- console.log("[flashloan-precheck]", {
47558
- fullTxSize,
47559
- overshoot,
47560
- sizeConstraint,
47561
- writableAccounts,
47562
- totalAccounts,
47563
- staticKeys: staticAccountKeys.length,
47564
- numLuts: addressTableLookups.length,
47565
- swapIxCount,
47566
- swapLutCount
47567
- });
47568
- return { fullTxSize, overshoot, writableAccounts, totalAccounts };
47569
- }
47570
- async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
47571
- const { bank, tokenProgram } = config;
47572
- switch (config.type) {
47573
- case "borrow":
47574
- return makeBorrowIx3({
47575
- program,
47576
- bank,
47577
- bankMap,
47578
- tokenProgram,
47579
- amount: 1,
47580
- marginfiAccount,
47581
- authority: marginfiAccount.authority,
47582
- isSync: true,
47583
- opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
47584
- });
47585
- case "repay":
47586
- return makeRepayIx3({
47587
- program,
47588
- bank,
47589
- tokenProgram,
47590
- amount: 1,
47591
- accountAddress: marginfiAccount.address,
47592
- authority: marginfiAccount.authority,
47593
- repayAll: false,
47594
- isSync: true,
47595
- opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
47596
- });
47597
- case "deposit":
47598
- return buildDepositBudgetIx(
47599
- config,
47600
- program,
47601
- marginfiAccount,
47602
- bankMetadataMap,
47603
- overrideInferAccounts
47604
- );
47605
- case "withdraw":
47606
- return buildWithdrawBudgetIx(
47607
- config,
47608
- program,
47609
- marginfiAccount,
47610
- bankMap,
47611
- bankMetadataMap,
47612
- overrideInferAccounts
47613
- );
47614
- }
47615
- }
47616
- async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
47617
- const { bank, tokenProgram } = config;
47618
- const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
47619
- switch (bank.config.assetTag) {
47620
- case 3 /* KAMINO */: {
47621
- const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
47622
- if (!reserve) {
47623
- throw TransactionBuildingError.kaminoReserveNotFound(
47624
- bank.address.toBase58(),
47625
- bank.mint.toBase58(),
47626
- bank.tokenSymbol
47627
- );
47628
- }
47629
- return makeKaminoDepositIx3({
47630
- program,
47631
- bank,
47632
- tokenProgram,
47633
- amount: 1,
47634
- accountAddress: marginfiAccount.address,
47635
- authority: marginfiAccount.authority,
47636
- group: marginfiAccount.group,
47637
- reserve,
47638
- isSync: true,
47639
- opts
47640
- });
47641
- }
47642
- case 4 /* DRIFT */: {
47643
- const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
47644
- if (!driftState) {
47645
- throw TransactionBuildingError.driftStateNotFound(
47646
- bank.address.toBase58(),
47647
- bank.mint.toBase58(),
47648
- bank.tokenSymbol
47649
- );
47650
- }
47651
- return makeDriftDepositIx3({
47652
- program,
47653
- bank,
47654
- tokenProgram,
47655
- amount: 1,
47656
- accountAddress: marginfiAccount.address,
47657
- authority: marginfiAccount.authority,
47658
- group: marginfiAccount.group,
47659
- driftMarketIndex: driftState.spotMarketState.marketIndex,
47660
- driftOracle: driftState.spotMarketState.oracle,
47661
- isSync: true,
47662
- opts
47663
- });
47664
- }
47665
- case 6 /* JUPLEND */: {
47666
- return makeJuplendDepositIx2({
47667
- program,
47668
- bank,
47669
- tokenProgram,
47670
- amount: 1,
47671
- accountAddress: marginfiAccount.address,
47672
- authority: marginfiAccount.authority,
47673
- group: marginfiAccount.group,
47674
- isSync: true,
47675
- opts
47676
- });
47677
- }
47678
- default: {
47679
- return makeDepositIx3({
47680
- program,
47681
- bank,
47682
- tokenProgram,
47683
- amount: 1,
47684
- accountAddress: marginfiAccount.address,
47685
- authority: marginfiAccount.authority,
47686
- group: marginfiAccount.group,
47687
- isSync: true,
47688
- opts
47689
- });
47690
- }
47691
- }
47692
- }
47693
- async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
47694
- const { bank, tokenProgram } = config;
47695
- const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
47696
- switch (bank.config.assetTag) {
47697
- case 3 /* KAMINO */: {
47698
- const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
47699
- if (!reserve) {
47700
- throw TransactionBuildingError.kaminoReserveNotFound(
47701
- bank.address.toBase58(),
47702
- bank.mint.toBase58(),
47703
- bank.tokenSymbol
47704
- );
47705
- }
47706
- return makeKaminoWithdrawIx3({
47707
- program,
47708
- bank,
47709
- bankMap,
47710
- tokenProgram,
47711
- cTokenAmount: 1,
47712
- marginfiAccount,
47713
- authority: marginfiAccount.authority,
47714
- reserve,
47715
- withdrawAll: false,
47716
- isSync: true,
47717
- opts
47718
- });
47719
- }
47720
- case 4 /* DRIFT */: {
47721
- const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
47722
- if (!driftState) {
47723
- throw TransactionBuildingError.driftStateNotFound(
47724
- bank.address.toBase58(),
47725
- bank.mint.toBase58(),
47726
- bank.tokenSymbol
47727
- );
47728
- }
47729
- return makeDriftWithdrawIx3({
47730
- program,
47731
- bank,
47732
- bankMap,
47733
- tokenProgram,
47734
- amount: 1,
47735
- marginfiAccount,
47736
- authority: marginfiAccount.authority,
47737
- driftSpotMarket: driftState.spotMarketState,
47738
- userRewards: driftState.userRewards,
47739
- withdrawAll: false,
47740
- isSync: true,
47741
- opts
47742
- });
47743
- }
47744
- case 6 /* JUPLEND */: {
47745
- const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
47746
- if (!jupLendState) {
47747
- throw TransactionBuildingError.jupLendStateNotFound(
47748
- bank.address.toBase58(),
47749
- bank.mint.toBase58(),
47750
- bank.tokenSymbol
47751
- );
47752
- }
47753
- return makeJuplendWithdrawIx2({
47754
- program,
47755
- bank,
47756
- bankMap,
47757
- tokenProgram,
47758
- amount: 1,
47759
- marginfiAccount,
47760
- authority: marginfiAccount.authority,
47761
- jupLendingState: jupLendState.jupLendingState,
47762
- withdrawAll: false,
47763
- opts
47764
- });
47765
- }
47766
- default: {
47767
- return makeWithdrawIx3({
47768
- program,
47769
- bank,
47770
- bankMap,
47771
- tokenProgram,
47772
- amount: 1,
47773
- marginfiAccount,
47774
- authority: marginfiAccount.authority,
47775
- withdrawAll: false,
47776
- isSync: true,
47777
- opts
47778
- });
47779
- }
47780
- }
47781
- }
47782
- async function computeFlashloanSwapConstraints({
47783
- program,
47784
- marginfiAccount,
47785
- bankMap,
47786
- addressLookupTableAccounts,
47787
- bankMetadataMap,
47788
- primaryIx,
47789
- secondaryIx,
47790
- overrideInferAccounts
47791
- }) {
47792
- const cuRequestIxs = [
47793
- web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
47794
- web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
47795
- ];
47796
- const [primaryResult, secondaryResult] = await Promise.all([
47797
- buildBudgetIx(
47798
- primaryIx,
47799
- program,
47800
- marginfiAccount,
47801
- bankMap,
47802
- bankMetadataMap,
47803
- overrideInferAccounts
47804
- ),
47805
- buildBudgetIx(
47806
- secondaryIx,
47807
- program,
47808
- marginfiAccount,
47809
- bankMap,
47810
- bankMetadataMap,
47811
- overrideInferAccounts
47812
- )
47813
- ]);
47814
- return computeFlashLoanNonSwapBudget({
47815
- program,
47816
- marginfiAccount,
47817
- bankMap,
47818
- addressLookupTableAccounts,
47819
- ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
47820
- });
47821
- }
47822
-
47823
- // src/services/account/actions/flash-loan.ts
47824
- async function makeBeginFlashLoanIx3(program, marginfiAccountPk, endIndex, authority, isSync) {
47825
- const ix = isSync && authority ? sync_instructions_default.makeBeginFlashLoanIx(
47826
- program.programId,
47827
- {
47828
- marginfiAccount: marginfiAccountPk,
47829
- authority
47830
- },
47831
- { endIndex: new BN11__default.default(endIndex) }
47832
- ) : await instructions_default.makeBeginFlashLoanIx(
47833
- program,
47834
- {
47835
- marginfiAccount: marginfiAccountPk,
47836
- authority
47837
- },
47838
- { endIndex: new BN11__default.default(endIndex) }
47839
- );
47840
- return { instructions: [ix], keys: [] };
47841
- }
47842
- async function makeEndFlashLoanIx3(program, marginfiAccountPk, projectedActiveBanks, authority, isSync) {
47843
- const remainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
47844
- const ix = isSync && authority ? sync_instructions_default.makeEndFlashLoanIx(
47845
- program.programId,
47846
- {
47847
- marginfiAccount: marginfiAccountPk,
47848
- authority
47849
- },
47850
- remainingAccounts.map((account) => ({
47851
- pubkey: account,
47852
- isSigner: false,
47853
- isWritable: false
47854
- }))
47855
- ) : await instructions_default.makeEndFlashLoanIx(
47856
- program,
47857
- {
47858
- marginfiAccount: marginfiAccountPk,
47859
- authority
47860
- },
47861
- remainingAccounts.map((account) => ({
47862
- pubkey: account,
47863
- isSigner: false,
47864
- isWritable: false
47865
- }))
47866
- );
47867
- return { instructions: [ix], keys: [] };
47868
- }
47869
- async function makeFlashLoanTx({
47870
- program,
47871
- marginfiAccount,
47872
- ixs,
47873
- bankMap,
47874
- blockhash,
47875
- addressLookupTableAccounts,
47876
- signers,
47877
- isSync
47878
- }) {
47879
- const endIndex = ixs.length + 1;
47880
- const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
47881
- marginfiAccount.balances,
47882
- ixs,
47883
- program
47884
- );
47885
- const projectedActiveBanks = projectedActiveBanksKeys.map((account) => {
47886
- const b = bankMap.get(account.toBase58());
47887
- if (!b) throw Error(`Bank ${account.toBase58()} not found, in makeFlashLoanTx function`);
47888
- return b;
47889
- });
47890
- const beginFlashLoanIx = await makeBeginFlashLoanIx3(
47891
- program,
47892
- marginfiAccount.address,
47893
- endIndex,
47894
- marginfiAccount.authority,
47895
- isSync
47896
- );
47897
- const endFlashLoanIx = await makeEndFlashLoanIx3(
47898
- program,
47899
- marginfiAccount.address,
47900
- projectedActiveBanks,
47901
- marginfiAccount.authority,
47902
- isSync
47903
- );
47904
- const message = new web3_js.TransactionMessage({
47905
- payerKey: marginfiAccount.authority,
47906
- recentBlockhash: blockhash,
47907
- instructions: [...beginFlashLoanIx.instructions, ...ixs, ...endFlashLoanIx.instructions]
47908
- }).compileToV0Message(addressLookupTableAccounts);
47909
- const tx = addTransactionMetadata(new web3_js.VersionedTransaction(message), {
47910
- addressLookupTables: addressLookupTableAccounts,
47911
- type: "FLASHLOAN" /* FLASHLOAN */,
47912
- signers
47913
- });
47914
- if (signers) {
47915
- tx.sign(signers);
47916
- }
47917
- return tx;
47918
- }
47919
-
47920
- // src/services/account/actions/loop.ts
47921
- async function makeLoopTx(params) {
47922
- const {
47923
- program,
47924
- marginfiAccount,
47925
- bankMap,
47926
- depositOpts,
47927
- borrowOpts,
47928
- bankMetadataMap,
47929
- addressLookupTableAccounts,
47930
- connection,
47931
- oraclePrices,
47932
- crossbarUrl,
47933
- additionalIxs = []
47934
- } = params;
47935
- const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
47936
- const setupIxs = await makeSetupIx({
47937
- connection,
47938
- authority: marginfiAccount.authority,
47939
- tokens: [
47940
- {
47941
- mint: borrowOpts.borrowBank.mint,
47942
- tokenProgram: borrowOpts.tokenProgram
47943
- },
47944
- {
47945
- mint: depositOpts.depositBank.mint,
47946
- tokenProgram: depositOpts.tokenProgram
47947
- }
47948
- ]
47949
- });
47950
- const updateJupLendRateIxs = makeUpdateJupLendRateIxs(
47951
- params.marginfiAccount,
47952
- params.bankMap,
47953
- [depositOpts.depositBank.address],
47954
- params.bankMetadataMap
47955
- );
47956
- const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
47957
- params.marginfiAccount,
47958
- params.bankMap,
47959
- [depositOpts.depositBank.address],
47960
- params.bankMetadataMap
47961
- );
47962
- const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
47963
- marginfiAccount,
47964
- bankMap,
47965
- [borrowOpts.borrowBank.address, depositOpts.depositBank.address],
47966
- bankMetadataMap
47967
- );
47968
- const { flashloanTx, setupInstructions, swapQuote, amountToDeposit, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
47969
- ...params,
47970
- blockhash
47971
- });
47972
- const jupiterSetupInstructions = setupInstructions.filter((ix) => {
47973
- if (ix.programId.equals(web3_js.ComputeBudgetProgram.programId)) {
47974
- return false;
47975
- }
47976
- if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
47977
- const mintKey = ix.keys[3]?.pubkey;
47978
- if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
47979
- return false;
47980
- }
47981
- }
47982
- return true;
47983
- });
47984
- setupIxs.push(...jupiterSetupInstructions);
47985
- const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
47986
- marginfiAccount,
47987
- bankMap,
47988
- oraclePrices,
47989
- assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
47990
- instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
47991
- program,
47992
- connection,
47993
- crossbarUrl
47994
- });
47995
- let additionalTxs = [];
47996
- if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
47997
- setupIxs.push(
47998
- ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber3.BigNumber(depositOpts.inputDepositAmount))
47999
- );
48000
- }
48001
- if (setupIxs.length > 0 || additionalIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0 || updateJupLendRateIxs.instructions.length > 0) {
48002
- const ixs = [
48003
- ...additionalIxs,
48004
- ...setupIxs,
48005
- ...kaminoRefreshIxs.instructions,
48006
- ...updateDriftMarketIxs.instructions,
48007
- ...updateJupLendRateIxs.instructions
48008
- ];
48009
- const txs = splitInstructionsToFitTransactions([], ixs, {
48010
- blockhash,
48011
- payerKey: marginfiAccount.authority,
48012
- luts: addressLookupTableAccounts ?? []
48013
- });
48014
- additionalTxs.push(
48015
- ...txs.map(
48016
- (tx) => addTransactionMetadata(tx, {
48017
- type: "CREATE_ATA" /* CREATE_ATA */,
48018
- addressLookupTables: addressLookupTableAccounts
48019
- })
48020
- )
48021
- );
48022
- }
48023
- if (updateFeedIxs.length > 0) {
48024
- const message = new web3_js.TransactionMessage({
48025
- payerKey: marginfiAccount.authority,
48026
- recentBlockhash: blockhash,
48027
- instructions: updateFeedIxs
48028
- }).compileToV0Message(feedLuts);
48029
- additionalTxs.push(
48030
- addTransactionMetadata(new web3_js.VersionedTransaction(message), {
48031
- addressLookupTables: feedLuts,
48032
- type: "CRANK" /* CRANK */
48033
- })
48034
- );
48035
- }
48036
- const transactions = [...additionalTxs, flashloanTx];
48037
- return {
48038
- transactions,
48039
- actionTxIndex: transactions.length - 1,
48040
- quoteResponse: swapQuote
48041
- };
48042
- }
48043
- async function buildLoopFlashloanTx({
48044
- program,
48045
- marginfiAccount,
48046
- bankMap,
48047
- borrowOpts,
48048
- depositOpts,
48049
- bankMetadataMap,
48050
- addressLookupTableAccounts,
48051
- connection,
48052
- swapOpts,
48053
- overrideInferAccounts,
48054
- blockhash
48055
- }) {
48056
- const cuRequestIxs = [
48057
- web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
48058
- web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
48059
- ];
48060
- let amountToDeposit;
48061
- let swapInstructions = [];
48062
- let setupInstructions = [];
48063
- let swapLookupTables = [];
48064
- let swapQuote;
48065
- let sizeConstraintUsed = 0;
48066
- if (depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint)) {
48067
- amountToDeposit = borrowOpts.borrowAmount + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
48068
- } else {
48069
- const destinationTokenAccount = getAssociatedTokenAddressSync(
48070
- new web3_js.PublicKey(depositOpts.depositBank.mint),
48071
- marginfiAccount.authority,
48072
- true,
48073
- depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
48074
- );
48075
- const swapConstraints = await computeFlashloanSwapConstraints({
48076
- program,
48077
- marginfiAccount,
48078
- bankMap,
48079
- bankMetadataMap,
48080
- addressLookupTableAccounts: addressLookupTableAccounts ?? [],
48081
- primaryIx: {
48082
- type: "borrow",
48083
- bank: borrowOpts.borrowBank,
48084
- tokenProgram: borrowOpts.tokenProgram
48085
- },
48086
- secondaryIx: {
48087
- type: "deposit",
48088
- bank: depositOpts.depositBank,
48089
- tokenProgram: depositOpts.tokenProgram
48090
- },
48091
- overrideInferAccounts
48092
- });
48093
- const swapResponse = await getSwapIxsForFlashloan({
48094
- inputMint: borrowOpts.borrowBank.mint.toBase58(),
48095
- outputMint: depositOpts.depositBank.mint.toBase58(),
48096
- amount: uiToNative(borrowOpts.borrowAmount, borrowOpts.borrowBank.mintDecimals).toNumber(),
48097
- swapMode: "ExactIn",
48098
- authority: marginfiAccount.authority,
48099
- connection,
48100
- destinationTokenAccount,
48101
- swapOpts,
48102
- sizeConstraint: swapConstraints.sizeConstraint,
48103
- maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
48104
- });
48105
- sizeConstraintUsed = swapConstraints.sizeConstraint;
48106
- const outAmountThreshold = nativeToUi(
48107
- swapResponse.quoteResponse.otherAmountThreshold,
48108
- depositOpts.depositBank.mintDecimals
48109
- );
48110
- amountToDeposit = outAmountThreshold + (depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0);
48111
- swapInstructions = swapResponse.swapInstructions;
48112
- setupInstructions = swapResponse.setupInstructions;
48113
- swapLookupTables = swapResponse.addressLookupTableAddresses;
48114
- swapQuote = swapResponse.quoteResponse;
48115
- }
48116
- const borrowIxs = await makeBorrowIx3({
48117
- program,
48118
- bank: borrowOpts.borrowBank,
48119
- bankMap,
48120
- tokenProgram: borrowOpts.tokenProgram,
48121
- amount: borrowOpts.borrowAmount,
48122
- marginfiAccount,
48123
- authority: marginfiAccount.authority,
48124
- isSync: false,
48125
- opts: {
48126
- createAtas: false,
48127
- wrapAndUnwrapSol: false,
48128
- overrideInferAccounts
48129
- }
48130
- });
48131
- let depositIxs;
48132
- switch (depositOpts.depositBank.config.assetTag) {
48133
- case 3 /* KAMINO */: {
48134
- const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
48135
- if (!reserve) {
48136
- throw TransactionBuildingError.kaminoReserveNotFound(
48137
- depositOpts.depositBank.address.toBase58(),
48138
- depositOpts.depositBank.mint.toBase58(),
48139
- depositOpts.depositBank.tokenSymbol
48140
- );
48141
- }
48142
- depositIxs = await makeKaminoDepositIx3({
48143
- program,
48144
- bank: depositOpts.depositBank,
48145
- tokenProgram: depositOpts.tokenProgram,
48146
- amount: amountToDeposit,
48147
- accountAddress: marginfiAccount.address,
48148
- authority: marginfiAccount.authority,
48149
- group: marginfiAccount.group,
48150
- reserve,
48151
- opts: {
48152
- wrapAndUnwrapSol: false,
48153
- overrideInferAccounts
48154
- }
48155
- });
48156
- break;
48157
- }
48158
- case 4 /* DRIFT */: {
48159
- const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
48160
- if (!driftState) {
48161
- throw TransactionBuildingError.driftStateNotFound(
48162
- depositOpts.depositBank.address.toBase58(),
48163
- depositOpts.depositBank.mint.toBase58(),
48164
- depositOpts.depositBank.tokenSymbol
48165
- );
48166
- }
48167
- const driftMarketIndex = driftState.spotMarketState.marketIndex;
48168
- const driftOracle = driftState.spotMarketState.oracle;
48169
- depositIxs = await makeDriftDepositIx3({
48170
- program,
48171
- bank: depositOpts.depositBank,
48172
- tokenProgram: depositOpts.tokenProgram,
48173
- amount: amountToDeposit,
48174
- accountAddress: marginfiAccount.address,
48175
- authority: marginfiAccount.authority,
48176
- group: marginfiAccount.group,
48177
- driftMarketIndex,
48178
- driftOracle,
48179
- opts: {
48180
- wrapAndUnwrapSol: false,
48181
- overrideInferAccounts
48182
- }
48183
- });
48184
- break;
48185
- }
48186
- case 6 /* JUPLEND */: {
48187
- depositIxs = await makeJuplendDepositIx2({
48188
- program,
48189
- bank: depositOpts.depositBank,
48190
- tokenProgram: depositOpts.tokenProgram,
48191
- amount: amountToDeposit,
48192
- accountAddress: marginfiAccount.address,
48193
- authority: marginfiAccount.authority,
48194
- group: marginfiAccount.group,
48195
- opts: {
48196
- wrapAndUnwrapSol: false,
48197
- overrideInferAccounts
48198
- }
48199
- });
48200
- break;
48201
- }
48202
- default: {
48203
- depositIxs = await makeDepositIx3({
48204
- program,
48205
- bank: depositOpts.depositBank,
48206
- tokenProgram: depositOpts.tokenProgram,
48207
- amount: amountToDeposit,
48208
- accountAddress: marginfiAccount.address,
48209
- authority: marginfiAccount.authority,
48210
- group: marginfiAccount.group,
48211
- opts: {
48212
- wrapAndUnwrapSol: false,
48213
- overrideInferAccounts
48214
- }
48215
- });
48216
- break;
48217
- }
48218
- }
48219
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
48220
- const allNonFlIxs = [
48221
- ...cuRequestIxs,
48222
- ...borrowIxs.instructions,
48223
- ...swapInstructions,
48224
- ...depositIxs.instructions
48225
- ];
48226
- if (swapInstructions.length > 0) {
48227
- compileFlashloanPrecheck({
48228
- allIxs: allNonFlIxs,
48229
- payer: marginfiAccount.authority,
48230
- luts,
48231
- sizeConstraint: sizeConstraintUsed,
48232
- swapIxCount: swapInstructions.length,
48233
- swapLutCount: swapLookupTables.length
48234
- });
48235
- }
48236
- const flashloanTx = await makeFlashLoanTx({
48237
- program,
48238
- marginfiAccount,
48239
- bankMap,
48240
- addressLookupTableAccounts: luts,
48241
- blockhash,
48242
- ixs: allNonFlIxs
48243
- });
48244
- const txSize = getTxSize(flashloanTx);
48245
- const totalKeys = getTotalAccountKeys(flashloanTx);
48246
- if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48247
- throw TransactionBuildingError.swapSizeExceededLoop(
48248
- txSize,
48249
- totalKeys,
48250
- swapOpts.swapConfig?.provider
48251
- );
48252
- }
48253
- return {
48254
- flashloanTx,
48255
- setupInstructions,
48256
- swapQuote,
48257
- borrowIxs,
48258
- depositIxs,
48259
- amountToDeposit
48260
- };
48261
- }
48262
-
48263
47830
  // src/services/account/actions/emissions.ts
48264
47831
  async function makeClearEmissionsIx(program, marginfiAccount, banks, bankAddress) {
48265
47832
  const bank = banks.get(bankAddress.toBase58());
@@ -48687,7 +48254,7 @@ async function buildSwapCollateralFlashloanTx({
48687
48254
  const txSize = getTxSize(flashloanTx);
48688
48255
  const totalKeys = getTotalAccountKeys(flashloanTx);
48689
48256
  if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48690
- throw TransactionBuildingError.swapSizeExceededLoop(
48257
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
48691
48258
  txSize,
48692
48259
  totalKeys,
48693
48260
  swapOpts.swapConfig?.provider
@@ -48948,7 +48515,7 @@ async function buildSwapDebtFlashloanTx({
48948
48515
  const txSize = getTxSize(flashloanTx);
48949
48516
  const totalKeys = getTotalAccountKeys(flashloanTx);
48950
48517
  if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
48951
- throw TransactionBuildingError.swapSizeExceededLoop(
48518
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
48952
48519
  txSize,
48953
48520
  totalKeys,
48954
48521
  swapOpts.swapConfig?.provider
@@ -48962,179 +48529,6 @@ async function buildSwapDebtFlashloanTx({
48962
48529
  repayIxs
48963
48530
  };
48964
48531
  }
48965
- var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
48966
- async function makeMintStakedLstIx(params) {
48967
- const { amount, authority, stakeAccountPk, validator, connection } = params;
48968
- const pool = findPoolAddress(validator);
48969
- const lstMint = findPoolMintAddress(pool);
48970
- const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
48971
- const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
48972
- const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
48973
- connection.getAccountInfo(lstAta),
48974
- connection.getParsedAccountInfo(stakeAccountPk),
48975
- connection.getMinimumBalanceForRentExemption(web3_js.StakeProgram.space)
48976
- ]);
48977
- const stakeAccParsed = stakeAccInfoParsed?.value?.data;
48978
- const amountLamports = Math.round(Number(amount) * web3_js.LAMPORTS_PER_SOL);
48979
- const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
48980
- const isFullStake = amountLamports >= stakeAccLamports;
48981
- const instructions2 = [];
48982
- const signers = [];
48983
- if (!lstAccInfo) {
48984
- instructions2.push(
48985
- createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
48986
- );
48987
- }
48988
- let targetStakePubkey;
48989
- if (!isFullStake) {
48990
- const splitStakeAccount = web3_js.Keypair.generate();
48991
- signers.push(splitStakeAccount);
48992
- targetStakePubkey = splitStakeAccount.publicKey;
48993
- instructions2.push(
48994
- ...web3_js.StakeProgram.split(
48995
- {
48996
- stakePubkey: stakeAccountPk,
48997
- authorizedPubkey: authority,
48998
- splitStakePubkey: splitStakeAccount.publicKey,
48999
- lamports: amountLamports
49000
- },
49001
- rentExemptReserve
49002
- ).instructions
49003
- );
49004
- } else {
49005
- targetStakePubkey = stakeAccountPk;
49006
- }
49007
- const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
49008
- web3_js.StakeProgram.authorize({
49009
- stakePubkey: targetStakePubkey,
49010
- authorizedPubkey: authority,
49011
- newAuthorizedPubkey: poolStakeAuth,
49012
- stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Staker
49013
- }).instructions,
49014
- web3_js.StakeProgram.authorize({
49015
- stakePubkey: targetStakePubkey,
49016
- authorizedPubkey: authority,
49017
- newAuthorizedPubkey: poolStakeAuth,
49018
- stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Withdrawer
49019
- }).instructions
49020
- ]);
49021
- [authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
49022
- if (ix) {
49023
- ix.keys = ix.keys.map((key) => ({
49024
- ...key,
49025
- isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
49026
- }));
49027
- }
49028
- });
49029
- instructions2.push(...authorizeStakerIx, ...authorizeWithdrawIx);
49030
- const depositStakeIx = await SinglePoolInstruction.depositStake(
49031
- pool,
49032
- targetStakePubkey,
49033
- lstAta,
49034
- authority
49035
- );
49036
- instructions2.push(depositStakeIx);
49037
- return { instructions: instructions2, keys: signers };
49038
- }
49039
- async function makeMintStakedLstTx(params) {
49040
- const { connection, luts, blockhash: providedBlockhash } = params;
49041
- const { instructions: instructions2, keys } = await makeMintStakedLstIx(params);
49042
- const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
49043
- const message = new web3_js.TransactionMessage({
49044
- payerKey: params.authority,
49045
- recentBlockhash: blockhash,
49046
- instructions: instructions2
49047
- }).compileToV0Message(luts);
49048
- const tx = new web3_js.VersionedTransaction(message);
49049
- return addTransactionMetadata(tx, {
49050
- signers: keys,
49051
- addressLookupTables: luts,
49052
- type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
49053
- });
49054
- }
49055
- async function makeRedeemStakedLstIx(params) {
49056
- const { amount, authority, validator, connection } = params;
49057
- const pool = findPoolAddress(validator);
49058
- const lstMint = findPoolMintAddress(pool);
49059
- const mintAuthority = findPoolMintAuthorityAddress(pool);
49060
- const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
49061
- const rentExemption = await connection.getMinimumBalanceForRentExemption(
49062
- web3_js.StakeProgram.space
49063
- );
49064
- const stakeAmount = new BigNumber3__default.default(new BigNumber3__default.default(amount).toString());
49065
- const instructions2 = [];
49066
- const signers = [];
49067
- const stakeAccount = web3_js.Keypair.generate();
49068
- signers.push(stakeAccount);
49069
- instructions2.push(
49070
- web3_js.SystemProgram.createAccount({
49071
- fromPubkey: authority,
49072
- newAccountPubkey: stakeAccount.publicKey,
49073
- lamports: rentExemption,
49074
- space: web3_js.StakeProgram.space,
49075
- programId: web3_js.StakeProgram.programId
49076
- })
49077
- );
49078
- instructions2.push(
49079
- createApproveInstruction(
49080
- lstAta,
49081
- mintAuthority,
49082
- authority,
49083
- BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
49084
- )
49085
- );
49086
- const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
49087
- pool,
49088
- stakeAccount.publicKey,
49089
- authority,
49090
- lstAta,
49091
- stakeAmount
49092
- );
49093
- instructions2.push(withdrawStakeIx);
49094
- return { instructions: instructions2, keys: signers };
49095
- }
49096
- async function makeRedeemStakedLstTx(params) {
49097
- const { connection, luts, blockhash: providedBlockhash } = params;
49098
- const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
49099
- const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
49100
- const message = new web3_js.TransactionMessage({
49101
- payerKey: params.authority,
49102
- recentBlockhash: blockhash,
49103
- instructions: instructions2
49104
- }).compileToV0Message(luts);
49105
- const tx = new web3_js.VersionedTransaction(message);
49106
- return addTransactionMetadata(tx, {
49107
- signers: keys,
49108
- addressLookupTables: luts,
49109
- type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
49110
- });
49111
- }
49112
- async function makeMergeStakeAccountsTx(params) {
49113
- const {
49114
- authority,
49115
- sourceStakeAccount,
49116
- destinationStakeAccount,
49117
- connection,
49118
- luts,
49119
- blockhash: providedBlockhash
49120
- } = params;
49121
- const mergeIx = web3_js.StakeProgram.merge({
49122
- stakePubkey: destinationStakeAccount,
49123
- sourceStakePubKey: sourceStakeAccount,
49124
- authorizedPubkey: authority
49125
- }).instructions;
49126
- const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
49127
- const message = new web3_js.TransactionMessage({
49128
- payerKey: authority,
49129
- recentBlockhash: blockhash,
49130
- instructions: mergeIx
49131
- }).compileToV0Message(luts);
49132
- const tx = new web3_js.VersionedTransaction(message);
49133
- return addTransactionMetadata(tx, {
49134
- addressLookupTables: luts,
49135
- type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
49136
- });
49137
- }
49138
48532
 
49139
48533
  // src/services/account/services/account-simulation.service.ts
49140
48534
  async function simulateAccountHealthCacheWithFallback(params) {
@@ -49983,7 +49377,7 @@ async function getTitanExactOutViaWebSocket(params) {
49983
49377
  inputMint: new web3_js.PublicKey(inputMint).toBytes(),
49984
49378
  outputMint: new web3_js.PublicKey(outputMint).toBytes(),
49985
49379
  amount,
49986
- swapMode: "ExactOut",
49380
+ swapMode: "ExactOut" /* ExactOut */,
49987
49381
  slippageBps
49988
49382
  },
49989
49383
  transaction: {
@@ -50241,140 +49635,575 @@ var getExactOutEstimate = async (params) => {
50241
49635
  );
50242
49636
  }
50243
49637
  }
50244
- const firstProvider = attempts[0]?.provider ?? "Swap";
50245
- throw TransactionBuildingError.swapQuoteFailed(
50246
- firstProvider,
50247
- inputMint,
50248
- outputMint,
50249
- lastError?.message ?? "No swap route available"
50250
- );
50251
- };
50252
- function mapJupiterQuoteToSwapQuoteResult(quote) {
50253
- return {
50254
- inAmount: quote.inAmount,
50255
- outAmount: quote.outAmount,
50256
- otherAmountThreshold: quote.otherAmountThreshold,
50257
- slippageBps: quote.slippageBps,
50258
- platformFee: quote.platformFee ? {
50259
- amount: quote.platformFee.amount ?? "0",
50260
- feeBps: quote.platformFee.feeBps ?? 0
50261
- } : void 0,
50262
- priceImpactPct: quote.priceImpactPct,
50263
- contextSlot: quote.contextSlot,
50264
- timeTaken: quote.timeTaken,
50265
- provider: "JUPITER" /* JUPITER */
50266
- };
50267
- }
50268
-
50269
- // src/services/account/utils/jupiter.utils.ts
50270
- var REFERRAL_PROGRAM_ID = new web3_js.PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
50271
- var REFERRAL_ACCOUNT_PUBKEY = new web3_js.PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
50272
- var getFeeAccount = (mint) => {
50273
- const [feeAccount] = web3_js.PublicKey.findProgramAddressSync(
50274
- [Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
50275
- REFERRAL_PROGRAM_ID
50276
- );
50277
- return feeAccount.toBase58();
50278
- };
50279
- var checkFeeAccount = async (connection, mint) => {
50280
- const feeAccount = getFeeAccount(mint);
50281
- const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
50282
- return { feeAccount, hasFeeAccount };
50283
- };
50284
- function deserializeJupiterInstruction(instruction) {
50285
- return new web3_js.TransactionInstruction({
50286
- programId: new web3_js.PublicKey(instruction.programId),
50287
- keys: instruction.accounts.map((key) => ({
50288
- pubkey: new web3_js.PublicKey(key.pubkey),
50289
- isSigner: key.isSigner,
50290
- isWritable: key.isWritable
50291
- })),
50292
- data: Buffer.from(instruction.data, "base64")
50293
- });
50294
- }
50295
- function toJupiterConfig(apiConfig) {
50296
- if (!apiConfig) return void 0;
50297
- return {
50298
- basePath: apiConfig.basePath,
50299
- apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
50300
- headers: apiConfig.headers
50301
- };
49638
+ const firstProvider = attempts[0]?.provider ?? "Swap";
49639
+ throw TransactionBuildingError.swapQuoteFailed(
49640
+ firstProvider,
49641
+ inputMint,
49642
+ outputMint,
49643
+ lastError?.message ?? "No swap route available"
49644
+ );
49645
+ };
49646
+ function mapJupiterQuoteToSwapQuoteResult(quote) {
49647
+ return {
49648
+ inAmount: quote.inAmount,
49649
+ outAmount: quote.outAmount,
49650
+ otherAmountThreshold: quote.otherAmountThreshold,
49651
+ slippageBps: quote.slippageBps,
49652
+ platformFee: quote.platformFee ? {
49653
+ amount: quote.platformFee.amount ?? "0",
49654
+ feeBps: quote.platformFee.feeBps ?? 0
49655
+ } : void 0,
49656
+ priceImpactPct: quote.priceImpactPct,
49657
+ contextSlot: quote.contextSlot,
49658
+ timeTaken: quote.timeTaken,
49659
+ provider: "JUPITER" /* JUPITER */
49660
+ };
49661
+ }
49662
+
49663
+ // src/services/account/utils/jupiter.utils.ts
49664
+ var REFERRAL_PROGRAM_ID = new web3_js.PublicKey("REFER4ZgmyYx9c6He5XfaTMiGfdLwRnkV4RPp9t9iF3");
49665
+ var REFERRAL_ACCOUNT_PUBKEY = new web3_js.PublicKey("Mm7HcujSK2JzPW4eX7g4oqTXbWYDuFxapNMHXe8yp1B");
49666
+ var getFeeAccount = (mint) => {
49667
+ const [feeAccount] = web3_js.PublicKey.findProgramAddressSync(
49668
+ [Buffer.from("referral_ata"), REFERRAL_ACCOUNT_PUBKEY.toBuffer(), mint.toBuffer()],
49669
+ REFERRAL_PROGRAM_ID
49670
+ );
49671
+ return feeAccount.toBase58();
49672
+ };
49673
+ var checkFeeAccount = async (connection, mint) => {
49674
+ const feeAccount = getFeeAccount(mint);
49675
+ const hasFeeAccount = !!await connection.getAccountInfo(new web3_js.PublicKey(feeAccount));
49676
+ return { feeAccount, hasFeeAccount };
49677
+ };
49678
+ function deserializeJupiterInstruction(instruction) {
49679
+ return new web3_js.TransactionInstruction({
49680
+ programId: new web3_js.PublicKey(instruction.programId),
49681
+ keys: instruction.accounts.map((key) => ({
49682
+ pubkey: new web3_js.PublicKey(key.pubkey),
49683
+ isSigner: key.isSigner,
49684
+ isWritable: key.isWritable
49685
+ })),
49686
+ data: Buffer.from(instruction.data, "base64")
49687
+ });
49688
+ }
49689
+ function toJupiterConfig(apiConfig) {
49690
+ if (!apiConfig) return void 0;
49691
+ return {
49692
+ basePath: apiConfig.basePath,
49693
+ apiKey: apiConfig.apiKey ? () => apiConfig.apiKey : void 0,
49694
+ headers: apiConfig.headers
49695
+ };
49696
+ }
49697
+ var getJupiterSwapIxsForFlashloan = async ({
49698
+ quoteParams,
49699
+ authority,
49700
+ connection,
49701
+ destinationTokenAccount,
49702
+ apiConfig,
49703
+ maxSwapAccounts
49704
+ }) => {
49705
+ const configParams = toJupiterConfig(apiConfig);
49706
+ const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
49707
+ const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
49708
+ const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new web3_js.PublicKey(feeMint));
49709
+ const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
49710
+ let finalQuoteParams = quoteParams;
49711
+ if (!hasFeeAccount) {
49712
+ console.warn("Warning: feeAccountInfo is undefined");
49713
+ finalQuoteParams = {
49714
+ ...quoteParams,
49715
+ platformFeeBps: void 0
49716
+ };
49717
+ }
49718
+ const JUPITER_MAX_ACCOUNTS_MARGIN = 4;
49719
+ const maxAccounts = maxSwapAccounts !== void 0 ? maxSwapAccounts - JUPITER_MAX_ACCOUNTS_MARGIN : 40;
49720
+ const swapQuote = await jupiterApiClient.quoteGet({
49721
+ ...finalQuoteParams,
49722
+ maxAccounts
49723
+ });
49724
+ const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
49725
+ swapRequest: {
49726
+ quoteResponse: swapQuote,
49727
+ userPublicKey: authority.toBase58(),
49728
+ feeAccount: hasFeeAccount ? feeAccount : void 0,
49729
+ wrapAndUnwrapSol: false,
49730
+ destinationTokenAccount: destinationTokenAccount.toBase58()
49731
+ }
49732
+ });
49733
+ const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
49734
+ const lutAccountsRaw = await connection.getMultipleAccountsInfo(
49735
+ lutAddresses.map((address) => new web3_js.PublicKey(address))
49736
+ );
49737
+ const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
49738
+ const addressLookupTableAddress = lutAddresses[index];
49739
+ if (!accountInfo || !addressLookupTableAddress) {
49740
+ return null;
49741
+ }
49742
+ return new web3_js.AddressLookupTableAccount({
49743
+ key: new web3_js.PublicKey(addressLookupTableAddress),
49744
+ state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
49745
+ });
49746
+ }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
49747
+ const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
49748
+ const setupInstructions = swapInstructionResponse.setupInstructions.map(
49749
+ deserializeJupiterInstruction
49750
+ );
49751
+ return {
49752
+ swapInstructions: [instruction],
49753
+ setupInstructions,
49754
+ addressLookupTableAddresses: addressLookupTableAccounts,
49755
+ quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
49756
+ };
49757
+ };
49758
+
49759
+ // src/services/account/utils/misc.utils.ts
49760
+ function floor(value, decimals) {
49761
+ return Math.floor(value * 10 ** decimals) / 10 ** decimals;
49762
+ }
49763
+ function ceil(value, decimals) {
49764
+ return Math.ceil(value * 10 ** decimals) / 10 ** decimals;
49765
+ }
49766
+ function computeClosePositionTokenAmount(position, mintDecimals) {
49767
+ const closePositionTokenAmount = position.isLending ? floor(position.amount, mintDecimals) : ceil(position.amount, mintDecimals);
49768
+ return closePositionTokenAmount;
49769
+ }
49770
+ function isWholePosition(position, amount, mintDecimals) {
49771
+ const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
49772
+ return amount >= closePositionTokenAmount;
49773
+ }
49774
+ var SWAP_MERGE_OVERHEAD = 150;
49775
+ var FL_IX_OVERHEAD = 52;
49776
+ function compactU16Size(n) {
49777
+ return n < 128 ? 1 : n < 16384 ? 2 : 3;
49778
+ }
49779
+ function computeV0TxSize(ixs, payerKey, luts) {
49780
+ const keyMap = /* @__PURE__ */ new Map();
49781
+ const payerStr = payerKey.toBase58();
49782
+ keyMap.set(payerStr, { isSigner: true, isWritable: true });
49783
+ const programIds = /* @__PURE__ */ new Set();
49784
+ for (const ix of ixs) {
49785
+ const progStr = ix.programId.toBase58();
49786
+ programIds.add(progStr);
49787
+ if (!keyMap.has(progStr)) {
49788
+ keyMap.set(progStr, { isSigner: false, isWritable: false });
49789
+ }
49790
+ for (const meta of ix.keys) {
49791
+ const keyStr = meta.pubkey.toBase58();
49792
+ const existing = keyMap.get(keyStr);
49793
+ if (existing) {
49794
+ existing.isSigner = existing.isSigner || meta.isSigner;
49795
+ existing.isWritable = existing.isWritable || meta.isWritable;
49796
+ } else {
49797
+ keyMap.set(keyStr, { isSigner: meta.isSigner, isWritable: meta.isWritable });
49798
+ }
49799
+ }
49800
+ }
49801
+ const lutLookup = /* @__PURE__ */ new Map();
49802
+ for (let li = 0; li < luts.length; li++) {
49803
+ const addresses = luts[li].state.addresses;
49804
+ for (let ai = 0; ai < addresses.length; ai++) {
49805
+ const addrStr = addresses[ai].toBase58();
49806
+ if (!lutLookup.has(addrStr)) {
49807
+ lutLookup.set(addrStr, { lutIdx: li, addrIdx: ai });
49808
+ }
49809
+ }
49810
+ }
49811
+ let numStaticKeys = 0;
49812
+ let numWritableStaticKeys = 0;
49813
+ const lutWritableIdxs = luts.map(() => /* @__PURE__ */ new Set());
49814
+ const lutReadonlyIdxs = luts.map(() => /* @__PURE__ */ new Set());
49815
+ for (const [keyStr, props] of keyMap) {
49816
+ if (props.isSigner || programIds.has(keyStr)) {
49817
+ numStaticKeys++;
49818
+ if (props.isWritable) numWritableStaticKeys++;
49819
+ continue;
49820
+ }
49821
+ const lutEntry = lutLookup.get(keyStr);
49822
+ if (lutEntry) {
49823
+ if (props.isWritable) {
49824
+ lutWritableIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
49825
+ } else {
49826
+ lutReadonlyIdxs[lutEntry.lutIdx].add(lutEntry.addrIdx);
49827
+ }
49828
+ } else {
49829
+ numStaticKeys++;
49830
+ if (props.isWritable) numWritableStaticKeys++;
49831
+ }
49832
+ }
49833
+ const fixedOverhead = 101;
49834
+ const staticKeysSection = compactU16Size(numStaticKeys) + numStaticKeys * 32;
49835
+ let ixSection = compactU16Size(ixs.length);
49836
+ for (const ix of ixs) {
49837
+ const numAccounts = ix.keys.length;
49838
+ ixSection += 1 + // programId index
49839
+ compactU16Size(numAccounts) + numAccounts + // account key indexes
49840
+ compactU16Size(ix.data.length) + ix.data.length;
49841
+ }
49842
+ let numUsedLuts = 0;
49843
+ let lutSection = 0;
49844
+ for (let li = 0; li < luts.length; li++) {
49845
+ const wCount = lutWritableIdxs[li].size;
49846
+ const rCount = lutReadonlyIdxs[li].size;
49847
+ if (wCount === 0 && rCount === 0) continue;
49848
+ numUsedLuts++;
49849
+ lutSection += 32 + // LUT address
49850
+ compactU16Size(wCount) + wCount + // writable indexes
49851
+ compactU16Size(rCount) + rCount;
49852
+ }
49853
+ lutSection += compactU16Size(numUsedLuts);
49854
+ let totalLutKeys = 0;
49855
+ for (let li = 0; li < luts.length; li++) {
49856
+ totalLutKeys += lutWritableIdxs[li].size + lutReadonlyIdxs[li].size;
49857
+ }
49858
+ const accountCount = numStaticKeys + totalLutKeys;
49859
+ let totalLutWritableKeys = 0;
49860
+ for (let li = 0; li < luts.length; li++) {
49861
+ totalLutWritableKeys += lutWritableIdxs[li].size;
49862
+ }
49863
+ const writableAccountCount = numWritableStaticKeys + totalLutWritableKeys;
49864
+ const size = fixedOverhead + staticKeysSection + ixSection + lutSection + 1;
49865
+ return { size, accountCount, writableAccountCount };
49866
+ }
49867
+ function computeFlashLoanNonSwapBudget({
49868
+ program,
49869
+ marginfiAccount,
49870
+ ixs,
49871
+ bankMap,
49872
+ addressLookupTableAccounts
49873
+ }) {
49874
+ const projectedActiveBanksKeys = computeProjectedActiveBanksNoCpi(
49875
+ marginfiAccount.balances,
49876
+ ixs,
49877
+ program
49878
+ );
49879
+ const projectedActiveBanks = projectedActiveBanksKeys.map((key) => {
49880
+ const b = bankMap.get(key.toBase58());
49881
+ if (!b) throw new Error(`Bank ${key.toBase58()} not found in computeFlashLoanNonSwapBudget`);
49882
+ return b;
49883
+ });
49884
+ const endIndex = ixs.length + 1;
49885
+ const beginFlIx = sync_instructions_default.makeBeginFlashLoanIx(
49886
+ program.programId,
49887
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
49888
+ { endIndex: new BN11__default.default(endIndex) }
49889
+ );
49890
+ const endFlRemainingAccounts = computeHealthAccountMetas(projectedActiveBanks);
49891
+ const endFlIx = sync_instructions_default.makeEndFlashLoanIx(
49892
+ program.programId,
49893
+ { marginfiAccount: marginfiAccount.address, authority: marginfiAccount.authority },
49894
+ endFlRemainingAccounts.map((pubkey) => ({ pubkey, isSigner: false, isWritable: false }))
49895
+ );
49896
+ const allNonSwapIxs = [beginFlIx, ...ixs, endFlIx];
49897
+ const nonSwapMsg = new web3_js.TransactionMessage({
49898
+ payerKey: marginfiAccount.authority,
49899
+ recentBlockhash: web3_js.PublicKey.default.toBase58(),
49900
+ instructions: allNonSwapIxs
49901
+ }).compileToV0Message(addressLookupTableAccounts);
49902
+ const nonSwapSize = new web3_js.VersionedTransaction(nonSwapMsg).serialize().length;
49903
+ const { header, staticAccountKeys, addressTableLookups } = nonSwapMsg;
49904
+ const nonSwapTotal = staticAccountKeys.length + addressTableLookups.reduce(
49905
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
49906
+ 0
49907
+ );
49908
+ const sizeConstraint = MAX_TX_SIZE - nonSwapSize - SWAP_MERGE_OVERHEAD;
49909
+ const maxSwapTotalAccounts = MAX_ACCOUNT_LOCKS - nonSwapTotal;
49910
+ console.log("[flashloan-budget]", {
49911
+ method: "compiled",
49912
+ nonSwapSize,
49913
+ nonSwapTotal,
49914
+ sizeConstraint,
49915
+ maxSwapTotalAccounts
49916
+ });
49917
+ return { sizeConstraint, maxSwapTotalAccounts };
49918
+ }
49919
+ function compileFlashloanPrecheck({
49920
+ allIxs,
49921
+ payer,
49922
+ luts,
49923
+ sizeConstraint,
49924
+ swapIxCount,
49925
+ swapLutCount
49926
+ }) {
49927
+ const msg = new web3_js.TransactionMessage({
49928
+ payerKey: payer,
49929
+ recentBlockhash: web3_js.PublicKey.default.toBase58(),
49930
+ instructions: allIxs
49931
+ }).compileToV0Message(luts);
49932
+ const rawSize = new web3_js.VersionedTransaction(msg).serialize().length;
49933
+ const fullTxSize = rawSize + FL_IX_OVERHEAD;
49934
+ const overshoot = fullTxSize - MAX_TX_SIZE;
49935
+ const { header, staticAccountKeys, addressTableLookups } = msg;
49936
+ const writableStatic = staticAccountKeys.length - header.numReadonlySignedAccounts - header.numReadonlyUnsignedAccounts;
49937
+ const writableLut = addressTableLookups.reduce((s, l) => s + l.writableIndexes.length, 0);
49938
+ const writableAccounts = writableStatic + writableLut;
49939
+ const totalAccounts = staticAccountKeys.length + addressTableLookups.reduce(
49940
+ (s, l) => s + l.writableIndexes.length + l.readonlyIndexes.length,
49941
+ 0
49942
+ );
49943
+ console.log("[flashloan-precheck]", {
49944
+ fullTxSize,
49945
+ overshoot,
49946
+ sizeConstraint,
49947
+ writableAccounts,
49948
+ totalAccounts,
49949
+ staticKeys: staticAccountKeys.length,
49950
+ numLuts: addressTableLookups.length,
49951
+ swapIxCount,
49952
+ swapLutCount
49953
+ });
49954
+ return { fullTxSize, overshoot, writableAccounts, totalAccounts };
49955
+ }
49956
+ async function buildBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
49957
+ const { bank, tokenProgram } = config;
49958
+ switch (config.type) {
49959
+ case "borrow":
49960
+ return makeBorrowIx3({
49961
+ program,
49962
+ bank,
49963
+ bankMap,
49964
+ tokenProgram,
49965
+ amount: 1,
49966
+ marginfiAccount,
49967
+ authority: marginfiAccount.authority,
49968
+ isSync: true,
49969
+ opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
49970
+ });
49971
+ case "repay":
49972
+ return makeRepayIx3({
49973
+ program,
49974
+ bank,
49975
+ tokenProgram,
49976
+ amount: 1,
49977
+ accountAddress: marginfiAccount.address,
49978
+ authority: marginfiAccount.authority,
49979
+ repayAll: false,
49980
+ isSync: true,
49981
+ opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
49982
+ });
49983
+ case "deposit":
49984
+ return buildDepositBudgetIx(
49985
+ config,
49986
+ program,
49987
+ marginfiAccount,
49988
+ bankMetadataMap,
49989
+ overrideInferAccounts
49990
+ );
49991
+ case "withdraw":
49992
+ return buildWithdrawBudgetIx(
49993
+ config,
49994
+ program,
49995
+ marginfiAccount,
49996
+ bankMap,
49997
+ bankMetadataMap,
49998
+ overrideInferAccounts
49999
+ );
50000
+ }
50001
+ }
50002
+ async function buildDepositBudgetIx(config, program, marginfiAccount, bankMetadataMap, overrideInferAccounts) {
50003
+ const { bank, tokenProgram } = config;
50004
+ const opts = { wrapAndUnwrapSol: false, overrideInferAccounts };
50005
+ switch (bank.config.assetTag) {
50006
+ case 3 /* KAMINO */: {
50007
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
50008
+ if (!reserve) {
50009
+ throw TransactionBuildingError.kaminoReserveNotFound(
50010
+ bank.address.toBase58(),
50011
+ bank.mint.toBase58(),
50012
+ bank.tokenSymbol
50013
+ );
50014
+ }
50015
+ return makeKaminoDepositIx3({
50016
+ program,
50017
+ bank,
50018
+ tokenProgram,
50019
+ amount: 1,
50020
+ accountAddress: marginfiAccount.address,
50021
+ authority: marginfiAccount.authority,
50022
+ group: marginfiAccount.group,
50023
+ reserve,
50024
+ isSync: true,
50025
+ opts
50026
+ });
50027
+ }
50028
+ case 4 /* DRIFT */: {
50029
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
50030
+ if (!driftState) {
50031
+ throw TransactionBuildingError.driftStateNotFound(
50032
+ bank.address.toBase58(),
50033
+ bank.mint.toBase58(),
50034
+ bank.tokenSymbol
50035
+ );
50036
+ }
50037
+ return makeDriftDepositIx3({
50038
+ program,
50039
+ bank,
50040
+ tokenProgram,
50041
+ amount: 1,
50042
+ accountAddress: marginfiAccount.address,
50043
+ authority: marginfiAccount.authority,
50044
+ group: marginfiAccount.group,
50045
+ driftMarketIndex: driftState.spotMarketState.marketIndex,
50046
+ driftOracle: driftState.spotMarketState.oracle,
50047
+ isSync: true,
50048
+ opts
50049
+ });
50050
+ }
50051
+ case 6 /* JUPLEND */: {
50052
+ return makeJuplendDepositIx2({
50053
+ program,
50054
+ bank,
50055
+ tokenProgram,
50056
+ amount: 1,
50057
+ accountAddress: marginfiAccount.address,
50058
+ authority: marginfiAccount.authority,
50059
+ group: marginfiAccount.group,
50060
+ isSync: true,
50061
+ opts
50062
+ });
50063
+ }
50064
+ default: {
50065
+ return makeDepositIx3({
50066
+ program,
50067
+ bank,
50068
+ tokenProgram,
50069
+ amount: 1,
50070
+ accountAddress: marginfiAccount.address,
50071
+ authority: marginfiAccount.authority,
50072
+ group: marginfiAccount.group,
50073
+ isSync: true,
50074
+ opts
50075
+ });
50076
+ }
50077
+ }
50302
50078
  }
50303
- var getJupiterSwapIxsForFlashloan = async ({
50304
- quoteParams,
50305
- authority,
50306
- connection,
50307
- destinationTokenAccount,
50308
- apiConfig,
50309
- maxSwapAccounts
50310
- }) => {
50311
- const configParams = toJupiterConfig(apiConfig);
50312
- const jupiterApiClient = configParams?.basePath ? new api.SwapApi(new api.Configuration(configParams)) : api.createJupiterApiClient(configParams);
50313
- const feeMint = quoteParams.swapMode === "ExactIn" ? quoteParams.outputMint : quoteParams.inputMint;
50314
- const { feeAccount, hasFeeAccount } = await checkFeeAccount(connection, new web3_js.PublicKey(feeMint));
50315
- const project0JupiterLut = (await connection.getAddressLookupTable(ADDRESS_LOOKUP_TABLE_FOR_SWAP))?.value;
50316
- let finalQuoteParams = quoteParams;
50317
- if (!hasFeeAccount) {
50318
- console.warn("Warning: feeAccountInfo is undefined");
50319
- finalQuoteParams = {
50320
- ...quoteParams,
50321
- platformFeeBps: void 0
50322
- };
50323
- }
50324
- const maxAccounts = maxSwapAccounts ?? 40;
50325
- const swapQuote = await jupiterApiClient.quoteGet({
50326
- ...finalQuoteParams,
50327
- maxAccounts
50328
- });
50329
- const swapInstructionResponse = await jupiterApiClient.swapInstructionsPost({
50330
- swapRequest: {
50331
- quoteResponse: swapQuote,
50332
- userPublicKey: authority.toBase58(),
50333
- feeAccount: hasFeeAccount ? feeAccount : void 0,
50334
- wrapAndUnwrapSol: false,
50335
- destinationTokenAccount: destinationTokenAccount.toBase58()
50079
+ async function buildWithdrawBudgetIx(config, program, marginfiAccount, bankMap, bankMetadataMap, overrideInferAccounts) {
50080
+ const { bank, tokenProgram } = config;
50081
+ const opts = { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts };
50082
+ switch (bank.config.assetTag) {
50083
+ case 3 /* KAMINO */: {
50084
+ const reserve = bankMetadataMap[bank.address.toBase58()]?.kaminoStates?.reserveState;
50085
+ if (!reserve) {
50086
+ throw TransactionBuildingError.kaminoReserveNotFound(
50087
+ bank.address.toBase58(),
50088
+ bank.mint.toBase58(),
50089
+ bank.tokenSymbol
50090
+ );
50091
+ }
50092
+ return makeKaminoWithdrawIx3({
50093
+ program,
50094
+ bank,
50095
+ bankMap,
50096
+ tokenProgram,
50097
+ cTokenAmount: 1,
50098
+ marginfiAccount,
50099
+ authority: marginfiAccount.authority,
50100
+ reserve,
50101
+ withdrawAll: false,
50102
+ isSync: true,
50103
+ opts
50104
+ });
50336
50105
  }
50337
- });
50338
- const lutAddresses = swapInstructionResponse.addressLookupTableAddresses;
50339
- const lutAccountsRaw = await connection.getMultipleAccountsInfo(
50340
- lutAddresses.map((address) => new web3_js.PublicKey(address))
50341
- );
50342
- const addressLookupTableAccounts = lutAccountsRaw.map((accountInfo, index) => {
50343
- const addressLookupTableAddress = lutAddresses[index];
50344
- if (!accountInfo || !addressLookupTableAddress) {
50345
- return null;
50106
+ case 4 /* DRIFT */: {
50107
+ const driftState = bankMetadataMap[bank.address.toBase58()]?.driftStates;
50108
+ if (!driftState) {
50109
+ throw TransactionBuildingError.driftStateNotFound(
50110
+ bank.address.toBase58(),
50111
+ bank.mint.toBase58(),
50112
+ bank.tokenSymbol
50113
+ );
50114
+ }
50115
+ return makeDriftWithdrawIx3({
50116
+ program,
50117
+ bank,
50118
+ bankMap,
50119
+ tokenProgram,
50120
+ amount: 1,
50121
+ marginfiAccount,
50122
+ authority: marginfiAccount.authority,
50123
+ driftSpotMarket: driftState.spotMarketState,
50124
+ userRewards: driftState.userRewards,
50125
+ withdrawAll: false,
50126
+ isSync: true,
50127
+ opts
50128
+ });
50346
50129
  }
50347
- return new web3_js.AddressLookupTableAccount({
50348
- key: new web3_js.PublicKey(addressLookupTableAddress),
50349
- state: web3_js.AddressLookupTableAccount.deserialize(accountInfo.data)
50350
- });
50351
- }).filter((account) => account !== null).concat(project0JupiterLut ? [project0JupiterLut] : []);
50352
- const instruction = deserializeJupiterInstruction(swapInstructionResponse.swapInstruction);
50353
- const setupInstructions = swapInstructionResponse.setupInstructions.map(
50354
- deserializeJupiterInstruction
50355
- );
50356
- return {
50357
- swapInstructions: [instruction],
50358
- setupInstructions,
50359
- addressLookupTableAddresses: addressLookupTableAccounts,
50360
- quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
50361
- };
50362
- };
50363
-
50364
- // src/services/account/utils/misc.utils.ts
50365
- function floor(value, decimals) {
50366
- return Math.floor(value * 10 ** decimals) / 10 ** decimals;
50367
- }
50368
- function ceil(value, decimals) {
50369
- return Math.ceil(value * 10 ** decimals) / 10 ** decimals;
50370
- }
50371
- function computeClosePositionTokenAmount(position, mintDecimals) {
50372
- const closePositionTokenAmount = position.isLending ? floor(position.amount, mintDecimals) : ceil(position.amount, mintDecimals);
50373
- return closePositionTokenAmount;
50130
+ case 6 /* JUPLEND */: {
50131
+ const jupLendState = bankMetadataMap[bank.address.toBase58()]?.jupLendStates;
50132
+ if (!jupLendState) {
50133
+ throw TransactionBuildingError.jupLendStateNotFound(
50134
+ bank.address.toBase58(),
50135
+ bank.mint.toBase58(),
50136
+ bank.tokenSymbol
50137
+ );
50138
+ }
50139
+ return makeJuplendWithdrawIx2({
50140
+ program,
50141
+ bank,
50142
+ bankMap,
50143
+ tokenProgram,
50144
+ amount: 1,
50145
+ marginfiAccount,
50146
+ authority: marginfiAccount.authority,
50147
+ jupLendingState: jupLendState.jupLendingState,
50148
+ withdrawAll: false,
50149
+ opts
50150
+ });
50151
+ }
50152
+ default: {
50153
+ return makeWithdrawIx3({
50154
+ program,
50155
+ bank,
50156
+ bankMap,
50157
+ tokenProgram,
50158
+ amount: 1,
50159
+ marginfiAccount,
50160
+ authority: marginfiAccount.authority,
50161
+ withdrawAll: false,
50162
+ isSync: true,
50163
+ opts
50164
+ });
50165
+ }
50166
+ }
50374
50167
  }
50375
- function isWholePosition(position, amount, mintDecimals) {
50376
- const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
50377
- return amount >= closePositionTokenAmount;
50168
+ async function computeFlashloanSwapConstraints({
50169
+ program,
50170
+ marginfiAccount,
50171
+ bankMap,
50172
+ addressLookupTableAccounts,
50173
+ bankMetadataMap,
50174
+ primaryIx,
50175
+ secondaryIx,
50176
+ overrideInferAccounts
50177
+ }) {
50178
+ const cuRequestIxs = [
50179
+ web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
50180
+ web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
50181
+ ];
50182
+ const [primaryResult, secondaryResult] = await Promise.all([
50183
+ buildBudgetIx(
50184
+ primaryIx,
50185
+ program,
50186
+ marginfiAccount,
50187
+ bankMap,
50188
+ bankMetadataMap,
50189
+ overrideInferAccounts
50190
+ ),
50191
+ buildBudgetIx(
50192
+ secondaryIx,
50193
+ program,
50194
+ marginfiAccount,
50195
+ bankMap,
50196
+ bankMetadataMap,
50197
+ overrideInferAccounts
50198
+ )
50199
+ ]);
50200
+ return computeFlashLoanNonSwapBudget({
50201
+ program,
50202
+ marginfiAccount,
50203
+ bankMap,
50204
+ addressLookupTableAccounts,
50205
+ ixs: [...cuRequestIxs, ...primaryResult.instructions, ...secondaryResult.instructions]
50206
+ });
50378
50207
  }
50379
50208
 
50380
50209
  // src/services/price/utils/smart-crank.utils.ts
@@ -52638,6 +52467,230 @@ function getValidatorVoteAccountByBank() {
52638
52467
  }
52639
52468
  return _voteAccountByBank;
52640
52469
  }
52470
+ async function computeStakedBankMultipliers(stakedBanks, connection) {
52471
+ const multiplierByBank = /* @__PURE__ */ new Map();
52472
+ if (stakedBanks.length === 0) {
52473
+ return multiplierByBank;
52474
+ }
52475
+ const metadataMap = getStakedBankMetadataMap();
52476
+ const stakedBankAddresses = [];
52477
+ const poolStakeAddresses = [];
52478
+ const lstMintAddresses = [];
52479
+ for (const bank of stakedBanks) {
52480
+ const metadata = metadataMap.get(bank.address.toBase58());
52481
+ if (!metadata) {
52482
+ multiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
52483
+ continue;
52484
+ }
52485
+ const pool = findPoolAddress(new web3_js.PublicKey(metadata.validatorVoteAccount));
52486
+ stakedBankAddresses.push(bank.address.toBase58());
52487
+ poolStakeAddresses.push(findPoolStakeAddress(pool));
52488
+ lstMintAddresses.push(findPoolMintAddress(pool));
52489
+ }
52490
+ if (stakedBankAddresses.length === 0) {
52491
+ return multiplierByBank;
52492
+ }
52493
+ const allAddresses = [
52494
+ ...poolStakeAddresses.map((a) => a.toBase58()),
52495
+ ...lstMintAddresses.map((a) => a.toBase58())
52496
+ ];
52497
+ const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(connection, allAddresses);
52498
+ const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
52499
+ const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
52500
+ for (let i = 0; i < stakedBankAddresses.length; i++) {
52501
+ const bankAddr = stakedBankAddresses[i];
52502
+ const poolStakeInfo = poolStakeInfos[i];
52503
+ const lstMintInfo = lstMintInfos[i];
52504
+ if (!poolStakeInfo || !lstMintInfo) {
52505
+ multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
52506
+ continue;
52507
+ }
52508
+ const stakeLamports = poolStakeInfo.lamports;
52509
+ const supplyBuffer = lstMintInfo.data.slice(36, 44);
52510
+ const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
52511
+ if (lstMintSupply === 0) {
52512
+ multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
52513
+ continue;
52514
+ }
52515
+ const adjustedStake = Math.max(stakeLamports - web3_js.LAMPORTS_PER_SOL, 0);
52516
+ const multiplier = new BigNumber3__default.default(adjustedStake).dividedBy(lstMintSupply);
52517
+ multiplierByBank.set(bankAddr, multiplier);
52518
+ }
52519
+ return multiplierByBank;
52520
+ }
52521
+ var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
52522
+ async function makeMintStakedLstIx(params) {
52523
+ const { amount, authority, stakeAccountPk, validator, connection } = params;
52524
+ const pool = findPoolAddress(validator);
52525
+ const lstMint = findPoolMintAddress(pool);
52526
+ const poolStakeAuth = findPoolStakeAuthorityAddress(pool);
52527
+ const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
52528
+ const [lstAccInfo, stakeAccInfoParsed, rentExemptReserve] = await Promise.all([
52529
+ connection.getAccountInfo(lstAta),
52530
+ connection.getParsedAccountInfo(stakeAccountPk),
52531
+ connection.getMinimumBalanceForRentExemption(web3_js.StakeProgram.space)
52532
+ ]);
52533
+ const stakeAccParsed = stakeAccInfoParsed?.value?.data;
52534
+ const amountLamports = Math.round(Number(amount) * web3_js.LAMPORTS_PER_SOL);
52535
+ const stakeAccLamports = Number(stakeAccParsed?.parsed?.info?.stake?.delegation?.stake ?? 0);
52536
+ const isFullStake = amountLamports >= stakeAccLamports;
52537
+ const instructions2 = [];
52538
+ const signers = [];
52539
+ if (!lstAccInfo) {
52540
+ instructions2.push(
52541
+ createAssociatedTokenAccountInstruction(authority, lstAta, authority, lstMint)
52542
+ );
52543
+ }
52544
+ let targetStakePubkey;
52545
+ if (!isFullStake) {
52546
+ const splitStakeAccount = web3_js.Keypair.generate();
52547
+ signers.push(splitStakeAccount);
52548
+ targetStakePubkey = splitStakeAccount.publicKey;
52549
+ instructions2.push(
52550
+ ...web3_js.StakeProgram.split(
52551
+ {
52552
+ stakePubkey: stakeAccountPk,
52553
+ authorizedPubkey: authority,
52554
+ splitStakePubkey: splitStakeAccount.publicKey,
52555
+ lamports: amountLamports
52556
+ },
52557
+ rentExemptReserve
52558
+ ).instructions
52559
+ );
52560
+ } else {
52561
+ targetStakePubkey = stakeAccountPk;
52562
+ }
52563
+ const [authorizeStakerIx, authorizeWithdrawIx] = await Promise.all([
52564
+ web3_js.StakeProgram.authorize({
52565
+ stakePubkey: targetStakePubkey,
52566
+ authorizedPubkey: authority,
52567
+ newAuthorizedPubkey: poolStakeAuth,
52568
+ stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Staker
52569
+ }).instructions,
52570
+ web3_js.StakeProgram.authorize({
52571
+ stakePubkey: targetStakePubkey,
52572
+ authorizedPubkey: authority,
52573
+ newAuthorizedPubkey: poolStakeAuth,
52574
+ stakeAuthorizationType: web3_js.StakeAuthorizationLayout.Withdrawer
52575
+ }).instructions
52576
+ ]);
52577
+ [authorizeStakerIx[0], authorizeWithdrawIx[0]].forEach((ix) => {
52578
+ if (ix) {
52579
+ ix.keys = ix.keys.map((key) => ({
52580
+ ...key,
52581
+ isWritable: key.pubkey.equals(SYSVAR_CLOCK_ID2) ? false : key.isWritable
52582
+ }));
52583
+ }
52584
+ });
52585
+ instructions2.push(...authorizeStakerIx, ...authorizeWithdrawIx);
52586
+ const depositStakeIx = await SinglePoolInstruction.depositStake(
52587
+ pool,
52588
+ targetStakePubkey,
52589
+ lstAta,
52590
+ authority
52591
+ );
52592
+ instructions2.push(depositStakeIx);
52593
+ return { instructions: instructions2, keys: signers };
52594
+ }
52595
+ async function makeMintStakedLstTx(params) {
52596
+ const { connection, luts, blockhash: providedBlockhash } = params;
52597
+ const { instructions: instructions2, keys } = await makeMintStakedLstIx(params);
52598
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52599
+ const message = new web3_js.TransactionMessage({
52600
+ payerKey: params.authority,
52601
+ recentBlockhash: blockhash,
52602
+ instructions: instructions2
52603
+ }).compileToV0Message(luts);
52604
+ const tx = new web3_js.VersionedTransaction(message);
52605
+ return addTransactionMetadata(tx, {
52606
+ signers: keys,
52607
+ addressLookupTables: luts,
52608
+ type: "DEPOSIT_STAKE" /* DEPOSIT_STAKE */
52609
+ });
52610
+ }
52611
+ async function makeRedeemStakedLstIx(params) {
52612
+ const { amount, authority, validator, connection } = params;
52613
+ const pool = findPoolAddress(validator);
52614
+ const lstMint = findPoolMintAddress(pool);
52615
+ const mintAuthority = findPoolMintAuthorityAddress(pool);
52616
+ const lstAta = getAssociatedTokenAddressSync(lstMint, authority);
52617
+ const rentExemption = await connection.getMinimumBalanceForRentExemption(
52618
+ web3_js.StakeProgram.space
52619
+ );
52620
+ const stakeAmount = new BigNumber3__default.default(new BigNumber3__default.default(amount).toString());
52621
+ const instructions2 = [];
52622
+ const signers = [];
52623
+ const stakeAccount = web3_js.Keypair.generate();
52624
+ signers.push(stakeAccount);
52625
+ instructions2.push(
52626
+ web3_js.SystemProgram.createAccount({
52627
+ fromPubkey: authority,
52628
+ newAccountPubkey: stakeAccount.publicKey,
52629
+ lamports: rentExemption,
52630
+ space: web3_js.StakeProgram.space,
52631
+ programId: web3_js.StakeProgram.programId
52632
+ })
52633
+ );
52634
+ instructions2.push(
52635
+ createApproveInstruction(
52636
+ lstAta,
52637
+ mintAuthority,
52638
+ authority,
52639
+ BigInt(stakeAmount.multipliedBy(1e9).toFixed(0))
52640
+ )
52641
+ );
52642
+ const withdrawStakeIx = await SinglePoolInstruction.withdrawStake(
52643
+ pool,
52644
+ stakeAccount.publicKey,
52645
+ authority,
52646
+ lstAta,
52647
+ stakeAmount
52648
+ );
52649
+ instructions2.push(withdrawStakeIx);
52650
+ return { instructions: instructions2, keys: signers };
52651
+ }
52652
+ async function makeRedeemStakedLstTx(params) {
52653
+ const { connection, luts, blockhash: providedBlockhash } = params;
52654
+ const { instructions: instructions2, keys } = await makeRedeemStakedLstIx(params);
52655
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52656
+ const message = new web3_js.TransactionMessage({
52657
+ payerKey: params.authority,
52658
+ recentBlockhash: blockhash,
52659
+ instructions: instructions2
52660
+ }).compileToV0Message(luts);
52661
+ const tx = new web3_js.VersionedTransaction(message);
52662
+ return addTransactionMetadata(tx, {
52663
+ signers: keys,
52664
+ addressLookupTables: luts,
52665
+ type: "WITHDRAW_STAKE" /* WITHDRAW_STAKE */
52666
+ });
52667
+ }
52668
+ async function makeMergeStakeAccountsTx(params) {
52669
+ const {
52670
+ authority,
52671
+ sourceStakeAccount,
52672
+ destinationStakeAccount,
52673
+ connection,
52674
+ luts,
52675
+ blockhash: providedBlockhash
52676
+ } = params;
52677
+ const mergeIx = web3_js.StakeProgram.merge({
52678
+ stakePubkey: destinationStakeAccount,
52679
+ sourceStakePubKey: sourceStakeAccount,
52680
+ authorizedPubkey: authority
52681
+ }).instructions;
52682
+ const blockhash = providedBlockhash ?? (await connection.getLatestBlockhash("confirmed")).blockhash;
52683
+ const message = new web3_js.TransactionMessage({
52684
+ payerKey: authority,
52685
+ recentBlockhash: blockhash,
52686
+ instructions: mergeIx
52687
+ }).compileToV0Message(luts);
52688
+ const tx = new web3_js.VersionedTransaction(message);
52689
+ return addTransactionMetadata(tx, {
52690
+ addressLookupTables: luts,
52691
+ type: "MERGE_STAKE_ACCOUNTS" /* MERGE_STAKE_ACCOUNTS */
52692
+ });
52693
+ }
52641
52694
  async function getKaminoMetadata(options) {
52642
52695
  const kaminoBanks = options.banks.filter((b) => b.config.assetTag === 3 /* KAMINO */);
52643
52696
  const DEFAULT_PUBKEY = web3_js.PublicKey.default;
@@ -55074,66 +55127,6 @@ var MarginfiAccountWrapper = class {
55074
55127
  return this.account.getHealthCheckAccounts(this.client.bankMap, mandatoryBanks, excludedBanks);
55075
55128
  }
55076
55129
  // ----------------------------------------------------------------------------
55077
- // Native stake actions
55078
- // Note: These call standalone action functions directly rather than routing
55079
- // through this.account because they interact with the SPL stake pool program,
55080
- // not the marginfi program. No MarginfiAccount state is needed.
55081
- // ----------------------------------------------------------------------------
55082
- /**
55083
- * Creates a transaction to mint LST from a native stake account.
55084
- *
55085
- * Converts a native stake account (or a portion of it) into LST tokens
55086
- * by depositing the stake into the single-validator pool.
55087
- *
55088
- * @param amount - SOL amount to convert (in UI units)
55089
- * @param stakeAccountPk - The stake account to convert
55090
- * @param validator - The validator vote account
55091
- */
55092
- async makeMintStakedLstTx(amount, stakeAccountPk, validator) {
55093
- return makeMintStakedLstTx({
55094
- amount,
55095
- authority: this.authority,
55096
- stakeAccountPk,
55097
- validator,
55098
- connection: this.client.program.provider.connection,
55099
- luts: this.client.addressLookupTables
55100
- });
55101
- }
55102
- /**
55103
- * Creates a transaction to redeem LST tokens back to a native stake account.
55104
- *
55105
- * Burns LST tokens and withdraws the underlying stake into a new stake account.
55106
- *
55107
- * @param amount - LST amount to redeem (in UI units)
55108
- * @param validator - The validator vote account
55109
- */
55110
- async makeRedeemStakedLstTx(amount, validator) {
55111
- return makeRedeemStakedLstTx({
55112
- amount,
55113
- authority: this.authority,
55114
- validator,
55115
- connection: this.client.program.provider.connection,
55116
- luts: this.client.addressLookupTables
55117
- });
55118
- }
55119
- /**
55120
- * Creates a transaction to merge two stake accounts.
55121
- *
55122
- * Both accounts must share the same authorized staker/withdrawer and vote account.
55123
- *
55124
- * @param sourceStakeAccount - The stake account to merge from (will be consumed)
55125
- * @param destinationStakeAccount - The stake account to merge into
55126
- */
55127
- async makeMergeStakeAccountsTx(sourceStakeAccount, destinationStakeAccount) {
55128
- return makeMergeStakeAccountsTx({
55129
- authority: this.authority,
55130
- sourceStakeAccount,
55131
- destinationStakeAccount,
55132
- connection: this.client.program.provider.connection,
55133
- luts: this.client.addressLookupTables
55134
- });
55135
- }
55136
- // ----------------------------------------------------------------------------
55137
55130
  // Helper methods
55138
55131
  // ----------------------------------------------------------------------------
55139
55132
  /**
@@ -55403,56 +55396,11 @@ var Project0Client = class _Project0Client {
55403
55396
  break;
55404
55397
  }
55405
55398
  });
55406
- const stakedBanks = banksArray.filter((b) => b.config.assetTag === 2 /* STAKED */);
55407
- if (stakedBanks.length > 0) {
55408
- const metadataMap = getStakedBankMetadataMap();
55409
- const stakedBankAddresses = [];
55410
- const poolStakeAddresses = [];
55411
- const lstMintAddresses = [];
55412
- for (const bank of stakedBanks) {
55413
- const metadata = metadataMap.get(bank.address.toBase58());
55414
- if (!metadata) {
55415
- assetShareMultiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
55416
- continue;
55417
- }
55418
- const pool = findPoolAddress(new web3_js.PublicKey(metadata.validatorVoteAccount));
55419
- stakedBankAddresses.push(bank.address.toBase58());
55420
- poolStakeAddresses.push(findPoolStakeAddress(pool));
55421
- lstMintAddresses.push(findPoolMintAddress(pool));
55422
- }
55423
- if (stakedBankAddresses.length > 0) {
55424
- const allAddresses = [
55425
- ...poolStakeAddresses.map((a) => a.toBase58()),
55426
- ...lstMintAddresses.map((a) => a.toBase58())
55427
- ];
55428
- const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(
55429
- connection,
55430
- allAddresses
55431
- );
55432
- const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
55433
- const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
55434
- for (let i = 0; i < stakedBankAddresses.length; i++) {
55435
- const bankAddr = stakedBankAddresses[i];
55436
- const poolStakeInfo = poolStakeInfos[i];
55437
- const lstMintInfo = lstMintInfos[i];
55438
- if (!poolStakeInfo || !lstMintInfo) {
55439
- assetShareMultiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
55440
- continue;
55441
- }
55442
- const stakeLamports = poolStakeInfo.lamports;
55443
- const supplyBuffer = lstMintInfo.data.slice(36, 44);
55444
- const lstMintSupply = Number(Buffer.from(supplyBuffer).readBigUInt64LE(0));
55445
- if (lstMintSupply === 0) {
55446
- assetShareMultiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
55447
- continue;
55448
- }
55449
- const LAMPORTS_PER_SOL5 = 1e9;
55450
- const adjustedStake = Math.max(stakeLamports - LAMPORTS_PER_SOL5, 0);
55451
- const multiplier = new BigNumber3__default.default(adjustedStake).dividedBy(lstMintSupply);
55452
- assetShareMultiplierByBank.set(bankAddr, multiplier);
55453
- }
55454
- }
55455
- }
55399
+ const stakedMultipliers = await computeStakedBankMultipliers(
55400
+ banksArray.filter((b) => b.config.assetTag === 2 /* STAKED */),
55401
+ connection
55402
+ );
55403
+ stakedMultipliers.forEach((v, k) => assetShareMultiplierByBank.set(k, v));
55456
55404
  const emodePairs = getEmodePairs(banksArray);
55457
55405
  return new _Project0Client(
55458
55406
  program,
@@ -55634,6 +55582,7 @@ exports.computeQuantity = computeQuantity;
55634
55582
  exports.computeQuantityUi = computeQuantityUi;
55635
55583
  exports.computeRemainingCapacity = computeRemainingCapacity;
55636
55584
  exports.computeSmartCrank = computeSmartCrank;
55585
+ exports.computeStakedBankMultipliers = computeStakedBankMultipliers;
55637
55586
  exports.computeTotalOutstandingEmissions = computeTotalOutstandingEmissions;
55638
55587
  exports.computeTvl = computeTvl;
55639
55588
  exports.computeUsdValue = computeUsdValue;