@0dotxyz/p0-ts-sdk 2.5.5-alpha.4 → 2.5.5-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -103,6 +103,7 @@ var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCod
103
103
  TransactionBuildingErrorCode2["TRANSFER_POSITIONS_INVALID_SELECTION"] = "TRANSFER_POSITIONS_INVALID_SELECTION";
104
104
  TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSUPPORTED_BANK"] = "TRANSFER_POSITIONS_UNSUPPORTED_BANK";
105
105
  TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSPLITTABLE"] = "TRANSFER_POSITIONS_UNSPLITTABLE";
106
+ TransactionBuildingErrorCode2["BRIDGE_CONFLICT"] = "BRIDGE_CONFLICT";
106
107
  return TransactionBuildingErrorCode2;
107
108
  })(TransactionBuildingErrorCode || {});
108
109
  var TransactionBuildingError = class _TransactionBuildingError extends Error {
@@ -233,6 +234,19 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
233
234
  { reason, sizeBytes, accountCount }
234
235
  );
235
236
  }
237
+ /**
238
+ * A bridged (double-hop) swap could not route because every bridge-token candidate bank
239
+ * conflicts with an existing opposite-side position on the account (marginfi forbids holding an
240
+ * asset and a liability on the same bank).
241
+ */
242
+ static bridgeConflict(conflictingBanks, bridgeTokenSide) {
243
+ const banksList = conflictingBanks.map((c) => c.symbol ?? c.mint).join(", ");
244
+ return new _TransactionBuildingError(
245
+ "BRIDGE_CONFLICT" /* BRIDGE_CONFLICT */,
246
+ `Every bridge-token candidate conflicts with an existing opposite-side position: ${banksList}`,
247
+ { conflictingBanks, bridgeTokenSide }
248
+ );
249
+ }
236
250
  /**
237
251
  * Generic escape hatch for custom errors
238
252
  */
@@ -249,6 +263,9 @@ var DECOMPOSABLE_SWAP_ERROR_CODES = /* @__PURE__ */ new Set([
249
263
  function isDecomposableSwapError(e) {
250
264
  return e instanceof TransactionBuildingError && DECOMPOSABLE_SWAP_ERROR_CODES.has(e.code);
251
265
  }
266
+ function isBridgeConflictError(e) {
267
+ return e instanceof TransactionBuildingError && e.code === "BRIDGE_CONFLICT" /* BRIDGE_CONFLICT */;
268
+ }
252
269
  var PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED = Buffer.from("liquidity_vault_auth");
253
270
  var PDA_BANK_INSURANCE_VAULT_AUTH_SEED = Buffer.from("insurance_vault_auth");
254
271
  var PDA_BANK_FEE_VAULT_AUTH_SEED = Buffer.from("fee_vault_auth");
@@ -408,6 +425,7 @@ var PRIORITY_TX_SIZE = 44;
408
425
  var WSOL_MINT = new PublicKey("So11111111111111111111111111111111111111112");
409
426
  var LST_MINT = new PublicKey("LSTxxxnJzKDFSLr4dUkPcmCf5VyryEqzPLz5j4bpxFp");
410
427
  var USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
428
+ var USDT_MINT = new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");
411
429
  var USDC_DECIMALS = 6;
412
430
 
413
431
  // src/utils/accounting.utils.ts
@@ -67209,1775 +67227,298 @@ function annotateFit(route, req) {
67209
67227
  };
67210
67228
  }
67211
67229
 
67212
- // src/services/account/actions/loop.ts
67213
- async function makeLoopTx(params) {
67214
- const {
67215
- program,
67216
- marginfiAccount,
67217
- bankMap,
67218
- depositOpts,
67219
- borrowOpts,
67220
- bankMetadataMap,
67221
- addressLookupTableAccounts,
67222
- connection,
67223
- oraclePrices,
67224
- crossbarUrl,
67225
- additionalIxs = []
67226
- } = params;
67227
- const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
67228
- const setupIxs = await makeSetupIx({
67229
- connection,
67230
- authority: marginfiAccount.authority,
67231
- tokens: [
67232
- {
67233
- mint: borrowOpts.borrowBank.mint,
67234
- tokenProgram: borrowOpts.tokenProgram
67235
- },
67236
- {
67237
- mint: depositOpts.depositBank.mint,
67238
- tokenProgram: depositOpts.tokenProgram
67239
- }
67240
- ]
67241
- });
67242
- const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
67243
- params.marginfiAccount,
67244
- params.bankMap,
67245
- [depositOpts.depositBank.address],
67246
- params.bankMetadataMap,
67247
- [borrowOpts.borrowBank.address, depositOpts.depositBank.address]
67248
- );
67249
- const { flashloanTx, setupInstructions, swapQuote, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
67250
- ...params,
67251
- blockhash
67252
- });
67253
- const jupiterSetupInstructions = setupInstructions.filter((ix) => {
67254
- if (ix.programId.equals(ComputeBudgetProgram.programId)) {
67255
- return false;
67256
- }
67257
- if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
67258
- const mintKey = ix.keys[3]?.pubkey;
67259
- if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
67260
- return false;
67261
- }
67262
- }
67263
- return true;
67264
- });
67265
- setupIxs.push(...jupiterSetupInstructions);
67266
- const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
67267
- marginfiAccount,
67268
- bankMap,
67269
- oraclePrices,
67270
- assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
67271
- instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
67272
- program,
67273
- connection,
67274
- crossbarUrl
67275
- });
67276
- let additionalTxs = [];
67277
- if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
67278
- setupIxs.push(
67279
- ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber(depositOpts.inputDepositAmount))
67280
- );
67230
+ // src/models/balance.ts
67231
+ var Balance = class _Balance {
67232
+ constructor(active, bankPk, assetShares, liabilityShares, emissionsOutstanding, lastUpdate) {
67233
+ this.active = active;
67234
+ this.bankPk = bankPk;
67235
+ this.assetShares = assetShares;
67236
+ this.liabilityShares = liabilityShares;
67237
+ this.emissionsOutstanding = emissionsOutstanding;
67238
+ this.lastUpdate = lastUpdate;
67281
67239
  }
67282
- if (setupIxs.length > 0 || additionalIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
67283
- const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
67284
- const txs = splitInstructionsToFitTransactions([], ixs, {
67285
- blockhash,
67286
- payerKey: marginfiAccount.authority,
67287
- luts: addressLookupTableAccounts ?? []
67288
- });
67289
- additionalTxs.push(
67290
- ...txs.map(
67291
- (tx) => addTransactionMetadata(tx, {
67292
- type: "CREATE_ATA" /* CREATE_ATA */,
67293
- addressLookupTables: addressLookupTableAccounts
67294
- })
67295
- )
67240
+ static from(balanceRaw) {
67241
+ const props = parseBalanceRaw(balanceRaw);
67242
+ return new _Balance(
67243
+ props.active,
67244
+ props.bankPk,
67245
+ props.assetShares,
67246
+ props.liabilityShares,
67247
+ props.emissionsOutstanding,
67248
+ props.lastUpdate
67296
67249
  );
67297
67250
  }
67298
- if (updateFeedIxs.length > 0) {
67299
- const message = new TransactionMessage({
67300
- payerKey: marginfiAccount.authority,
67301
- recentBlockhash: blockhash,
67302
- instructions: updateFeedIxs
67303
- }).compileToV0Message(feedLuts);
67304
- additionalTxs.push(
67305
- addTransactionMetadata(new VersionedTransaction(message), {
67306
- addressLookupTables: feedLuts,
67307
- type: "CRANK" /* CRANK */
67308
- })
67251
+ static fromBalanceType(balance) {
67252
+ return new _Balance(
67253
+ balance.active,
67254
+ balance.bankPk,
67255
+ balance.assetShares,
67256
+ balance.liabilityShares,
67257
+ balance.emissionsOutstanding,
67258
+ balance.lastUpdate
67309
67259
  );
67310
67260
  }
67311
- const transactions = [...additionalTxs, flashloanTx];
67312
- return {
67313
- transactions,
67314
- actionTxIndex: transactions.length - 1,
67315
- quoteResponse: swapQuote
67316
- };
67317
- }
67318
- async function buildLoopFlashloanTx(params) {
67319
- const { depositOpts } = params;
67320
- const { descriptor, swapNeeded, borrowIxs, depositIxs } = await buildLoopNonSwapIxs(params);
67321
- if (!swapNeeded) {
67322
- const flashloanTx2 = await finalizeLoopFlashloanTx({
67323
- params,
67324
- innerIxs: descriptor.innerIxs,
67325
- luts: descriptor.luts,
67326
- swapIxCount: 0,
67327
- swapLutCount: 0,
67328
- sizeConstraint: descriptor.sizeConstraint
67261
+ static createEmpty(bankPk) {
67262
+ const balance = createEmptyBalance(bankPk);
67263
+ return this.fromBalanceType(balance);
67264
+ }
67265
+ computeUsdValue(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
67266
+ return computeBalanceUsdValue({
67267
+ balance: this,
67268
+ bank,
67269
+ oraclePrice,
67270
+ marginRequirement,
67271
+ assetShareValueMultiplier,
67272
+ activeEmodeWeights
67329
67273
  });
67330
- return {
67331
- flashloanTx: flashloanTx2,
67332
- setupInstructions: [],
67333
- swapQuote: void 0,
67334
- borrowIxs,
67335
- depositIxs
67336
- };
67337
67274
  }
67338
- const engineResult = await runLoopSwapEngine(descriptor, params);
67339
- const finalIxs = [...descriptor.innerIxs];
67340
- finalIxs.splice(descriptor.swapSlotIndex, 0, ...engineResult.swapInstructions);
67341
- const principalNative = depositOpts.loopMode === "DEPOSIT" ? uiToNative(depositOpts.inputDepositAmount, depositOpts.depositBank.mintDecimals) : new BN9(0);
67342
- const finalDepositNative = engineResult.outputAmountNative.add(principalNative);
67343
- const depositIxPosition = descriptor.depositIxIndex + engineResult.swapInstructions.length;
67344
- patchDepositAmount(finalIxs[depositIxPosition], finalDepositNative);
67345
- const luts = [...descriptor.luts, ...engineResult.swapLuts];
67346
- const flashloanTx = await finalizeLoopFlashloanTx({
67347
- params,
67348
- innerIxs: finalIxs,
67349
- luts,
67350
- swapIxCount: engineResult.swapInstructions.length,
67351
- swapLutCount: engineResult.swapLuts.length,
67352
- sizeConstraint: descriptor.sizeConstraint
67353
- });
67354
- return {
67355
- flashloanTx,
67356
- setupInstructions: engineResult.setupInstructions,
67357
- swapQuote: engineResult.quoteResponse,
67358
- borrowIxs,
67359
- depositIxs
67360
- };
67361
- }
67362
- async function buildLoopNonSwapIxs(params) {
67363
- const {
67364
- program,
67365
- marginfiAccount,
67366
- bankMap,
67367
- borrowOpts,
67368
- depositOpts,
67369
- bankMetadataMap,
67370
- addressLookupTableAccounts,
67371
- overrideInferAccounts
67372
- } = params;
67373
- const cuRequestIxs = [
67374
- ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
67375
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
67376
- ];
67377
- const swapNeeded = !depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint);
67378
- const destinationTokenAccount = getAssociatedTokenAddressSync(
67379
- new PublicKey(depositOpts.depositBank.mint),
67380
- marginfiAccount.authority,
67381
- true,
67382
- depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
67383
- );
67384
- const principalUi = depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0;
67385
- let depositAmountUi;
67386
- let sizeConstraint = 0;
67387
- let maxSwapTotalAccounts = 0;
67388
- if (!swapNeeded) {
67389
- depositAmountUi = borrowOpts.borrowAmount + principalUi;
67390
- } else {
67391
- const swapConstraints = await computeFlashloanSwapConstraints({
67392
- program,
67393
- marginfiAccount,
67394
- bankMap,
67395
- bankMetadataMap,
67396
- addressLookupTableAccounts: addressLookupTableAccounts ?? [],
67397
- primaryIx: {
67398
- type: "borrow",
67399
- bank: borrowOpts.borrowBank,
67400
- tokenProgram: borrowOpts.tokenProgram
67401
- },
67402
- secondaryIx: {
67403
- type: "deposit",
67404
- bank: depositOpts.depositBank,
67405
- tokenProgram: depositOpts.tokenProgram
67406
- },
67407
- overrideInferAccounts
67275
+ getUsdValueWithPriceBias(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
67276
+ return getBalanceUsdValueWithPriceBias({
67277
+ balance: this,
67278
+ bank,
67279
+ oraclePrice,
67280
+ marginRequirement,
67281
+ assetShareValueMultiplier,
67282
+ activeEmodeWeights
67408
67283
  });
67409
- sizeConstraint = swapConstraints.sizeConstraint;
67410
- maxSwapTotalAccounts = swapConstraints.maxSwapTotalAccounts;
67411
- const estimateUi = borrowOpts.borrowAmount * borrowOpts.marketPrice / depositOpts.marketPrice;
67412
- depositAmountUi = estimateUi + principalUi;
67413
67284
  }
67414
- const borrowIxs = await makeBorrowIx3({
67415
- program,
67416
- bank: borrowOpts.borrowBank,
67417
- bankMap,
67418
- tokenProgram: borrowOpts.tokenProgram,
67419
- amount: borrowOpts.borrowAmount,
67420
- marginfiAccount,
67421
- authority: marginfiAccount.authority,
67422
- isSync: false,
67423
- opts: {
67424
- createAtas: false,
67425
- wrapAndUnwrapSol: false,
67426
- overrideInferAccounts
67427
- }
67428
- });
67429
- const depositIxs = await buildDepositIxs(params, depositAmountUi);
67430
- const innerIxsBeforeSwap = [...cuRequestIxs, ...borrowIxs.instructions];
67431
- const swapSlotIndex = innerIxsBeforeSwap.length;
67432
- const innerIxs = [...innerIxsBeforeSwap, ...depositIxs.instructions];
67433
- const depositIxIndex = innerIxs.findIndex(isDepositIx);
67434
- if (depositIxIndex < 0) {
67435
- throw new Error(
67436
- "buildLoopNonSwapIxs: could not locate deposit instruction for amount patching"
67437
- );
67285
+ computeQuantity(bank) {
67286
+ return computeQuantity(this, bank);
67438
67287
  }
67439
- const descriptor = {
67440
- innerIxs,
67441
- swapSlotIndex,
67442
- depositIxIndex,
67443
- inputMint: borrowOpts.borrowBank.mint.toBase58(),
67444
- outputMint: depositOpts.depositBank.mint.toBase58(),
67445
- inputDecimals: borrowOpts.borrowBank.mintDecimals,
67446
- outputDecimals: depositOpts.depositBank.mintDecimals,
67447
- inAmountNative: uiToNative(
67448
- borrowOpts.borrowAmount,
67449
- borrowOpts.borrowBank.mintDecimals
67450
- ).toNumber(),
67451
- destinationTokenAccount,
67452
- sizeConstraint,
67453
- maxSwapTotalAccounts,
67454
- luts: addressLookupTableAccounts ?? []
67455
- };
67456
- return { descriptor, swapNeeded, borrowIxs, depositIxs };
67457
- }
67458
- async function buildDepositIxs(params, amountUi) {
67459
- const { program, marginfiAccount, depositOpts, bankMetadataMap, overrideInferAccounts } = params;
67460
- switch (depositOpts.depositBank.config.assetTag) {
67461
- case 3 /* KAMINO */: {
67462
- const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
67463
- if (!reserve) {
67464
- throw TransactionBuildingError.kaminoReserveNotFound(
67465
- depositOpts.depositBank.address.toBase58(),
67466
- depositOpts.depositBank.mint.toBase58(),
67467
- depositOpts.depositBank.tokenSymbol
67468
- );
67469
- }
67470
- return makeKaminoDepositIx3({
67471
- program,
67472
- bank: depositOpts.depositBank,
67473
- tokenProgram: depositOpts.tokenProgram,
67474
- amount: amountUi,
67475
- accountAddress: marginfiAccount.address,
67476
- authority: marginfiAccount.authority,
67477
- group: marginfiAccount.group,
67478
- reserve,
67479
- opts: {
67480
- wrapAndUnwrapSol: false,
67481
- overrideInferAccounts
67482
- }
67483
- });
67484
- }
67485
- case 4 /* DRIFT */: {
67486
- const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
67487
- if (!driftState) {
67488
- throw TransactionBuildingError.driftStateNotFound(
67489
- depositOpts.depositBank.address.toBase58(),
67490
- depositOpts.depositBank.mint.toBase58(),
67491
- depositOpts.depositBank.tokenSymbol
67492
- );
67493
- }
67494
- return makeDriftDepositIx3({
67495
- program,
67496
- bank: depositOpts.depositBank,
67497
- tokenProgram: depositOpts.tokenProgram,
67498
- amount: amountUi,
67499
- accountAddress: marginfiAccount.address,
67500
- authority: marginfiAccount.authority,
67501
- group: marginfiAccount.group,
67502
- driftMarketIndex: driftState.spotMarketState.marketIndex,
67503
- driftOracle: driftState.spotMarketState.oracle,
67504
- opts: {
67505
- wrapAndUnwrapSol: false,
67506
- overrideInferAccounts
67507
- }
67508
- });
67509
- }
67510
- case 6 /* JUPLEND */: {
67511
- return makeJuplendDepositIx2({
67512
- program,
67513
- bank: depositOpts.depositBank,
67514
- tokenProgram: depositOpts.tokenProgram,
67515
- amount: amountUi,
67516
- accountAddress: marginfiAccount.address,
67517
- authority: marginfiAccount.authority,
67518
- group: marginfiAccount.group,
67519
- opts: {
67520
- wrapAndUnwrapSol: false,
67521
- overrideInferAccounts
67522
- }
67523
- });
67524
- }
67525
- default: {
67526
- return makeDepositIx3({
67527
- program,
67528
- bank: depositOpts.depositBank,
67529
- tokenProgram: depositOpts.tokenProgram,
67530
- amount: amountUi,
67531
- accountAddress: marginfiAccount.address,
67532
- authority: marginfiAccount.authority,
67533
- group: marginfiAccount.group,
67534
- opts: {
67535
- wrapAndUnwrapSol: false,
67536
- overrideInferAccounts
67537
- }
67538
- });
67539
- }
67288
+ computeQuantityUi(bank, assetShareValueMultiplier) {
67289
+ return computeQuantityUi(this, bank, assetShareValueMultiplier);
67540
67290
  }
67541
- }
67542
- async function runLoopSwapEngine(descriptor, params) {
67543
- const { connection, swapOpts, marginfiAccount, swapEngineRunner } = params;
67544
- if (swapOpts.swapIxs) {
67545
- return {
67546
- swapInstructions: swapOpts.swapIxs.instructions,
67547
- setupInstructions: [],
67548
- swapLuts: swapOpts.swapIxs.lookupTables,
67549
- quoteResponse: {
67550
- inAmount: String(descriptor.inAmountNative),
67551
- outAmount: "0",
67552
- otherAmountThreshold: "0",
67553
- slippageBps: 0
67554
- },
67555
- outputAmountNative: new BN9(0)
67556
- };
67291
+ computeTotalOutstandingEmissions(bank) {
67292
+ return computeTotalOutstandingEmissions(this, bank);
67557
67293
  }
67558
- const runEngine = swapEngineRunner ?? runSwapEngine;
67559
- const engineResult = await runEngine({
67560
- inputMint: descriptor.inputMint,
67561
- outputMint: descriptor.outputMint,
67562
- amountNative: descriptor.inAmountNative,
67563
- inputDecimals: descriptor.inputDecimals,
67564
- outputDecimals: descriptor.outputDecimals,
67565
- ...swapEngineQuoteFieldsFromOpts(swapOpts),
67566
- taker: marginfiAccount.authority,
67567
- destinationTokenAccount: descriptor.destinationTokenAccount,
67568
- connection,
67569
- footprint: {
67570
- instructions: descriptor.innerIxs,
67571
- luts: descriptor.luts,
67572
- payer: marginfiAccount.authority,
67573
- sizeConstraint: descriptor.sizeConstraint,
67574
- maxSwapTotalAccounts: descriptor.maxSwapTotalAccounts
67575
- },
67576
- providers: swapEngineProvidersFromOpts(swapOpts)
67577
- });
67578
- return {
67579
- swapInstructions: engineResult.swapInstructions,
67580
- setupInstructions: engineResult.setupInstructions,
67581
- swapLuts: engineResult.swapLuts,
67582
- quoteResponse: engineResult.quoteResponse,
67583
- outputAmountNative: engineResult.outputAmountNative
67584
- };
67585
- }
67586
- async function finalizeLoopFlashloanTx({
67587
- params,
67588
- innerIxs,
67589
- luts,
67590
- swapIxCount,
67591
- swapLutCount,
67592
- sizeConstraint
67593
- }) {
67594
- const { program, marginfiAccount, bankMap, swapOpts, blockhash } = params;
67595
- if (swapIxCount > 0) {
67596
- compileFlashloanPrecheck({
67597
- allIxs: innerIxs,
67598
- payer: marginfiAccount.authority,
67599
- luts,
67600
- sizeConstraint,
67601
- swapIxCount,
67602
- swapLutCount
67603
- });
67294
+ computeClaimedEmissions(bank, currentTimestamp) {
67295
+ return computeClaimedEmissions(this, bank, currentTimestamp);
67604
67296
  }
67605
- const flashloanTx = await makeFlashLoanTx({
67606
- program,
67607
- marginfiAccount,
67608
- bankMap,
67609
- addressLookupTableAccounts: luts,
67610
- blockhash,
67611
- ixs: innerIxs
67612
- });
67613
- const txSize = getTxSize(flashloanTx);
67614
- const totalKeys = getTotalAccountKeys(flashloanTx);
67615
- if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
67616
- throw TransactionBuildingError.swapSizeExceededLoop(
67617
- txSize,
67618
- totalKeys,
67619
- swapOpts.swapConfig?.provider
67297
+ };
67298
+
67299
+ // src/models/health-cache.ts
67300
+ var HealthCache = class _HealthCache {
67301
+ constructor(assetValue, liabilityValue, assetValueMaint, liabilityValueMaint, assetValueEquity, liabilityValueEquity, timestamp, flags, prices, simulationStatus) {
67302
+ this.assetValue = assetValue;
67303
+ this.liabilityValue = liabilityValue;
67304
+ this.assetValueMaint = assetValueMaint;
67305
+ this.liabilityValueMaint = liabilityValueMaint;
67306
+ this.assetValueEquity = assetValueEquity;
67307
+ this.liabilityValueEquity = liabilityValueEquity;
67308
+ this.timestamp = timestamp;
67309
+ this.flags = flags;
67310
+ this.prices = prices;
67311
+ this.simulationStatus = simulationStatus;
67312
+ }
67313
+ static fromHealthCacheType(healthCacheType) {
67314
+ return new _HealthCache(
67315
+ healthCacheType.assetValue,
67316
+ healthCacheType.liabilityValue,
67317
+ healthCacheType.assetValueMaint,
67318
+ healthCacheType.liabilityValueMaint,
67319
+ healthCacheType.assetValueEquity,
67320
+ healthCacheType.liabilityValueEquity,
67321
+ healthCacheType.timestamp,
67322
+ healthCacheType.flags,
67323
+ healthCacheType.prices,
67324
+ healthCacheType.simulationStatus
67620
67325
  );
67621
67326
  }
67622
- return flashloanTx;
67623
- }
67624
- async function makeSwapCollateralTx(params) {
67625
- const {
67626
- program,
67627
- marginfiAccount,
67628
- connection,
67629
- bankMap,
67630
- oraclePrices,
67631
- withdrawOpts,
67632
- depositOpts,
67633
- bankMetadataMap,
67634
- assetShareValueMultiplierByBank,
67635
- addressLookupTableAccounts,
67636
- crossbarUrl,
67637
- additionalIxs = []
67638
- } = params;
67639
- const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
67640
- const setupIxs = await makeSetupIx({
67641
- connection,
67642
- authority: marginfiAccount.authority,
67643
- tokens: [
67644
- { mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
67645
- { mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
67646
- ]
67647
- });
67648
- const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
67649
- marginfiAccount,
67650
- bankMap,
67651
- [withdrawOpts.withdrawBank.address, depositOpts.depositBank.address],
67652
- bankMetadataMap
67653
- );
67654
- const { flashloanTx, setupInstructions, swapQuote, withdrawIxs, depositIxs } = await buildSwapCollateralFlashloanTx({
67655
- ...params,
67656
- blockhash
67657
- });
67658
- const jupiterSetupInstructions = setupInstructions.filter((ix) => {
67659
- if (ix.programId.equals(ComputeBudgetProgram.programId)) {
67660
- return false;
67661
- }
67662
- if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
67663
- const mintKey = ix.keys[3]?.pubkey;
67664
- if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(depositOpts.depositBank.mint)) {
67665
- return false;
67666
- }
67667
- }
67668
- return true;
67669
- });
67670
- setupIxs.push(...jupiterSetupInstructions);
67671
- const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
67672
- marginfiAccount,
67673
- bankMap,
67674
- oraclePrices,
67675
- assetShareValueMultiplierByBank,
67676
- instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
67677
- program,
67678
- connection,
67679
- crossbarUrl
67680
- });
67681
- let additionalTxs = [];
67682
- if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
67683
- const ixs = [...setupIxs, ...refreshIntegrationIxs.instructions];
67684
- const txs = splitInstructionsToFitTransactions([], ixs, {
67685
- blockhash,
67686
- payerKey: marginfiAccount.authority,
67687
- luts: addressLookupTableAccounts ?? []
67688
- });
67689
- additionalTxs.push(
67690
- ...txs.map(
67691
- (tx) => addTransactionMetadata(tx, {
67692
- type: "CREATE_ATA" /* CREATE_ATA */,
67693
- addressLookupTables: addressLookupTableAccounts
67694
- })
67695
- )
67696
- );
67327
+ static from(healthCacheRaw) {
67328
+ return this.fromHealthCacheType(parseHealthCacheRaw(healthCacheRaw));
67697
67329
  }
67698
- if (updateFeedIxs.length > 0) {
67699
- const message = new TransactionMessage({
67700
- payerKey: marginfiAccount.authority,
67701
- recentBlockhash: blockhash,
67702
- instructions: updateFeedIxs
67703
- }).compileToV0Message(feedLuts);
67704
- additionalTxs.push(
67705
- addTransactionMetadata(new VersionedTransaction(message), {
67706
- addressLookupTables: feedLuts,
67707
- type: "CRANK" /* CRANK */
67708
- })
67709
- );
67330
+ };
67331
+
67332
+ // src/models/account.ts
67333
+ var MarginfiAccount = class _MarginfiAccount {
67334
+ constructor(address, group, authority, balances, accountFlags, emissionsDestinationAccount, healthCache) {
67335
+ this.address = address;
67336
+ this.group = group;
67337
+ this.authority = authority;
67338
+ this.balances = balances;
67339
+ this.accountFlags = accountFlags;
67340
+ this.emissionsDestinationAccount = emissionsDestinationAccount;
67341
+ this.healthCache = healthCache;
67710
67342
  }
67711
- const transactions = [...additionalTxs, flashloanTx];
67712
- return {
67713
- transactions,
67714
- actionTxIndex: transactions.length - 1,
67715
- quoteResponse: swapQuote
67716
- };
67717
- }
67718
- async function buildSwapCollateralFlashloanTx({
67719
- program,
67720
- marginfiAccount,
67721
- bankMap,
67722
- withdrawOpts,
67723
- depositOpts,
67724
- swapOpts,
67725
- bankMetadataMap,
67726
- assetShareValueMultiplierByBank,
67727
- addressLookupTableAccounts,
67728
- connection,
67729
- overrideInferAccounts,
67730
- blockhash,
67731
- swapEngineRunner
67732
- }) {
67733
- const {
67734
- withdrawBank,
67735
- tokenProgram: withdrawTokenProgram,
67736
- totalPositionAmount,
67737
- withdrawAmount
67738
- } = withdrawOpts;
67739
- const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
67740
- if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
67741
- throw new Error("withdrawAmount must be greater than 0");
67343
+ /**
67344
+ * Fetches a marginfi account from on-chain data.
67345
+ *
67346
+ * @param address - The public key of the marginfi account
67347
+ * @param program - The Marginfi program instance
67348
+ *
67349
+ * @returns Promise resolving to a MarginfiAccount instance
67350
+ */
67351
+ static async fetch(address, program) {
67352
+ const data = await program.account.marginfiAccount.fetch(address);
67353
+ return _MarginfiAccount.fromAccountParsed(address, data);
67742
67354
  }
67743
- const actualWithdrawAmount = Math.min(withdrawAmount ?? totalPositionAmount, totalPositionAmount);
67744
- const isFullWithdraw = isWholePosition(
67745
- { amount: totalPositionAmount, isLending: true },
67746
- actualWithdrawAmount,
67747
- withdrawBank.mintDecimals
67748
- );
67749
- const cuRequestIxs = [
67750
- ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
67751
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
67752
- ];
67753
- let amountToDeposit;
67754
- let swapInstructions = [];
67755
- let setupInstructions = [];
67756
- let swapLookupTables = [];
67757
- let swapQuote;
67758
- let sizeConstraintUsed = 0;
67759
- let withdrawIxs;
67760
- switch (withdrawOpts.withdrawBank.config.assetTag) {
67761
- case 3 /* KAMINO */: {
67762
- const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
67763
- if (!reserve) {
67764
- throw TransactionBuildingError.kaminoReserveNotFound(
67765
- withdrawOpts.withdrawBank.address.toBase58(),
67766
- withdrawOpts.withdrawBank.mint.toBase58(),
67767
- withdrawOpts.withdrawBank.tokenSymbol
67768
- );
67769
- }
67770
- const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber(1);
67771
- const adjustedAmount = new BigNumber(actualWithdrawAmount).div(multiplier).times(1.0001).toNumber();
67772
- withdrawIxs = await makeKaminoWithdrawIx3({
67773
- program,
67774
- bank: withdrawBank,
67775
- bankMap,
67776
- tokenProgram: withdrawTokenProgram,
67777
- cTokenAmount: adjustedAmount,
67778
- marginfiAccount,
67779
- authority: marginfiAccount.authority,
67780
- reserve,
67781
- withdrawAll: isFullWithdraw,
67782
- isSync: false,
67783
- opts: {
67784
- createAtas: false,
67785
- wrapAndUnwrapSol: false,
67786
- overrideInferAccounts
67787
- }
67788
- });
67789
- break;
67790
- }
67791
- case 4 /* DRIFT */: {
67792
- const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
67793
- if (!driftState) {
67794
- throw TransactionBuildingError.driftStateNotFound(
67795
- withdrawOpts.withdrawBank.address.toBase58(),
67796
- withdrawOpts.withdrawBank.mint.toBase58(),
67797
- withdrawOpts.withdrawBank.tokenSymbol
67798
- );
67799
- }
67800
- withdrawIxs = await makeDriftWithdrawIx3({
67801
- program,
67802
- bank: withdrawOpts.withdrawBank,
67803
- bankMap,
67804
- tokenProgram: withdrawOpts.tokenProgram,
67805
- amount: actualWithdrawAmount,
67806
- marginfiAccount,
67807
- authority: marginfiAccount.authority,
67808
- driftSpotMarket: driftState.spotMarketState,
67809
- userRewards: driftState.userRewards,
67810
- withdrawAll: isFullWithdraw,
67811
- isSync: false,
67812
- opts: {
67813
- createAtas: false,
67814
- wrapAndUnwrapSol: false,
67815
- overrideInferAccounts
67816
- }
67817
- });
67818
- break;
67819
- }
67820
- case 6 /* JUPLEND */: {
67821
- const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
67822
- if (!jupLendState) {
67823
- throw TransactionBuildingError.jupLendStateNotFound(
67824
- withdrawOpts.withdrawBank.address.toBase58(),
67825
- withdrawOpts.withdrawBank.mint.toBase58(),
67826
- withdrawOpts.withdrawBank.tokenSymbol
67827
- );
67828
- }
67829
- withdrawIxs = await makeJuplendWithdrawIx2({
67830
- program,
67831
- bank: withdrawBank,
67832
- bankMap,
67833
- tokenProgram: withdrawTokenProgram,
67834
- amount: actualWithdrawAmount,
67835
- marginfiAccount,
67836
- authority: marginfiAccount.authority,
67837
- jupLendingState: jupLendState.jupLendingState,
67838
- withdrawAll: isFullWithdraw,
67839
- opts: {
67840
- createAtas: false,
67841
- wrapAndUnwrapSol: false,
67842
- overrideInferAccounts
67843
- }
67844
- });
67845
- break;
67846
- }
67847
- default: {
67848
- withdrawIxs = await makeWithdrawIx3({
67849
- program,
67850
- bank: withdrawBank,
67851
- bankMap,
67852
- tokenProgram: withdrawTokenProgram,
67853
- amount: actualWithdrawAmount,
67854
- marginfiAccount,
67855
- authority: marginfiAccount.authority,
67856
- withdrawAll: isFullWithdraw,
67857
- isSync: false,
67858
- opts: {
67859
- createAtas: false,
67860
- wrapAndUnwrapSol: false,
67861
- overrideInferAccounts
67862
- }
67863
- });
67864
- break;
67865
- }
67355
+ static decodeAccountRaw(encoded, idl) {
67356
+ return decodeAccountRaw(encoded, idl);
67866
67357
  }
67867
- const swapNeeded = !depositBank.mint.equals(withdrawBank.mint);
67868
- amountToDeposit = swapNeeded ? 0 : actualWithdrawAmount;
67869
- let depositIxs;
67870
- switch (depositBank.config.assetTag) {
67871
- case 3 /* KAMINO */: {
67872
- const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
67873
- if (!reserve) {
67874
- throw TransactionBuildingError.kaminoReserveNotFound(
67875
- depositBank.address.toBase58(),
67876
- depositBank.mint.toBase58(),
67877
- depositBank.tokenSymbol
67878
- );
67879
- }
67880
- depositIxs = await makeKaminoDepositIx3({
67881
- program,
67882
- bank: depositBank,
67883
- tokenProgram: depositTokenProgram,
67884
- amount: amountToDeposit,
67885
- accountAddress: marginfiAccount.address,
67886
- authority: marginfiAccount.authority,
67887
- group: marginfiAccount.group,
67888
- reserve,
67889
- opts: {
67890
- wrapAndUnwrapSol: false,
67891
- overrideInferAccounts
67892
- }
67893
- });
67894
- break;
67895
- }
67896
- case 4 /* DRIFT */: {
67897
- const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
67898
- if (!driftState) {
67899
- throw TransactionBuildingError.driftStateNotFound(
67900
- depositBank.address.toBase58(),
67901
- depositBank.mint.toBase58(),
67902
- depositBank.tokenSymbol
67903
- );
67904
- }
67905
- const driftMarketIndex = driftState.spotMarketState.marketIndex;
67906
- const driftOracle = driftState.spotMarketState.oracle;
67907
- depositIxs = await makeDriftDepositIx3({
67908
- program,
67909
- bank: depositBank,
67910
- tokenProgram: depositTokenProgram,
67911
- amount: amountToDeposit,
67912
- accountAddress: marginfiAccount.address,
67913
- authority: marginfiAccount.authority,
67914
- group: marginfiAccount.group,
67915
- driftMarketIndex,
67916
- driftOracle,
67917
- opts: {
67918
- wrapAndUnwrapSol: false,
67919
- overrideInferAccounts
67920
- }
67921
- });
67922
- break;
67923
- }
67924
- case 6 /* JUPLEND */: {
67925
- depositIxs = await makeJuplendDepositIx2({
67926
- program,
67927
- bank: depositBank,
67928
- tokenProgram: depositTokenProgram,
67929
- amount: amountToDeposit,
67930
- accountAddress: marginfiAccount.address,
67931
- authority: marginfiAccount.authority,
67932
- group: marginfiAccount.group,
67933
- opts: {
67934
- wrapAndUnwrapSol: false,
67935
- overrideInferAccounts
67936
- }
67937
- });
67938
- break;
67939
- }
67940
- default: {
67941
- depositIxs = await makeDepositIx3({
67942
- program,
67943
- bank: depositBank,
67944
- tokenProgram: depositTokenProgram,
67945
- amount: amountToDeposit,
67946
- accountAddress: marginfiAccount.address,
67947
- authority: marginfiAccount.authority,
67948
- group: marginfiAccount.group,
67949
- opts: {
67950
- wrapAndUnwrapSol: false,
67951
- overrideInferAccounts
67952
- }
67953
- });
67954
- break;
67955
- }
67358
+ static fromAccountType(account) {
67359
+ return new _MarginfiAccount(
67360
+ account.address,
67361
+ account.group,
67362
+ account.authority,
67363
+ account.balances.map((b) => Balance.fromBalanceType(b)),
67364
+ account.accountFlags,
67365
+ account.emissionsDestinationAccount,
67366
+ account.healthCache
67367
+ );
67956
67368
  }
67957
- if (swapNeeded) {
67958
- const destinationTokenAccount = getAssociatedTokenAddressSync(
67959
- depositBank.mint,
67960
- marginfiAccount.authority,
67961
- true,
67962
- depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
67369
+ /**
67370
+ * Creates a MarginfiAccount instance from parsed account data.
67371
+ *
67372
+ * @param marginfiAccountPk - The public key of the marginfi account
67373
+ * @param accountData - The raw account data from the program
67374
+ *
67375
+ * @returns A new MarginfiAccount instance
67376
+ */
67377
+ static fromAccountParsed(marginfiAccountPk, accountData) {
67378
+ const props = parseMarginfiAccountRaw(marginfiAccountPk, accountData);
67379
+ return new _MarginfiAccount(
67380
+ props.address,
67381
+ props.group,
67382
+ props.authority,
67383
+ props.balances.map((b) => Balance.fromBalanceType(b)),
67384
+ props.accountFlags,
67385
+ props.emissionsDestinationAccount,
67386
+ HealthCache.fromHealthCacheType(props.healthCache)
67963
67387
  );
67964
- const swapConstraints = await computeFlashloanSwapConstraints({
67965
- program,
67966
- marginfiAccount,
67967
- bankMap,
67968
- bankMetadataMap,
67969
- addressLookupTableAccounts: addressLookupTableAccounts ?? [],
67970
- primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
67971
- secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
67972
- overrideInferAccounts
67973
- });
67974
- sizeConstraintUsed = swapConstraints.sizeConstraint;
67975
- const runEngine = swapEngineRunner ?? runSwapEngine;
67976
- const engineResult = await runEngine({
67977
- inputMint: withdrawBank.mint.toBase58(),
67978
- outputMint: depositBank.mint.toBase58(),
67979
- amountNative: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
67980
- inputDecimals: withdrawBank.mintDecimals,
67981
- outputDecimals: depositBank.mintDecimals,
67982
- ...swapEngineQuoteFieldsFromOpts(swapOpts),
67983
- taker: marginfiAccount.authority,
67984
- destinationTokenAccount,
67985
- connection,
67986
- footprint: {
67987
- instructions: [...cuRequestIxs, ...withdrawIxs.instructions, ...depositIxs.instructions],
67988
- luts: addressLookupTableAccounts ?? [],
67989
- payer: marginfiAccount.authority,
67990
- sizeConstraint: swapConstraints.sizeConstraint,
67991
- maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
67992
- },
67993
- providers: swapEngineProvidersFromOpts(swapOpts)
67994
- });
67995
- const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
67996
- if (!depositIxToPatch) {
67997
- throw new Error("swap-collateral: could not locate deposit instruction for amount patching");
67998
- }
67999
- patchDepositAmount(depositIxToPatch, engineResult.outputAmountNative);
68000
- swapInstructions = engineResult.swapInstructions;
68001
- setupInstructions = engineResult.setupInstructions;
68002
- swapLookupTables = engineResult.swapLuts;
68003
- swapQuote = engineResult.quoteResponse;
68004
67388
  }
68005
- const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
68006
- const allNonFlIxs = [
68007
- ...cuRequestIxs,
68008
- ...withdrawIxs.instructions,
68009
- ...swapInstructions,
68010
- ...depositIxs.instructions
68011
- ];
68012
- if (swapInstructions.length > 0) {
68013
- compileFlashloanPrecheck({
68014
- allIxs: allNonFlIxs,
68015
- payer: marginfiAccount.authority,
68016
- luts,
68017
- sizeConstraint: sizeConstraintUsed,
68018
- swapIxCount: swapInstructions.length,
68019
- swapLutCount: swapLookupTables.length
67389
+ /**
67390
+ * Simulates and updates the health cache for this account.
67391
+ *
67392
+ * Fetches current oracle prices and computes fresh health values. Returns a new
67393
+ * account instance with updated health cache (does not mutate this instance).
67394
+ *
67395
+ * @param params - Configuration for health cache simulation (excluding marginfiAccount)
67396
+ * @returns Object containing the updated account and any errors
67397
+ */
67398
+ async simulateHealthCache(params) {
67399
+ const accountWithHealthCache = await simulateAccountHealthCacheWithFallback({
67400
+ marginfiAccount: this,
67401
+ ...params
68020
67402
  });
67403
+ return {
67404
+ account: _MarginfiAccount.fromAccountType(accountWithHealthCache.marginfiAccount),
67405
+ error: accountWithHealthCache.error
67406
+ };
68021
67407
  }
68022
- const flashloanTx = await makeFlashLoanTx({
68023
- program,
68024
- marginfiAccount,
68025
- bankMap,
68026
- addressLookupTableAccounts: luts,
68027
- blockhash,
68028
- ixs: allNonFlIxs,
68029
- isSync: false
68030
- });
68031
- const txSize = getTxSize(flashloanTx);
68032
- const totalKeys = getTotalAccountKeys(flashloanTx);
68033
- if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
68034
- throw TransactionBuildingError.swapSizeExceededPositionSwap(
68035
- txSize,
68036
- totalKeys,
68037
- swapOpts.swapConfig?.provider
68038
- );
67408
+ static fromAccountDataRaw(marginfiAccountPk, rawData, idl) {
67409
+ const marginfiAccountData = _MarginfiAccount.decodeAccountRaw(rawData, idl);
67410
+ return _MarginfiAccount.fromAccountParsed(marginfiAccountPk, marginfiAccountData);
68039
67411
  }
68040
- return {
68041
- flashloanTx,
68042
- setupInstructions,
68043
- swapQuote,
68044
- withdrawIxs,
68045
- depositIxs
68046
- };
68047
- }
68048
- async function makeSwapDebtTx(params) {
68049
- const {
68050
- program,
68051
- marginfiAccount,
68052
- connection,
68053
- bankMap,
68054
- oraclePrices,
68055
- repayOpts,
68056
- borrowOpts,
68057
- bankMetadataMap,
68058
- assetShareValueMultiplierByBank,
68059
- addressLookupTableAccounts,
68060
- crossbarUrl,
68061
- additionalIxs = []
68062
- } = params;
68063
- const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
68064
- const setupIxs = await makeSetupIx({
68065
- connection,
68066
- authority: marginfiAccount.authority,
68067
- tokens: [
68068
- { mint: repayOpts.repayBank.mint, tokenProgram: repayOpts.tokenProgram },
68069
- { mint: borrowOpts.borrowBank.mint, tokenProgram: borrowOpts.tokenProgram }
68070
- ]
68071
- });
68072
- const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
68073
- marginfiAccount,
68074
- bankMap,
68075
- [],
68076
- bankMetadataMap,
68077
- [repayOpts.repayBank.address, borrowOpts.borrowBank.address]
68078
- );
68079
- const { flashloanTx, setupInstructions, swapQuote, borrowIxs, repayIxs } = await buildSwapDebtFlashloanTx({
68080
- ...params,
68081
- blockhash
68082
- });
68083
- const jupiterSetupInstructions = setupInstructions.filter((ix) => {
68084
- if (ix.programId.equals(ComputeBudgetProgram.programId)) {
68085
- return false;
68086
- }
68087
- if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
68088
- const mintKey = ix.keys[3]?.pubkey;
68089
- if (mintKey?.equals(repayOpts.repayBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
68090
- return false;
68091
- }
68092
- }
68093
- return true;
68094
- });
68095
- setupIxs.push(...jupiterSetupInstructions);
68096
- const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
68097
- marginfiAccount,
68098
- bankMap,
68099
- oraclePrices,
68100
- assetShareValueMultiplierByBank,
68101
- instructions: [...borrowIxs.instructions, ...repayIxs.instructions],
68102
- program,
68103
- connection,
68104
- crossbarUrl
68105
- });
68106
- let additionalTxs = [];
68107
- if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
68108
- const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
68109
- const txs = splitInstructionsToFitTransactions([], ixs, {
68110
- blockhash,
68111
- payerKey: marginfiAccount.authority,
68112
- luts: addressLookupTableAccounts ?? []
68113
- });
68114
- additionalTxs.push(
68115
- ...txs.map(
68116
- (tx) => addTransactionMetadata(tx, {
68117
- type: "CREATE_ATA" /* CREATE_ATA */,
68118
- addressLookupTables: addressLookupTableAccounts
68119
- })
68120
- )
68121
- );
67412
+ // ----------------------------------------------------------------------------
67413
+ // Attributes
67414
+ // ----------------------------------------------------------------------------
67415
+ /**
67416
+ * Gets all balances that are currently active (non-zero).
67417
+ *
67418
+ * @returns Array of active Balance instances
67419
+ */
67420
+ get activeBalances() {
67421
+ return this.balances.filter((b) => b.active);
68122
67422
  }
68123
- if (updateFeedIxs.length > 0) {
68124
- const message = new TransactionMessage({
68125
- payerKey: marginfiAccount.authority,
68126
- recentBlockhash: blockhash,
68127
- instructions: updateFeedIxs
68128
- }).compileToV0Message(feedLuts);
68129
- additionalTxs.push(
68130
- addTransactionMetadata(new VersionedTransaction(message), {
68131
- addressLookupTables: feedLuts,
68132
- type: "CRANK" /* CRANK */
68133
- })
68134
- );
67423
+ /**
67424
+ * Gets the balance for a specific bank.
67425
+ *
67426
+ * @param bankPk - The public key of the bank
67427
+ *
67428
+ * @returns The Balance instance for the bank (may be empty)
67429
+ */
67430
+ getBalance(bankPk) {
67431
+ return Balance.fromBalanceType(getBalance(bankPk, this.balances));
68135
67432
  }
68136
- const transactions = [...additionalTxs, flashloanTx];
68137
- return {
68138
- transactions,
68139
- actionTxIndex: transactions.length - 1,
68140
- quoteResponse: swapQuote
68141
- };
68142
- }
68143
- async function buildSwapDebtFlashloanTx({
68144
- program,
68145
- marginfiAccount,
68146
- bankMap,
68147
- repayOpts,
68148
- borrowOpts,
68149
- swapOpts,
68150
- bankMetadataMap,
68151
- addressLookupTableAccounts,
68152
- connection,
68153
- overrideInferAccounts,
68154
- blockhash,
68155
- swapEngineRunner
68156
- }) {
68157
- const {
68158
- repayBank,
68159
- tokenProgram: repayTokenProgram,
68160
- totalPositionAmount,
68161
- repayAmount
68162
- } = repayOpts;
68163
- const { borrowBank, tokenProgram: borrowTokenProgram } = borrowOpts;
68164
- if (repayAmount !== void 0 && repayAmount <= 0) {
68165
- throw new Error("repayAmount must be greater than 0");
67433
+ /**
67434
+ * Checks if the account is disabled.
67435
+ *
67436
+ * @returns True if the account is disabled, false otherwise
67437
+ */
67438
+ get isDisabled() {
67439
+ return this.accountFlags.includes(1 /* ACCOUNT_DISABLED */);
68166
67440
  }
68167
- const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
68168
- const cuRequestIxs = [
68169
- ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
68170
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
68171
- ];
68172
- const destinationTokenAccount = getAssociatedTokenAddressSync(
68173
- repayBank.mint,
68174
- marginfiAccount.authority,
68175
- true,
68176
- repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
68177
- );
68178
- const estimatedBorrowAmount = computeBorrowEstimateForRepay({
68179
- repayTargetUi: actualRepayAmount,
68180
- repayMarketPrice: repayOpts.marketPrice,
68181
- borrowMarketPrice: borrowOpts.marketPrice,
68182
- slippageBps: swapOpts.swapConfig?.slippageBps,
68183
- isRepayAll: actualRepayAmount >= totalPositionAmount
68184
- });
68185
- const swapConstraints = await computeFlashloanSwapConstraints({
68186
- program,
68187
- marginfiAccount,
68188
- bankMap,
68189
- bankMetadataMap,
68190
- addressLookupTableAccounts: addressLookupTableAccounts ?? [],
68191
- primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
68192
- secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
68193
- overrideInferAccounts
68194
- });
68195
- const footprintBorrowIxs = await makeBorrowIx3({
68196
- program,
68197
- bank: borrowBank,
68198
- bankMap,
68199
- tokenProgram: borrowTokenProgram,
68200
- amount: estimatedBorrowAmount,
68201
- marginfiAccount,
68202
- authority: marginfiAccount.authority,
68203
- isSync: true,
68204
- opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
68205
- });
68206
- const footprintRepayIxs = await makeRepayIx3({
68207
- program,
68208
- bank: repayBank,
68209
- tokenProgram: repayTokenProgram,
68210
- amount: actualRepayAmount,
68211
- accountAddress: marginfiAccount.address,
68212
- authority: marginfiAccount.authority,
68213
- isSync: true,
68214
- opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
68215
- });
68216
- const runEngine = swapEngineRunner ?? runSwapEngine;
68217
- const engineResult = await runEngine({
68218
- inputMint: borrowBank.mint.toBase58(),
68219
- outputMint: repayBank.mint.toBase58(),
68220
- amountNative: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
68221
- inputDecimals: borrowBank.mintDecimals,
68222
- outputDecimals: repayBank.mintDecimals,
68223
- ...swapEngineQuoteFieldsFromOpts(swapOpts),
68224
- taker: marginfiAccount.authority,
68225
- destinationTokenAccount,
68226
- connection,
68227
- footprint: {
68228
- instructions: [
68229
- ...cuRequestIxs,
68230
- ...footprintBorrowIxs.instructions,
68231
- ...footprintRepayIxs.instructions
68232
- ],
68233
- luts: addressLookupTableAccounts ?? [],
68234
- payer: marginfiAccount.authority,
68235
- sizeConstraint: swapConstraints.sizeConstraint,
68236
- maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
68237
- },
68238
- providers: swapEngineProvidersFromOpts(swapOpts)
68239
- });
68240
- const quoteResponse = engineResult.quoteResponse;
68241
- const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
68242
- const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
68243
- const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
68244
- const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
68245
- const borrowIxs = await makeBorrowIx3({
68246
- program,
68247
- bank: borrowBank,
68248
- bankMap,
68249
- tokenProgram: borrowTokenProgram,
68250
- amount: borrowAmount,
68251
- marginfiAccount,
68252
- authority: marginfiAccount.authority,
68253
- isSync: true,
68254
- opts: {
68255
- createAtas: false,
68256
- wrapAndUnwrapSol: false,
68257
- overrideInferAccounts
68258
- }
68259
- });
68260
- const repayIxs = await makeRepayIx3({
68261
- program,
68262
- bank: repayBank,
68263
- tokenProgram: repayTokenProgram,
68264
- amount: amountToRepay,
68265
- accountAddress: marginfiAccount.address,
68266
- authority: marginfiAccount.authority,
68267
- repayAll: isWholePosition(
68268
- {
68269
- amount: totalPositionAmount,
68270
- isLending: false
68271
- },
68272
- amountToRepay,
68273
- repayBank.mintDecimals
68274
- ),
68275
- isSync: true,
68276
- opts: {
68277
- wrapAndUnwrapSol: false,
68278
- overrideInferAccounts
68279
- }
68280
- });
68281
- const luts = [...addressLookupTableAccounts ?? [], ...engineResult.swapLuts];
68282
- const allNonFlIxs = [
68283
- ...cuRequestIxs,
68284
- ...borrowIxs.instructions,
68285
- ...engineResult.swapInstructions,
68286
- ...repayIxs.instructions
68287
- ];
68288
- compileFlashloanPrecheck({
68289
- allIxs: allNonFlIxs,
68290
- payer: marginfiAccount.authority,
68291
- luts,
68292
- sizeConstraint: swapConstraints.sizeConstraint,
68293
- swapIxCount: engineResult.swapInstructions.length,
68294
- swapLutCount: engineResult.swapLuts.length
68295
- });
68296
- const flashloanTx = await makeFlashLoanTx({
68297
- program,
68298
- marginfiAccount,
68299
- bankMap,
68300
- addressLookupTableAccounts: luts,
68301
- blockhash,
68302
- ixs: allNonFlIxs,
68303
- isSync: true
68304
- });
68305
- const txSize = getTxSize(flashloanTx);
68306
- const totalKeys = getTotalAccountKeys(flashloanTx);
68307
- if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
68308
- throw TransactionBuildingError.swapSizeExceededPositionSwap(
68309
- txSize,
68310
- totalKeys,
68311
- swapOpts.swapConfig?.provider
68312
- );
67441
+ /**
67442
+ * Checks if the account is currently in a flash loan.
67443
+ *
67444
+ * @returns True if a flash loan is active, false otherwise
67445
+ */
67446
+ get isFlashLoanEnabled() {
67447
+ return this.accountFlags.includes(2 /* ACCOUNT_IN_FLASHLOAN */);
68313
67448
  }
68314
- return {
68315
- flashloanTx,
68316
- setupInstructions: engineResult.setupInstructions,
68317
- swapQuote: quoteResponse,
68318
- borrowIxs,
68319
- repayIxs
68320
- };
68321
- }
68322
- var DEFAULT_ROLL_SLIPPAGE_BPS = 50;
68323
- var TRADE_PT_EVENT_AMOUNT_OUT_OFFSET = 138;
68324
- var MERGE_EVENT_AMOUNT_SY_OUT_OFFSET = 296;
68325
- async function makeRollPtTx(params) {
68326
- const {
68327
- program,
68328
- marginfiAccount,
68329
- connection,
68330
- bankMap,
68331
- oraclePrices,
68332
- withdrawOpts,
68333
- depositOpts,
68334
- rollOpts,
68335
- assetShareValueMultiplierByBank,
68336
- addressLookupTableAccounts,
68337
- crossbarUrl
68338
- } = params;
68339
- if (!rollOpts.maturedMarket && !rollOpts.maturedVault) {
68340
- throw new Error("roll-pt: rollOpts.maturedMarket or maturedVault is required");
67449
+ /**
67450
+ * Checks if account authority transfer is enabled.
67451
+ *
67452
+ * @returns True if authority transfer is allowed, false otherwise
67453
+ */
67454
+ get isTransferAccountAuthorityEnabled() {
67455
+ return this.accountFlags.includes(8 /* ACCOUNT_TRANSFER_AUTHORITY_ALLOWED */);
68341
67456
  }
68342
- const merge = await resolveExponentMergeContext({
68343
- connection,
68344
- owner: marginfiAccount.authority,
68345
- market: rollOpts.maturedMarket,
68346
- vault: rollOpts.maturedVault,
68347
- ptYtTokenProgram: withdrawOpts.tokenProgram,
68348
- syTokenProgram: rollOpts.syTokenProgram
68349
- });
68350
- const clmm = await resolveExponentClmmTradePtContext({
68351
- connection,
68352
- owner: marginfiAccount.authority,
68353
- market: rollOpts.successorMarket,
68354
- ptTokenProgram: depositOpts.tokenProgram,
68355
- syTokenProgram: rollOpts.syTokenProgram
68356
- });
68357
- const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
68358
- const setupIxs = await makeSetupIx({
68359
- connection,
68360
- authority: marginfiAccount.authority,
68361
- tokens: [
68362
- { mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
68363
- { mint: merge.mergeAccounts.mintYt, tokenProgram: withdrawOpts.tokenProgram },
68364
- { mint: merge.underlying.mint, tokenProgram: merge.underlying.tokenProgram },
68365
- { mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
68366
- ]
68367
- });
68368
- const { flashloanTx, swapQuote, withdrawIxs, depositIxs } = await buildRollPtFlashloanTx({
68369
- params,
68370
- merge,
68371
- clmm,
68372
- setupIxs,
68373
- blockhash
68374
- });
68375
- const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
68376
- marginfiAccount,
68377
- bankMap,
68378
- oraclePrices,
68379
- assetShareValueMultiplierByBank,
68380
- instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
68381
- program,
68382
- connection,
68383
- crossbarUrl
68384
- });
68385
- const additionalTxs = [];
68386
- if (setupIxs.length > 0) {
68387
- const txs = splitInstructionsToFitTransactions([], setupIxs, {
68388
- blockhash,
68389
- payerKey: marginfiAccount.authority,
68390
- luts: addressLookupTableAccounts ?? []
68391
- });
68392
- additionalTxs.push(
68393
- ...txs.map(
68394
- (tx) => addTransactionMetadata(tx, {
68395
- type: "CREATE_ATA" /* CREATE_ATA */,
68396
- addressLookupTables: addressLookupTableAccounts
68397
- })
68398
- )
68399
- );
67457
+ /**
67458
+ * Sets the health cache for this account.
67459
+ *
67460
+ * Note: This mutates the account instance. Consider using simulateHealthCache()
67461
+ * for a pure functional approach that returns a new account instance.
67462
+ *
67463
+ * @param value - The new health cache to set
67464
+ */
67465
+ setHealthCache(value) {
67466
+ this.healthCache = value;
68400
67467
  }
68401
- if (updateFeedIxs.length > 0) {
68402
- const message = new TransactionMessage({
68403
- payerKey: marginfiAccount.authority,
68404
- recentBlockhash: blockhash,
68405
- instructions: updateFeedIxs
68406
- }).compileToV0Message(feedLuts);
68407
- additionalTxs.push(
68408
- addTransactionMetadata(new VersionedTransaction(message), {
68409
- addressLookupTables: feedLuts,
68410
- type: "CRANK" /* CRANK */
68411
- })
68412
- );
67468
+ /**
67469
+ * Computes free collateral using cached health values.
67470
+ *
67471
+ * Free collateral represents the amount of collateral that is not backing any liabilities.
67472
+ *
67473
+ * @param opts - Optional configuration
67474
+ * @param opts.clamped - If true, clamps negative values to zero
67475
+ *
67476
+ * @returns The free collateral amount in USD
67477
+ */
67478
+ computeFreeCollateralFromCache(opts) {
67479
+ return computeFreeCollateralFromCache(this, opts);
68413
67480
  }
68414
- const transactions = [...additionalTxs, flashloanTx];
68415
- return {
68416
- transactions,
68417
- actionTxIndex: transactions.length - 1,
68418
- quoteResponse: swapQuote
68419
- };
68420
- }
68421
- async function buildRollPtFlashloanTx({
68422
- params,
68423
- merge,
68424
- clmm,
68425
- setupIxs,
68426
- blockhash
68427
- }) {
68428
- const {
68429
- program,
68430
- marginfiAccount,
68431
- bankMap,
68432
- withdrawOpts,
68433
- depositOpts,
68434
- bankMetadataMap,
68435
- connection,
68436
- addressLookupTableAccounts,
68437
- overrideInferAccounts,
68438
- rollOpts
68439
- } = params;
68440
- const { withdrawBank, tokenProgram: withdrawTokenProgram, totalPositionAmount, withdrawAmount } = withdrawOpts;
68441
- const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
68442
- const authority = marginfiAccount.authority;
68443
- if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
68444
- throw new Error("withdrawAmount must be greater than 0");
67481
+ /**
67482
+ * Computes free collateral from balances using Initial margin requirements.
67483
+ *
67484
+ * Free collateral represents the amount of value available for new borrows or withdrawals.
67485
+ * By default, negative values are clamped to zero.
67486
+ *
67487
+ * @param params - Configuration for free collateral computation (excluding activeBalances)
67488
+ * @returns Free collateral value in USD (clamped to zero by default)
67489
+ */
67490
+ computeFreeCollateralFromBalances(params) {
67491
+ return computeFreeCollateralFromBalances({
67492
+ activeBalances: this.activeBalances,
67493
+ ...params
67494
+ });
68445
67495
  }
68446
- const actualWithdrawAmount = Math.min(withdrawAmount ?? totalPositionAmount, totalPositionAmount);
68447
- const isFullWithdraw = isWholePosition(
68448
- { amount: totalPositionAmount, isLending: true },
68449
- actualWithdrawAmount,
68450
- withdrawBank.mintDecimals
68451
- );
68452
- const withdrawNative = BigInt(
68453
- uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toString()
68454
- );
68455
- const cuRequestIxs = [
68456
- ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
68457
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
68458
- ];
68459
- const withdrawIxs = await makeWithdrawIx3({
68460
- program,
68461
- bank: withdrawBank,
68462
- bankMap,
68463
- tokenProgram: withdrawTokenProgram,
68464
- amount: actualWithdrawAmount,
68465
- marginfiAccount,
68466
- authority,
68467
- withdrawAll: isFullWithdraw,
68468
- isSync: false,
68469
- opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
68470
- });
68471
- const mergeIx = makeExponentMergeIx(merge.mergeAccounts, withdrawNative);
68472
- const depositIxs = await makeDepositIx3({
68473
- program,
68474
- bank: depositBank,
68475
- tokenProgram: depositTokenProgram,
68476
- amount: 0,
68477
- accountAddress: marginfiAccount.address,
68478
- authority,
68479
- group: marginfiAccount.group,
68480
- opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
68481
- });
68482
- let luts;
68483
- if (rollOpts.lookupTable) {
68484
- const fetched = (await connection.getAddressLookupTable(rollOpts.lookupTable)).value;
68485
- if (!fetched) {
68486
- throw new Error(`roll-pt: PT-roll lookup table not found: ${rollOpts.lookupTable.toBase58()}`);
68487
- }
68488
- luts = [fetched, merge.addressLookupTable, clmm.addressLookupTable];
68489
- } else {
68490
- luts = [
68491
- ...addressLookupTableAccounts ?? [],
68492
- merge.addressLookupTable,
68493
- clmm.addressLookupTable
68494
- ];
67496
+ /**
67497
+ * Computes health components using cached health values.
67498
+ *
67499
+ * Returns weighted asset and liability values based on the margin requirement type.
67500
+ *
67501
+ * @param marginReqType - The margin requirement type (Initial, Maintenance, or Equity)
67502
+ *
67503
+ * @returns Object containing assets and liabilities values in USD
67504
+ */
67505
+ computeHealthComponentsFromCache(marginRequirement) {
67506
+ return computeHealthComponentsFromCache(this, marginRequirement);
68495
67507
  }
68496
- const redeemIxs = [...setupIxs, ...cuRequestIxs, ...withdrawIxs.instructions, mergeIx];
68497
- const mergeReturn = await simulateRollReturn({
68498
- program,
68499
- marginfiAccount,
68500
- bankMap,
68501
- connection,
68502
- blockhash,
68503
- luts,
68504
- ixs: redeemIxs,
68505
- programId: EXPONENT_CORE_PROGRAM_ID,
68506
- label: "merge"
68507
- });
68508
- const syExact = readReturnU64(mergeReturn, MERGE_EVENT_AMOUNT_SY_OUT_OFFSET, "merge amount_sy_out");
68509
- if (syExact <= 0n) {
68510
- throw new Error("roll-pt: merge would redeem 0 SY (empty/invalid matured vault state)");
68511
- }
68512
- const exactPtOut = await quoteClmmTradeOut({
68513
- connection,
68514
- clmm,
68515
- amountInSyNative: syExact,
68516
- payer: authority
68517
- });
68518
- const slippageBps = rollOpts.slippageBps ?? DEFAULT_ROLL_SLIPPAGE_BPS;
68519
- const minPtOut = exactPtOut * BigInt(1e4 - slippageBps) / 10000n;
68520
- if (minPtOut <= 0n) {
68521
- throw new Error("roll-pt: quoted PT out is 0 (insufficient CLMM liquidity for this size)");
68522
- }
68523
- const tradeIx = makeExponentClmmTradePtIx(
68524
- clmm.tradePtAccounts,
68525
- exponentClmmBuyPtArgs({ amountInSyNative: syExact, minPtOutNative: minPtOut })
68526
- );
68527
- const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
68528
- if (!depositIxToPatch) {
68529
- throw new Error("roll-pt: could not locate deposit instruction for amount patching");
68530
- }
68531
- patchDepositAmount(depositIxToPatch, new BN9(minPtOut.toString()));
68532
- const allNonFlIxs = [
68533
- ...cuRequestIxs,
68534
- ...withdrawIxs.instructions,
68535
- mergeIx,
68536
- tradeIx,
68537
- ...depositIxs.instructions
68538
- ];
68539
- const { sizeConstraint } = computeFlashLoanNonSwapBudget({
68540
- program,
68541
- marginfiAccount,
68542
- bankMap,
68543
- addressLookupTableAccounts: luts,
68544
- ixs: allNonFlIxs
68545
- });
68546
- compileFlashloanPrecheck({
68547
- allIxs: allNonFlIxs,
68548
- payer: authority,
68549
- luts,
68550
- sizeConstraint,
68551
- swapIxCount: 0,
68552
- swapLutCount: 0
68553
- });
68554
- const flashloanTx = await makeFlashLoanTx({
68555
- program,
68556
- marginfiAccount,
68557
- bankMap,
68558
- addressLookupTableAccounts: luts,
68559
- blockhash,
68560
- ixs: allNonFlIxs,
68561
- isSync: false
68562
- });
68563
- const txSize = getTxSize(flashloanTx);
68564
- const totalKeys = getTotalAccountKeys(flashloanTx);
68565
- if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
68566
- throw TransactionBuildingError.swapSizeExceededPositionSwap(txSize, totalKeys, void 0);
68567
- }
68568
- const swapQuote = {
68569
- inAmount: syExact.toString(),
68570
- outAmount: exactPtOut.toString(),
68571
- otherAmountThreshold: minPtOut.toString(),
68572
- slippageBps
68573
- };
68574
- return { flashloanTx, swapQuote, withdrawIxs, depositIxs };
68575
- }
68576
- async function simulateRollReturn({
68577
- program,
68578
- marginfiAccount,
68579
- bankMap,
68580
- connection,
68581
- blockhash,
68582
- luts,
68583
- ixs,
68584
- programId,
68585
- label
68586
- }) {
68587
- const quoteTx = await makeFlashLoanTx({
68588
- program,
68589
- marginfiAccount,
68590
- bankMap,
68591
- addressLookupTableAccounts: luts,
68592
- blockhash,
68593
- ixs,
68594
- isSync: false
68595
- });
68596
- const sim = await connection.simulateTransaction(quoteTx, {
68597
- sigVerify: false,
68598
- replaceRecentBlockhash: true
68599
- });
68600
- const logs = sim.value.logs ?? [];
68601
- if (process.env.ROLL_DEBUG) {
68602
- console.error(
68603
- `[roll ${label} sim] err:`,
68604
- JSON.stringify(sim.value.err),
68605
- "returnData:",
68606
- JSON.stringify(sim.value.returnData),
68607
- "logsLen:",
68608
- logs.length,
68609
- "truncated:",
68610
- logs.some((l) => l.includes("truncated"))
68611
- );
68612
- }
68613
- const prefix = `Program return: ${programId.toBase58()} `;
68614
- const line = [...logs].reverse().find((l) => l.startsWith(prefix));
68615
- if (!line) {
68616
- throw new Error(
68617
- `roll-pt: could not read ${label} return data from quote simulation (err=${JSON.stringify(
68618
- sim.value.err
68619
- )})`
68620
- );
68621
- }
68622
- return Buffer.from(line.slice(prefix.length), "base64");
68623
- }
68624
- function readReturnU64(data, offset, what) {
68625
- if (data.length < offset + 8) {
68626
- throw new Error(`roll-pt: ${what} return data too short (${data.length} bytes)`);
68627
- }
68628
- return data.readBigUInt64LE(offset);
68629
- }
68630
- async function quoteClmmTradeOut({
68631
- connection,
68632
- clmm,
68633
- amountInSyNative,
68634
- payer
68635
- }) {
68636
- const excluded = /* @__PURE__ */ new Set([
68637
- clmm.tradePtAccounts.tokenSyEscrow.toBase58(),
68638
- clmm.tradePtAccounts.tokenFeeTreasurySy.toBase58()
68639
- ]);
68640
- const largest = await connection.getTokenLargestAccounts(clmm.sy.mint);
68641
- const funded = largest.value.find(
68642
- (a) => !excluded.has(a.address.toBase58()) && BigInt(a.amount) >= amountInSyNative
68643
- );
68644
- if (!funded) {
68645
- throw new Error(
68646
- "roll-pt: no SY holder large enough to quote the buy \u2014 the roll size exceeds available CLMM liquidity for this pair"
68647
- );
68648
- }
68649
- const parsed = await connection.getParsedAccountInfo(funded.address);
68650
- const info = parsed.value?.data?.parsed?.info;
68651
- if (!info?.owner) throw new Error("roll-pt: could not resolve the quote SY holder's owner");
68652
- const trader = new PublicKey(info.owner);
68653
- const ptTokenProgram = clmm.pt.tokenProgram ?? TOKEN_PROGRAM_ID;
68654
- const tokenPtTrader = getAssociatedTokenAddressSync(clmm.pt.mint, trader, true, ptTokenProgram);
68655
- const quoteIx = makeExponentClmmTradePtIx(
68656
- { ...clmm.tradePtAccounts, trader, tokenSyTrader: funded.address, tokenPtTrader },
68657
- exponentClmmBuyPtArgs({ amountInSyNative, minPtOutNative: 1n })
68658
- );
68659
- const createPtAta = createAssociatedTokenAccountIdempotentInstruction(
68660
- payer,
68661
- tokenPtTrader,
68662
- trader,
68663
- clmm.pt.mint,
68664
- ptTokenProgram
68665
- );
68666
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
68667
- const message = new TransactionMessage({
68668
- payerKey: payer,
68669
- recentBlockhash: blockhash,
68670
- instructions: [createPtAta, quoteIx]
68671
- }).compileToV0Message([clmm.addressLookupTable]);
68672
- const sim = await connection.simulateTransaction(new VersionedTransaction(message), {
68673
- sigVerify: false,
68674
- replaceRecentBlockhash: true
68675
- });
68676
- const rd = sim.value.returnData;
68677
- if (process.env.ROLL_DEBUG) {
68678
- console.error("[roll trade quote] err:", JSON.stringify(sim.value.err), "returnData?", !!rd);
68679
- }
68680
- if (!rd?.data || rd.programId !== EXPONENT_CLMM_PROGRAM_ID.toBase58()) {
68681
- throw new Error(
68682
- `roll-pt: CLMM trade quote produced no return data (err=${JSON.stringify(sim.value.err)})`
68683
- );
68684
- }
68685
- const data = Buffer.from(rd.data[0], rd.data[1]);
68686
- return readReturnU64(data, TRADE_PT_EVENT_AMOUNT_OUT_OFFSET, "trade_pt amount_out");
68687
- }
68688
-
68689
- // src/models/balance.ts
68690
- var Balance = class _Balance {
68691
- constructor(active, bankPk, assetShares, liabilityShares, emissionsOutstanding, lastUpdate) {
68692
- this.active = active;
68693
- this.bankPk = bankPk;
68694
- this.assetShares = assetShares;
68695
- this.liabilityShares = liabilityShares;
68696
- this.emissionsOutstanding = emissionsOutstanding;
68697
- this.lastUpdate = lastUpdate;
68698
- }
68699
- static from(balanceRaw) {
68700
- const props = parseBalanceRaw(balanceRaw);
68701
- return new _Balance(
68702
- props.active,
68703
- props.bankPk,
68704
- props.assetShares,
68705
- props.liabilityShares,
68706
- props.emissionsOutstanding,
68707
- props.lastUpdate
68708
- );
68709
- }
68710
- static fromBalanceType(balance) {
68711
- return new _Balance(
68712
- balance.active,
68713
- balance.bankPk,
68714
- balance.assetShares,
68715
- balance.liabilityShares,
68716
- balance.emissionsOutstanding,
68717
- balance.lastUpdate
68718
- );
68719
- }
68720
- static createEmpty(bankPk) {
68721
- const balance = createEmptyBalance(bankPk);
68722
- return this.fromBalanceType(balance);
68723
- }
68724
- computeUsdValue(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
68725
- return computeBalanceUsdValue({
68726
- balance: this,
68727
- bank,
68728
- oraclePrice,
68729
- marginRequirement,
68730
- assetShareValueMultiplier,
68731
- activeEmodeWeights
68732
- });
68733
- }
68734
- getUsdValueWithPriceBias(bank, oraclePrice, marginRequirement = 2 /* Equity */, assetShareValueMultiplier, activeEmodeWeights) {
68735
- return getBalanceUsdValueWithPriceBias({
68736
- balance: this,
68737
- bank,
68738
- oraclePrice,
68739
- marginRequirement,
68740
- assetShareValueMultiplier,
68741
- activeEmodeWeights
68742
- });
68743
- }
68744
- computeQuantity(bank) {
68745
- return computeQuantity(this, bank);
68746
- }
68747
- computeQuantityUi(bank, assetShareValueMultiplier) {
68748
- return computeQuantityUi(this, bank, assetShareValueMultiplier);
68749
- }
68750
- computeTotalOutstandingEmissions(bank) {
68751
- return computeTotalOutstandingEmissions(this, bank);
68752
- }
68753
- computeClaimedEmissions(bank, currentTimestamp) {
68754
- return computeClaimedEmissions(this, bank, currentTimestamp);
68755
- }
68756
- };
68757
-
68758
- // src/models/health-cache.ts
68759
- var HealthCache = class _HealthCache {
68760
- constructor(assetValue, liabilityValue, assetValueMaint, liabilityValueMaint, assetValueEquity, liabilityValueEquity, timestamp, flags, prices, simulationStatus) {
68761
- this.assetValue = assetValue;
68762
- this.liabilityValue = liabilityValue;
68763
- this.assetValueMaint = assetValueMaint;
68764
- this.liabilityValueMaint = liabilityValueMaint;
68765
- this.assetValueEquity = assetValueEquity;
68766
- this.liabilityValueEquity = liabilityValueEquity;
68767
- this.timestamp = timestamp;
68768
- this.flags = flags;
68769
- this.prices = prices;
68770
- this.simulationStatus = simulationStatus;
68771
- }
68772
- static fromHealthCacheType(healthCacheType) {
68773
- return new _HealthCache(
68774
- healthCacheType.assetValue,
68775
- healthCacheType.liabilityValue,
68776
- healthCacheType.assetValueMaint,
68777
- healthCacheType.liabilityValueMaint,
68778
- healthCacheType.assetValueEquity,
68779
- healthCacheType.liabilityValueEquity,
68780
- healthCacheType.timestamp,
68781
- healthCacheType.flags,
68782
- healthCacheType.prices,
68783
- healthCacheType.simulationStatus
68784
- );
68785
- }
68786
- static from(healthCacheRaw) {
68787
- return this.fromHealthCacheType(parseHealthCacheRaw(healthCacheRaw));
68788
- }
68789
- };
68790
-
68791
- // src/models/account.ts
68792
- var MarginfiAccount = class _MarginfiAccount {
68793
- constructor(address, group, authority, balances, accountFlags, emissionsDestinationAccount, healthCache) {
68794
- this.address = address;
68795
- this.group = group;
68796
- this.authority = authority;
68797
- this.balances = balances;
68798
- this.accountFlags = accountFlags;
68799
- this.emissionsDestinationAccount = emissionsDestinationAccount;
68800
- this.healthCache = healthCache;
68801
- }
68802
- /**
68803
- * Fetches a marginfi account from on-chain data.
68804
- *
68805
- * @param address - The public key of the marginfi account
68806
- * @param program - The Marginfi program instance
68807
- *
68808
- * @returns Promise resolving to a MarginfiAccount instance
68809
- */
68810
- static async fetch(address, program) {
68811
- const data = await program.account.marginfiAccount.fetch(address);
68812
- return _MarginfiAccount.fromAccountParsed(address, data);
68813
- }
68814
- static decodeAccountRaw(encoded, idl) {
68815
- return decodeAccountRaw(encoded, idl);
68816
- }
68817
- static fromAccountType(account) {
68818
- return new _MarginfiAccount(
68819
- account.address,
68820
- account.group,
68821
- account.authority,
68822
- account.balances.map((b) => Balance.fromBalanceType(b)),
68823
- account.accountFlags,
68824
- account.emissionsDestinationAccount,
68825
- account.healthCache
68826
- );
68827
- }
68828
- /**
68829
- * Creates a MarginfiAccount instance from parsed account data.
68830
- *
68831
- * @param marginfiAccountPk - The public key of the marginfi account
68832
- * @param accountData - The raw account data from the program
68833
- *
68834
- * @returns A new MarginfiAccount instance
68835
- */
68836
- static fromAccountParsed(marginfiAccountPk, accountData) {
68837
- const props = parseMarginfiAccountRaw(marginfiAccountPk, accountData);
68838
- return new _MarginfiAccount(
68839
- props.address,
68840
- props.group,
68841
- props.authority,
68842
- props.balances.map((b) => Balance.fromBalanceType(b)),
68843
- props.accountFlags,
68844
- props.emissionsDestinationAccount,
68845
- HealthCache.fromHealthCacheType(props.healthCache)
68846
- );
68847
- }
68848
- /**
68849
- * Simulates and updates the health cache for this account.
68850
- *
68851
- * Fetches current oracle prices and computes fresh health values. Returns a new
68852
- * account instance with updated health cache (does not mutate this instance).
68853
- *
68854
- * @param params - Configuration for health cache simulation (excluding marginfiAccount)
68855
- * @returns Object containing the updated account and any errors
68856
- */
68857
- async simulateHealthCache(params) {
68858
- const accountWithHealthCache = await simulateAccountHealthCacheWithFallback({
68859
- marginfiAccount: this,
68860
- ...params
68861
- });
68862
- return {
68863
- account: _MarginfiAccount.fromAccountType(accountWithHealthCache.marginfiAccount),
68864
- error: accountWithHealthCache.error
68865
- };
68866
- }
68867
- static fromAccountDataRaw(marginfiAccountPk, rawData, idl) {
68868
- const marginfiAccountData = _MarginfiAccount.decodeAccountRaw(rawData, idl);
68869
- return _MarginfiAccount.fromAccountParsed(marginfiAccountPk, marginfiAccountData);
68870
- }
68871
- // ----------------------------------------------------------------------------
68872
- // Attributes
68873
- // ----------------------------------------------------------------------------
68874
- /**
68875
- * Gets all balances that are currently active (non-zero).
68876
- *
68877
- * @returns Array of active Balance instances
68878
- */
68879
- get activeBalances() {
68880
- return this.balances.filter((b) => b.active);
68881
- }
68882
- /**
68883
- * Gets the balance for a specific bank.
68884
- *
68885
- * @param bankPk - The public key of the bank
68886
- *
68887
- * @returns The Balance instance for the bank (may be empty)
68888
- */
68889
- getBalance(bankPk) {
68890
- return Balance.fromBalanceType(getBalance(bankPk, this.balances));
68891
- }
68892
- /**
68893
- * Checks if the account is disabled.
68894
- *
68895
- * @returns True if the account is disabled, false otherwise
68896
- */
68897
- get isDisabled() {
68898
- return this.accountFlags.includes(1 /* ACCOUNT_DISABLED */);
68899
- }
68900
- /**
68901
- * Checks if the account is currently in a flash loan.
68902
- *
68903
- * @returns True if a flash loan is active, false otherwise
68904
- */
68905
- get isFlashLoanEnabled() {
68906
- return this.accountFlags.includes(2 /* ACCOUNT_IN_FLASHLOAN */);
68907
- }
68908
- /**
68909
- * Checks if account authority transfer is enabled.
68910
- *
68911
- * @returns True if authority transfer is allowed, false otherwise
68912
- */
68913
- get isTransferAccountAuthorityEnabled() {
68914
- return this.accountFlags.includes(8 /* ACCOUNT_TRANSFER_AUTHORITY_ALLOWED */);
68915
- }
68916
- /**
68917
- * Sets the health cache for this account.
68918
- *
68919
- * Note: This mutates the account instance. Consider using simulateHealthCache()
68920
- * for a pure functional approach that returns a new account instance.
68921
- *
68922
- * @param value - The new health cache to set
68923
- */
68924
- setHealthCache(value) {
68925
- this.healthCache = value;
68926
- }
68927
- /**
68928
- * Computes free collateral using cached health values.
68929
- *
68930
- * Free collateral represents the amount of collateral that is not backing any liabilities.
68931
- *
68932
- * @param opts - Optional configuration
68933
- * @param opts.clamped - If true, clamps negative values to zero
68934
- *
68935
- * @returns The free collateral amount in USD
68936
- */
68937
- computeFreeCollateralFromCache(opts) {
68938
- return computeFreeCollateralFromCache(this, opts);
68939
- }
68940
- /**
68941
- * Computes free collateral from balances using Initial margin requirements.
68942
- *
68943
- * Free collateral represents the amount of value available for new borrows or withdrawals.
68944
- * By default, negative values are clamped to zero.
68945
- *
68946
- * @param params - Configuration for free collateral computation (excluding activeBalances)
68947
- * @returns Free collateral value in USD (clamped to zero by default)
68948
- */
68949
- computeFreeCollateralFromBalances(params) {
68950
- return computeFreeCollateralFromBalances({
68951
- activeBalances: this.activeBalances,
68952
- ...params
68953
- });
68954
- }
68955
- /**
68956
- * Computes health components using cached health values.
68957
- *
68958
- * Returns weighted asset and liability values based on the margin requirement type.
68959
- *
68960
- * @param marginReqType - The margin requirement type (Initial, Maintenance, or Equity)
68961
- *
68962
- * @returns Object containing assets and liabilities values in USD
68963
- */
68964
- computeHealthComponentsFromCache(marginRequirement) {
68965
- return computeHealthComponentsFromCache(this, marginRequirement);
68966
- }
68967
- /**
68968
- * Computes health components from balances with price bias.
68969
- *
68970
- * Returns weighted asset and liability values using conservative pricing
68971
- * (Lowest for assets, Highest for liabilities).
68972
- *
68973
- * @param params - Configuration for health computation (excluding activeBalances)
68974
- * @returns Object containing assets and liabilities values in USD
68975
- */
68976
- computeHealthComponentsFromBalances(params) {
68977
- return computeHealthComponentsFromBalances({
68978
- activeBalances: this.activeBalances,
68979
- ...params
68980
- });
67508
+ /**
67509
+ * Computes health components from balances with price bias.
67510
+ *
67511
+ * Returns weighted asset and liability values using conservative pricing
67512
+ * (Lowest for assets, Highest for liabilities).
67513
+ *
67514
+ * @param params - Configuration for health computation (excluding activeBalances)
67515
+ * @returns Object containing assets and liabilities values in USD
67516
+ */
67517
+ computeHealthComponentsFromBalances(params) {
67518
+ return computeHealthComponentsFromBalances({
67519
+ activeBalances: this.activeBalances,
67520
+ ...params
67521
+ });
68981
67522
  }
68982
67523
  /**
68983
67524
  * Computes the total account value (equity).
@@ -69382,6 +67923,86 @@ var MarginfiAccount = class _MarginfiAccount {
69382
67923
  }
69383
67924
  });
69384
67925
  }
67926
+ /**
67927
+ * Creates a loop transaction with a transparent bridged (double-hop) fallback.
67928
+ *
67929
+ * One call: tries the direct {@link makeLoopTx} first; if its borrow→deposit swap can't fit one
67930
+ * transaction (size / account-locks) or has no route, it loops the deposit asset against a
67931
+ * value-equivalent borrow of a high-liquidity bridge token, then debt-swaps the bridge debt to
67932
+ * the requested borrow asset — both legs composed into ONE atomic Jito bundle.
67933
+ *
67934
+ * Bridge candidates default to USDC → wSOL → USDT and can be reordered/overridden via
67935
+ * `params.bridgeOpts.bridgeCandidateMints`; `bridgeOpts` also accepts known token programs (skips RPC
67936
+ * lookups), a bundle-size ceiling, and an abort signal. `result.bridgeMint` is set only when the
67937
+ * bridged path was used.
67938
+ *
67939
+ * Intended for existing accounts — a fresh account's loop fits the direct path, so flows that
67940
+ * create the account in the same action should call {@link makeLoopTx} directly.
67941
+ *
67942
+ * @param params - Loop transaction parameters plus optional `bridgeOpts`
67943
+ * @returns Object containing transactions, action index, merged swap quote, and the bridge mint
67944
+ *
67945
+ * @see {@link makeBridgedLoopTx} for detailed implementation
67946
+ */
67947
+ async makeBridgedLoopTx(params) {
67948
+ return makeBridgedLoopTx({
67949
+ ...params,
67950
+ marginfiAccount: this,
67951
+ overrideInferAccounts: {
67952
+ authority: this.authority,
67953
+ group: this.group,
67954
+ ...params.overrideInferAccounts
67955
+ }
67956
+ });
67957
+ }
67958
+ /**
67959
+ * Creates a collateral-swap transaction with a transparent bridged (double-hop) fallback.
67960
+ *
67961
+ * One call: tries the direct {@link makeSwapCollateralTx} first; if the swap `A → C` can't fit
67962
+ * one transaction or has no route, it decomposes into `A → bridge` + `bridge → C` through a
67963
+ * high-liquidity bridge collateral, both legs composed into ONE atomic Jito bundle. See
67964
+ * {@link makeBridgedLoopTx} for the `bridgeOpts` knobs.
67965
+ *
67966
+ * @param params - Swap collateral transaction parameters plus optional `bridgeOpts`
67967
+ * @returns Object containing transactions, action index, merged swap quote, and the bridge mint
67968
+ *
67969
+ * @see {@link makeBridgedSwapCollateralTx} for detailed implementation
67970
+ */
67971
+ async makeBridgedSwapCollateralTx(params) {
67972
+ return makeBridgedSwapCollateralTx({
67973
+ ...params,
67974
+ marginfiAccount: this,
67975
+ overrideInferAccounts: {
67976
+ authority: this.authority,
67977
+ group: this.group,
67978
+ ...params.overrideInferAccounts
67979
+ }
67980
+ });
67981
+ }
67982
+ /**
67983
+ * Creates a debt-swap transaction with a transparent bridged (double-hop) fallback.
67984
+ *
67985
+ * One call: tries the direct {@link makeSwapDebtTx} first; if the swap `A → C` can't fit one
67986
+ * transaction or has no route, the first leg repays A by borrowing a bridge token and the second
67987
+ * leg repays exactly that bridge debt while borrowing C — both legs composed into ONE atomic
67988
+ * Jito bundle. See {@link makeBridgedLoopTx} for the `bridgeOpts` knobs.
67989
+ *
67990
+ * @param params - Swap debt transaction parameters plus optional `bridgeOpts`
67991
+ * @returns Object containing transactions, action index, merged swap quote, and the bridge mint
67992
+ *
67993
+ * @see {@link makeBridgedSwapDebtTx} for detailed implementation
67994
+ */
67995
+ async makeBridgedSwapDebtTx(params) {
67996
+ return makeBridgedSwapDebtTx({
67997
+ ...params,
67998
+ marginfiAccount: this,
67999
+ overrideInferAccounts: {
68000
+ authority: this.authority,
68001
+ group: this.group,
68002
+ ...params.overrideInferAccounts
68003
+ }
68004
+ });
68005
+ }
69385
68006
  /**
69386
68007
  * Creates a transaction to repay debt using collateral.
69387
68008
  *
@@ -69421,425 +68042,2168 @@ var MarginfiAccount = class _MarginfiAccount {
69421
68042
  }
69422
68043
  });
69423
68044
  }
69424
- /**
69425
- * Creates a transaction to swap one collateral position to another using a flash loan.
69426
- *
69427
- * A swap collateral transaction:
69428
- * 1. Withdraws existing collateral via flash loan
69429
- * 2. Swaps collateral to new asset (via Jupiter)
69430
- * 3. Deposits swapped assets as new collateral
69431
- *
69432
- * This allows users to change their collateral type (e.g., JitoSOL -> mSOL) without
69433
- * withdrawing and affecting their health during the swap.
69434
- *
69435
- * @param params - Swap collateral transaction parameters
69436
- * @param params.connection - Solana connection instance
69437
- * @param params.oraclePrices - Map of current oracle prices
69438
- * @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
69439
- * @param params.depositOpts - Deposit configuration (bank, tokenProgram)
69440
- * @param params.swapOpts - Swap configuration (venue, slippage, fees)
69441
- * @param params.addressLookupTableAccounts - Address lookup tables
69442
- * @param params.overrideInferAccounts - Optional account overrides
69443
- * @param params.additionalIxs - Additional instructions to include
69444
- * @param params.crossbarUrl - Crossbar URL for oracle updates
69445
- *
69446
- * @returns Object containing transactions array, action index, and swap quote
69447
- *
69448
- * @throws {TransactionBuildingError} If swap exceeds transaction size limits
69449
- * @throws {TransactionBuildingError} If Kamino reserve not found
69450
- *
69451
- * @see {@link makeSwapCollateralTx} for detailed implementation
69452
- */
69453
- async makeSwapCollateralTx(params) {
69454
- return makeSwapCollateralTx({
69455
- ...params,
69456
- marginfiAccount: this,
69457
- overrideInferAccounts: {
69458
- authority: this.authority,
69459
- group: this.group,
69460
- ...params.overrideInferAccounts
69461
- }
68045
+ /**
68046
+ * Creates a transaction to swap one collateral position to another using a flash loan.
68047
+ *
68048
+ * A swap collateral transaction:
68049
+ * 1. Withdraws existing collateral via flash loan
68050
+ * 2. Swaps collateral to new asset (via Jupiter)
68051
+ * 3. Deposits swapped assets as new collateral
68052
+ *
68053
+ * This allows users to change their collateral type (e.g., JitoSOL -> mSOL) without
68054
+ * withdrawing and affecting their health during the swap.
68055
+ *
68056
+ * @param params - Swap collateral transaction parameters
68057
+ * @param params.connection - Solana connection instance
68058
+ * @param params.oraclePrices - Map of current oracle prices
68059
+ * @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
68060
+ * @param params.depositOpts - Deposit configuration (bank, tokenProgram)
68061
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
68062
+ * @param params.addressLookupTableAccounts - Address lookup tables
68063
+ * @param params.overrideInferAccounts - Optional account overrides
68064
+ * @param params.additionalIxs - Additional instructions to include
68065
+ * @param params.crossbarUrl - Crossbar URL for oracle updates
68066
+ *
68067
+ * @returns Object containing transactions array, action index, and swap quote
68068
+ *
68069
+ * @throws {TransactionBuildingError} If swap exceeds transaction size limits
68070
+ * @throws {TransactionBuildingError} If Kamino reserve not found
68071
+ *
68072
+ * @see {@link makeSwapCollateralTx} for detailed implementation
68073
+ */
68074
+ async makeSwapCollateralTx(params) {
68075
+ return makeSwapCollateralTx({
68076
+ ...params,
68077
+ marginfiAccount: this,
68078
+ overrideInferAccounts: {
68079
+ authority: this.authority,
68080
+ group: this.group,
68081
+ ...params.overrideInferAccounts
68082
+ }
68083
+ });
68084
+ }
68085
+ /**
68086
+ * Creates a transaction to roll a matured Exponent PT collateral position into its
68087
+ * next-maturity PT, in one flash-loan-wrapped bundle
68088
+ * (withdraw PT_old → `wrapper_merge` to base → swap-engine buy PT_new → deposit).
68089
+ * See {@link makeRollPtTx}.
68090
+ *
68091
+ * @param params - Roll-PT parameters (`withdrawOpts`/`depositOpts`/`swapOpts`/`rollOpts`).
68092
+ */
68093
+ async makeRollPtTx(params) {
68094
+ return makeRollPtTx({
68095
+ ...params,
68096
+ marginfiAccount: this,
68097
+ overrideInferAccounts: {
68098
+ authority: this.authority,
68099
+ group: this.group,
68100
+ ...params.overrideInferAccounts
68101
+ }
68102
+ });
68103
+ }
68104
+ /**
68105
+ * Creates a transaction to swap one debt position to another using a flash loan.
68106
+ *
68107
+ * A swap debt transaction:
68108
+ * 1. Borrows new asset via flash loan (new debt)
68109
+ * 2. Swaps new asset to old debt asset (via Jupiter)
68110
+ * 3. Repays old debt with swapped assets
68111
+ *
68112
+ * This allows users to change their debt type (e.g., USDC debt -> SOL debt) without
68113
+ * repaying and affecting their health during the swap.
68114
+ *
68115
+ * @param params - Swap debt transaction parameters
68116
+ * @param params.connection - Solana connection instance
68117
+ * @param params.oraclePrices - Map of current oracle prices
68118
+ * @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
68119
+ * @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
68120
+ * @param params.swapOpts - Swap configuration (venue, slippage, fees)
68121
+ * @param params.addressLookupTableAccounts - Address lookup tables
68122
+ * @param params.overrideInferAccounts - Optional account overrides
68123
+ * @param params.additionalIxs - Additional instructions to include
68124
+ * @param params.crossbarUrl - Crossbar URL for oracle updates
68125
+ *
68126
+ * @returns Object containing transactions array, action index, and swap quote
68127
+ *
68128
+ * @throws {TransactionBuildingError} If swap exceeds transaction size limits
68129
+ *
68130
+ * @see {@link makeSwapDebtTx} for detailed implementation
68131
+ */
68132
+ async makeSwapDebtTx(params) {
68133
+ return makeSwapDebtTx({
68134
+ ...params,
68135
+ marginfiAccount: this,
68136
+ overrideInferAccounts: {
68137
+ authority: this.authority,
68138
+ group: this.group,
68139
+ ...params.overrideInferAccounts
68140
+ }
68141
+ });
68142
+ }
68143
+ /**
68144
+ * Creates a deposit transaction.
68145
+ *
68146
+ * @param params - Parameters for the deposit transaction
68147
+ * @returns Promise resolving to an ExtendedTransaction
68148
+ *
68149
+ * @see {@link makeDepositTx} for detailed implementation
68150
+ */
68151
+ async makeDepositTx(params) {
68152
+ return makeDepositTx({
68153
+ ...params,
68154
+ accountAddress: this.address,
68155
+ authority: this.authority,
68156
+ group: this.group
68157
+ });
68158
+ }
68159
+ /**
68160
+ * Creates a Drift deposit transaction.
68161
+ *
68162
+ * @param params - Parameters for the Drift deposit transaction
68163
+ * @returns Promise resolving to an ExtendedV0Transaction
68164
+ *
68165
+ * @see {@link makeDriftDepositTx} for detailed implementation
68166
+ */
68167
+ async makeDriftDepositTx(params) {
68168
+ return makeDriftDepositTx({
68169
+ ...params,
68170
+ accountAddress: this.address,
68171
+ authority: this.authority,
68172
+ group: this.group
68173
+ });
68174
+ }
68175
+ /**
68176
+ * Creates a Kamino deposit transaction.
68177
+ *
68178
+ * @param params - Parameters for the Kamino deposit transaction
68179
+ * @returns Promise resolving to an ExtendedV0Transaction
68180
+ *
68181
+ * @see {@link makeKaminoDepositTx} for detailed implementation
68182
+ */
68183
+ async makeKaminoDepositTx(params) {
68184
+ return makeKaminoDepositTx({
68185
+ ...params,
68186
+ accountAddress: this.address,
68187
+ authority: this.authority,
68188
+ group: this.group
68189
+ });
68190
+ }
68191
+ /**
68192
+ * Creates a borrow transaction.
68193
+ *
68194
+ * @param params - Parameters for the borrow transaction
68195
+ * @returns Promise resolving to a TransactionBuilderResult
68196
+ *
68197
+ * @see {@link makeBorrowTx} for detailed implementation
68198
+ */
68199
+ async makeBorrowTx(params) {
68200
+ return makeBorrowTx({
68201
+ ...params,
68202
+ marginfiAccount: this,
68203
+ opts: {
68204
+ ...params.opts,
68205
+ overrideInferAccounts: {
68206
+ authority: this.authority,
68207
+ ...params.opts?.overrideInferAccounts
68208
+ }
68209
+ }
68210
+ });
68211
+ }
68212
+ /**
68213
+ * Creates a repay transaction.
68214
+ *
68215
+ * @param params - Parameters for the repay transaction
68216
+ * @returns Promise resolving to an ExtendedTransaction
68217
+ *
68218
+ * @see {@link makeRepayTx} for detailed implementation
68219
+ */
68220
+ async makeRepayTx(params) {
68221
+ return makeRepayTx({
68222
+ ...params,
68223
+ accountAddress: this.address,
68224
+ authority: this.authority
68225
+ });
68226
+ }
68227
+ /**
68228
+ * Creates a withdraw transaction.
68229
+ *
68230
+ * @param params - Parameters for the withdraw transaction
68231
+ * @returns Promise resolving to a TransactionBuilderResult
68232
+ *
68233
+ * @see {@link makeWithdrawTx} for detailed implementation
68234
+ */
68235
+ async makeWithdrawTx(params) {
68236
+ return makeWithdrawTx({
68237
+ ...params,
68238
+ marginfiAccount: this,
68239
+ opts: {
68240
+ ...params.opts,
68241
+ overrideInferAccounts: {
68242
+ authority: this.authority,
68243
+ group: this.group,
68244
+ ...params.opts?.overrideInferAccounts
68245
+ }
68246
+ }
68247
+ });
68248
+ }
68249
+ /**
68250
+ * Creates a Drift withdraw transaction.
68251
+ *
68252
+ * @param params - Parameters for the Drift withdraw transaction
68253
+ * @returns Promise resolving to an ExtendedV0Transaction
68254
+ *
68255
+ * @see {@link makeDriftWithdrawTx} for detailed implementation
68256
+ */
68257
+ async makeDriftWithdrawTx(params) {
68258
+ return makeDriftWithdrawTx({
68259
+ ...params,
68260
+ marginfiAccount: this,
68261
+ opts: {
68262
+ ...params.opts,
68263
+ overrideInferAccounts: {
68264
+ authority: this.authority,
68265
+ group: this.group,
68266
+ ...params.opts?.overrideInferAccounts
68267
+ }
68268
+ }
68269
+ });
68270
+ }
68271
+ /**
68272
+ * Creates a Kamino withdraw transaction.
68273
+ *
68274
+ * @param params - Parameters for the Kamino withdraw transaction
68275
+ * @returns Promise resolving to a TransactionBuilderResult
68276
+ *
68277
+ * @see {@link makeKaminoWithdrawTx} for detailed implementation
68278
+ */
68279
+ async makeKaminoWithdrawTx(params) {
68280
+ return makeKaminoWithdrawTx({
68281
+ ...params,
68282
+ marginfiAccount: this,
68283
+ opts: {
68284
+ ...params.opts,
68285
+ overrideInferAccounts: {
68286
+ authority: this.authority,
68287
+ group: this.group,
68288
+ ...params.opts?.overrideInferAccounts
68289
+ }
68290
+ }
68291
+ });
68292
+ }
68293
+ /**
68294
+ * Creates a flash loan transaction.
68295
+ *
68296
+ * @param params - Parameters for the flash loan transaction
68297
+ * @returns Promise resolving to flash loan transaction details
68298
+ *
68299
+ * @see {@link makeFlashLoanTx} for detailed implementation
68300
+ */
68301
+ async makeFlashLoanTx(params) {
68302
+ return makeFlashLoanTx({
68303
+ ...params,
68304
+ marginfiAccount: this
68305
+ });
68306
+ }
68307
+ };
68308
+
68309
+ // src/services/account/actions/bridge-swap.ts
68310
+ var MAX_BRIDGED_BUNDLE_TXS = 5;
68311
+ function classifyTxs(txs) {
68312
+ const out = { setups: [], cranks: [], flashloans: [] };
68313
+ for (const tx of txs) {
68314
+ if (tx.type === "CREATE_ATA" /* CREATE_ATA */) out.setups.push(tx);
68315
+ else if (tx.type === "CRANK" /* CRANK */) out.cranks.push(tx);
68316
+ else out.flashloans.push(tx);
68317
+ }
68318
+ return out;
68319
+ }
68320
+ function ixIdentity(ix) {
68321
+ const keys = ix.keys.map((k) => k.pubkey.toBase58()).join(",");
68322
+ return `${ix.programId.toBase58()}|${keys}|${Buffer.from(ix.data).toString("base64")}`;
68323
+ }
68324
+ function mergeSetupTxs(txs, payer, blockhash) {
68325
+ if (txs.length === 0) return null;
68326
+ if (txs.length === 1) return txs[0];
68327
+ const lutMap = /* @__PURE__ */ new Map();
68328
+ const seen = /* @__PURE__ */ new Set();
68329
+ const ixs = [];
68330
+ for (const tx of txs) {
68331
+ const luts2 = tx.addressLookupTables ?? [];
68332
+ luts2.forEach((l) => lutMap.set(l.key.toBase58(), l));
68333
+ const msg = decompileV0Transaction(tx, luts2);
68334
+ for (const ix of msg.instructions) {
68335
+ const id = ixIdentity(ix);
68336
+ if (seen.has(id)) continue;
68337
+ seen.add(id);
68338
+ ixs.push(ix);
68339
+ }
68340
+ }
68341
+ const luts = [...lutMap.values()];
68342
+ const split = splitInstructionsToFitTransactions([], ixs, { blockhash, payerKey: payer, luts });
68343
+ if (split.length !== 1) return null;
68344
+ return addTransactionMetadata(split[0], {
68345
+ type: "CREATE_ATA" /* CREATE_ATA */,
68346
+ addressLookupTables: luts
68347
+ });
68348
+ }
68349
+ function projectAccountAfterFirstLeg(account, firstLegFlashloanTxs, program, banksMap, multipliers) {
68350
+ const ixs = [];
68351
+ for (const tx of firstLegFlashloanTxs) {
68352
+ const luts = tx.addressLookupTables ?? [];
68353
+ ixs.push(...decompileV0Transaction(tx, luts).instructions);
68354
+ }
68355
+ const { projectedBalances } = computeProjectedActiveBalancesNoCpi({
68356
+ account,
68357
+ instructions: ixs,
68358
+ program,
68359
+ banksMap,
68360
+ assetShareValueMultiplierByBank: multipliers
68361
+ });
68362
+ return new MarginfiAccount(
68363
+ account.address,
68364
+ account.group,
68365
+ account.authority,
68366
+ projectedBalances.map((b) => Balance.fromBalanceType(b)),
68367
+ account.accountFlags,
68368
+ account.emissionsDestinationAccount,
68369
+ account.healthCache
68370
+ );
68371
+ }
68372
+ function composeBundle(firstLegTxs, secondLegTxs, payer, blockhash, maxBundleTxs) {
68373
+ const c1 = classifyTxs(firstLegTxs);
68374
+ const c2 = classifyTxs(secondLegTxs);
68375
+ const mergedSetup = mergeSetupTxs([...c1.setups, ...c2.setups], payer, blockhash);
68376
+ if ([...c1.setups, ...c2.setups].length > 0 && !mergedSetup) return null;
68377
+ const result = [
68378
+ ...mergedSetup ? [mergedSetup] : [],
68379
+ ...c1.cranks,
68380
+ ...c1.flashloans,
68381
+ // firstLegFL(s)
68382
+ ...c2.cranks,
68383
+ ...c2.flashloans
68384
+ // secondLegFL(s)
68385
+ ];
68386
+ if (result.length > maxBundleTxs) return null;
68387
+ return result;
68388
+ }
68389
+ function compoundQuoteRisk(firstLeg, secondLeg) {
68390
+ const compound = (a, b) => {
68391
+ if (a == null && b == null) return void 0;
68392
+ const x = Number(a ?? 0);
68393
+ const y = Number(b ?? 0);
68394
+ return String(1 - (1 - x) * (1 - y));
68395
+ };
68396
+ return {
68397
+ slippageBps: Math.round(
68398
+ (1 - (1 - firstLeg.slippageBps / 1e4) * (1 - secondLeg.slippageBps / 1e4)) * 1e4
68399
+ ),
68400
+ priceImpactPct: compound(firstLeg.priceImpactPct, secondLeg.priceImpactPct)
68401
+ };
68402
+ }
68403
+ function mergeBridgeQuotes(firstLeg, secondLeg) {
68404
+ return {
68405
+ inAmount: firstLeg.inAmount,
68406
+ outAmount: secondLeg.outAmount,
68407
+ otherAmountThreshold: secondLeg.otherAmountThreshold,
68408
+ ...compoundQuoteRisk(firstLeg, secondLeg),
68409
+ provider: firstLeg.provider
68410
+ };
68411
+ }
68412
+ function mergeBridgeQuotesDebt(firstLeg, secondLeg) {
68413
+ return {
68414
+ inAmount: firstLeg.outAmount,
68415
+ outAmount: secondLeg.inAmount,
68416
+ otherAmountThreshold: secondLeg.inAmount,
68417
+ ...compoundQuoteRisk(firstLeg, secondLeg),
68418
+ provider: firstLeg.provider
68419
+ };
68420
+ }
68421
+ function mergeBridgeQuotesLoop(firstLeg, secondLeg) {
68422
+ return {
68423
+ inAmount: secondLeg.inAmount,
68424
+ outAmount: firstLeg.outAmount,
68425
+ otherAmountThreshold: firstLeg.otherAmountThreshold,
68426
+ ...compoundQuoteRisk(firstLeg, secondLeg),
68427
+ provider: firstLeg.provider
68428
+ };
68429
+ }
68430
+ function blockhashOf(leg) {
68431
+ const tx = leg.transactions[0];
68432
+ return tx ? tx.message.recentBlockhash : PublicKey.default.toBase58();
68433
+ }
68434
+ async function composeBridgedSwap(params) {
68435
+ const {
68436
+ firstLeg,
68437
+ buildSecondLeg,
68438
+ marginfiAccount,
68439
+ program,
68440
+ banksMap,
68441
+ assetShareValueMultiplierByBank,
68442
+ feePayer,
68443
+ maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS
68444
+ } = params;
68445
+ if (!firstLeg.quoteResponse) return null;
68446
+ const projectedAccount = projectAccountAfterFirstLeg(
68447
+ marginfiAccount,
68448
+ classifyTxs(firstLeg.transactions).flashloans,
68449
+ program,
68450
+ banksMap,
68451
+ assetShareValueMultiplierByBank
68452
+ );
68453
+ const secondLeg = await buildSecondLeg(projectedAccount);
68454
+ if (!secondLeg.quoteResponse) return null;
68455
+ const transactions = composeBundle(
68456
+ firstLeg.transactions,
68457
+ secondLeg.transactions,
68458
+ feePayer,
68459
+ blockhashOf(firstLeg),
68460
+ maxBundleTxs
68461
+ );
68462
+ if (!transactions) return null;
68463
+ return { transactions, firstLegQuote: firstLeg.quoteResponse, secondLegQuote: secondLeg.quoteResponse };
68464
+ }
68465
+ async function makeSwapDebtTx(params) {
68466
+ const {
68467
+ program,
68468
+ marginfiAccount,
68469
+ connection,
68470
+ bankMap,
68471
+ oraclePrices,
68472
+ repayOpts,
68473
+ borrowOpts,
68474
+ bankMetadataMap,
68475
+ assetShareValueMultiplierByBank,
68476
+ addressLookupTableAccounts,
68477
+ crossbarUrl,
68478
+ additionalIxs = []
68479
+ } = params;
68480
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
68481
+ const setupIxs = await makeSetupIx({
68482
+ connection,
68483
+ authority: marginfiAccount.authority,
68484
+ tokens: [
68485
+ { mint: repayOpts.repayBank.mint, tokenProgram: repayOpts.tokenProgram },
68486
+ { mint: borrowOpts.borrowBank.mint, tokenProgram: borrowOpts.tokenProgram }
68487
+ ]
68488
+ });
68489
+ const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
68490
+ marginfiAccount,
68491
+ bankMap,
68492
+ [],
68493
+ bankMetadataMap,
68494
+ [repayOpts.repayBank.address, borrowOpts.borrowBank.address]
68495
+ );
68496
+ const { flashloanTx, setupInstructions, swapQuote, borrowIxs, repayIxs } = await buildSwapDebtFlashloanTx({
68497
+ ...params,
68498
+ blockhash
68499
+ });
68500
+ const jupiterSetupInstructions = setupInstructions.filter((ix) => {
68501
+ if (ix.programId.equals(ComputeBudgetProgram.programId)) {
68502
+ return false;
68503
+ }
68504
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
68505
+ const mintKey = ix.keys[3]?.pubkey;
68506
+ if (mintKey?.equals(repayOpts.repayBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
68507
+ return false;
68508
+ }
68509
+ }
68510
+ return true;
68511
+ });
68512
+ setupIxs.push(...jupiterSetupInstructions);
68513
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
68514
+ marginfiAccount,
68515
+ bankMap,
68516
+ oraclePrices,
68517
+ assetShareValueMultiplierByBank,
68518
+ instructions: [...borrowIxs.instructions, ...repayIxs.instructions],
68519
+ program,
68520
+ connection,
68521
+ crossbarUrl
68522
+ });
68523
+ let additionalTxs = [];
68524
+ if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
68525
+ const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
68526
+ const txs = splitInstructionsToFitTransactions([], ixs, {
68527
+ blockhash,
68528
+ payerKey: marginfiAccount.authority,
68529
+ luts: addressLookupTableAccounts ?? []
68530
+ });
68531
+ additionalTxs.push(
68532
+ ...txs.map(
68533
+ (tx) => addTransactionMetadata(tx, {
68534
+ type: "CREATE_ATA" /* CREATE_ATA */,
68535
+ addressLookupTables: addressLookupTableAccounts
68536
+ })
68537
+ )
68538
+ );
68539
+ }
68540
+ if (updateFeedIxs.length > 0) {
68541
+ const message = new TransactionMessage({
68542
+ payerKey: marginfiAccount.authority,
68543
+ recentBlockhash: blockhash,
68544
+ instructions: updateFeedIxs
68545
+ }).compileToV0Message(feedLuts);
68546
+ additionalTxs.push(
68547
+ addTransactionMetadata(new VersionedTransaction(message), {
68548
+ addressLookupTables: feedLuts,
68549
+ type: "CRANK" /* CRANK */
68550
+ })
68551
+ );
68552
+ }
68553
+ const transactions = [...additionalTxs, flashloanTx];
68554
+ return {
68555
+ transactions,
68556
+ actionTxIndex: transactions.length - 1,
68557
+ quoteResponse: swapQuote
68558
+ };
68559
+ }
68560
+ async function buildSwapDebtFlashloanTx({
68561
+ program,
68562
+ marginfiAccount,
68563
+ bankMap,
68564
+ repayOpts,
68565
+ borrowOpts,
68566
+ swapOpts,
68567
+ bankMetadataMap,
68568
+ addressLookupTableAccounts,
68569
+ connection,
68570
+ overrideInferAccounts,
68571
+ blockhash,
68572
+ swapEngineRunner
68573
+ }) {
68574
+ const {
68575
+ repayBank,
68576
+ tokenProgram: repayTokenProgram,
68577
+ totalPositionAmount,
68578
+ repayAmount
68579
+ } = repayOpts;
68580
+ const { borrowBank, tokenProgram: borrowTokenProgram } = borrowOpts;
68581
+ if (repayAmount !== void 0 && repayAmount <= 0) {
68582
+ throw new Error("repayAmount must be greater than 0");
68583
+ }
68584
+ const actualRepayAmount = Math.min(repayAmount ?? totalPositionAmount, totalPositionAmount);
68585
+ const cuRequestIxs = [
68586
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
68587
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
68588
+ ];
68589
+ const destinationTokenAccount = getAssociatedTokenAddressSync(
68590
+ repayBank.mint,
68591
+ marginfiAccount.authority,
68592
+ true,
68593
+ repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
68594
+ );
68595
+ const estimatedBorrowAmount = computeBorrowEstimateForRepay({
68596
+ repayTargetUi: actualRepayAmount,
68597
+ repayMarketPrice: repayOpts.marketPrice,
68598
+ borrowMarketPrice: borrowOpts.marketPrice,
68599
+ slippageBps: swapOpts.swapConfig?.slippageBps,
68600
+ isRepayAll: actualRepayAmount >= totalPositionAmount
68601
+ });
68602
+ const swapConstraints = await computeFlashloanSwapConstraints({
68603
+ program,
68604
+ marginfiAccount,
68605
+ bankMap,
68606
+ bankMetadataMap,
68607
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
68608
+ primaryIx: { type: "borrow", bank: borrowBank, tokenProgram: borrowTokenProgram },
68609
+ secondaryIx: { type: "repay", bank: repayBank, tokenProgram: repayTokenProgram },
68610
+ overrideInferAccounts
68611
+ });
68612
+ const footprintBorrowIxs = await makeBorrowIx3({
68613
+ program,
68614
+ bank: borrowBank,
68615
+ bankMap,
68616
+ tokenProgram: borrowTokenProgram,
68617
+ amount: estimatedBorrowAmount,
68618
+ marginfiAccount,
68619
+ authority: marginfiAccount.authority,
68620
+ isSync: true,
68621
+ opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
68622
+ });
68623
+ const footprintRepayIxs = await makeRepayIx3({
68624
+ program,
68625
+ bank: repayBank,
68626
+ tokenProgram: repayTokenProgram,
68627
+ amount: actualRepayAmount,
68628
+ accountAddress: marginfiAccount.address,
68629
+ authority: marginfiAccount.authority,
68630
+ isSync: true,
68631
+ opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
68632
+ });
68633
+ const runEngine = swapEngineRunner ?? runSwapEngine;
68634
+ const engineResult = await runEngine({
68635
+ inputMint: borrowBank.mint.toBase58(),
68636
+ outputMint: repayBank.mint.toBase58(),
68637
+ amountNative: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
68638
+ inputDecimals: borrowBank.mintDecimals,
68639
+ outputDecimals: repayBank.mintDecimals,
68640
+ ...swapEngineQuoteFieldsFromOpts(swapOpts),
68641
+ taker: marginfiAccount.authority,
68642
+ destinationTokenAccount,
68643
+ connection,
68644
+ footprint: {
68645
+ instructions: [
68646
+ ...cuRequestIxs,
68647
+ ...footprintBorrowIxs.instructions,
68648
+ ...footprintRepayIxs.instructions
68649
+ ],
68650
+ luts: addressLookupTableAccounts ?? [],
68651
+ payer: marginfiAccount.authority,
68652
+ sizeConstraint: swapConstraints.sizeConstraint,
68653
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
68654
+ },
68655
+ providers: swapEngineProvidersFromOpts(swapOpts)
68656
+ });
68657
+ const quoteResponse = engineResult.quoteResponse;
68658
+ const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
68659
+ const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
68660
+ const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
68661
+ const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
68662
+ const borrowIxs = await makeBorrowIx3({
68663
+ program,
68664
+ bank: borrowBank,
68665
+ bankMap,
68666
+ tokenProgram: borrowTokenProgram,
68667
+ amount: borrowAmount,
68668
+ marginfiAccount,
68669
+ authority: marginfiAccount.authority,
68670
+ isSync: true,
68671
+ opts: {
68672
+ createAtas: false,
68673
+ wrapAndUnwrapSol: false,
68674
+ overrideInferAccounts
68675
+ }
68676
+ });
68677
+ const repayIxs = await makeRepayIx3({
68678
+ program,
68679
+ bank: repayBank,
68680
+ tokenProgram: repayTokenProgram,
68681
+ amount: amountToRepay,
68682
+ accountAddress: marginfiAccount.address,
68683
+ authority: marginfiAccount.authority,
68684
+ repayAll: isWholePosition(
68685
+ {
68686
+ amount: totalPositionAmount,
68687
+ isLending: false
68688
+ },
68689
+ amountToRepay,
68690
+ repayBank.mintDecimals
68691
+ ),
68692
+ isSync: true,
68693
+ opts: {
68694
+ wrapAndUnwrapSol: false,
68695
+ overrideInferAccounts
68696
+ }
68697
+ });
68698
+ const luts = [...addressLookupTableAccounts ?? [], ...engineResult.swapLuts];
68699
+ const allNonFlIxs = [
68700
+ ...cuRequestIxs,
68701
+ ...borrowIxs.instructions,
68702
+ ...engineResult.swapInstructions,
68703
+ ...repayIxs.instructions
68704
+ ];
68705
+ compileFlashloanPrecheck({
68706
+ allIxs: allNonFlIxs,
68707
+ payer: marginfiAccount.authority,
68708
+ luts,
68709
+ sizeConstraint: swapConstraints.sizeConstraint,
68710
+ swapIxCount: engineResult.swapInstructions.length,
68711
+ swapLutCount: engineResult.swapLuts.length
68712
+ });
68713
+ const flashloanTx = await makeFlashLoanTx({
68714
+ program,
68715
+ marginfiAccount,
68716
+ bankMap,
68717
+ addressLookupTableAccounts: luts,
68718
+ blockhash,
68719
+ ixs: allNonFlIxs,
68720
+ isSync: true
68721
+ });
68722
+ const txSize = getTxSize(flashloanTx);
68723
+ const totalKeys = getTotalAccountKeys(flashloanTx);
68724
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
68725
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
68726
+ txSize,
68727
+ totalKeys,
68728
+ swapOpts.swapConfig?.provider
68729
+ );
68730
+ }
68731
+ return {
68732
+ flashloanTx,
68733
+ setupInstructions: engineResult.setupInstructions,
68734
+ swapQuote: quoteResponse,
68735
+ borrowIxs,
68736
+ repayIxs
68737
+ };
68738
+ }
68739
+ async function makeBridgedSwapDebtTx(params) {
68740
+ const { bridgeOpts, ...directParams } = params;
68741
+ try {
68742
+ return await makeSwapDebtTx(directParams);
68743
+ } catch (directError) {
68744
+ if (!isDecomposableSwapError(directError)) throw directError;
68745
+ const bridged = await tryBridgedDebtSwap(directParams, bridgeOpts);
68746
+ if (bridged) return bridged;
68747
+ throw directError;
68748
+ }
68749
+ }
68750
+ async function tryBridgedDebtSwap(params, bridgeOpts) {
68751
+ const sourceBank = params.repayOpts.repayBank;
68752
+ const destinationBank = params.borrowOpts.borrowBank;
68753
+ const repayAmount = params.repayOpts.repayAmount ?? params.repayOpts.totalPositionAmount;
68754
+ const oraclePriceOf = (bank) => params.oraclePrices.get(bank.address.toBase58())?.priceRealtime.price.toNumber() ?? 0;
68755
+ const { usableBridgeBanks, conflictingBridgeBanks } = selectSwapBridges({
68756
+ sourceMint: sourceBank.mint,
68757
+ destinationMint: destinationBank.mint,
68758
+ bankMap: params.bankMap,
68759
+ marginfiAccount: params.marginfiAccount,
68760
+ bridgeTokenSide: "borrow",
68761
+ bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
68762
+ });
68763
+ const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
68764
+ return tryBridgeCandidates({
68765
+ usableBridgeBanks,
68766
+ conflictingBridgeBanks,
68767
+ bridgeTokenSide: "borrow",
68768
+ abortSignal: bridgeOpts?.abortSignal,
68769
+ buildBundleThroughBridge: async (bridgeBank) => {
68770
+ const bridgeTokenProgram = await resolveTokenProgramForMint(
68771
+ bridgeBank.mint,
68772
+ params.connection,
68773
+ tokenProgramCache
68774
+ );
68775
+ const firstLeg = await makeSwapDebtTx({
68776
+ ...sharedBridgeLegContext(params),
68777
+ repayOpts: {
68778
+ totalPositionAmount: params.repayOpts.totalPositionAmount,
68779
+ repayAmount,
68780
+ repayBank: sourceBank,
68781
+ tokenProgram: params.repayOpts.tokenProgram,
68782
+ marketPrice: oraclePriceOf(sourceBank)
68783
+ },
68784
+ borrowOpts: {
68785
+ borrowBank: bridgeBank,
68786
+ tokenProgram: bridgeTokenProgram,
68787
+ marketPrice: oraclePriceOf(bridgeBank)
68788
+ }
68789
+ });
68790
+ if (!firstLeg.quoteResponse) return null;
68791
+ const bridgeBorrowedUi = nativeToUi(firstLeg.quoteResponse.inAmount, bridgeBank.mintDecimals);
68792
+ if (bridgeBorrowedUi <= 0) return null;
68793
+ const result = await composeBridgedSwap({
68794
+ firstLeg,
68795
+ buildSecondLeg: (projectedAccount) => makeSwapDebtTx({
68796
+ ...sharedBridgeLegContext(params),
68797
+ marginfiAccount: projectedAccount,
68798
+ repayOpts: {
68799
+ totalPositionAmount: bridgeBorrowedUi,
68800
+ repayAmount: bridgeBorrowedUi,
68801
+ repayBank: bridgeBank,
68802
+ tokenProgram: bridgeTokenProgram,
68803
+ marketPrice: oraclePriceOf(bridgeBank)
68804
+ },
68805
+ borrowOpts: {
68806
+ borrowBank: destinationBank,
68807
+ tokenProgram: params.borrowOpts.tokenProgram,
68808
+ marketPrice: oraclePriceOf(destinationBank)
68809
+ }
68810
+ }),
68811
+ marginfiAccount: params.marginfiAccount,
68812
+ program: params.program,
68813
+ banksMap: params.bankMap,
68814
+ assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
68815
+ feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
68816
+ maxBundleTxs: bridgeOpts?.maxBundleTxs
68817
+ });
68818
+ if (!result) return null;
68819
+ return {
68820
+ transactions: result.transactions,
68821
+ actionTxIndex: result.transactions.length - 1,
68822
+ quoteResponse: mergeBridgeQuotesDebt(result.firstLegQuote, result.secondLegQuote),
68823
+ bridgeMint: bridgeBank.mint
68824
+ };
68825
+ }
68826
+ });
68827
+ }
68828
+
68829
+ // src/services/account/actions/loop.ts
68830
+ async function makeLoopTx(params) {
68831
+ const {
68832
+ program,
68833
+ marginfiAccount,
68834
+ bankMap,
68835
+ depositOpts,
68836
+ borrowOpts,
68837
+ bankMetadataMap,
68838
+ addressLookupTableAccounts,
68839
+ connection,
68840
+ oraclePrices,
68841
+ crossbarUrl,
68842
+ additionalIxs = []
68843
+ } = params;
68844
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
68845
+ const setupIxs = await makeSetupIx({
68846
+ connection,
68847
+ authority: marginfiAccount.authority,
68848
+ tokens: [
68849
+ {
68850
+ mint: borrowOpts.borrowBank.mint,
68851
+ tokenProgram: borrowOpts.tokenProgram
68852
+ },
68853
+ {
68854
+ mint: depositOpts.depositBank.mint,
68855
+ tokenProgram: depositOpts.tokenProgram
68856
+ }
68857
+ ]
68858
+ });
68859
+ const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
68860
+ params.marginfiAccount,
68861
+ params.bankMap,
68862
+ [depositOpts.depositBank.address],
68863
+ params.bankMetadataMap,
68864
+ [borrowOpts.borrowBank.address, depositOpts.depositBank.address]
68865
+ );
68866
+ const { flashloanTx, setupInstructions, swapQuote, depositIxs, borrowIxs } = await buildLoopFlashloanTx({
68867
+ ...params,
68868
+ blockhash
68869
+ });
68870
+ const jupiterSetupInstructions = setupInstructions.filter((ix) => {
68871
+ if (ix.programId.equals(ComputeBudgetProgram.programId)) {
68872
+ return false;
68873
+ }
68874
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
68875
+ const mintKey = ix.keys[3]?.pubkey;
68876
+ if (mintKey?.equals(depositOpts.depositBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
68877
+ return false;
68878
+ }
68879
+ }
68880
+ return true;
68881
+ });
68882
+ setupIxs.push(...jupiterSetupInstructions);
68883
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
68884
+ marginfiAccount,
68885
+ bankMap,
68886
+ oraclePrices,
68887
+ assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
68888
+ instructions: [...borrowIxs.instructions, ...depositIxs.instructions],
68889
+ program,
68890
+ connection,
68891
+ crossbarUrl
68892
+ });
68893
+ let additionalTxs = [];
68894
+ if (depositOpts.depositBank.mint.equals(NATIVE_MINT) && depositOpts.inputDepositAmount) {
68895
+ setupIxs.push(
68896
+ ...makeWrapSolIxs(marginfiAccount.authority, new BigNumber(depositOpts.inputDepositAmount))
68897
+ );
68898
+ }
68899
+ if (setupIxs.length > 0 || additionalIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
68900
+ const ixs = [...additionalIxs, ...setupIxs, ...refreshIntegrationIxs.instructions];
68901
+ const txs = splitInstructionsToFitTransactions([], ixs, {
68902
+ blockhash,
68903
+ payerKey: marginfiAccount.authority,
68904
+ luts: addressLookupTableAccounts ?? []
68905
+ });
68906
+ additionalTxs.push(
68907
+ ...txs.map(
68908
+ (tx) => addTransactionMetadata(tx, {
68909
+ type: "CREATE_ATA" /* CREATE_ATA */,
68910
+ addressLookupTables: addressLookupTableAccounts
68911
+ })
68912
+ )
68913
+ );
68914
+ }
68915
+ if (updateFeedIxs.length > 0) {
68916
+ const message = new TransactionMessage({
68917
+ payerKey: marginfiAccount.authority,
68918
+ recentBlockhash: blockhash,
68919
+ instructions: updateFeedIxs
68920
+ }).compileToV0Message(feedLuts);
68921
+ additionalTxs.push(
68922
+ addTransactionMetadata(new VersionedTransaction(message), {
68923
+ addressLookupTables: feedLuts,
68924
+ type: "CRANK" /* CRANK */
68925
+ })
68926
+ );
68927
+ }
68928
+ const transactions = [...additionalTxs, flashloanTx];
68929
+ return {
68930
+ transactions,
68931
+ actionTxIndex: transactions.length - 1,
68932
+ quoteResponse: swapQuote
68933
+ };
68934
+ }
68935
+ async function buildLoopFlashloanTx(params) {
68936
+ const { depositOpts } = params;
68937
+ const { descriptor, swapNeeded, borrowIxs, depositIxs } = await buildLoopNonSwapIxs(params);
68938
+ if (!swapNeeded) {
68939
+ const flashloanTx2 = await finalizeLoopFlashloanTx({
68940
+ params,
68941
+ innerIxs: descriptor.innerIxs,
68942
+ luts: descriptor.luts,
68943
+ swapIxCount: 0,
68944
+ swapLutCount: 0,
68945
+ sizeConstraint: descriptor.sizeConstraint
69462
68946
  });
68947
+ return {
68948
+ flashloanTx: flashloanTx2,
68949
+ setupInstructions: [],
68950
+ swapQuote: void 0,
68951
+ borrowIxs,
68952
+ depositIxs
68953
+ };
69463
68954
  }
69464
- /**
69465
- * Creates a transaction to roll a matured Exponent PT collateral position into its
69466
- * next-maturity PT, in one flash-loan-wrapped bundle
69467
- * (withdraw PT_old `wrapper_merge` to base swap-engine buy PT_new → deposit).
69468
- * See {@link makeRollPtTx}.
69469
- *
69470
- * @param params - Roll-PT parameters (`withdrawOpts`/`depositOpts`/`swapOpts`/`rollOpts`).
69471
- */
69472
- async makeRollPtTx(params) {
69473
- return makeRollPtTx({
69474
- ...params,
69475
- marginfiAccount: this,
69476
- overrideInferAccounts: {
69477
- authority: this.authority,
69478
- group: this.group,
69479
- ...params.overrideInferAccounts
69480
- }
68955
+ const engineResult = await runLoopSwapEngine(descriptor, params);
68956
+ const finalIxs = [...descriptor.innerIxs];
68957
+ finalIxs.splice(descriptor.swapSlotIndex, 0, ...engineResult.swapInstructions);
68958
+ const principalNative = depositOpts.loopMode === "DEPOSIT" ? uiToNative(depositOpts.inputDepositAmount, depositOpts.depositBank.mintDecimals) : new BN9(0);
68959
+ const finalDepositNative = engineResult.outputAmountNative.add(principalNative);
68960
+ const depositIxPosition = descriptor.depositIxIndex + engineResult.swapInstructions.length;
68961
+ patchDepositAmount(finalIxs[depositIxPosition], finalDepositNative);
68962
+ const luts = [...descriptor.luts, ...engineResult.swapLuts];
68963
+ const flashloanTx = await finalizeLoopFlashloanTx({
68964
+ params,
68965
+ innerIxs: finalIxs,
68966
+ luts,
68967
+ swapIxCount: engineResult.swapInstructions.length,
68968
+ swapLutCount: engineResult.swapLuts.length,
68969
+ sizeConstraint: descriptor.sizeConstraint
68970
+ });
68971
+ return {
68972
+ flashloanTx,
68973
+ setupInstructions: engineResult.setupInstructions,
68974
+ swapQuote: engineResult.quoteResponse,
68975
+ borrowIxs,
68976
+ depositIxs
68977
+ };
68978
+ }
68979
+ async function buildLoopNonSwapIxs(params) {
68980
+ const {
68981
+ program,
68982
+ marginfiAccount,
68983
+ bankMap,
68984
+ borrowOpts,
68985
+ depositOpts,
68986
+ bankMetadataMap,
68987
+ addressLookupTableAccounts,
68988
+ overrideInferAccounts
68989
+ } = params;
68990
+ const cuRequestIxs = [
68991
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
68992
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
68993
+ ];
68994
+ const swapNeeded = !depositOpts.depositBank.mint.equals(borrowOpts.borrowBank.mint);
68995
+ const destinationTokenAccount = getAssociatedTokenAddressSync(
68996
+ new PublicKey(depositOpts.depositBank.mint),
68997
+ marginfiAccount.authority,
68998
+ true,
68999
+ depositOpts.tokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
69000
+ );
69001
+ const principalUi = depositOpts.loopMode === "DEPOSIT" ? depositOpts.inputDepositAmount : 0;
69002
+ let depositAmountUi;
69003
+ let sizeConstraint = 0;
69004
+ let maxSwapTotalAccounts = 0;
69005
+ if (!swapNeeded) {
69006
+ depositAmountUi = borrowOpts.borrowAmount + principalUi;
69007
+ } else {
69008
+ const swapConstraints = await computeFlashloanSwapConstraints({
69009
+ program,
69010
+ marginfiAccount,
69011
+ bankMap,
69012
+ bankMetadataMap,
69013
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
69014
+ primaryIx: {
69015
+ type: "borrow",
69016
+ bank: borrowOpts.borrowBank,
69017
+ tokenProgram: borrowOpts.tokenProgram
69018
+ },
69019
+ secondaryIx: {
69020
+ type: "deposit",
69021
+ bank: depositOpts.depositBank,
69022
+ tokenProgram: depositOpts.tokenProgram
69023
+ },
69024
+ overrideInferAccounts
69481
69025
  });
69026
+ sizeConstraint = swapConstraints.sizeConstraint;
69027
+ maxSwapTotalAccounts = swapConstraints.maxSwapTotalAccounts;
69028
+ const estimateUi = borrowOpts.borrowAmount * borrowOpts.marketPrice / depositOpts.marketPrice;
69029
+ depositAmountUi = estimateUi + principalUi;
69482
69030
  }
69483
- /**
69484
- * Creates a transaction to swap one debt position to another using a flash loan.
69485
- *
69486
- * A swap debt transaction:
69487
- * 1. Borrows new asset via flash loan (new debt)
69488
- * 2. Swaps new asset to old debt asset (via Jupiter)
69489
- * 3. Repays old debt with swapped assets
69490
- *
69491
- * This allows users to change their debt type (e.g., USDC debt -> SOL debt) without
69492
- * repaying and affecting their health during the swap.
69493
- *
69494
- * @param params - Swap debt transaction parameters
69495
- * @param params.connection - Solana connection instance
69496
- * @param params.oraclePrices - Map of current oracle prices
69497
- * @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
69498
- * @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
69499
- * @param params.swapOpts - Swap configuration (venue, slippage, fees)
69500
- * @param params.addressLookupTableAccounts - Address lookup tables
69501
- * @param params.overrideInferAccounts - Optional account overrides
69502
- * @param params.additionalIxs - Additional instructions to include
69503
- * @param params.crossbarUrl - Crossbar URL for oracle updates
69504
- *
69505
- * @returns Object containing transactions array, action index, and swap quote
69506
- *
69507
- * @throws {TransactionBuildingError} If swap exceeds transaction size limits
69508
- *
69509
- * @see {@link makeSwapDebtTx} for detailed implementation
69510
- */
69511
- async makeSwapDebtTx(params) {
69512
- return makeSwapDebtTx({
69513
- ...params,
69514
- marginfiAccount: this,
69515
- overrideInferAccounts: {
69516
- authority: this.authority,
69517
- group: this.group,
69518
- ...params.overrideInferAccounts
69031
+ const borrowIxs = await makeBorrowIx3({
69032
+ program,
69033
+ bank: borrowOpts.borrowBank,
69034
+ bankMap,
69035
+ tokenProgram: borrowOpts.tokenProgram,
69036
+ amount: borrowOpts.borrowAmount,
69037
+ marginfiAccount,
69038
+ authority: marginfiAccount.authority,
69039
+ isSync: false,
69040
+ opts: {
69041
+ createAtas: false,
69042
+ wrapAndUnwrapSol: false,
69043
+ overrideInferAccounts
69044
+ }
69045
+ });
69046
+ const depositIxs = await buildDepositIxs(params, depositAmountUi);
69047
+ const innerIxsBeforeSwap = [...cuRequestIxs, ...borrowIxs.instructions];
69048
+ const swapSlotIndex = innerIxsBeforeSwap.length;
69049
+ const innerIxs = [...innerIxsBeforeSwap, ...depositIxs.instructions];
69050
+ const depositIxIndex = innerIxs.findIndex(isDepositIx);
69051
+ if (depositIxIndex < 0) {
69052
+ throw new Error(
69053
+ "buildLoopNonSwapIxs: could not locate deposit instruction for amount patching"
69054
+ );
69055
+ }
69056
+ const descriptor = {
69057
+ innerIxs,
69058
+ swapSlotIndex,
69059
+ depositIxIndex,
69060
+ inputMint: borrowOpts.borrowBank.mint.toBase58(),
69061
+ outputMint: depositOpts.depositBank.mint.toBase58(),
69062
+ inputDecimals: borrowOpts.borrowBank.mintDecimals,
69063
+ outputDecimals: depositOpts.depositBank.mintDecimals,
69064
+ inAmountNative: uiToNative(
69065
+ borrowOpts.borrowAmount,
69066
+ borrowOpts.borrowBank.mintDecimals
69067
+ ).toNumber(),
69068
+ destinationTokenAccount,
69069
+ sizeConstraint,
69070
+ maxSwapTotalAccounts,
69071
+ luts: addressLookupTableAccounts ?? []
69072
+ };
69073
+ return { descriptor, swapNeeded, borrowIxs, depositIxs };
69074
+ }
69075
+ async function buildDepositIxs(params, amountUi) {
69076
+ const { program, marginfiAccount, depositOpts, bankMetadataMap, overrideInferAccounts } = params;
69077
+ switch (depositOpts.depositBank.config.assetTag) {
69078
+ case 3 /* KAMINO */: {
69079
+ const reserve = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.kaminoStates?.reserveState;
69080
+ if (!reserve) {
69081
+ throw TransactionBuildingError.kaminoReserveNotFound(
69082
+ depositOpts.depositBank.address.toBase58(),
69083
+ depositOpts.depositBank.mint.toBase58(),
69084
+ depositOpts.depositBank.tokenSymbol
69085
+ );
69519
69086
  }
69520
- });
69087
+ return makeKaminoDepositIx3({
69088
+ program,
69089
+ bank: depositOpts.depositBank,
69090
+ tokenProgram: depositOpts.tokenProgram,
69091
+ amount: amountUi,
69092
+ accountAddress: marginfiAccount.address,
69093
+ authority: marginfiAccount.authority,
69094
+ group: marginfiAccount.group,
69095
+ reserve,
69096
+ opts: {
69097
+ wrapAndUnwrapSol: false,
69098
+ overrideInferAccounts
69099
+ }
69100
+ });
69101
+ }
69102
+ case 4 /* DRIFT */: {
69103
+ const driftState = bankMetadataMap[depositOpts.depositBank.address.toBase58()]?.driftStates;
69104
+ if (!driftState) {
69105
+ throw TransactionBuildingError.driftStateNotFound(
69106
+ depositOpts.depositBank.address.toBase58(),
69107
+ depositOpts.depositBank.mint.toBase58(),
69108
+ depositOpts.depositBank.tokenSymbol
69109
+ );
69110
+ }
69111
+ return makeDriftDepositIx3({
69112
+ program,
69113
+ bank: depositOpts.depositBank,
69114
+ tokenProgram: depositOpts.tokenProgram,
69115
+ amount: amountUi,
69116
+ accountAddress: marginfiAccount.address,
69117
+ authority: marginfiAccount.authority,
69118
+ group: marginfiAccount.group,
69119
+ driftMarketIndex: driftState.spotMarketState.marketIndex,
69120
+ driftOracle: driftState.spotMarketState.oracle,
69121
+ opts: {
69122
+ wrapAndUnwrapSol: false,
69123
+ overrideInferAccounts
69124
+ }
69125
+ });
69126
+ }
69127
+ case 6 /* JUPLEND */: {
69128
+ return makeJuplendDepositIx2({
69129
+ program,
69130
+ bank: depositOpts.depositBank,
69131
+ tokenProgram: depositOpts.tokenProgram,
69132
+ amount: amountUi,
69133
+ accountAddress: marginfiAccount.address,
69134
+ authority: marginfiAccount.authority,
69135
+ group: marginfiAccount.group,
69136
+ opts: {
69137
+ wrapAndUnwrapSol: false,
69138
+ overrideInferAccounts
69139
+ }
69140
+ });
69141
+ }
69142
+ default: {
69143
+ return makeDepositIx3({
69144
+ program,
69145
+ bank: depositOpts.depositBank,
69146
+ tokenProgram: depositOpts.tokenProgram,
69147
+ amount: amountUi,
69148
+ accountAddress: marginfiAccount.address,
69149
+ authority: marginfiAccount.authority,
69150
+ group: marginfiAccount.group,
69151
+ opts: {
69152
+ wrapAndUnwrapSol: false,
69153
+ overrideInferAccounts
69154
+ }
69155
+ });
69156
+ }
69521
69157
  }
69522
- /**
69523
- * Creates a deposit transaction.
69524
- *
69525
- * @param params - Parameters for the deposit transaction
69526
- * @returns Promise resolving to an ExtendedTransaction
69527
- *
69528
- * @see {@link makeDepositTx} for detailed implementation
69529
- */
69530
- async makeDepositTx(params) {
69531
- return makeDepositTx({
69532
- ...params,
69533
- accountAddress: this.address,
69534
- authority: this.authority,
69535
- group: this.group
69536
- });
69158
+ }
69159
+ async function runLoopSwapEngine(descriptor, params) {
69160
+ const { connection, swapOpts, marginfiAccount, swapEngineRunner } = params;
69161
+ if (swapOpts.swapIxs) {
69162
+ return {
69163
+ swapInstructions: swapOpts.swapIxs.instructions,
69164
+ setupInstructions: [],
69165
+ swapLuts: swapOpts.swapIxs.lookupTables,
69166
+ quoteResponse: {
69167
+ inAmount: String(descriptor.inAmountNative),
69168
+ outAmount: "0",
69169
+ otherAmountThreshold: "0",
69170
+ slippageBps: 0
69171
+ },
69172
+ outputAmountNative: new BN9(0)
69173
+ };
69537
69174
  }
69538
- /**
69539
- * Creates a Drift deposit transaction.
69540
- *
69541
- * @param params - Parameters for the Drift deposit transaction
69542
- * @returns Promise resolving to an ExtendedV0Transaction
69543
- *
69544
- * @see {@link makeDriftDepositTx} for detailed implementation
69545
- */
69546
- async makeDriftDepositTx(params) {
69547
- return makeDriftDepositTx({
69548
- ...params,
69549
- accountAddress: this.address,
69550
- authority: this.authority,
69551
- group: this.group
69175
+ const runEngine = swapEngineRunner ?? runSwapEngine;
69176
+ const engineResult = await runEngine({
69177
+ inputMint: descriptor.inputMint,
69178
+ outputMint: descriptor.outputMint,
69179
+ amountNative: descriptor.inAmountNative,
69180
+ inputDecimals: descriptor.inputDecimals,
69181
+ outputDecimals: descriptor.outputDecimals,
69182
+ ...swapEngineQuoteFieldsFromOpts(swapOpts),
69183
+ taker: marginfiAccount.authority,
69184
+ destinationTokenAccount: descriptor.destinationTokenAccount,
69185
+ connection,
69186
+ footprint: {
69187
+ instructions: descriptor.innerIxs,
69188
+ luts: descriptor.luts,
69189
+ payer: marginfiAccount.authority,
69190
+ sizeConstraint: descriptor.sizeConstraint,
69191
+ maxSwapTotalAccounts: descriptor.maxSwapTotalAccounts
69192
+ },
69193
+ providers: swapEngineProvidersFromOpts(swapOpts)
69194
+ });
69195
+ return {
69196
+ swapInstructions: engineResult.swapInstructions,
69197
+ setupInstructions: engineResult.setupInstructions,
69198
+ swapLuts: engineResult.swapLuts,
69199
+ quoteResponse: engineResult.quoteResponse,
69200
+ outputAmountNative: engineResult.outputAmountNative
69201
+ };
69202
+ }
69203
+ async function finalizeLoopFlashloanTx({
69204
+ params,
69205
+ innerIxs,
69206
+ luts,
69207
+ swapIxCount,
69208
+ swapLutCount,
69209
+ sizeConstraint
69210
+ }) {
69211
+ const { program, marginfiAccount, bankMap, swapOpts, blockhash } = params;
69212
+ if (swapIxCount > 0) {
69213
+ compileFlashloanPrecheck({
69214
+ allIxs: innerIxs,
69215
+ payer: marginfiAccount.authority,
69216
+ luts,
69217
+ sizeConstraint,
69218
+ swapIxCount,
69219
+ swapLutCount
69552
69220
  });
69553
69221
  }
69554
- /**
69555
- * Creates a Kamino deposit transaction.
69556
- *
69557
- * @param params - Parameters for the Kamino deposit transaction
69558
- * @returns Promise resolving to an ExtendedV0Transaction
69559
- *
69560
- * @see {@link makeKaminoDepositTx} for detailed implementation
69561
- */
69562
- async makeKaminoDepositTx(params) {
69563
- return makeKaminoDepositTx({
69564
- ...params,
69565
- accountAddress: this.address,
69566
- authority: this.authority,
69567
- group: this.group
69568
- });
69222
+ const flashloanTx = await makeFlashLoanTx({
69223
+ program,
69224
+ marginfiAccount,
69225
+ bankMap,
69226
+ addressLookupTableAccounts: luts,
69227
+ blockhash,
69228
+ ixs: innerIxs
69229
+ });
69230
+ const txSize = getTxSize(flashloanTx);
69231
+ const totalKeys = getTotalAccountKeys(flashloanTx);
69232
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
69233
+ throw TransactionBuildingError.swapSizeExceededLoop(
69234
+ txSize,
69235
+ totalKeys,
69236
+ swapOpts.swapConfig?.provider
69237
+ );
69569
69238
  }
69570
- /**
69571
- * Creates a borrow transaction.
69572
- *
69573
- * @param params - Parameters for the borrow transaction
69574
- * @returns Promise resolving to a TransactionBuilderResult
69575
- *
69576
- * @see {@link makeBorrowTx} for detailed implementation
69577
- */
69578
- async makeBorrowTx(params) {
69579
- return makeBorrowTx({
69580
- ...params,
69581
- marginfiAccount: this,
69582
- opts: {
69583
- ...params.opts,
69584
- overrideInferAccounts: {
69585
- authority: this.authority,
69586
- ...params.opts?.overrideInferAccounts
69239
+ return flashloanTx;
69240
+ }
69241
+ async function makeBridgedLoopTx(params) {
69242
+ const { bridgeOpts, ...loopParams } = params;
69243
+ try {
69244
+ return await makeLoopTx(loopParams);
69245
+ } catch (directError) {
69246
+ if (!isDecomposableSwapError(directError)) throw directError;
69247
+ const bridged = await tryBridgedLoop(loopParams, bridgeOpts);
69248
+ if (bridged) return bridged;
69249
+ throw directError;
69250
+ }
69251
+ }
69252
+ async function tryBridgedLoop(params, bridgeOpts) {
69253
+ const { depositBank } = params.depositOpts;
69254
+ const { borrowBank } = params.borrowOpts;
69255
+ const { usableBridgeBanks, conflictingBridgeBanks } = selectSwapBridges({
69256
+ sourceMint: depositBank.mint,
69257
+ destinationMint: borrowBank.mint,
69258
+ bankMap: params.bankMap,
69259
+ marginfiAccount: params.marginfiAccount,
69260
+ bridgeTokenSide: "borrow",
69261
+ bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
69262
+ });
69263
+ const oraclePriceOf = (bank) => params.oraclePrices.get(bank.address.toBase58())?.priceRealtime.price.toNumber() ?? 0;
69264
+ const borrowBankPrice = oraclePriceOf(borrowBank);
69265
+ if (borrowBankPrice) return null;
69266
+ const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
69267
+ return tryBridgeCandidates({
69268
+ usableBridgeBanks,
69269
+ conflictingBridgeBanks,
69270
+ bridgeTokenSide: "borrow",
69271
+ abortSignal: bridgeOpts?.abortSignal,
69272
+ buildBundleThroughBridge: async (bridgeBank) => {
69273
+ const birdgeBankPrice = oraclePriceOf(bridgeBank);
69274
+ if (birdgeBankPrice <= 0) return null;
69275
+ const bridgeBorrowUi = params.borrowOpts.borrowAmount * borrowBankPrice / birdgeBankPrice;
69276
+ if (bridgeBorrowUi <= 0) return null;
69277
+ const bridgeTokenProgram = await resolveTokenProgramForMint(
69278
+ bridgeBank.mint,
69279
+ params.connection,
69280
+ tokenProgramCache
69281
+ );
69282
+ const firstLeg = await makeLoopTx({
69283
+ ...params,
69284
+ depositOpts: {
69285
+ ...params.depositOpts,
69286
+ marketPrice: oraclePriceOf(depositBank)
69287
+ },
69288
+ borrowOpts: {
69289
+ borrowAmount: bridgeBorrowUi,
69290
+ borrowBank: bridgeBank,
69291
+ tokenProgram: bridgeTokenProgram,
69292
+ marketPrice: birdgeBankPrice
69587
69293
  }
69294
+ });
69295
+ if (!firstLeg.quoteResponse) return null;
69296
+ const result = await composeBridgedSwap({
69297
+ firstLeg,
69298
+ // Second leg: debt-swap the bridge debt → X (repay exactly the bridge the first leg
69299
+ // borrowed — exact, so no slippage residual; repay-all clears it — and borrow X).
69300
+ buildSecondLeg: (projectedAccount) => makeSwapDebtTx({
69301
+ ...sharedBridgeLegContext(params),
69302
+ marginfiAccount: projectedAccount,
69303
+ repayOpts: {
69304
+ totalPositionAmount: bridgeBorrowUi,
69305
+ repayAmount: bridgeBorrowUi,
69306
+ repayBank: bridgeBank,
69307
+ tokenProgram: bridgeTokenProgram,
69308
+ marketPrice: birdgeBankPrice
69309
+ },
69310
+ borrowOpts: {
69311
+ borrowBank,
69312
+ tokenProgram: params.borrowOpts.tokenProgram,
69313
+ marketPrice: borrowBankPrice
69314
+ }
69315
+ }),
69316
+ marginfiAccount: params.marginfiAccount,
69317
+ program: params.program,
69318
+ banksMap: params.bankMap,
69319
+ assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
69320
+ feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
69321
+ maxBundleTxs: bridgeOpts?.maxBundleTxs
69322
+ });
69323
+ if (!result) return null;
69324
+ return {
69325
+ transactions: result.transactions,
69326
+ actionTxIndex: result.transactions.length - 1,
69327
+ quoteResponse: mergeBridgeQuotesLoop(result.firstLegQuote, result.secondLegQuote),
69328
+ bridgeMint: bridgeBank.mint
69329
+ };
69330
+ }
69331
+ });
69332
+ }
69333
+ async function makeSwapCollateralTx(params) {
69334
+ const {
69335
+ program,
69336
+ marginfiAccount,
69337
+ connection,
69338
+ bankMap,
69339
+ oraclePrices,
69340
+ withdrawOpts,
69341
+ depositOpts,
69342
+ bankMetadataMap,
69343
+ assetShareValueMultiplierByBank,
69344
+ addressLookupTableAccounts,
69345
+ crossbarUrl,
69346
+ additionalIxs = []
69347
+ } = params;
69348
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
69349
+ const setupIxs = await makeSetupIx({
69350
+ connection,
69351
+ authority: marginfiAccount.authority,
69352
+ tokens: [
69353
+ { mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
69354
+ { mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
69355
+ ]
69356
+ });
69357
+ const refreshIntegrationIxs = makeRefreshIntegrationBanksIxs(
69358
+ marginfiAccount,
69359
+ bankMap,
69360
+ [withdrawOpts.withdrawBank.address, depositOpts.depositBank.address],
69361
+ bankMetadataMap
69362
+ );
69363
+ const { flashloanTx, setupInstructions, swapQuote, withdrawIxs, depositIxs } = await buildSwapCollateralFlashloanTx({
69364
+ ...params,
69365
+ blockhash
69366
+ });
69367
+ const jupiterSetupInstructions = setupInstructions.filter((ix) => {
69368
+ if (ix.programId.equals(ComputeBudgetProgram.programId)) {
69369
+ return false;
69370
+ }
69371
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
69372
+ const mintKey = ix.keys[3]?.pubkey;
69373
+ if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(depositOpts.depositBank.mint)) {
69374
+ return false;
69588
69375
  }
69376
+ }
69377
+ return true;
69378
+ });
69379
+ setupIxs.push(...jupiterSetupInstructions);
69380
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
69381
+ marginfiAccount,
69382
+ bankMap,
69383
+ oraclePrices,
69384
+ assetShareValueMultiplierByBank,
69385
+ instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
69386
+ program,
69387
+ connection,
69388
+ crossbarUrl
69389
+ });
69390
+ let additionalTxs = [];
69391
+ if (setupIxs.length > 0 || refreshIntegrationIxs.instructions.length > 0) {
69392
+ const ixs = [...setupIxs, ...refreshIntegrationIxs.instructions];
69393
+ const txs = splitInstructionsToFitTransactions([], ixs, {
69394
+ blockhash,
69395
+ payerKey: marginfiAccount.authority,
69396
+ luts: addressLookupTableAccounts ?? []
69589
69397
  });
69398
+ additionalTxs.push(
69399
+ ...txs.map(
69400
+ (tx) => addTransactionMetadata(tx, {
69401
+ type: "CREATE_ATA" /* CREATE_ATA */,
69402
+ addressLookupTables: addressLookupTableAccounts
69403
+ })
69404
+ )
69405
+ );
69590
69406
  }
69591
- /**
69592
- * Creates a repay transaction.
69593
- *
69594
- * @param params - Parameters for the repay transaction
69595
- * @returns Promise resolving to an ExtendedTransaction
69596
- *
69597
- * @see {@link makeRepayTx} for detailed implementation
69598
- */
69599
- async makeRepayTx(params) {
69600
- return makeRepayTx({
69601
- ...params,
69602
- accountAddress: this.address,
69603
- authority: this.authority
69604
- });
69407
+ if (updateFeedIxs.length > 0) {
69408
+ const message = new TransactionMessage({
69409
+ payerKey: marginfiAccount.authority,
69410
+ recentBlockhash: blockhash,
69411
+ instructions: updateFeedIxs
69412
+ }).compileToV0Message(feedLuts);
69413
+ additionalTxs.push(
69414
+ addTransactionMetadata(new VersionedTransaction(message), {
69415
+ addressLookupTables: feedLuts,
69416
+ type: "CRANK" /* CRANK */
69417
+ })
69418
+ );
69605
69419
  }
69606
- /**
69607
- * Creates a withdraw transaction.
69608
- *
69609
- * @param params - Parameters for the withdraw transaction
69610
- * @returns Promise resolving to a TransactionBuilderResult
69611
- *
69612
- * @see {@link makeWithdrawTx} for detailed implementation
69613
- */
69614
- async makeWithdrawTx(params) {
69615
- return makeWithdrawTx({
69616
- ...params,
69617
- marginfiAccount: this,
69618
- opts: {
69619
- ...params.opts,
69620
- overrideInferAccounts: {
69621
- authority: this.authority,
69622
- group: this.group,
69623
- ...params.opts?.overrideInferAccounts
69420
+ const transactions = [...additionalTxs, flashloanTx];
69421
+ return {
69422
+ transactions,
69423
+ actionTxIndex: transactions.length - 1,
69424
+ quoteResponse: swapQuote
69425
+ };
69426
+ }
69427
+ async function buildSwapCollateralFlashloanTx({
69428
+ program,
69429
+ marginfiAccount,
69430
+ bankMap,
69431
+ withdrawOpts,
69432
+ depositOpts,
69433
+ swapOpts,
69434
+ bankMetadataMap,
69435
+ assetShareValueMultiplierByBank,
69436
+ addressLookupTableAccounts,
69437
+ connection,
69438
+ overrideInferAccounts,
69439
+ blockhash,
69440
+ swapEngineRunner
69441
+ }) {
69442
+ const {
69443
+ withdrawBank,
69444
+ tokenProgram: withdrawTokenProgram,
69445
+ totalPositionAmount,
69446
+ withdrawAmount
69447
+ } = withdrawOpts;
69448
+ const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
69449
+ if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
69450
+ throw new Error("withdrawAmount must be greater than 0");
69451
+ }
69452
+ const actualWithdrawAmount = Math.min(withdrawAmount ?? totalPositionAmount, totalPositionAmount);
69453
+ const isFullWithdraw = isWholePosition(
69454
+ { amount: totalPositionAmount, isLending: true },
69455
+ actualWithdrawAmount,
69456
+ withdrawBank.mintDecimals
69457
+ );
69458
+ const cuRequestIxs = [
69459
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
69460
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
69461
+ ];
69462
+ let amountToDeposit;
69463
+ let swapInstructions = [];
69464
+ let setupInstructions = [];
69465
+ let swapLookupTables = [];
69466
+ let swapQuote;
69467
+ let sizeConstraintUsed = 0;
69468
+ let withdrawIxs;
69469
+ switch (withdrawOpts.withdrawBank.config.assetTag) {
69470
+ case 3 /* KAMINO */: {
69471
+ const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
69472
+ if (!reserve) {
69473
+ throw TransactionBuildingError.kaminoReserveNotFound(
69474
+ withdrawOpts.withdrawBank.address.toBase58(),
69475
+ withdrawOpts.withdrawBank.mint.toBase58(),
69476
+ withdrawOpts.withdrawBank.tokenSymbol
69477
+ );
69478
+ }
69479
+ const multiplier = assetShareValueMultiplierByBank.get(withdrawOpts.withdrawBank.address.toBase58()) ?? new BigNumber(1);
69480
+ const adjustedAmount = new BigNumber(actualWithdrawAmount).div(multiplier).times(1.0001).toNumber();
69481
+ withdrawIxs = await makeKaminoWithdrawIx3({
69482
+ program,
69483
+ bank: withdrawBank,
69484
+ bankMap,
69485
+ tokenProgram: withdrawTokenProgram,
69486
+ cTokenAmount: adjustedAmount,
69487
+ marginfiAccount,
69488
+ authority: marginfiAccount.authority,
69489
+ reserve,
69490
+ withdrawAll: isFullWithdraw,
69491
+ isSync: false,
69492
+ opts: {
69493
+ createAtas: false,
69494
+ wrapAndUnwrapSol: false,
69495
+ overrideInferAccounts
69624
69496
  }
69497
+ });
69498
+ break;
69499
+ }
69500
+ case 4 /* DRIFT */: {
69501
+ const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
69502
+ if (!driftState) {
69503
+ throw TransactionBuildingError.driftStateNotFound(
69504
+ withdrawOpts.withdrawBank.address.toBase58(),
69505
+ withdrawOpts.withdrawBank.mint.toBase58(),
69506
+ withdrawOpts.withdrawBank.tokenSymbol
69507
+ );
69625
69508
  }
69626
- });
69627
- }
69628
- /**
69629
- * Creates a Drift withdraw transaction.
69630
- *
69631
- * @param params - Parameters for the Drift withdraw transaction
69632
- * @returns Promise resolving to an ExtendedV0Transaction
69633
- *
69634
- * @see {@link makeDriftWithdrawTx} for detailed implementation
69635
- */
69636
- async makeDriftWithdrawTx(params) {
69637
- return makeDriftWithdrawTx({
69638
- ...params,
69639
- marginfiAccount: this,
69640
- opts: {
69641
- ...params.opts,
69642
- overrideInferAccounts: {
69643
- authority: this.authority,
69644
- group: this.group,
69645
- ...params.opts?.overrideInferAccounts
69509
+ withdrawIxs = await makeDriftWithdrawIx3({
69510
+ program,
69511
+ bank: withdrawOpts.withdrawBank,
69512
+ bankMap,
69513
+ tokenProgram: withdrawOpts.tokenProgram,
69514
+ amount: actualWithdrawAmount,
69515
+ marginfiAccount,
69516
+ authority: marginfiAccount.authority,
69517
+ driftSpotMarket: driftState.spotMarketState,
69518
+ userRewards: driftState.userRewards,
69519
+ withdrawAll: isFullWithdraw,
69520
+ isSync: false,
69521
+ opts: {
69522
+ createAtas: false,
69523
+ wrapAndUnwrapSol: false,
69524
+ overrideInferAccounts
69646
69525
  }
69526
+ });
69527
+ break;
69528
+ }
69529
+ case 6 /* JUPLEND */: {
69530
+ const jupLendState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.jupLendStates;
69531
+ if (!jupLendState) {
69532
+ throw TransactionBuildingError.jupLendStateNotFound(
69533
+ withdrawOpts.withdrawBank.address.toBase58(),
69534
+ withdrawOpts.withdrawBank.mint.toBase58(),
69535
+ withdrawOpts.withdrawBank.tokenSymbol
69536
+ );
69647
69537
  }
69648
- });
69538
+ withdrawIxs = await makeJuplendWithdrawIx2({
69539
+ program,
69540
+ bank: withdrawBank,
69541
+ bankMap,
69542
+ tokenProgram: withdrawTokenProgram,
69543
+ amount: actualWithdrawAmount,
69544
+ marginfiAccount,
69545
+ authority: marginfiAccount.authority,
69546
+ jupLendingState: jupLendState.jupLendingState,
69547
+ withdrawAll: isFullWithdraw,
69548
+ opts: {
69549
+ createAtas: false,
69550
+ wrapAndUnwrapSol: false,
69551
+ overrideInferAccounts
69552
+ }
69553
+ });
69554
+ break;
69555
+ }
69556
+ default: {
69557
+ withdrawIxs = await makeWithdrawIx3({
69558
+ program,
69559
+ bank: withdrawBank,
69560
+ bankMap,
69561
+ tokenProgram: withdrawTokenProgram,
69562
+ amount: actualWithdrawAmount,
69563
+ marginfiAccount,
69564
+ authority: marginfiAccount.authority,
69565
+ withdrawAll: isFullWithdraw,
69566
+ isSync: false,
69567
+ opts: {
69568
+ createAtas: false,
69569
+ wrapAndUnwrapSol: false,
69570
+ overrideInferAccounts
69571
+ }
69572
+ });
69573
+ break;
69574
+ }
69649
69575
  }
69650
- /**
69651
- * Creates a Kamino withdraw transaction.
69652
- *
69653
- * @param params - Parameters for the Kamino withdraw transaction
69654
- * @returns Promise resolving to a TransactionBuilderResult
69655
- *
69656
- * @see {@link makeKaminoWithdrawTx} for detailed implementation
69657
- */
69658
- async makeKaminoWithdrawTx(params) {
69659
- return makeKaminoWithdrawTx({
69660
- ...params,
69661
- marginfiAccount: this,
69662
- opts: {
69663
- ...params.opts,
69664
- overrideInferAccounts: {
69665
- authority: this.authority,
69666
- group: this.group,
69667
- ...params.opts?.overrideInferAccounts
69576
+ const swapNeeded = !depositBank.mint.equals(withdrawBank.mint);
69577
+ amountToDeposit = swapNeeded ? 0 : actualWithdrawAmount;
69578
+ let depositIxs;
69579
+ switch (depositBank.config.assetTag) {
69580
+ case 3 /* KAMINO */: {
69581
+ const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
69582
+ if (!reserve) {
69583
+ throw TransactionBuildingError.kaminoReserveNotFound(
69584
+ depositBank.address.toBase58(),
69585
+ depositBank.mint.toBase58(),
69586
+ depositBank.tokenSymbol
69587
+ );
69588
+ }
69589
+ depositIxs = await makeKaminoDepositIx3({
69590
+ program,
69591
+ bank: depositBank,
69592
+ tokenProgram: depositTokenProgram,
69593
+ amount: amountToDeposit,
69594
+ accountAddress: marginfiAccount.address,
69595
+ authority: marginfiAccount.authority,
69596
+ group: marginfiAccount.group,
69597
+ reserve,
69598
+ opts: {
69599
+ wrapAndUnwrapSol: false,
69600
+ overrideInferAccounts
69668
69601
  }
69602
+ });
69603
+ break;
69604
+ }
69605
+ case 4 /* DRIFT */: {
69606
+ const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
69607
+ if (!driftState) {
69608
+ throw TransactionBuildingError.driftStateNotFound(
69609
+ depositBank.address.toBase58(),
69610
+ depositBank.mint.toBase58(),
69611
+ depositBank.tokenSymbol
69612
+ );
69669
69613
  }
69614
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
69615
+ const driftOracle = driftState.spotMarketState.oracle;
69616
+ depositIxs = await makeDriftDepositIx3({
69617
+ program,
69618
+ bank: depositBank,
69619
+ tokenProgram: depositTokenProgram,
69620
+ amount: amountToDeposit,
69621
+ accountAddress: marginfiAccount.address,
69622
+ authority: marginfiAccount.authority,
69623
+ group: marginfiAccount.group,
69624
+ driftMarketIndex,
69625
+ driftOracle,
69626
+ opts: {
69627
+ wrapAndUnwrapSol: false,
69628
+ overrideInferAccounts
69629
+ }
69630
+ });
69631
+ break;
69632
+ }
69633
+ case 6 /* JUPLEND */: {
69634
+ depositIxs = await makeJuplendDepositIx2({
69635
+ program,
69636
+ bank: depositBank,
69637
+ tokenProgram: depositTokenProgram,
69638
+ amount: amountToDeposit,
69639
+ accountAddress: marginfiAccount.address,
69640
+ authority: marginfiAccount.authority,
69641
+ group: marginfiAccount.group,
69642
+ opts: {
69643
+ wrapAndUnwrapSol: false,
69644
+ overrideInferAccounts
69645
+ }
69646
+ });
69647
+ break;
69648
+ }
69649
+ default: {
69650
+ depositIxs = await makeDepositIx3({
69651
+ program,
69652
+ bank: depositBank,
69653
+ tokenProgram: depositTokenProgram,
69654
+ amount: amountToDeposit,
69655
+ accountAddress: marginfiAccount.address,
69656
+ authority: marginfiAccount.authority,
69657
+ group: marginfiAccount.group,
69658
+ opts: {
69659
+ wrapAndUnwrapSol: false,
69660
+ overrideInferAccounts
69661
+ }
69662
+ });
69663
+ break;
69664
+ }
69665
+ }
69666
+ if (swapNeeded) {
69667
+ const destinationTokenAccount = getAssociatedTokenAddressSync(
69668
+ depositBank.mint,
69669
+ marginfiAccount.authority,
69670
+ true,
69671
+ depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
69672
+ );
69673
+ const swapConstraints = await computeFlashloanSwapConstraints({
69674
+ program,
69675
+ marginfiAccount,
69676
+ bankMap,
69677
+ bankMetadataMap,
69678
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
69679
+ primaryIx: { type: "withdraw", bank: withdrawBank, tokenProgram: withdrawTokenProgram },
69680
+ secondaryIx: { type: "deposit", bank: depositBank, tokenProgram: depositTokenProgram },
69681
+ overrideInferAccounts
69682
+ });
69683
+ sizeConstraintUsed = swapConstraints.sizeConstraint;
69684
+ const runEngine = swapEngineRunner ?? runSwapEngine;
69685
+ const engineResult = await runEngine({
69686
+ inputMint: withdrawBank.mint.toBase58(),
69687
+ outputMint: depositBank.mint.toBase58(),
69688
+ amountNative: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
69689
+ inputDecimals: withdrawBank.mintDecimals,
69690
+ outputDecimals: depositBank.mintDecimals,
69691
+ ...swapEngineQuoteFieldsFromOpts(swapOpts),
69692
+ taker: marginfiAccount.authority,
69693
+ destinationTokenAccount,
69694
+ connection,
69695
+ footprint: {
69696
+ instructions: [...cuRequestIxs, ...withdrawIxs.instructions, ...depositIxs.instructions],
69697
+ luts: addressLookupTableAccounts ?? [],
69698
+ payer: marginfiAccount.authority,
69699
+ sizeConstraint: swapConstraints.sizeConstraint,
69700
+ maxSwapTotalAccounts: swapConstraints.maxSwapTotalAccounts
69701
+ },
69702
+ providers: swapEngineProvidersFromOpts(swapOpts)
69670
69703
  });
69704
+ const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
69705
+ if (!depositIxToPatch) {
69706
+ throw new Error("swap-collateral: could not locate deposit instruction for amount patching");
69707
+ }
69708
+ patchDepositAmount(depositIxToPatch, engineResult.outputAmountNative);
69709
+ swapInstructions = engineResult.swapInstructions;
69710
+ setupInstructions = engineResult.setupInstructions;
69711
+ swapLookupTables = engineResult.swapLuts;
69712
+ swapQuote = engineResult.quoteResponse;
69671
69713
  }
69672
- /**
69673
- * Creates a flash loan transaction.
69674
- *
69675
- * @param params - Parameters for the flash loan transaction
69676
- * @returns Promise resolving to flash loan transaction details
69677
- *
69678
- * @see {@link makeFlashLoanTx} for detailed implementation
69679
- */
69680
- async makeFlashLoanTx(params) {
69681
- return makeFlashLoanTx({
69682
- ...params,
69683
- marginfiAccount: this
69714
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
69715
+ const allNonFlIxs = [
69716
+ ...cuRequestIxs,
69717
+ ...withdrawIxs.instructions,
69718
+ ...swapInstructions,
69719
+ ...depositIxs.instructions
69720
+ ];
69721
+ if (swapInstructions.length > 0) {
69722
+ compileFlashloanPrecheck({
69723
+ allIxs: allNonFlIxs,
69724
+ payer: marginfiAccount.authority,
69725
+ luts,
69726
+ sizeConstraint: sizeConstraintUsed,
69727
+ swapIxCount: swapInstructions.length,
69728
+ swapLutCount: swapLookupTables.length
69729
+ });
69730
+ }
69731
+ const flashloanTx = await makeFlashLoanTx({
69732
+ program,
69733
+ marginfiAccount,
69734
+ bankMap,
69735
+ addressLookupTableAccounts: luts,
69736
+ blockhash,
69737
+ ixs: allNonFlIxs,
69738
+ isSync: false
69739
+ });
69740
+ const txSize = getTxSize(flashloanTx);
69741
+ const totalKeys = getTotalAccountKeys(flashloanTx);
69742
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
69743
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(
69744
+ txSize,
69745
+ totalKeys,
69746
+ swapOpts.swapConfig?.provider
69747
+ );
69748
+ }
69749
+ return {
69750
+ flashloanTx,
69751
+ setupInstructions,
69752
+ swapQuote,
69753
+ withdrawIxs,
69754
+ depositIxs
69755
+ };
69756
+ }
69757
+ var SECOND_LEG_ROUNDING_HEADROOM_NATIVE = 10;
69758
+ async function makeBridgedSwapCollateralTx(params) {
69759
+ const { bridgeOpts, ...directParams } = params;
69760
+ try {
69761
+ return await makeSwapCollateralTx(directParams);
69762
+ } catch (directError) {
69763
+ if (!isDecomposableSwapError(directError)) throw directError;
69764
+ const bridged = await tryBridgedCollateralSwap(directParams, bridgeOpts);
69765
+ if (bridged) return bridged;
69766
+ throw directError;
69767
+ }
69768
+ }
69769
+ async function tryBridgedCollateralSwap(params, bridgeOpts) {
69770
+ const sourceBank = params.withdrawOpts.withdrawBank;
69771
+ const destinationBank = params.depositOpts.depositBank;
69772
+ const withdrawAmount = params.withdrawOpts.withdrawAmount ?? params.withdrawOpts.totalPositionAmount;
69773
+ const { usableBridgeBanks, conflictingBridgeBanks } = selectSwapBridges({
69774
+ sourceMint: sourceBank.mint,
69775
+ destinationMint: destinationBank.mint,
69776
+ bankMap: params.bankMap,
69777
+ marginfiAccount: params.marginfiAccount,
69778
+ bridgeTokenSide: "deposit",
69779
+ bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
69780
+ });
69781
+ const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
69782
+ return tryBridgeCandidates({
69783
+ usableBridgeBanks,
69784
+ conflictingBridgeBanks,
69785
+ bridgeTokenSide: "deposit",
69786
+ abortSignal: bridgeOpts?.abortSignal,
69787
+ buildBundleThroughBridge: async (bridgeBank) => {
69788
+ const bridgeTokenProgram = await resolveTokenProgramForMint(
69789
+ bridgeBank.mint,
69790
+ params.connection,
69791
+ tokenProgramCache
69792
+ );
69793
+ const firstLeg = await makeSwapCollateralTx({
69794
+ ...sharedBridgeLegContext(params),
69795
+ withdrawOpts: {
69796
+ totalPositionAmount: params.withdrawOpts.totalPositionAmount,
69797
+ withdrawAmount,
69798
+ withdrawBank: sourceBank,
69799
+ tokenProgram: params.withdrawOpts.tokenProgram
69800
+ },
69801
+ depositOpts: { depositBank: bridgeBank, tokenProgram: bridgeTokenProgram }
69802
+ });
69803
+ if (!firstLeg.quoteResponse) return null;
69804
+ const bridgeMinOutNative = Number(firstLeg.quoteResponse.otherAmountThreshold);
69805
+ const secondLegAmountNative = bridgeMinOutNative - SECOND_LEG_ROUNDING_HEADROOM_NATIVE;
69806
+ if (secondLegAmountNative <= 0) return null;
69807
+ const secondLegAmountUi = nativeToUi(secondLegAmountNative, bridgeBank.mintDecimals);
69808
+ const hasBridgeDeposit = params.marginfiAccount.balances.some(
69809
+ (b) => b.active && b.bankPk.equals(bridgeBank.address) && b.assetShares.gt(0)
69810
+ );
69811
+ const result = await composeBridgedSwap({
69812
+ firstLeg,
69813
+ // The second leg builds against the first leg's projected effect.
69814
+ buildSecondLeg: (projectedAccount) => makeSwapCollateralTx({
69815
+ ...sharedBridgeLegContext(params),
69816
+ marginfiAccount: projectedAccount,
69817
+ withdrawOpts: {
69818
+ totalPositionAmount: hasBridgeDeposit ? nativeToUi(bridgeMinOutNative, bridgeBank.mintDecimals) : secondLegAmountUi,
69819
+ withdrawAmount: secondLegAmountUi,
69820
+ withdrawBank: bridgeBank,
69821
+ tokenProgram: bridgeTokenProgram
69822
+ },
69823
+ depositOpts: params.depositOpts
69824
+ }),
69825
+ marginfiAccount: params.marginfiAccount,
69826
+ program: params.program,
69827
+ banksMap: params.bankMap,
69828
+ assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
69829
+ feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
69830
+ maxBundleTxs: bridgeOpts?.maxBundleTxs
69831
+ });
69832
+ if (!result) return null;
69833
+ return {
69834
+ transactions: result.transactions,
69835
+ actionTxIndex: result.transactions.length - 1,
69836
+ quoteResponse: mergeBridgeQuotes(result.firstLegQuote, result.secondLegQuote),
69837
+ bridgeMint: bridgeBank.mint
69838
+ };
69839
+ }
69840
+ });
69841
+ }
69842
+ var DEFAULT_ROLL_SLIPPAGE_BPS = 50;
69843
+ var TRADE_PT_EVENT_AMOUNT_OUT_OFFSET = 138;
69844
+ var MERGE_EVENT_AMOUNT_SY_OUT_OFFSET = 296;
69845
+ async function makeRollPtTx(params) {
69846
+ const {
69847
+ program,
69848
+ marginfiAccount,
69849
+ connection,
69850
+ bankMap,
69851
+ oraclePrices,
69852
+ withdrawOpts,
69853
+ depositOpts,
69854
+ rollOpts,
69855
+ assetShareValueMultiplierByBank,
69856
+ addressLookupTableAccounts,
69857
+ crossbarUrl
69858
+ } = params;
69859
+ if (!rollOpts.maturedMarket && !rollOpts.maturedVault) {
69860
+ throw new Error("roll-pt: rollOpts.maturedMarket or maturedVault is required");
69861
+ }
69862
+ const merge = await resolveExponentMergeContext({
69863
+ connection,
69864
+ owner: marginfiAccount.authority,
69865
+ market: rollOpts.maturedMarket,
69866
+ vault: rollOpts.maturedVault,
69867
+ ptYtTokenProgram: withdrawOpts.tokenProgram,
69868
+ syTokenProgram: rollOpts.syTokenProgram
69869
+ });
69870
+ const clmm = await resolveExponentClmmTradePtContext({
69871
+ connection,
69872
+ owner: marginfiAccount.authority,
69873
+ market: rollOpts.successorMarket,
69874
+ ptTokenProgram: depositOpts.tokenProgram,
69875
+ syTokenProgram: rollOpts.syTokenProgram
69876
+ });
69877
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
69878
+ const setupIxs = await makeSetupIx({
69879
+ connection,
69880
+ authority: marginfiAccount.authority,
69881
+ tokens: [
69882
+ { mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
69883
+ { mint: merge.mergeAccounts.mintYt, tokenProgram: withdrawOpts.tokenProgram },
69884
+ { mint: merge.underlying.mint, tokenProgram: merge.underlying.tokenProgram },
69885
+ { mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
69886
+ ]
69887
+ });
69888
+ const { flashloanTx, swapQuote, withdrawIxs, depositIxs } = await buildRollPtFlashloanTx({
69889
+ params,
69890
+ merge,
69891
+ clmm,
69892
+ setupIxs,
69893
+ blockhash
69894
+ });
69895
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
69896
+ marginfiAccount,
69897
+ bankMap,
69898
+ oraclePrices,
69899
+ assetShareValueMultiplierByBank,
69900
+ instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
69901
+ program,
69902
+ connection,
69903
+ crossbarUrl
69904
+ });
69905
+ const additionalTxs = [];
69906
+ if (setupIxs.length > 0) {
69907
+ const txs = splitInstructionsToFitTransactions([], setupIxs, {
69908
+ blockhash,
69909
+ payerKey: marginfiAccount.authority,
69910
+ luts: addressLookupTableAccounts ?? []
69684
69911
  });
69912
+ additionalTxs.push(
69913
+ ...txs.map(
69914
+ (tx) => addTransactionMetadata(tx, {
69915
+ type: "CREATE_ATA" /* CREATE_ATA */,
69916
+ addressLookupTables: addressLookupTableAccounts
69917
+ })
69918
+ )
69919
+ );
69685
69920
  }
69686
- };
69687
-
69688
- // src/services/account/actions/bridge-swap.ts
69689
- var MAX_BRIDGED_BUNDLE_TXS = 5;
69690
- function classifyTxs(txs) {
69691
- const out = { setups: [], cranks: [], flashloans: [] };
69692
- for (const tx of txs) {
69693
- if (tx.type === "CREATE_ATA" /* CREATE_ATA */) out.setups.push(tx);
69694
- else if (tx.type === "CRANK" /* CRANK */) out.cranks.push(tx);
69695
- else out.flashloans.push(tx);
69921
+ if (updateFeedIxs.length > 0) {
69922
+ const message = new TransactionMessage({
69923
+ payerKey: marginfiAccount.authority,
69924
+ recentBlockhash: blockhash,
69925
+ instructions: updateFeedIxs
69926
+ }).compileToV0Message(feedLuts);
69927
+ additionalTxs.push(
69928
+ addTransactionMetadata(new VersionedTransaction(message), {
69929
+ addressLookupTables: feedLuts,
69930
+ type: "CRANK" /* CRANK */
69931
+ })
69932
+ );
69696
69933
  }
69697
- return out;
69698
- }
69699
- function ixIdentity(ix) {
69700
- const keys = ix.keys.map((k) => k.pubkey.toBase58()).join(",");
69701
- return `${ix.programId.toBase58()}|${keys}|${Buffer.from(ix.data).toString("base64")}`;
69934
+ const transactions = [...additionalTxs, flashloanTx];
69935
+ return {
69936
+ transactions,
69937
+ actionTxIndex: transactions.length - 1,
69938
+ quoteResponse: swapQuote
69939
+ };
69702
69940
  }
69703
- function mergeSetupTxs(txs, payer, blockhash) {
69704
- if (txs.length === 0) return null;
69705
- if (txs.length === 1) return txs[0];
69706
- const lutMap = /* @__PURE__ */ new Map();
69707
- const seen = /* @__PURE__ */ new Set();
69708
- const ixs = [];
69709
- for (const tx of txs) {
69710
- const luts2 = tx.addressLookupTables ?? [];
69711
- luts2.forEach((l) => lutMap.set(l.key.toBase58(), l));
69712
- const msg = decompileV0Transaction(tx, luts2);
69713
- for (const ix of msg.instructions) {
69714
- const id = ixIdentity(ix);
69715
- if (seen.has(id)) continue;
69716
- seen.add(id);
69717
- ixs.push(ix);
69718
- }
69941
+ async function buildRollPtFlashloanTx({
69942
+ params,
69943
+ merge,
69944
+ clmm,
69945
+ setupIxs,
69946
+ blockhash
69947
+ }) {
69948
+ const {
69949
+ program,
69950
+ marginfiAccount,
69951
+ bankMap,
69952
+ withdrawOpts,
69953
+ depositOpts,
69954
+ bankMetadataMap,
69955
+ connection,
69956
+ addressLookupTableAccounts,
69957
+ overrideInferAccounts,
69958
+ rollOpts
69959
+ } = params;
69960
+ const { withdrawBank, tokenProgram: withdrawTokenProgram, totalPositionAmount, withdrawAmount } = withdrawOpts;
69961
+ const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
69962
+ const authority = marginfiAccount.authority;
69963
+ if (withdrawAmount !== void 0 && withdrawAmount <= 0) {
69964
+ throw new Error("withdrawAmount must be greater than 0");
69719
69965
  }
69720
- const luts = [...lutMap.values()];
69721
- const split = splitInstructionsToFitTransactions([], ixs, { blockhash, payerKey: payer, luts });
69722
- if (split.length !== 1) return null;
69723
- return addTransactionMetadata(split[0], {
69724
- type: "CREATE_ATA" /* CREATE_ATA */,
69725
- addressLookupTables: luts
69966
+ const actualWithdrawAmount = Math.min(withdrawAmount ?? totalPositionAmount, totalPositionAmount);
69967
+ const isFullWithdraw = isWholePosition(
69968
+ { amount: totalPositionAmount, isLending: true },
69969
+ actualWithdrawAmount,
69970
+ withdrawBank.mintDecimals
69971
+ );
69972
+ const withdrawNative = BigInt(
69973
+ uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toString()
69974
+ );
69975
+ const cuRequestIxs = [
69976
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
69977
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
69978
+ ];
69979
+ const withdrawIxs = await makeWithdrawIx3({
69980
+ program,
69981
+ bank: withdrawBank,
69982
+ bankMap,
69983
+ tokenProgram: withdrawTokenProgram,
69984
+ amount: actualWithdrawAmount,
69985
+ marginfiAccount,
69986
+ authority,
69987
+ withdrawAll: isFullWithdraw,
69988
+ isSync: false,
69989
+ opts: { createAtas: false, wrapAndUnwrapSol: false, overrideInferAccounts }
69726
69990
  });
69727
- }
69728
- function projectAccountAfterFirstLeg(account, firstLegFlashloanTxs, program, banksMap, multipliers) {
69729
- const ixs = [];
69730
- for (const tx of firstLegFlashloanTxs) {
69731
- const luts = tx.addressLookupTables ?? [];
69732
- ixs.push(...decompileV0Transaction(tx, luts).instructions);
69991
+ const mergeIx = makeExponentMergeIx(merge.mergeAccounts, withdrawNative);
69992
+ const depositIxs = await makeDepositIx3({
69993
+ program,
69994
+ bank: depositBank,
69995
+ tokenProgram: depositTokenProgram,
69996
+ amount: 0,
69997
+ accountAddress: marginfiAccount.address,
69998
+ authority,
69999
+ group: marginfiAccount.group,
70000
+ opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
70001
+ });
70002
+ let luts;
70003
+ if (rollOpts.lookupTable) {
70004
+ const fetched = (await connection.getAddressLookupTable(rollOpts.lookupTable)).value;
70005
+ if (!fetched) {
70006
+ throw new Error(`roll-pt: PT-roll lookup table not found: ${rollOpts.lookupTable.toBase58()}`);
70007
+ }
70008
+ luts = [fetched, merge.addressLookupTable, clmm.addressLookupTable];
70009
+ } else {
70010
+ luts = [
70011
+ ...addressLookupTableAccounts ?? [],
70012
+ merge.addressLookupTable,
70013
+ clmm.addressLookupTable
70014
+ ];
69733
70015
  }
69734
- const { projectedBalances } = computeProjectedActiveBalancesNoCpi({
69735
- account,
69736
- instructions: ixs,
70016
+ const redeemIxs = [...setupIxs, ...cuRequestIxs, ...withdrawIxs.instructions, mergeIx];
70017
+ const mergeReturn = await simulateRollReturn({
69737
70018
  program,
69738
- banksMap,
69739
- assetShareValueMultiplierByBank: multipliers
70019
+ marginfiAccount,
70020
+ bankMap,
70021
+ connection,
70022
+ blockhash,
70023
+ luts,
70024
+ ixs: redeemIxs,
70025
+ programId: EXPONENT_CORE_PROGRAM_ID,
70026
+ label: "merge"
69740
70027
  });
69741
- return new MarginfiAccount(
69742
- account.address,
69743
- account.group,
69744
- account.authority,
69745
- projectedBalances.map((b) => Balance.fromBalanceType(b)),
69746
- account.accountFlags,
69747
- account.emissionsDestinationAccount,
69748
- account.healthCache
70028
+ const syExact = readReturnU64(mergeReturn, MERGE_EVENT_AMOUNT_SY_OUT_OFFSET, "merge amount_sy_out");
70029
+ if (syExact <= 0n) {
70030
+ throw new Error("roll-pt: merge would redeem 0 SY (empty/invalid matured vault state)");
70031
+ }
70032
+ const exactPtOut = await quoteClmmTradeOut({
70033
+ connection,
70034
+ clmm,
70035
+ amountInSyNative: syExact,
70036
+ payer: authority
70037
+ });
70038
+ const slippageBps = rollOpts.slippageBps ?? DEFAULT_ROLL_SLIPPAGE_BPS;
70039
+ const minPtOut = exactPtOut * BigInt(1e4 - slippageBps) / 10000n;
70040
+ if (minPtOut <= 0n) {
70041
+ throw new Error("roll-pt: quoted PT out is 0 (insufficient CLMM liquidity for this size)");
70042
+ }
70043
+ const tradeIx = makeExponentClmmTradePtIx(
70044
+ clmm.tradePtAccounts,
70045
+ exponentClmmBuyPtArgs({ amountInSyNative: syExact, minPtOutNative: minPtOut })
69749
70046
  );
69750
- }
69751
- function composeBundle(firstLegTxs, secondLegTxs, payer, blockhash, maxBundleTxs) {
69752
- const c1 = classifyTxs(firstLegTxs);
69753
- const c2 = classifyTxs(secondLegTxs);
69754
- const mergedSetup = mergeSetupTxs([...c1.setups, ...c2.setups], payer, blockhash);
69755
- if ([...c1.setups, ...c2.setups].length > 0 && !mergedSetup) return null;
69756
- const result = [
69757
- ...mergedSetup ? [mergedSetup] : [],
69758
- ...c1.cranks,
69759
- ...c1.flashloans,
69760
- // firstLegFL(s)
69761
- ...c2.cranks,
69762
- ...c2.flashloans
69763
- // secondLegFL(s)
70047
+ const depositIxToPatch = depositIxs.instructions.find(isDepositIx);
70048
+ if (!depositIxToPatch) {
70049
+ throw new Error("roll-pt: could not locate deposit instruction for amount patching");
70050
+ }
70051
+ patchDepositAmount(depositIxToPatch, new BN9(minPtOut.toString()));
70052
+ const allNonFlIxs = [
70053
+ ...cuRequestIxs,
70054
+ ...withdrawIxs.instructions,
70055
+ mergeIx,
70056
+ tradeIx,
70057
+ ...depositIxs.instructions
69764
70058
  ];
69765
- if (result.length > maxBundleTxs) return null;
69766
- return result;
69767
- }
69768
- function compoundQuoteRisk(firstLeg, secondLeg) {
69769
- const compound = (a, b) => {
69770
- if (a == null && b == null) return void 0;
69771
- const x = Number(a ?? 0);
69772
- const y = Number(b ?? 0);
69773
- return String(1 - (1 - x) * (1 - y));
69774
- };
69775
- return {
69776
- slippageBps: Math.round(
69777
- (1 - (1 - firstLeg.slippageBps / 1e4) * (1 - secondLeg.slippageBps / 1e4)) * 1e4
69778
- ),
69779
- priceImpactPct: compound(firstLeg.priceImpactPct, secondLeg.priceImpactPct)
69780
- };
69781
- }
69782
- function mergeBridgeQuotes(firstLeg, secondLeg) {
69783
- return {
69784
- inAmount: firstLeg.inAmount,
69785
- outAmount: secondLeg.outAmount,
69786
- otherAmountThreshold: secondLeg.otherAmountThreshold,
69787
- ...compoundQuoteRisk(firstLeg, secondLeg),
69788
- provider: firstLeg.provider
69789
- };
69790
- }
69791
- function mergeBridgeQuotesDebt(firstLeg, secondLeg) {
69792
- return {
69793
- inAmount: firstLeg.outAmount,
69794
- outAmount: secondLeg.inAmount,
69795
- otherAmountThreshold: secondLeg.inAmount,
69796
- ...compoundQuoteRisk(firstLeg, secondLeg),
69797
- provider: firstLeg.provider
69798
- };
69799
- }
69800
- function mergeBridgeQuotesLoop(firstLeg, secondLeg) {
69801
- return {
69802
- inAmount: secondLeg.inAmount,
69803
- outAmount: firstLeg.outAmount,
69804
- otherAmountThreshold: firstLeg.otherAmountThreshold,
69805
- ...compoundQuoteRisk(firstLeg, secondLeg),
69806
- provider: firstLeg.provider
69807
- };
69808
- }
69809
- function blockhashOf(leg) {
69810
- const tx = leg.transactions[0];
69811
- return tx ? tx.message.recentBlockhash : PublicKey.default.toBase58();
69812
- }
69813
- async function composeBridgedSwap(params) {
69814
- const {
69815
- firstLeg,
69816
- buildSecondLeg,
70059
+ const { sizeConstraint } = computeFlashLoanNonSwapBudget({
70060
+ program,
69817
70061
  marginfiAccount,
70062
+ bankMap,
70063
+ addressLookupTableAccounts: luts,
70064
+ ixs: allNonFlIxs
70065
+ });
70066
+ compileFlashloanPrecheck({
70067
+ allIxs: allNonFlIxs,
70068
+ payer: authority,
70069
+ luts,
70070
+ sizeConstraint,
70071
+ swapIxCount: 0,
70072
+ swapLutCount: 0
70073
+ });
70074
+ const flashloanTx = await makeFlashLoanTx({
69818
70075
  program,
69819
- banksMap,
69820
- assetShareValueMultiplierByBank,
69821
- feePayer,
69822
- maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS
69823
- } = params;
69824
- if (!firstLeg.quoteResponse) return null;
69825
- const projectedAccount = projectAccountAfterFirstLeg(
69826
70076
  marginfiAccount,
69827
- classifyTxs(firstLeg.transactions).flashloans,
70077
+ bankMap,
70078
+ addressLookupTableAccounts: luts,
70079
+ blockhash,
70080
+ ixs: allNonFlIxs,
70081
+ isSync: false
70082
+ });
70083
+ const txSize = getTxSize(flashloanTx);
70084
+ const totalKeys = getTotalAccountKeys(flashloanTx);
70085
+ if (txSize > MAX_TX_SIZE || totalKeys > MAX_ACCOUNT_LOCKS) {
70086
+ throw TransactionBuildingError.swapSizeExceededPositionSwap(txSize, totalKeys, void 0);
70087
+ }
70088
+ const swapQuote = {
70089
+ inAmount: syExact.toString(),
70090
+ outAmount: exactPtOut.toString(),
70091
+ otherAmountThreshold: minPtOut.toString(),
70092
+ slippageBps
70093
+ };
70094
+ return { flashloanTx, swapQuote, withdrawIxs, depositIxs };
70095
+ }
70096
+ async function simulateRollReturn({
70097
+ program,
70098
+ marginfiAccount,
70099
+ bankMap,
70100
+ connection,
70101
+ blockhash,
70102
+ luts,
70103
+ ixs,
70104
+ programId,
70105
+ label
70106
+ }) {
70107
+ const quoteTx = await makeFlashLoanTx({
69828
70108
  program,
69829
- banksMap,
69830
- assetShareValueMultiplierByBank
70109
+ marginfiAccount,
70110
+ bankMap,
70111
+ addressLookupTableAccounts: luts,
70112
+ blockhash,
70113
+ ixs,
70114
+ isSync: false
70115
+ });
70116
+ const sim = await connection.simulateTransaction(quoteTx, {
70117
+ sigVerify: false,
70118
+ replaceRecentBlockhash: true
70119
+ });
70120
+ const logs = sim.value.logs ?? [];
70121
+ if (process.env.ROLL_DEBUG) {
70122
+ console.error(
70123
+ `[roll ${label} sim] err:`,
70124
+ JSON.stringify(sim.value.err),
70125
+ "returnData:",
70126
+ JSON.stringify(sim.value.returnData),
70127
+ "logsLen:",
70128
+ logs.length,
70129
+ "truncated:",
70130
+ logs.some((l) => l.includes("truncated"))
70131
+ );
70132
+ }
70133
+ const prefix = `Program return: ${programId.toBase58()} `;
70134
+ const line = [...logs].reverse().find((l) => l.startsWith(prefix));
70135
+ if (!line) {
70136
+ throw new Error(
70137
+ `roll-pt: could not read ${label} return data from quote simulation (err=${JSON.stringify(
70138
+ sim.value.err
70139
+ )})`
70140
+ );
70141
+ }
70142
+ return Buffer.from(line.slice(prefix.length), "base64");
70143
+ }
70144
+ function readReturnU64(data, offset, what) {
70145
+ if (data.length < offset + 8) {
70146
+ throw new Error(`roll-pt: ${what} return data too short (${data.length} bytes)`);
70147
+ }
70148
+ return data.readBigUInt64LE(offset);
70149
+ }
70150
+ async function quoteClmmTradeOut({
70151
+ connection,
70152
+ clmm,
70153
+ amountInSyNative,
70154
+ payer
70155
+ }) {
70156
+ const excluded = /* @__PURE__ */ new Set([
70157
+ clmm.tradePtAccounts.tokenSyEscrow.toBase58(),
70158
+ clmm.tradePtAccounts.tokenFeeTreasurySy.toBase58()
70159
+ ]);
70160
+ const largest = await connection.getTokenLargestAccounts(clmm.sy.mint);
70161
+ const funded = largest.value.find(
70162
+ (a) => !excluded.has(a.address.toBase58()) && BigInt(a.amount) >= amountInSyNative
69831
70163
  );
69832
- const secondLeg = await buildSecondLeg(projectedAccount);
69833
- if (!secondLeg.quoteResponse) return null;
69834
- const transactions = composeBundle(
69835
- firstLeg.transactions,
69836
- secondLeg.transactions,
69837
- feePayer,
69838
- blockhashOf(firstLeg),
69839
- maxBundleTxs
70164
+ if (!funded) {
70165
+ throw new Error(
70166
+ "roll-pt: no SY holder large enough to quote the buy \u2014 the roll size exceeds available CLMM liquidity for this pair"
70167
+ );
70168
+ }
70169
+ const parsed = await connection.getParsedAccountInfo(funded.address);
70170
+ const info = parsed.value?.data?.parsed?.info;
70171
+ if (!info?.owner) throw new Error("roll-pt: could not resolve the quote SY holder's owner");
70172
+ const trader = new PublicKey(info.owner);
70173
+ const ptTokenProgram = clmm.pt.tokenProgram ?? TOKEN_PROGRAM_ID;
70174
+ const tokenPtTrader = getAssociatedTokenAddressSync(clmm.pt.mint, trader, true, ptTokenProgram);
70175
+ const quoteIx = makeExponentClmmTradePtIx(
70176
+ { ...clmm.tradePtAccounts, trader, tokenSyTrader: funded.address, tokenPtTrader },
70177
+ exponentClmmBuyPtArgs({ amountInSyNative, minPtOutNative: 1n })
69840
70178
  );
69841
- if (!transactions) return null;
69842
- return { transactions, firstLegQuote: firstLeg.quoteResponse, secondLegQuote: secondLeg.quoteResponse };
70179
+ const createPtAta = createAssociatedTokenAccountIdempotentInstruction(
70180
+ payer,
70181
+ tokenPtTrader,
70182
+ trader,
70183
+ clmm.pt.mint,
70184
+ ptTokenProgram
70185
+ );
70186
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
70187
+ const message = new TransactionMessage({
70188
+ payerKey: payer,
70189
+ recentBlockhash: blockhash,
70190
+ instructions: [createPtAta, quoteIx]
70191
+ }).compileToV0Message([clmm.addressLookupTable]);
70192
+ const sim = await connection.simulateTransaction(new VersionedTransaction(message), {
70193
+ sigVerify: false,
70194
+ replaceRecentBlockhash: true
70195
+ });
70196
+ const rd = sim.value.returnData;
70197
+ if (process.env.ROLL_DEBUG) {
70198
+ console.error("[roll trade quote] err:", JSON.stringify(sim.value.err), "returnData?", !!rd);
70199
+ }
70200
+ if (!rd?.data || rd.programId !== EXPONENT_CLMM_PROGRAM_ID.toBase58()) {
70201
+ throw new Error(
70202
+ `roll-pt: CLMM trade quote produced no return data (err=${JSON.stringify(sim.value.err)})`
70203
+ );
70204
+ }
70205
+ const data = Buffer.from(rd.data[0], rd.data[1]);
70206
+ return readReturnU64(data, TRADE_PT_EVENT_AMOUNT_OUT_OFFSET, "trade_pt amount_out");
69843
70207
  }
69844
70208
  var MAX_BALANCES = 16;
69845
70209
  var DEFAULT_MAX_TRANSFER_POSITIONS = 5;
@@ -71322,30 +71686,95 @@ function patchDepositAmount(ix, amountNative) {
71322
71686
  }
71323
71687
 
71324
71688
  // src/services/account/utils/bridge.utils.ts
71325
- function accountConflictsWithBridge(account, bankPk, side) {
71326
- const balance = account.balances.find((b) => b.active && b.bankPk.equals(bankPk));
71689
+ function accountConflictsWithBridgeBank(marginfiAccount, bridgeBankPk, bridgeTokenSide) {
71690
+ const balance = marginfiAccount.balances.find((b) => b.active && b.bankPk.equals(bridgeBankPk));
71327
71691
  if (!balance) return false;
71328
- return side === "deposit" ? balance.liabilityShares.gt(0) : balance.assetShares.gt(0);
71692
+ return bridgeTokenSide === "deposit" ? balance.liabilityShares.gt(0) : balance.assetShares.gt(0);
71329
71693
  }
71330
- function resolveBridgeBanks(params) {
71331
- const { orderedBridgeMints, banks, marginfiAccount, side } = params;
71332
- const passesSideFilter = side === "borrow" ? isStandardBorrowable : isStandardDepositable;
71333
- const bridges = [];
71334
- const conflicts = [];
71694
+ function resolveBridgeCandidateBanks(params) {
71695
+ const { prioritizedBridgeCandidateMints, groupBanks, marginfiAccount, bridgeTokenSide } = params;
71696
+ const passesSideFilter = bridgeTokenSide === "borrow" ? isStandardBorrowable : isStandardDepositable;
71697
+ const usableBridgeBanks = [];
71698
+ const conflictingBridgeBanks = [];
71335
71699
  const seenMints = /* @__PURE__ */ new Set();
71336
- for (const mint of orderedBridgeMints) {
71700
+ for (const mint of prioritizedBridgeCandidateMints) {
71337
71701
  const mintKey = mint.toBase58();
71338
71702
  if (seenMints.has(mintKey)) continue;
71339
71703
  seenMints.add(mintKey);
71340
- const bank = banks.find((b) => b.mint.equals(mint) && passesSideFilter(b));
71704
+ const bank = groupBanks.find((b) => b.mint.equals(mint) && passesSideFilter(b));
71341
71705
  if (!bank) continue;
71342
- if (accountConflictsWithBridge(marginfiAccount, bank.address, side)) {
71343
- conflicts.push(bank);
71706
+ if (accountConflictsWithBridgeBank(marginfiAccount, bank.address, bridgeTokenSide)) {
71707
+ conflictingBridgeBanks.push(bank);
71344
71708
  } else {
71345
- bridges.push(bank);
71709
+ usableBridgeBanks.push(bank);
71710
+ }
71711
+ }
71712
+ return { usableBridgeBanks, conflictingBridgeBanks };
71713
+ }
71714
+
71715
+ // src/services/account/utils/bridge-routing.utils.ts
71716
+ var DEFAULT_BRIDGE_MINTS = [USDC_MINT, WSOL_MINT, USDT_MINT];
71717
+ async function resolveTokenProgramForMint(mint, connection, tokenProgramCacheByMint) {
71718
+ const mintKey = mint.toBase58();
71719
+ const cached = tokenProgramCacheByMint.get(mintKey);
71720
+ if (cached) return cached;
71721
+ const owner = (await connection.getAccountInfo(mint))?.owner ?? TOKEN_PROGRAM_ID;
71722
+ tokenProgramCacheByMint.set(mintKey, owner);
71723
+ return owner;
71724
+ }
71725
+ function selectSwapBridges(args) {
71726
+ const prioritizedCandidateMints = (args.bridgeCandidateMints ?? DEFAULT_BRIDGE_MINTS).filter(
71727
+ (mint) => !mint.equals(args.sourceMint) && !mint.equals(args.destinationMint)
71728
+ );
71729
+ return resolveBridgeCandidateBanks({
71730
+ prioritizedBridgeCandidateMints: prioritizedCandidateMints,
71731
+ groupBanks: [...args.bankMap.values()],
71732
+ marginfiAccount: args.marginfiAccount,
71733
+ bridgeTokenSide: args.bridgeTokenSide
71734
+ });
71735
+ }
71736
+ function isAbortError(e) {
71737
+ return e instanceof DOMException && e.name === "AbortError";
71738
+ }
71739
+ async function tryBridgeCandidates(args) {
71740
+ for (const bridgeBank of args.usableBridgeBanks) {
71741
+ if (args.abortSignal?.aborted) {
71742
+ throw new DOMException("Operation was aborted", "AbortError");
71743
+ }
71744
+ try {
71745
+ const result = await args.buildBundleThroughBridge(bridgeBank);
71746
+ if (result) return result;
71747
+ } catch (e) {
71748
+ if (isAbortError(e)) throw e;
71346
71749
  }
71347
71750
  }
71348
- return { bridges, conflicts };
71751
+ if (args.usableBridgeBanks.length === 0 && args.conflictingBridgeBanks.length > 0) {
71752
+ throw TransactionBuildingError.bridgeConflict(
71753
+ args.conflictingBridgeBanks.map((bank) => ({
71754
+ bankAddress: bank.address.toBase58(),
71755
+ mint: bank.mint.toBase58(),
71756
+ symbol: bank.tokenSymbol
71757
+ })),
71758
+ args.bridgeTokenSide
71759
+ );
71760
+ }
71761
+ return null;
71762
+ }
71763
+ function sharedBridgeLegContext(params) {
71764
+ return {
71765
+ program: params.program,
71766
+ marginfiAccount: params.marginfiAccount,
71767
+ connection: params.connection,
71768
+ bankMap: params.bankMap,
71769
+ oraclePrices: params.oraclePrices,
71770
+ bankMetadataMap: params.bankMetadataMap,
71771
+ assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
71772
+ swapOpts: params.swapOpts,
71773
+ addressLookupTableAccounts: params.addressLookupTableAccounts,
71774
+ overrideInferAccounts: params.overrideInferAccounts,
71775
+ crossbarUrl: params.crossbarUrl,
71776
+ swapEngineRunner: params.swapEngineRunner
71777
+ };
71349
71778
  }
71350
71779
 
71351
71780
  // src/services/price/utils/smart-crank.utils.ts
@@ -75228,6 +75657,82 @@ var MarginfiAccountWrapper = class {
75228
75657
  };
75229
75658
  return this.account.makeSwapDebtTx(fullParams);
75230
75659
  }
75660
+ /**
75661
+ * Creates a loop (leverage) transaction with a transparent bridged (double-hop) fallback and
75662
+ * auto-injected client data.
75663
+ *
75664
+ * One call: tries the direct {@link makeLoopTx} first; if its borrow→deposit swap can't fit one
75665
+ * transaction or has no route, it loops the deposit asset against a value-equivalent borrow of a
75666
+ * bridge token (USDC/wSOL/USDT by default, override via `bridgeOpts.bridgeCandidateMints`) and
75667
+ * debt-swaps that bridge debt to the requested borrow asset — one atomic Jito bundle.
75668
+ * `result.bridgeMint` is set only when the bridged path was used.
75669
+ *
75670
+ * Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
75671
+ * addressLookupTables, assetShareValueMultiplierByBank
75672
+ *
75673
+ * @param params - Loop parameters (user provides: connection, depositOpts, borrowOpts, swapOpts, bridgeOpts?, etc.)
75674
+ */
75675
+ async makeBridgedLoopTx(params) {
75676
+ return this.account.makeBridgedLoopTx({
75677
+ ...params,
75678
+ program: this.client.program,
75679
+ bankMap: this.client.bankMap,
75680
+ oraclePrices: this.client.oraclePriceByBank,
75681
+ bankMetadataMap: this.client.bankIntegrationMap,
75682
+ addressLookupTableAccounts: this.client.addressLookupTables,
75683
+ assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank
75684
+ });
75685
+ }
75686
+ /**
75687
+ * Creates a collateral-swap transaction with a transparent bridged (double-hop) fallback and
75688
+ * auto-injected client data.
75689
+ *
75690
+ * One call: tries the direct {@link makeSwapCollateralTx} first; if the swap `A → C` can't fit
75691
+ * one transaction or has no route, it decomposes into `A → bridge` + `bridge → C` through a
75692
+ * bridge token, composed as one atomic Jito bundle. `result.bridgeMint` is set only when the
75693
+ * bridged path was used.
75694
+ *
75695
+ * Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
75696
+ * addressLookupTables, assetShareValueMultiplierByBank
75697
+ *
75698
+ * @param params - Swap collateral parameters (user provides: connection, withdrawOpts, depositOpts, swapOpts, bridgeOpts?, etc.)
75699
+ */
75700
+ async makeBridgedSwapCollateralTx(params) {
75701
+ return this.account.makeBridgedSwapCollateralTx({
75702
+ ...params,
75703
+ program: this.client.program,
75704
+ bankMap: this.client.bankMap,
75705
+ oraclePrices: this.client.oraclePriceByBank,
75706
+ bankMetadataMap: this.client.bankIntegrationMap,
75707
+ addressLookupTableAccounts: this.client.addressLookupTables,
75708
+ assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank
75709
+ });
75710
+ }
75711
+ /**
75712
+ * Creates a debt-swap transaction with a transparent bridged (double-hop) fallback and
75713
+ * auto-injected client data.
75714
+ *
75715
+ * One call: tries the direct {@link makeSwapDebtTx} first; if the swap `A → C` can't fit one
75716
+ * transaction or has no route, the first leg repays A by borrowing a bridge token and the second
75717
+ * leg repays exactly that bridge debt while borrowing C — one atomic Jito bundle.
75718
+ * `result.bridgeMint` is set only when the bridged path was used.
75719
+ *
75720
+ * Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
75721
+ * addressLookupTables, assetShareValueMultiplierByBank
75722
+ *
75723
+ * @param params - Swap debt parameters (user provides: connection, repayOpts, borrowOpts, swapOpts, bridgeOpts?, etc.)
75724
+ */
75725
+ async makeBridgedSwapDebtTx(params) {
75726
+ return this.account.makeBridgedSwapDebtTx({
75727
+ ...params,
75728
+ program: this.client.program,
75729
+ bankMap: this.client.bankMap,
75730
+ oraclePrices: this.client.oraclePriceByBank,
75731
+ bankMetadataMap: this.client.bankIntegrationMap,
75732
+ addressLookupTableAccounts: this.client.addressLookupTables,
75733
+ assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank
75734
+ });
75735
+ }
75231
75736
  /**
75232
75737
  * Creates a deposit transaction with auto-injected client data.
75233
75738
  *
@@ -75985,6 +76490,6 @@ var EmodeSettings = class _EmodeSettings {
75985
76490
  }
75986
76491
  };
75987
76492
 
75988
- export { ADDRESS_LOOKUP_TABLE_FOR_GROUP, ADDRESS_LOOKUP_TABLE_FOR_GROUP_NATIVE_STAKE, ADDRESS_LOOKUP_TABLE_FOR_SWAP, AccountFlags, AccountType, AssetTag, BUNDLE_TX_SIZE, Balance, Bank, BankConfig, BankConfigFlag, BankVaultType, DEFAULT_CROSSBAR_URL, DEFAULT_FALLBACK_CROSSBAR_URL, DEFAULT_ORACLE_MAX_AGE, DEFAULT_REPAY_ALL_EXTRA_BUFFER_BPS, DISABLED_FLAG, EMPTY_HEALTH_CACHE, EmodeEntryFlags, EmodeFlags, EmodeImpactStatus, EmodeSettings, EmodeTag, FLASHLOAN_ENABLED_FLAG, HOURS_PER_YEAR, HealthCache, HealthCacheFlags, HealthCacheSimulationError, HealthCacheStatus, JUPITER_V6_PROGRAM, JUP_SWAP_LUT_PROGRAM_AUTHORITY_INDEX, LST_MINT, MARGINFI_IDL, MARGINFI_PROGRAM, MARGINFI_PROGRAM_STAGING, MARGINFI_PROGRAM_STAGING_ALT, MARGINFI_SPONSORED_SHARD_ID, MAX_ACCOUNT_LOCKS, MAX_CONFIDENCE_INTERVAL_RATIO, MAX_TX_SIZE, MAX_U64, MPL_METADATA_PROGRAM_ID, MarginRequirementType, MarginfiAccount, MarginfiAccountWrapper, MarginfiGroup, OperationalState, OracleSetup, PDA_BANK_EMISSIONS_AUTH_SEED, PDA_BANK_EMISSIONS_VAULT_SEED, PDA_BANK_FEE_STATE_SEED, PDA_BANK_FEE_VAULT_AUTH_SEED, PDA_BANK_FEE_VAULT_SEED, PDA_BANK_INSURANCE_VAULT_AUTH_SEED, PDA_BANK_INSURANCE_VAULT_SEED, PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED, PDA_BANK_LIQUIDITY_VAULT_SEED, PDA_MARGINFI_ACCOUNT_SEED, PRIORITY_TX_SIZE, PYTH_PRICE_CONF_INTERVALS, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, PriceBias, Project0Client, RiskTier, SINGLE_POOL_PROGRAM_ID, STAKED_ORACLE_DISABLED_FLAG, STAKED_ORACLE_USES_ONRAMP_FLAG, STAKE_CONFIG_ID, STAKE_PROGRAM_ID, SWAP_ADAPTERS, SWB_PRICE_CONF_INTERVALS, SYSTEM_PROGRAM_ID, SYSVAR_CLOCK_ID, SYSVAR_RENT_ID, SYSVAR_STAKE_HISTORY_ID, SwapProvider, TRANSFER_ACCOUNT_AUTHORITY_FLAG, TransactionArenaKeyMap, TransactionBuildingError, TransactionBuildingErrorCode, TransactionConfigMap, TransactionType, USDC_DECIMALS, USDC_MINT, WSOL_MINT, ZERO_ORACLE_KEY, accountConflictsWithBridge, accountFlagToBN, addOracleToBanksIx, addTransactionMetadata, adjustPriceComponent, aprToApy, apyToApr, balanceToDto, bankConfigRawToDto, bankConfigToBankConfigRaw, bankMetadataMapToDto, bankMetadataToDto, bankRateLimiterRawToDto, bankRawToDto, bigNumberToWrappedI80F48, bpsToPercentile, buildCollateralLegIxs, calculateApyFromInterest, calculateInterestFromApy, capConfidenceInterval, categorizePythBanks, checkBatchOracleCrankability, checkJupiterFeeAccount, checkMultipleOraclesCrankability, checkTitanFeeAccount, chunkedGetRawMultipleAccountInfoOrdered, chunkedGetRawMultipleAccountInfoOrderedWithNulls, chunkedGetRawMultipleAccountInfos, classifyAndValidate, compileFlashloanPrecheck, composeBridgedSwap, composeRemainingAccounts, computeAccountValue, computeActiveEmodePairs, computeAssetHealthComponent, computeAssetUsdValue, computeBalanceUsdValue, computeBankBorrowApy, computeBankBorrowCapRemaining, computeBankDepositCapRemaining, computeBankMetrics, computeBankPoolSize, computeBankSupplyApy, computeBankTotalBorrows, computeBankTotalBorrowsUsd, computeBankTotalDeposits, computeBankTotalDepositsUsd, computeBaseInterestRate, computeBorrowEstimateForRepay, computeClaimedEmissions, computeClosePositionTokenAmount, computeEmodeImpacts, computeFlashLoanNonSwapBudget, computeFlashloanSwapConstraints, computeFreeCollateralFromBalances, computeFreeCollateralFromCache, computeHealthAccountMetas, computeHealthCacheStatus, computeHealthCheckAccounts, computeHealthComponentsFromBalances, computeHealthComponentsFromCache, computeInterestRates, computeLiabilityHealthComponent, computeLiabilityUsdValue, computeLiquidationPriceForBank, computeLoopingParams, computeLowestEmodeWeights, computeMaxBorrowForBank, computeMaxLeverage, computeMaxWithdrawForBank, computeNetApy, computeProjectedActiveBalancesNoCpi, computeProjectedActiveBanksNoCpi, computeQuantity, computeQuantityUi, computeRemainingCapacity, computeSmartCrank, computeStakedBankMultipliers, computeTotalOutstandingEmissions, computeTvl, computeUsdValue, computeUtilizationRate, computeV0TxSize, convertVoteAccCoeffsToBankCoeffs, createActiveEmodePairFromPairs, createEmptyBalance, decodeAccountRaw, decodeBankRaw, decodeInstruction, decompileV0Transaction, deriveBankEmissionsAuth, deriveBankEmissionsVault, deriveBankFeeVault, deriveBankFeeVaultAuthority, deriveBankInsuranceVault, deriveBankInsuranceVaultAuthority, deriveBankLiquidityVault, deriveBankLiquidityVaultAuthority, deriveFeeState, deriveMarginfiAccount, deserializeInstruction, deserializeLut, deserializeSwapEngineRequest, deserializeSwapEngineResult, dtoToBalance, dtoToBank, dtoToBankConfig, dtoToBankConfigRaw, dtoToBankMetadata, dtoToBankMetadataMap, dtoToBankRateLimiter, dtoToBankRateLimiterRaw, dtoToBankRaw, dtoToEmodeSettings, dtoToEmodeSettingsRaw, dtoToGroup, dtoToHealthCache, dtoToInterestRateConfig, dtoToMarginfiAccount, dtoToOraclePrice, dtoToValidatorStakeGroup, emodeSettingsRawToDto, extractPythOracleKeys, fetchBank, fetchBankIntegrationMetadata, fetchMarginfiAccountActiveBalancesForBank, fetchMarginfiAccountAddresses, fetchMarginfiAccountAddressesHoldingBank, fetchMarginfiAccountData, fetchMultipleBanks, fetchNativeStakeAccounts, fetchOracleData, fetchProgramForMints, fetchPythOracleData, fetchPythOraclePricesFromAPI, fetchPythOraclePricesFromChain, fetchStakeAccount, fetchStakePoolActiveStates, fetchStakePoolMev, fetchSwbOracleAccountsFromAPI, fetchSwbOracleAccountsFromChain, fetchSwbOracleData, fetchSwbOraclePricesFromAPI, fetchSwbOraclePricesFromCrossbar, findRandomAvailableAccountIndex, freezeBankConfigIx, generateDummyAccount, getAccountKeys, getActiveAccountFlags, getActiveBalances, getActiveEmodeEntryFlags, getActiveEmodeFlags, getActiveHealthCacheFlags, getAssetQuantity, getAssetShares, getAssetWeight, getBalance, getBalanceUsdValueWithPriceBias, getBankVaultAuthority, getBankVaultSeeds, getBirdeyeFallbackPricesByFeedId, getBirdeyePricesForMints, getConfig, getDriftCTokenMultiplier, getDriftMetadata, getDriftStatesDto, getEmodePairs, getExactOutEstimate, getFallbackPricesByFeedId, getFallbackPricesForMints, getHealthCacheStatusDescription, getHealthSimulationTransactions, getJupLendFTokenMultiplier, getJupLendMetadata, getJupLendStatesDto, getJupiterReferralFeeAccount, getJupiterSwapIxsForFlashloan, getKaminoCTokenMultiplier, getKaminoMetadata, getKaminoStatesDto, getLiabilityQuantity, getLiabilityShares, getLiabilityWeight, getOracleSourceFromBank, getOracleSourceFromOracleSetup, getOracleSourceNameFromKey, getPrice, getPriceWithConfidence, getStakedBankMetadataMap, getSwapAdapter, getSwapIxsForFlashloan, getTitanExactOutEstimate, getTitanSwapIxsForFlashloan, getTotalAccountKeys, getTotalAssetQuantity, getTotalLiabilityQuantity, getTxSize, getValidatorVoteAccountByBank, getWritableAccountKeys, groupToDto, hasAccountFlag, hasEmodeEntryFlag, hasEmodeFlag, hasHealthCacheFlag, healthCacheToDto, isDecomposableSwapError, isDepositIx, isFlashloan, isGroupRateLimiterEnabled, isStandardBorrowable, isStandardDepositable, isV0Tx, isWeightedPrice, isWholePosition, makeAccountTransferToNewAccountTx, makeAddPermissionlessStakedBankIx, makeBeginFlashLoanIx3 as makeBeginFlashLoanIx, makeBorrowIx3 as makeBorrowIx, makeBorrowTx, makeBulkRepayTx, makeBulkWithdrawTx, makeBundleTipIx, makeCloseMarginfiAccountIx, makeCloseMarginfiAccountTx, makeCrankSwbFeedIx, makeCreateAccountIxWithProjection, makeCreateAccountTxWithProjection, makeCreateMarginfiAccountIx, makeCreateMarginfiAccountTx, makeDepositIx3 as makeDepositIx, makeDepositTx, makeDriftDepositIx3 as makeDriftDepositIx, makeDriftDepositTx, makeDriftWithdrawIx3 as makeDriftWithdrawIx, makeDriftWithdrawTx, makeEndFlashLoanIx3 as makeEndFlashLoanIx, makeFlashLoanTx, makeJuplendDepositIx2 as makeJuplendDepositIx, makeJuplendDepositTx, makeJuplendWithdrawIx2 as makeJuplendWithdrawIx, makeJuplendWithdrawTx, makeKaminoDepositIx3 as makeKaminoDepositIx, makeKaminoDepositTx, makeKaminoWithdrawIx3 as makeKaminoWithdrawIx, makeKaminoWithdrawTx, makeLoopTx, makeMergeStakeAccountsTx, makeMintStakedLstIx, makeMintStakedLstTx, makePoolAddBankIx3 as makePoolAddBankIx, makePoolConfigureBankIx3 as makePoolConfigureBankIx, makePriorityFeeIx, makePriorityFeeMicroIx, makePulseHealthIx2 as makePulseHealthIx, makeRedeemStakedLstIx, makeRedeemStakedLstTx, makeRefreshIntegrationBanksIxs, makeRefreshKaminoBanksIxs, makeRepayIx3 as makeRepayIx, makeRepayTx, makeRepayWithCollatTx, makeRollPtTx, makeSetupIx, makeSmartCrankSwbFeedIx, makeSmartCrankSwbFeedIxForAccounts, makeSwapCollateralTx, makeSwapDebtTx, makeTransferPositionsTx, makeTxPriorityIx, makeUnwrapSolIx, makeUpdateDriftMarketIxs, makeUpdateJupLendRateIxs, makeUpdateSwbFeedIx, makeVersionedTransaction, makeWithdrawIx3 as makeWithdrawIx, makeWithdrawTx, makeWrapSolIxs, mapBrokenFeedsToOraclePrices, mapJupiterQuoteToSwapQuoteResult, mapPythBanksToOraclePrices, mapSwbBanksToOraclePrices, marginfiAccountToDto, mergeBridgeQuotes, mergeBridgeQuotesDebt, mergeBridgeQuotesLoop, nativeToUi, oraclePriceToDto, parseBalanceRaw, parseBankConfigRaw, parseBankRateLimiterRaw, parseBankRaw, parseEmodeSettingsRaw, parseEmodeTag, parseHealthCacheRaw, parseMarginfiAccountRaw, parseOperationalState, parseOracleSetup, parseOraclePriceData as parsePriceInfo, parseRiskTier, parseRpcPythPriceData, parseSwbOraclePriceData, partitionBanksByCrankability, patchDepositAmount, requireBank, requireTokenProgram, resolveAmount, resolveBridgeBanks, runSwapEngine, selectLutsForAccountAction, selectLutsForBanks, serializeBankConfigOpt, serializeInstruction, serializeInterestRateConfig, serializeLut, serializeOperationalState, serializeOracleSetup, serializeOracleSetupToIndex, serializeRiskTier, serializeSwapEngineRequest, serializeSwapEngineResult, shortenAddress, simulateAccountHealthCache, simulateAccountHealthCacheWithFallback, simulateBundle, splitInstructionsToFitTransactions, swapEngineProvidersFromOpts, swapEngineQuoteFieldsFromOpts, toBankConfigDto, toBankDto, toBankRateLimiterDto, toBigNumber, toEmodeSettingsDto, toInterestRateConfigDto, toJupiterConfig, toNumber, uiToNative, uiToNativeBigNumber, validatorStakeGroupToDto, wrappedI80F48toBigNumber };
76493
+ export { ADDRESS_LOOKUP_TABLE_FOR_GROUP, ADDRESS_LOOKUP_TABLE_FOR_GROUP_NATIVE_STAKE, ADDRESS_LOOKUP_TABLE_FOR_SWAP, AccountFlags, AccountType, AssetTag, BUNDLE_TX_SIZE, Balance, Bank, BankConfig, BankConfigFlag, BankVaultType, DEFAULT_BRIDGE_MINTS, DEFAULT_CROSSBAR_URL, DEFAULT_FALLBACK_CROSSBAR_URL, DEFAULT_ORACLE_MAX_AGE, DEFAULT_REPAY_ALL_EXTRA_BUFFER_BPS, DISABLED_FLAG, EMPTY_HEALTH_CACHE, EmodeEntryFlags, EmodeFlags, EmodeImpactStatus, EmodeSettings, EmodeTag, FLASHLOAN_ENABLED_FLAG, HOURS_PER_YEAR, HealthCache, HealthCacheFlags, HealthCacheSimulationError, HealthCacheStatus, JUPITER_V6_PROGRAM, JUP_SWAP_LUT_PROGRAM_AUTHORITY_INDEX, LST_MINT, MARGINFI_IDL, MARGINFI_PROGRAM, MARGINFI_PROGRAM_STAGING, MARGINFI_PROGRAM_STAGING_ALT, MARGINFI_SPONSORED_SHARD_ID, MAX_ACCOUNT_LOCKS, MAX_CONFIDENCE_INTERVAL_RATIO, MAX_TX_SIZE, MAX_U64, MPL_METADATA_PROGRAM_ID, MarginRequirementType, MarginfiAccount, MarginfiAccountWrapper, MarginfiGroup, OperationalState, OracleSetup, PDA_BANK_EMISSIONS_AUTH_SEED, PDA_BANK_EMISSIONS_VAULT_SEED, PDA_BANK_FEE_STATE_SEED, PDA_BANK_FEE_VAULT_AUTH_SEED, PDA_BANK_FEE_VAULT_SEED, PDA_BANK_INSURANCE_VAULT_AUTH_SEED, PDA_BANK_INSURANCE_VAULT_SEED, PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED, PDA_BANK_LIQUIDITY_VAULT_SEED, PDA_MARGINFI_ACCOUNT_SEED, PRIORITY_TX_SIZE, PYTH_PRICE_CONF_INTERVALS, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, PriceBias, Project0Client, RiskTier, SINGLE_POOL_PROGRAM_ID, STAKED_ORACLE_DISABLED_FLAG, STAKED_ORACLE_USES_ONRAMP_FLAG, STAKE_CONFIG_ID, STAKE_PROGRAM_ID, SWAP_ADAPTERS, SWB_PRICE_CONF_INTERVALS, SYSTEM_PROGRAM_ID, SYSVAR_CLOCK_ID, SYSVAR_RENT_ID, SYSVAR_STAKE_HISTORY_ID, SwapProvider, TRANSFER_ACCOUNT_AUTHORITY_FLAG, TransactionArenaKeyMap, TransactionBuildingError, TransactionBuildingErrorCode, TransactionConfigMap, TransactionType, USDC_DECIMALS, USDC_MINT, USDT_MINT, WSOL_MINT, ZERO_ORACLE_KEY, accountConflictsWithBridgeBank, accountFlagToBN, addOracleToBanksIx, addTransactionMetadata, adjustPriceComponent, aprToApy, apyToApr, balanceToDto, bankConfigRawToDto, bankConfigToBankConfigRaw, bankMetadataMapToDto, bankMetadataToDto, bankRateLimiterRawToDto, bankRawToDto, bigNumberToWrappedI80F48, bpsToPercentile, buildCollateralLegIxs, calculateApyFromInterest, calculateInterestFromApy, capConfidenceInterval, categorizePythBanks, checkBatchOracleCrankability, checkJupiterFeeAccount, checkMultipleOraclesCrankability, checkTitanFeeAccount, chunkedGetRawMultipleAccountInfoOrdered, chunkedGetRawMultipleAccountInfoOrderedWithNulls, chunkedGetRawMultipleAccountInfos, classifyAndValidate, compileFlashloanPrecheck, composeBridgedSwap, composeRemainingAccounts, computeAccountValue, computeActiveEmodePairs, computeAssetHealthComponent, computeAssetUsdValue, computeBalanceUsdValue, computeBankBorrowApy, computeBankBorrowCapRemaining, computeBankDepositCapRemaining, computeBankMetrics, computeBankPoolSize, computeBankSupplyApy, computeBankTotalBorrows, computeBankTotalBorrowsUsd, computeBankTotalDeposits, computeBankTotalDepositsUsd, computeBaseInterestRate, computeBorrowEstimateForRepay, computeClaimedEmissions, computeClosePositionTokenAmount, computeEmodeImpacts, computeFlashLoanNonSwapBudget, computeFlashloanSwapConstraints, computeFreeCollateralFromBalances, computeFreeCollateralFromCache, computeHealthAccountMetas, computeHealthCacheStatus, computeHealthCheckAccounts, computeHealthComponentsFromBalances, computeHealthComponentsFromCache, computeInterestRates, computeLiabilityHealthComponent, computeLiabilityUsdValue, computeLiquidationPriceForBank, computeLoopingParams, computeLowestEmodeWeights, computeMaxBorrowForBank, computeMaxLeverage, computeMaxWithdrawForBank, computeNetApy, computeProjectedActiveBalancesNoCpi, computeProjectedActiveBanksNoCpi, computeQuantity, computeQuantityUi, computeRemainingCapacity, computeSmartCrank, computeStakedBankMultipliers, computeTotalOutstandingEmissions, computeTvl, computeUsdValue, computeUtilizationRate, computeV0TxSize, convertVoteAccCoeffsToBankCoeffs, createActiveEmodePairFromPairs, createEmptyBalance, decodeAccountRaw, decodeBankRaw, decodeInstruction, decompileV0Transaction, deriveBankEmissionsAuth, deriveBankEmissionsVault, deriveBankFeeVault, deriveBankFeeVaultAuthority, deriveBankInsuranceVault, deriveBankInsuranceVaultAuthority, deriveBankLiquidityVault, deriveBankLiquidityVaultAuthority, deriveFeeState, deriveMarginfiAccount, deserializeInstruction, deserializeLut, deserializeSwapEngineRequest, deserializeSwapEngineResult, dtoToBalance, dtoToBank, dtoToBankConfig, dtoToBankConfigRaw, dtoToBankMetadata, dtoToBankMetadataMap, dtoToBankRateLimiter, dtoToBankRateLimiterRaw, dtoToBankRaw, dtoToEmodeSettings, dtoToEmodeSettingsRaw, dtoToGroup, dtoToHealthCache, dtoToInterestRateConfig, dtoToMarginfiAccount, dtoToOraclePrice, dtoToValidatorStakeGroup, emodeSettingsRawToDto, extractPythOracleKeys, fetchBank, fetchBankIntegrationMetadata, fetchMarginfiAccountActiveBalancesForBank, fetchMarginfiAccountAddresses, fetchMarginfiAccountAddressesHoldingBank, fetchMarginfiAccountData, fetchMultipleBanks, fetchNativeStakeAccounts, fetchOracleData, fetchProgramForMints, fetchPythOracleData, fetchPythOraclePricesFromAPI, fetchPythOraclePricesFromChain, fetchStakeAccount, fetchStakePoolActiveStates, fetchStakePoolMev, fetchSwbOracleAccountsFromAPI, fetchSwbOracleAccountsFromChain, fetchSwbOracleData, fetchSwbOraclePricesFromAPI, fetchSwbOraclePricesFromCrossbar, findRandomAvailableAccountIndex, freezeBankConfigIx, generateDummyAccount, getAccountKeys, getActiveAccountFlags, getActiveBalances, getActiveEmodeEntryFlags, getActiveEmodeFlags, getActiveHealthCacheFlags, getAssetQuantity, getAssetShares, getAssetWeight, getBalance, getBalanceUsdValueWithPriceBias, getBankVaultAuthority, getBankVaultSeeds, getBirdeyeFallbackPricesByFeedId, getBirdeyePricesForMints, getConfig, getDriftCTokenMultiplier, getDriftMetadata, getDriftStatesDto, getEmodePairs, getExactOutEstimate, getFallbackPricesByFeedId, getFallbackPricesForMints, getHealthCacheStatusDescription, getHealthSimulationTransactions, getJupLendFTokenMultiplier, getJupLendMetadata, getJupLendStatesDto, getJupiterReferralFeeAccount, getJupiterSwapIxsForFlashloan, getKaminoCTokenMultiplier, getKaminoMetadata, getKaminoStatesDto, getLiabilityQuantity, getLiabilityShares, getLiabilityWeight, getOracleSourceFromBank, getOracleSourceFromOracleSetup, getOracleSourceNameFromKey, getPrice, getPriceWithConfidence, getStakedBankMetadataMap, getSwapAdapter, getSwapIxsForFlashloan, getTitanExactOutEstimate, getTitanSwapIxsForFlashloan, getTotalAccountKeys, getTotalAssetQuantity, getTotalLiabilityQuantity, getTxSize, getValidatorVoteAccountByBank, getWritableAccountKeys, groupToDto, hasAccountFlag, hasEmodeEntryFlag, hasEmodeFlag, hasHealthCacheFlag, healthCacheToDto, isBridgeConflictError, isDecomposableSwapError, isDepositIx, isFlashloan, isGroupRateLimiterEnabled, isStandardBorrowable, isStandardDepositable, isV0Tx, isWeightedPrice, isWholePosition, makeAccountTransferToNewAccountTx, makeAddPermissionlessStakedBankIx, makeBeginFlashLoanIx3 as makeBeginFlashLoanIx, makeBorrowIx3 as makeBorrowIx, makeBorrowTx, makeBridgedLoopTx, makeBridgedSwapCollateralTx, makeBridgedSwapDebtTx, makeBulkRepayTx, makeBulkWithdrawTx, makeBundleTipIx, makeCloseMarginfiAccountIx, makeCloseMarginfiAccountTx, makeCrankSwbFeedIx, makeCreateAccountIxWithProjection, makeCreateAccountTxWithProjection, makeCreateMarginfiAccountIx, makeCreateMarginfiAccountTx, makeDepositIx3 as makeDepositIx, makeDepositTx, makeDriftDepositIx3 as makeDriftDepositIx, makeDriftDepositTx, makeDriftWithdrawIx3 as makeDriftWithdrawIx, makeDriftWithdrawTx, makeEndFlashLoanIx3 as makeEndFlashLoanIx, makeFlashLoanTx, makeJuplendDepositIx2 as makeJuplendDepositIx, makeJuplendDepositTx, makeJuplendWithdrawIx2 as makeJuplendWithdrawIx, makeJuplendWithdrawTx, makeKaminoDepositIx3 as makeKaminoDepositIx, makeKaminoDepositTx, makeKaminoWithdrawIx3 as makeKaminoWithdrawIx, makeKaminoWithdrawTx, makeLoopTx, makeMergeStakeAccountsTx, makeMintStakedLstIx, makeMintStakedLstTx, makePoolAddBankIx3 as makePoolAddBankIx, makePoolConfigureBankIx3 as makePoolConfigureBankIx, makePriorityFeeIx, makePriorityFeeMicroIx, makePulseHealthIx2 as makePulseHealthIx, makeRedeemStakedLstIx, makeRedeemStakedLstTx, makeRefreshIntegrationBanksIxs, makeRefreshKaminoBanksIxs, makeRepayIx3 as makeRepayIx, makeRepayTx, makeRepayWithCollatTx, makeRollPtTx, makeSetupIx, makeSmartCrankSwbFeedIx, makeSmartCrankSwbFeedIxForAccounts, makeSwapCollateralTx, makeSwapDebtTx, makeTransferPositionsTx, makeTxPriorityIx, makeUnwrapSolIx, makeUpdateDriftMarketIxs, makeUpdateJupLendRateIxs, makeUpdateSwbFeedIx, makeVersionedTransaction, makeWithdrawIx3 as makeWithdrawIx, makeWithdrawTx, makeWrapSolIxs, mapBrokenFeedsToOraclePrices, mapJupiterQuoteToSwapQuoteResult, mapPythBanksToOraclePrices, mapSwbBanksToOraclePrices, marginfiAccountToDto, mergeBridgeQuotes, mergeBridgeQuotesDebt, mergeBridgeQuotesLoop, nativeToUi, oraclePriceToDto, parseBalanceRaw, parseBankConfigRaw, parseBankRateLimiterRaw, parseBankRaw, parseEmodeSettingsRaw, parseEmodeTag, parseHealthCacheRaw, parseMarginfiAccountRaw, parseOperationalState, parseOracleSetup, parseOraclePriceData as parsePriceInfo, parseRiskTier, parseRpcPythPriceData, parseSwbOraclePriceData, partitionBanksByCrankability, patchDepositAmount, requireBank, requireTokenProgram, resolveAmount, resolveBridgeCandidateBanks, resolveTokenProgramForMint, runSwapEngine, selectLutsForAccountAction, selectLutsForBanks, selectSwapBridges, serializeBankConfigOpt, serializeInstruction, serializeInterestRateConfig, serializeLut, serializeOperationalState, serializeOracleSetup, serializeOracleSetupToIndex, serializeRiskTier, serializeSwapEngineRequest, serializeSwapEngineResult, sharedBridgeLegContext, shortenAddress, simulateAccountHealthCache, simulateAccountHealthCacheWithFallback, simulateBundle, splitInstructionsToFitTransactions, swapEngineProvidersFromOpts, swapEngineQuoteFieldsFromOpts, toBankConfigDto, toBankDto, toBankRateLimiterDto, toBigNumber, toEmodeSettingsDto, toInterestRateConfigDto, toJupiterConfig, toNumber, tryBridgeCandidates, uiToNative, uiToNativeBigNumber, validatorStakeGroupToDto, wrappedI80F48toBigNumber };
75989
76494
  //# sourceMappingURL=index.js.map
75990
76495
  //# sourceMappingURL=index.js.map