@0dotxyz/p0-ts-sdk 1.1.1 → 1.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -33284,7 +33284,8 @@ async function makeSetupIx({ connection, authority, tokens }) {
33284
33284
  }
33285
33285
  }
33286
33286
  return ixs;
33287
- } catch {
33287
+ } catch (error) {
33288
+ console.error("[makeSetupIx] Failed to create setup instructions:", error);
33288
33289
  return [];
33289
33290
  }
33290
33291
  }
@@ -43237,104 +43238,729 @@ async function makeWithdrawEmissionsIx(program, marginfiAccount, banks, mintData
43237
43238
  ixs.push(withdrawEmissionsIx);
43238
43239
  return { instructions: ixs, keys: [] };
43239
43240
  }
43240
-
43241
- // src/services/account/services/account-simulation.service.ts
43242
- async function simulateAccountHealthCacheWithFallback(props) {
43243
- let marginfiAccount = props.marginfiAccount;
43244
- const activeBalances = props.balances.filter((b) => b.active);
43245
- const { assets: assetValueEquity, liabilities: liabilityValueEquity } = computeHealthComponentsWithoutBiasLegacy(
43246
- activeBalances,
43247
- props.bankMap,
43248
- props.oraclePrices,
43249
- 2 /* Equity */
43241
+ async function makeSwapCollateralTx(params) {
43242
+ const {
43243
+ program,
43244
+ marginfiAccount,
43245
+ connection,
43246
+ bankMap,
43247
+ oraclePrices,
43248
+ withdrawOpts,
43249
+ depositOpts,
43250
+ bankMetadataMap,
43251
+ addressLookupTableAccounts,
43252
+ crossbarUrl,
43253
+ additionalIxs = []
43254
+ } = params;
43255
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
43256
+ const setupIxs = await makeSetupIx({
43257
+ connection,
43258
+ authority: marginfiAccount.authority,
43259
+ tokens: [
43260
+ { mint: withdrawOpts.withdrawBank.mint, tokenProgram: withdrawOpts.tokenProgram },
43261
+ { mint: depositOpts.depositBank.mint, tokenProgram: depositOpts.tokenProgram }
43262
+ ]
43263
+ });
43264
+ const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
43265
+ marginfiAccount,
43266
+ bankMap,
43267
+ [withdrawOpts.withdrawBank.address],
43268
+ bankMetadataMap
43250
43269
  );
43251
- try {
43252
- const simulatedAccount = await simulateAccountHealthCache({
43253
- program: props.program,
43254
- bankMap: props.bankMap,
43255
- marginfiAccountPk: props.marginfiAccount.address,
43256
- balances: props.balances,
43257
- bankMetadataMap: props.bankMetadataMap
43270
+ const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
43271
+ marginfiAccount,
43272
+ bankMap,
43273
+ [withdrawOpts.withdrawBank.address, depositOpts.depositBank.address],
43274
+ bankMetadataMap
43275
+ );
43276
+ const { flashloanTx, setupInstructions, swapQuote, withdrawIxs, depositIxs } = await buildSwapCollateralFlashloanTx({
43277
+ ...params,
43278
+ blockhash
43279
+ });
43280
+ const jupiterSetupInstructions = setupInstructions.filter((ix) => {
43281
+ if (ix.programId.equals(web3_js.ComputeBudgetProgram.programId)) {
43282
+ return false;
43283
+ }
43284
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
43285
+ const mintKey = ix.keys[3]?.pubkey;
43286
+ if (mintKey?.equals(withdrawOpts.withdrawBank.mint) || mintKey?.equals(depositOpts.depositBank.mint)) {
43287
+ return false;
43288
+ }
43289
+ }
43290
+ return true;
43291
+ });
43292
+ setupIxs.push(...jupiterSetupInstructions);
43293
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
43294
+ marginfiAccount,
43295
+ bankMap,
43296
+ oraclePrices,
43297
+ instructions: [...withdrawIxs.instructions, ...depositIxs.instructions],
43298
+ program,
43299
+ connection,
43300
+ crossbarUrl
43301
+ });
43302
+ let additionalTxs = [];
43303
+ if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0) {
43304
+ const ixs = [
43305
+ ...setupIxs,
43306
+ ...kaminoRefreshIxs.instructions,
43307
+ ...updateDriftMarketIxs.instructions
43308
+ ];
43309
+ const txs = splitInstructionsToFitTransactions([], ixs, {
43310
+ blockhash,
43311
+ payerKey: marginfiAccount.authority,
43312
+ luts: addressLookupTableAccounts ?? []
43258
43313
  });
43259
- simulatedAccount.healthCache.assetValueEquity = bigNumberToWrappedI80F48(assetValueEquity);
43260
- simulatedAccount.healthCache.liabilityValueEquity = bigNumberToWrappedI80F48(liabilityValueEquity);
43261
- marginfiAccount = parseMarginfiAccountRaw(props.marginfiAccount.address, simulatedAccount);
43262
- } catch (e) {
43263
- console.log("e", e);
43264
- const { assets: assetValueMaint, liabilities: liabilityValueMaint } = computeHealthComponentsLegacy(
43265
- activeBalances,
43266
- props.bankMap,
43267
- props.oraclePrices,
43268
- 1 /* Maintenance */,
43269
- []
43314
+ additionalTxs.push(
43315
+ ...txs.map(
43316
+ (tx) => addTransactionMetadata(tx, {
43317
+ type: "CREATE_ATA" /* CREATE_ATA */,
43318
+ addressLookupTables: addressLookupTableAccounts
43319
+ })
43320
+ )
43270
43321
  );
43271
- const { assets: assetValueInitial, liabilities: liabilityValueInitial } = computeHealthComponentsLegacy(
43272
- activeBalances,
43273
- props.bankMap,
43274
- props.oraclePrices,
43275
- 0 /* Initial */,
43276
- []
43322
+ }
43323
+ if (updateFeedIxs.length > 0) {
43324
+ const message = new web3_js.TransactionMessage({
43325
+ payerKey: marginfiAccount.authority,
43326
+ recentBlockhash: blockhash,
43327
+ instructions: updateFeedIxs
43328
+ }).compileToV0Message(feedLuts);
43329
+ additionalTxs.push(
43330
+ addTransactionMetadata(new web3_js.VersionedTransaction(message), {
43331
+ addressLookupTables: feedLuts,
43332
+ type: "CRANK" /* CRANK */
43333
+ })
43277
43334
  );
43278
- marginfiAccount.healthCache = {
43279
- assetValue: assetValueInitial,
43280
- liabilityValue: liabilityValueInitial,
43281
- assetValueMaint,
43282
- liabilityValueMaint,
43283
- assetValueEquity,
43284
- liabilityValueEquity,
43285
- timestamp: new BigNumber10__default.default(0),
43286
- flags: [],
43287
- prices: [],
43288
- simulationStatus: 2 /* COMPUTED */
43289
- };
43290
- if (e instanceof HealthCacheSimulationError) {
43291
- return { marginfiAccount, error: e };
43292
- }
43293
43335
  }
43294
- return { marginfiAccount };
43336
+ const transactions = [...additionalTxs, flashloanTx];
43337
+ return {
43338
+ transactions,
43339
+ actionTxIndex: transactions.length - 1,
43340
+ quoteResponse: swapQuote
43341
+ };
43295
43342
  }
43296
- async function simulateAccountHealthCache(props) {
43297
- const { program, bankMap, marginfiAccountPk, balances, bankMetadataMap } = props;
43298
- const activeBalances = balances.filter((b) => b.active);
43299
- const activeBanks = activeBalances.map((balance) => bankMap.get(balance.bankPk.toBase58())).filter((bank) => !!bank);
43300
- const kaminoBanks = activeBanks.filter((bank) => bank.config.assetTag === 3 /* KAMINO */);
43301
- const driftBanks = activeBanks.filter((bank) => bank.config.assetTag === 4 /* DRIFT */);
43302
- const staleSwbOracles = activeBanks.filter(
43303
- (bank) => bank.config.oracleSetup === "SwitchboardPull" /* SwitchboardPull */ || bank.config.oracleSetup === "SwitchboardV2" /* SwitchboardV2 */ || bank.config.oracleSetup === "KaminoSwitchboardPull" /* KaminoSwitchboardPull */ || bank.config.oracleSetup === "DriftSwitchboardPull" /* DriftSwitchboardPull */ || bank.config.oracleSetup === "SolendSwitchboardPull" /* SolendSwitchboardPull */
43304
- ).filter((bank) => !bank.oracleKey.equals(new web3_js.PublicKey(ZERO_ORACLE_KEY)));
43305
- const computeIx = web3_js.ComputeBudgetProgram.setComputeUnitLimit({
43306
- units: 14e5
43307
- });
43308
- const blockhash = (await program.provider.connection.getLatestBlockhash("confirmed")).blockhash;
43309
- const fundAccountIx = web3_js.SystemProgram.transfer({
43310
- fromPubkey: new web3_js.PublicKey("DD3AeAssFvjqTvRTrRAtpfjkBF8FpVKnFuwnMLN9haXD"),
43311
- // marginfi SOL VAULT
43312
- toPubkey: program.provider.publicKey,
43313
- lamports: 1e8
43314
- // 0.1 SOL
43315
- });
43316
- const updateDriftMarketData = driftBanks.map((bank) => {
43317
- const bankMetadata = bankMetadataMap?.[bank.address.toBase58()];
43318
- if (!bankMetadata?.driftStates) {
43319
- console.error(`Bank metadata for drift bank ${bank.address.toBase58()} not found`);
43320
- return;
43343
+ async function buildSwapCollateralFlashloanTx({
43344
+ program,
43345
+ marginfiAccount,
43346
+ bankMap,
43347
+ withdrawOpts,
43348
+ depositOpts,
43349
+ swapOpts,
43350
+ bankMetadataMap,
43351
+ addressLookupTableAccounts,
43352
+ connection,
43353
+ overrideInferAccounts,
43354
+ blockhash
43355
+ }) {
43356
+ const { withdrawBank, tokenProgram: withdrawTokenProgram, totalPositionAmount } = withdrawOpts;
43357
+ const { depositBank, tokenProgram: depositTokenProgram } = depositOpts;
43358
+ const swapResult = [];
43359
+ const cuRequestIxs = [
43360
+ web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
43361
+ web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
43362
+ ];
43363
+ let withdrawIxs;
43364
+ switch (withdrawOpts.withdrawBank.config.assetTag) {
43365
+ case 3 /* KAMINO */: {
43366
+ const reserve = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.kaminoStates?.reserveState;
43367
+ if (!reserve) {
43368
+ throw TransactionBuildingError.kaminoReserveNotFound(
43369
+ withdrawOpts.withdrawBank.address.toBase58(),
43370
+ withdrawOpts.withdrawBank.mint.toBase58(),
43371
+ withdrawOpts.withdrawBank.tokenSymbol
43372
+ );
43373
+ }
43374
+ const adjustedAmount = new BigNumber10.BigNumber(totalPositionAmount).div(withdrawOpts.withdrawBank.assetShareValue).times(1.0001).toNumber();
43375
+ withdrawIxs = await makeKaminoWithdrawIx3({
43376
+ program,
43377
+ bank: withdrawBank,
43378
+ bankMap,
43379
+ tokenProgram: withdrawTokenProgram,
43380
+ amount: adjustedAmount,
43381
+ marginfiAccount,
43382
+ authority: marginfiAccount.authority,
43383
+ reserve,
43384
+ withdrawAll: true,
43385
+ isSync: true,
43386
+ opts: {
43387
+ createAtas: false,
43388
+ wrapAndUnwrapSol: false,
43389
+ overrideInferAccounts
43390
+ }
43391
+ });
43392
+ break;
43321
43393
  }
43322
- const driftMarket = bankMetadata.driftStates.spotMarketState;
43323
- return driftMarket;
43324
- }).filter((state) => !!state);
43325
- const refreshReserveData = kaminoBanks.map((bank) => {
43326
- const bankMetadata = bankMetadataMap?.[bank.address.toBase58()];
43327
- if (!bankMetadata?.kaminoStates) {
43328
- console.error(`Bank metadata for kamino bank ${bank.address.toBase58()} not found`);
43329
- return;
43394
+ case 4 /* DRIFT */: {
43395
+ const driftState = bankMetadataMap[withdrawOpts.withdrawBank.address.toBase58()]?.driftStates;
43396
+ if (!driftState) {
43397
+ throw TransactionBuildingError.driftStateNotFound(
43398
+ withdrawOpts.withdrawBank.address.toBase58(),
43399
+ withdrawOpts.withdrawBank.mint.toBase58(),
43400
+ withdrawOpts.withdrawBank.tokenSymbol
43401
+ );
43402
+ }
43403
+ withdrawIxs = await makeDriftWithdrawIx3({
43404
+ program,
43405
+ bank: withdrawOpts.withdrawBank,
43406
+ bankMap,
43407
+ tokenProgram: withdrawOpts.tokenProgram,
43408
+ amount: totalPositionAmount,
43409
+ marginfiAccount,
43410
+ authority: marginfiAccount.authority,
43411
+ driftSpotMarket: driftState.spotMarketState,
43412
+ userRewards: driftState.userRewards,
43413
+ withdrawAll: true,
43414
+ isSync: false,
43415
+ opts: {
43416
+ createAtas: false,
43417
+ wrapAndUnwrapSol: false,
43418
+ overrideInferAccounts
43419
+ }
43420
+ });
43421
+ break;
43330
43422
  }
43331
- if (!bankMetadata?.kaminoStates || !bank.kaminoIntegrationAccounts) {
43332
- console.error(`Integration data for kamino bank ${bank.address.toBase58()} not found`);
43333
- return;
43423
+ default: {
43424
+ withdrawIxs = await makeWithdrawIx3({
43425
+ program,
43426
+ bank: withdrawBank,
43427
+ bankMap,
43428
+ tokenProgram: withdrawTokenProgram,
43429
+ amount: totalPositionAmount,
43430
+ marginfiAccount,
43431
+ authority: marginfiAccount.authority,
43432
+ withdrawAll: true,
43433
+ isSync: true,
43434
+ opts: {
43435
+ createAtas: false,
43436
+ wrapAndUnwrapSol: false,
43437
+ overrideInferAccounts
43438
+ }
43439
+ });
43440
+ break;
43334
43441
  }
43335
- const kaminoReserve = bank.kaminoIntegrationAccounts.kaminoReserve;
43336
- const lendingMarket = bankMetadata.kaminoStates.reserveState.lendingMarket;
43337
- return {
43442
+ }
43443
+ if (depositBank.mint.equals(withdrawBank.mint)) {
43444
+ swapResult.push({
43445
+ amountToDeposit: totalPositionAmount,
43446
+ swapInstructions: [],
43447
+ setupInstructions: [],
43448
+ swapLookupTables: []
43449
+ });
43450
+ } else {
43451
+ const destinationTokenAccount = getAssociatedTokenAddressSync(
43452
+ depositBank.mint,
43453
+ marginfiAccount.authority,
43454
+ true,
43455
+ depositTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
43456
+ );
43457
+ const swapResponses = await getJupiterSwapIxsForFlashloan({
43458
+ quoteParams: {
43459
+ inputMint: withdrawBank.mint.toBase58(),
43460
+ outputMint: depositBank.mint.toBase58(),
43461
+ amount: uiToNative(totalPositionAmount, withdrawBank.mintDecimals).toNumber(),
43462
+ dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
43463
+ slippageBps: swapOpts.jupiterOptions?.slippageBps,
43464
+ swapMode: "ExactIn",
43465
+ platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps,
43466
+ onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
43467
+ },
43468
+ authority: marginfiAccount.authority,
43469
+ connection,
43470
+ destinationTokenAccount,
43471
+ configParams: swapOpts.jupiterOptions?.configParams
43472
+ });
43473
+ swapResponses.forEach((response) => {
43474
+ const outAmountThreshold = nativeToUi(
43475
+ response.quoteResponse.otherAmountThreshold,
43476
+ depositBank.mintDecimals
43477
+ );
43478
+ swapResult.push({
43479
+ amountToDeposit: outAmountThreshold,
43480
+ swapInstructions: [response.swapInstruction],
43481
+ setupInstructions: response.setupInstructions,
43482
+ swapLookupTables: response.addressLookupTableAddresses,
43483
+ quoteResponse: response.quoteResponse
43484
+ });
43485
+ });
43486
+ }
43487
+ if (swapResult.length === 0) {
43488
+ throw new Error(
43489
+ `No swap routes found for ${withdrawBank.mint.toBase58()} -> ${depositBank.mint.toBase58()}`
43490
+ );
43491
+ }
43492
+ for (const [index, item] of swapResult.entries()) {
43493
+ const {
43494
+ amountToDeposit,
43495
+ swapInstructions,
43496
+ setupInstructions,
43497
+ swapLookupTables,
43498
+ quoteResponse
43499
+ } = item;
43500
+ let depositIxs;
43501
+ switch (depositBank.config.assetTag) {
43502
+ case 3 /* KAMINO */: {
43503
+ const reserve = bankMetadataMap[depositBank.address.toBase58()]?.kaminoStates?.reserveState;
43504
+ if (!reserve) {
43505
+ throw TransactionBuildingError.kaminoReserveNotFound(
43506
+ depositBank.address.toBase58(),
43507
+ depositBank.mint.toBase58(),
43508
+ depositBank.tokenSymbol
43509
+ );
43510
+ }
43511
+ depositIxs = await makeKaminoDepositIx3({
43512
+ program,
43513
+ bank: depositBank,
43514
+ tokenProgram: depositTokenProgram,
43515
+ amount: amountToDeposit,
43516
+ accountAddress: marginfiAccount.address,
43517
+ authority: marginfiAccount.authority,
43518
+ group: marginfiAccount.group,
43519
+ reserve,
43520
+ opts: {
43521
+ wrapAndUnwrapSol: false,
43522
+ overrideInferAccounts
43523
+ }
43524
+ });
43525
+ break;
43526
+ }
43527
+ case 4 /* DRIFT */: {
43528
+ const driftState = bankMetadataMap[depositBank.address.toBase58()]?.driftStates;
43529
+ if (!driftState) {
43530
+ throw TransactionBuildingError.driftStateNotFound(
43531
+ depositBank.address.toBase58(),
43532
+ depositBank.mint.toBase58(),
43533
+ depositBank.tokenSymbol
43534
+ );
43535
+ }
43536
+ const driftMarketIndex = driftState.spotMarketState.marketIndex;
43537
+ const driftOracle = driftState.spotMarketState.oracle;
43538
+ depositIxs = await makeDriftDepositIx3({
43539
+ program,
43540
+ bank: depositBank,
43541
+ tokenProgram: depositTokenProgram,
43542
+ amount: amountToDeposit,
43543
+ accountAddress: marginfiAccount.address,
43544
+ authority: marginfiAccount.authority,
43545
+ group: marginfiAccount.group,
43546
+ driftMarketIndex,
43547
+ driftOracle,
43548
+ opts: {
43549
+ wrapAndUnwrapSol: false,
43550
+ overrideInferAccounts
43551
+ }
43552
+ });
43553
+ break;
43554
+ }
43555
+ default: {
43556
+ depositIxs = await makeDepositIx3({
43557
+ program,
43558
+ bank: depositBank,
43559
+ tokenProgram: depositTokenProgram,
43560
+ amount: amountToDeposit,
43561
+ accountAddress: marginfiAccount.address,
43562
+ authority: marginfiAccount.authority,
43563
+ group: marginfiAccount.group,
43564
+ opts: {
43565
+ wrapAndUnwrapSol: false,
43566
+ overrideInferAccounts
43567
+ }
43568
+ });
43569
+ break;
43570
+ }
43571
+ }
43572
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
43573
+ const flashloanParams = {
43574
+ program,
43575
+ marginfiAccount,
43576
+ bankMap,
43577
+ addressLookupTableAccounts: luts,
43578
+ blockhash
43579
+ };
43580
+ const flashloanTx = await makeFlashLoanTx({
43581
+ ...flashloanParams,
43582
+ ixs: [
43583
+ ...cuRequestIxs,
43584
+ ...withdrawIxs.instructions,
43585
+ ...swapInstructions,
43586
+ ...depositIxs.instructions
43587
+ ],
43588
+ isSync: true
43589
+ });
43590
+ const txSize = getTxSize(flashloanTx);
43591
+ const keySize = getAccountKeys(flashloanTx, luts);
43592
+ const isLast = index === swapResult.length - 1;
43593
+ if (txSize > MAX_TX_SIZE || keySize > 64) {
43594
+ if (isLast) {
43595
+ throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
43596
+ } else {
43597
+ continue;
43598
+ }
43599
+ } else {
43600
+ return {
43601
+ flashloanTx,
43602
+ setupInstructions,
43603
+ swapQuote: quoteResponse,
43604
+ withdrawIxs,
43605
+ depositIxs
43606
+ };
43607
+ }
43608
+ }
43609
+ throw new Error("Failed to build swap collateral flashloan tx");
43610
+ }
43611
+ async function makeSwapDebtTx(params) {
43612
+ const {
43613
+ program,
43614
+ marginfiAccount,
43615
+ connection,
43616
+ bankMap,
43617
+ oraclePrices,
43618
+ repayOpts,
43619
+ borrowOpts,
43620
+ bankMetadataMap,
43621
+ addressLookupTableAccounts,
43622
+ crossbarUrl,
43623
+ additionalIxs = []
43624
+ } = params;
43625
+ const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
43626
+ const setupIxs = await makeSetupIx({
43627
+ connection,
43628
+ authority: marginfiAccount.authority,
43629
+ tokens: [
43630
+ { mint: repayOpts.repayBank.mint, tokenProgram: repayOpts.tokenProgram },
43631
+ { mint: borrowOpts.borrowBank.mint, tokenProgram: borrowOpts.tokenProgram }
43632
+ ]
43633
+ });
43634
+ const updateDriftMarketIxs = makeUpdateDriftMarketIxs(
43635
+ marginfiAccount,
43636
+ bankMap,
43637
+ [],
43638
+ // debt can be in a drift bank
43639
+ bankMetadataMap
43640
+ );
43641
+ const kaminoRefreshIxs = makeRefreshKaminoBanksIxs(
43642
+ marginfiAccount,
43643
+ bankMap,
43644
+ [repayOpts.repayBank.address, borrowOpts.borrowBank.address],
43645
+ bankMetadataMap
43646
+ );
43647
+ const { flashloanTx, setupInstructions, swapQuote, borrowIxs, repayIxs } = await buildSwapDebtFlashloanTx({
43648
+ ...params,
43649
+ blockhash
43650
+ });
43651
+ const jupiterSetupInstructions = setupInstructions.filter((ix) => {
43652
+ if (ix.programId.equals(web3_js.ComputeBudgetProgram.programId)) {
43653
+ return false;
43654
+ }
43655
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
43656
+ const mintKey = ix.keys[3]?.pubkey;
43657
+ if (mintKey?.equals(repayOpts.repayBank.mint) || mintKey?.equals(borrowOpts.borrowBank.mint)) {
43658
+ return false;
43659
+ }
43660
+ }
43661
+ return true;
43662
+ });
43663
+ setupIxs.push(...jupiterSetupInstructions);
43664
+ const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
43665
+ marginfiAccount,
43666
+ bankMap,
43667
+ oraclePrices,
43668
+ instructions: [...borrowIxs.instructions, ...repayIxs.instructions],
43669
+ program,
43670
+ connection,
43671
+ crossbarUrl
43672
+ });
43673
+ let additionalTxs = [];
43674
+ if (setupIxs.length > 0 || kaminoRefreshIxs.instructions.length > 0 || updateDriftMarketIxs.instructions.length > 0) {
43675
+ const ixs = [
43676
+ ...additionalIxs,
43677
+ ...setupIxs,
43678
+ ...kaminoRefreshIxs.instructions,
43679
+ ...updateDriftMarketIxs.instructions
43680
+ ];
43681
+ const txs = splitInstructionsToFitTransactions([], ixs, {
43682
+ blockhash,
43683
+ payerKey: marginfiAccount.authority,
43684
+ luts: addressLookupTableAccounts ?? []
43685
+ });
43686
+ additionalTxs.push(
43687
+ ...txs.map(
43688
+ (tx) => addTransactionMetadata(tx, {
43689
+ type: "CREATE_ATA" /* CREATE_ATA */,
43690
+ addressLookupTables: addressLookupTableAccounts
43691
+ })
43692
+ )
43693
+ );
43694
+ }
43695
+ if (updateFeedIxs.length > 0) {
43696
+ const message = new web3_js.TransactionMessage({
43697
+ payerKey: marginfiAccount.authority,
43698
+ recentBlockhash: blockhash,
43699
+ instructions: updateFeedIxs
43700
+ }).compileToV0Message(feedLuts);
43701
+ additionalTxs.push(
43702
+ addTransactionMetadata(new web3_js.VersionedTransaction(message), {
43703
+ addressLookupTables: feedLuts,
43704
+ type: "CRANK" /* CRANK */
43705
+ })
43706
+ );
43707
+ }
43708
+ const transactions = [...additionalTxs, flashloanTx];
43709
+ return {
43710
+ transactions,
43711
+ actionTxIndex: transactions.length - 1,
43712
+ quoteResponse: swapQuote
43713
+ };
43714
+ }
43715
+ async function buildSwapDebtFlashloanTx({
43716
+ program,
43717
+ marginfiAccount,
43718
+ bankMap,
43719
+ repayOpts,
43720
+ borrowOpts,
43721
+ swapOpts,
43722
+ bankMetadataMap,
43723
+ addressLookupTableAccounts,
43724
+ connection,
43725
+ overrideInferAccounts,
43726
+ blockhash
43727
+ }) {
43728
+ const { repayBank, tokenProgram: repayTokenProgram, totalPositionAmount } = repayOpts;
43729
+ const { borrowBank, tokenProgram: borrowTokenProgram } = borrowOpts;
43730
+ const swapResult = [];
43731
+ const cuRequestIxs = [
43732
+ web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 12e5 }),
43733
+ web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
43734
+ ];
43735
+ if (borrowBank.mint.equals(repayBank.mint)) {
43736
+ swapResult.push({
43737
+ amountToRepay: totalPositionAmount,
43738
+ borrowAmount: totalPositionAmount,
43739
+ swapInstructions: [],
43740
+ setupInstructions: [],
43741
+ swapLookupTables: []
43742
+ });
43743
+ } else {
43744
+ const destinationTokenAccount = getAssociatedTokenAddressSync(
43745
+ repayBank.mint,
43746
+ marginfiAccount.authority,
43747
+ true,
43748
+ repayTokenProgram.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : void 0
43749
+ );
43750
+ const swapResponses = await getJupiterSwapIxsForFlashloan({
43751
+ quoteParams: {
43752
+ inputMint: borrowBank.mint.toBase58(),
43753
+ outputMint: repayBank.mint.toBase58(),
43754
+ amount: uiToNative(totalPositionAmount, repayBank.mintDecimals).toNumber(),
43755
+ dynamicSlippage: swapOpts.jupiterOptions ? swapOpts.jupiterOptions.slippageMode === "DYNAMIC" : true,
43756
+ slippageBps: swapOpts.jupiterOptions?.slippageBps,
43757
+ swapMode: "ExactOut",
43758
+ platformFeeBps: swapOpts.jupiterOptions?.platformFeeBps,
43759
+ onlyDirectRoutes: swapOpts.jupiterOptions?.directRoutesOnly ?? false
43760
+ },
43761
+ authority: marginfiAccount.authority,
43762
+ connection,
43763
+ destinationTokenAccount,
43764
+ configParams: swapOpts.jupiterOptions?.configParams
43765
+ });
43766
+ swapResponses.forEach((response) => {
43767
+ const borrowAmount = nativeToUi(response.quoteResponse.inAmount, borrowBank.mintDecimals);
43768
+ swapResult.push({
43769
+ amountToRepay: totalPositionAmount,
43770
+ borrowAmount,
43771
+ swapInstructions: [response.swapInstruction],
43772
+ setupInstructions: response.setupInstructions,
43773
+ swapLookupTables: response.addressLookupTableAddresses,
43774
+ quoteResponse: response.quoteResponse
43775
+ });
43776
+ });
43777
+ }
43778
+ if (swapResult.length === 0) {
43779
+ throw new Error(
43780
+ `No swap routes found for ${borrowBank.mint.toBase58()} -> ${repayBank.mint.toBase58()}`
43781
+ );
43782
+ }
43783
+ for (const [index, item] of swapResult.entries()) {
43784
+ const {
43785
+ amountToRepay,
43786
+ borrowAmount,
43787
+ swapInstructions,
43788
+ setupInstructions,
43789
+ swapLookupTables,
43790
+ quoteResponse
43791
+ } = item;
43792
+ const borrowIxs = await makeBorrowIx3({
43793
+ program,
43794
+ bank: borrowBank,
43795
+ bankMap,
43796
+ tokenProgram: borrowTokenProgram,
43797
+ amount: borrowAmount,
43798
+ marginfiAccount,
43799
+ authority: marginfiAccount.authority,
43800
+ isSync: true,
43801
+ opts: {
43802
+ createAtas: false,
43803
+ wrapAndUnwrapSol: false,
43804
+ overrideInferAccounts
43805
+ }
43806
+ });
43807
+ const repayIxs = await makeRepayIx3({
43808
+ program,
43809
+ bank: repayBank,
43810
+ tokenProgram: repayTokenProgram,
43811
+ amount: amountToRepay,
43812
+ accountAddress: marginfiAccount.address,
43813
+ authority: marginfiAccount.authority,
43814
+ repayAll: isWholePosition(
43815
+ {
43816
+ amount: totalPositionAmount,
43817
+ isLending: false
43818
+ },
43819
+ amountToRepay,
43820
+ repayBank.mintDecimals
43821
+ ),
43822
+ isSync: true,
43823
+ opts: {
43824
+ wrapAndUnwrapSol: false,
43825
+ overrideInferAccounts
43826
+ }
43827
+ });
43828
+ const luts = [...addressLookupTableAccounts ?? [], ...swapLookupTables];
43829
+ const flashloanParams = {
43830
+ program,
43831
+ marginfiAccount,
43832
+ bankMap,
43833
+ addressLookupTableAccounts: luts,
43834
+ blockhash
43835
+ };
43836
+ const flashloanTx = await makeFlashLoanTx({
43837
+ ...flashloanParams,
43838
+ ixs: [
43839
+ ...cuRequestIxs,
43840
+ ...borrowIxs.instructions,
43841
+ ...swapInstructions,
43842
+ ...repayIxs.instructions
43843
+ ],
43844
+ isSync: true
43845
+ });
43846
+ const txSize = getTxSize(flashloanTx);
43847
+ const keySize = getAccountKeys(flashloanTx, luts);
43848
+ const isLast = index === swapResult.length - 1;
43849
+ if (txSize > MAX_TX_SIZE || keySize > 64) {
43850
+ if (isLast) {
43851
+ throw TransactionBuildingError.jupiterSwapSizeExceededLoop(txSize, keySize);
43852
+ } else {
43853
+ continue;
43854
+ }
43855
+ } else {
43856
+ return {
43857
+ flashloanTx,
43858
+ setupInstructions,
43859
+ swapQuote: quoteResponse,
43860
+ borrowIxs,
43861
+ repayIxs
43862
+ };
43863
+ }
43864
+ }
43865
+ throw new Error("Failed to build swap debt flashloan tx");
43866
+ }
43867
+
43868
+ // src/services/account/services/account-simulation.service.ts
43869
+ async function simulateAccountHealthCacheWithFallback(props) {
43870
+ let marginfiAccount = props.marginfiAccount;
43871
+ const activeBalances = marginfiAccount.balances.filter((b) => b.active);
43872
+ const { assets: assetValueEquity, liabilities: liabilityValueEquity } = computeHealthComponentsWithoutBiasLegacy(
43873
+ activeBalances,
43874
+ props.bankMap,
43875
+ props.oraclePrices,
43876
+ 2 /* Equity */
43877
+ );
43878
+ try {
43879
+ const simulatedAccount = await simulateAccountHealthCache({
43880
+ program: props.program,
43881
+ bankMap: props.bankMap,
43882
+ marginfiAccount: props.marginfiAccount,
43883
+ bankMetadataMap: props.bankMetadataMap
43884
+ });
43885
+ simulatedAccount.healthCache.assetValueEquity = bigNumberToWrappedI80F48(assetValueEquity);
43886
+ simulatedAccount.healthCache.liabilityValueEquity = bigNumberToWrappedI80F48(liabilityValueEquity);
43887
+ marginfiAccount = parseMarginfiAccountRaw(props.marginfiAccount.address, simulatedAccount);
43888
+ } catch (e) {
43889
+ console.log("e", e);
43890
+ const { assets: assetValueMaint, liabilities: liabilityValueMaint } = computeHealthComponentsLegacy(
43891
+ activeBalances,
43892
+ props.bankMap,
43893
+ props.oraclePrices,
43894
+ 1 /* Maintenance */,
43895
+ []
43896
+ );
43897
+ const { assets: assetValueInitial, liabilities: liabilityValueInitial } = computeHealthComponentsLegacy(
43898
+ activeBalances,
43899
+ props.bankMap,
43900
+ props.oraclePrices,
43901
+ 0 /* Initial */,
43902
+ []
43903
+ );
43904
+ marginfiAccount.healthCache = {
43905
+ assetValue: assetValueInitial,
43906
+ liabilityValue: liabilityValueInitial,
43907
+ assetValueMaint,
43908
+ liabilityValueMaint,
43909
+ assetValueEquity,
43910
+ liabilityValueEquity,
43911
+ timestamp: new BigNumber10__default.default(0),
43912
+ flags: [],
43913
+ prices: [],
43914
+ simulationStatus: 2 /* COMPUTED */
43915
+ };
43916
+ if (e instanceof HealthCacheSimulationError) {
43917
+ return { marginfiAccount, error: e };
43918
+ }
43919
+ }
43920
+ return { marginfiAccount };
43921
+ }
43922
+ async function simulateAccountHealthCache(props) {
43923
+ const { program, bankMap, marginfiAccount, bankMetadataMap } = props;
43924
+ const activeBalances = marginfiAccount.balances.filter((b) => b.active);
43925
+ const activeBanks = activeBalances.map((balance) => bankMap.get(balance.bankPk.toBase58())).filter((bank) => !!bank);
43926
+ const kaminoBanks = activeBanks.filter((bank) => bank.config.assetTag === 3 /* KAMINO */);
43927
+ const driftBanks = activeBanks.filter((bank) => bank.config.assetTag === 4 /* DRIFT */);
43928
+ const staleSwbOracles = activeBanks.filter(
43929
+ (bank) => bank.config.oracleSetup === "SwitchboardPull" /* SwitchboardPull */ || bank.config.oracleSetup === "SwitchboardV2" /* SwitchboardV2 */ || bank.config.oracleSetup === "KaminoSwitchboardPull" /* KaminoSwitchboardPull */ || bank.config.oracleSetup === "DriftSwitchboardPull" /* DriftSwitchboardPull */ || bank.config.oracleSetup === "SolendSwitchboardPull" /* SolendSwitchboardPull */
43930
+ ).filter((bank) => !bank.oracleKey.equals(new web3_js.PublicKey(ZERO_ORACLE_KEY)));
43931
+ const computeIx = web3_js.ComputeBudgetProgram.setComputeUnitLimit({
43932
+ units: 14e5
43933
+ });
43934
+ const blockhash = (await program.provider.connection.getLatestBlockhash("confirmed")).blockhash;
43935
+ const fundAccountIx = web3_js.SystemProgram.transfer({
43936
+ fromPubkey: new web3_js.PublicKey("DD3AeAssFvjqTvRTrRAtpfjkBF8FpVKnFuwnMLN9haXD"),
43937
+ // marginfi SOL VAULT
43938
+ toPubkey: marginfiAccount.authority,
43939
+ lamports: 1e8
43940
+ // 0.1 SOL
43941
+ });
43942
+ const updateDriftMarketData = driftBanks.map((bank) => {
43943
+ const bankMetadata = bankMetadataMap?.[bank.address.toBase58()];
43944
+ if (!bankMetadata?.driftStates) {
43945
+ console.error(`Bank metadata for drift bank ${bank.address.toBase58()} not found`);
43946
+ return;
43947
+ }
43948
+ const driftMarket = bankMetadata.driftStates.spotMarketState;
43949
+ return driftMarket;
43950
+ }).filter((state) => !!state);
43951
+ const refreshReserveData = kaminoBanks.map((bank) => {
43952
+ const bankMetadata = bankMetadataMap?.[bank.address.toBase58()];
43953
+ if (!bankMetadata?.kaminoStates) {
43954
+ console.error(`Bank metadata for kamino bank ${bank.address.toBase58()} not found`);
43955
+ return;
43956
+ }
43957
+ if (!bankMetadata?.kaminoStates || !bank.kaminoIntegrationAccounts) {
43958
+ console.error(`Integration data for kamino bank ${bank.address.toBase58()} not found`);
43959
+ return;
43960
+ }
43961
+ const kaminoReserve = bank.kaminoIntegrationAccounts.kaminoReserve;
43962
+ const lendingMarket = bankMetadata.kaminoStates.reserveState.lendingMarket;
43963
+ return {
43338
43964
  reserve: kaminoReserve,
43339
43965
  lendingMarket
43340
43966
  };
@@ -43348,7 +43974,7 @@ async function simulateAccountHealthCache(props) {
43348
43974
  swbPullOracles: staleSwbOracles.map((oracle) => ({
43349
43975
  key: oracle.oracleKey
43350
43976
  })),
43351
- feePayer: program.provider.publicKey,
43977
+ feePayer: marginfiAccount.authority,
43352
43978
  connection: program.provider.connection
43353
43979
  }) : { instructions: [], luts: [] };
43354
43980
  const updateDriftMarketIxs = updateDriftMarketData.map((market) => ({
@@ -43358,16 +43984,16 @@ async function simulateAccountHealthCache(props) {
43358
43984
  }));
43359
43985
  const healthPulseIxs = await makePulseHealthIx2(
43360
43986
  program,
43361
- marginfiAccountPk,
43987
+ marginfiAccount.address,
43362
43988
  bankMap,
43363
- balances,
43989
+ marginfiAccount.balances,
43364
43990
  activeBalances.map((b) => b.bankPk),
43365
43991
  []
43366
43992
  );
43367
43993
  const txs = [];
43368
43994
  const additionalTx = new web3_js.VersionedTransaction(
43369
43995
  new web3_js.TransactionMessage({
43370
- payerKey: program.provider.publicKey,
43996
+ payerKey: marginfiAccount.authority,
43371
43997
  recentBlockhash: blockhash,
43372
43998
  instructions: [
43373
43999
  computeIx,
@@ -43380,7 +44006,7 @@ async function simulateAccountHealthCache(props) {
43380
44006
  txs.push(additionalTx);
43381
44007
  const swbTx = new web3_js.VersionedTransaction(
43382
44008
  new web3_js.TransactionMessage({
43383
- payerKey: program.provider.publicKey,
44009
+ payerKey: marginfiAccount.authority,
43384
44010
  recentBlockhash: blockhash,
43385
44011
  instructions: [...crankSwbIxs.instructions]
43386
44012
  }).compileToV0Message([...crankSwbIxs.luts])
@@ -43388,7 +44014,7 @@ async function simulateAccountHealthCache(props) {
43388
44014
  txs.push(swbTx);
43389
44015
  const healthTx = new web3_js.VersionedTransaction(
43390
44016
  new web3_js.TransactionMessage({
43391
- payerKey: program.provider.publicKey,
44017
+ payerKey: marginfiAccount.authority,
43392
44018
  recentBlockhash: blockhash,
43393
44019
  instructions: [computeIx, ...healthPulseIxs.instructions]
43394
44020
  }).compileToV0Message([])
@@ -43399,7 +44025,7 @@ async function simulateAccountHealthCache(props) {
43399
44025
  throw new Error("Too many transactions");
43400
44026
  }
43401
44027
  const simulationResult = await simulateBundle(program.provider.connection.rpcEndpoint, txs, [
43402
- marginfiAccountPk
44028
+ marginfiAccount.address
43403
44029
  ]);
43404
44030
  const postExecutionAccount = simulationResult.find(
43405
44031
  (result) => result.postExecutionAccounts.length > 0
@@ -43614,23 +44240,19 @@ var fetchMarginfiAccountAddresses = async (program, authority, group) => {
43614
44240
  return marginfiAccounts;
43615
44241
  };
43616
44242
  var fetchMarginfiAccountData = async (program, marginfiAccountPk, bankMap, bankMetadataMap) => {
43617
- const marginfiAccountRaw = await program.account.marginfiAccount.fetch(marginfiAccountPk, "confirmed");
43618
- const marginfiAccount = parseMarginfiAccountRaw(
44243
+ const marginfiAccountRaw = await program.account.marginfiAccount.fetch(
43619
44244
  marginfiAccountPk,
43620
- marginfiAccountRaw
44245
+ "confirmed"
43621
44246
  );
44247
+ const marginfiAccount = parseMarginfiAccountRaw(marginfiAccountPk, marginfiAccountRaw);
43622
44248
  try {
43623
44249
  const simulatedAccount = await simulateAccountHealthCache({
43624
44250
  program,
43625
44251
  bankMap,
43626
- marginfiAccountPk,
43627
- balances: marginfiAccount.balances,
44252
+ marginfiAccount,
43628
44253
  bankMetadataMap
43629
44254
  });
43630
- const marginfiAccountWithCache = parseMarginfiAccountRaw(
43631
- marginfiAccountPk,
43632
- simulatedAccount
43633
- );
44255
+ const marginfiAccountWithCache = parseMarginfiAccountRaw(marginfiAccountPk, simulatedAccount);
43634
44256
  return { marginfiAccount: marginfiAccountWithCache };
43635
44257
  } catch (e) {
43636
44258
  console.error("Error simulating account health cache", e);
@@ -43652,10 +44274,7 @@ async function findRandomAvailableAccountIndex(connection, programId, group, aut
43652
44274
  const BATCH_SIZE = 16;
43653
44275
  const MAX_ATTEMPTS = 8;
43654
44276
  for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
43655
- const indices = randomDistinctIndices(
43656
- Math.min(BATCH_SIZE, MAX_INDEX),
43657
- MAX_INDEX
43658
- );
44277
+ const indices = randomDistinctIndices(Math.min(BATCH_SIZE, MAX_INDEX), MAX_INDEX);
43659
44278
  const pdas = indices.map(
43660
44279
  (i) => deriveMarginfiAccount(programId, group, authority, i, thirdPartyId)[0]
43661
44280
  );
@@ -43843,6 +44462,7 @@ var getJupiterSwapIxsForFlashloan = async ({
43843
44462
  });
43844
44463
  })
43845
44464
  );
44465
+ hasFeeAccount && finalQuoteParams.platformFeeBps && finalQuoteParams.platformFeeBps > 0;
43846
44466
  const swapInstructionResponses = await Promise.all(
43847
44467
  swapQuotes.map(
43848
44468
  (quote) => jupiterApiClient.swapInstructionsPost({
@@ -43867,7 +44487,6 @@ var getJupiterSwapIxsForFlashloan = async ({
43867
44487
  for (let i = 0; i < swapInstructionResponses.length; i++) {
43868
44488
  const response = swapInstructionResponses[i];
43869
44489
  const quote = swapQuotes[i];
43870
- i === swapInstructionResponses.length - 1;
43871
44490
  if (!response || !quote) continue;
43872
44491
  const address = response.addressLookupTableAddresses;
43873
44492
  const addressesLength = address.length;
@@ -46460,7 +47079,6 @@ var MarginfiAccount = class _MarginfiAccount {
46460
47079
  bankMap,
46461
47080
  oraclePrices,
46462
47081
  marginfiAccount: this,
46463
- balances: this.balances,
46464
47082
  bankMetadataMap
46465
47083
  });
46466
47084
  return {
@@ -47009,6 +47627,75 @@ var MarginfiAccount = class _MarginfiAccount {
47009
47627
  marginfiAccount: this
47010
47628
  });
47011
47629
  }
47630
+ /**
47631
+ * Creates a transaction to swap one collateral position to another using a flash loan.
47632
+ *
47633
+ * A swap collateral transaction:
47634
+ * 1. Withdraws existing collateral via flash loan
47635
+ * 2. Swaps collateral to new asset (via Jupiter)
47636
+ * 3. Deposits swapped assets as new collateral
47637
+ *
47638
+ * This allows users to change their collateral type (e.g., JitoSOL -> mSOL) without
47639
+ * withdrawing and affecting their health during the swap.
47640
+ *
47641
+ * @param params - Swap collateral transaction parameters
47642
+ * @param params.connection - Solana connection instance
47643
+ * @param params.oraclePrices - Map of current oracle prices
47644
+ * @param params.withdrawOpts - Withdraw configuration (bank, amount, tokenProgram)
47645
+ * @param params.depositOpts - Deposit configuration (bank, tokenProgram)
47646
+ * @param params.swapOpts - Jupiter swap configuration
47647
+ * @param params.addressLookupTableAccounts - Address lookup tables
47648
+ * @param params.overrideInferAccounts - Optional account overrides
47649
+ * @param params.additionalIxs - Additional instructions to include
47650
+ * @param params.crossbarUrl - Crossbar URL for oracle updates
47651
+ *
47652
+ * @returns Object containing transactions array, action index, and swap quote
47653
+ *
47654
+ * @throws {TransactionBuildingError} If swap exceeds transaction size limits
47655
+ * @throws {TransactionBuildingError} If Kamino reserve not found
47656
+ *
47657
+ * @see {@link makeSwapCollateralTx} for detailed implementation
47658
+ */
47659
+ async makeSwapCollateralTx(params) {
47660
+ return makeSwapCollateralTx({
47661
+ ...params,
47662
+ marginfiAccount: this
47663
+ });
47664
+ }
47665
+ /**
47666
+ * Creates a transaction to swap one debt position to another using a flash loan.
47667
+ *
47668
+ * A swap debt transaction:
47669
+ * 1. Borrows new asset via flash loan (new debt)
47670
+ * 2. Swaps new asset to old debt asset (via Jupiter)
47671
+ * 3. Repays old debt with swapped assets
47672
+ *
47673
+ * This allows users to change their debt type (e.g., USDC debt -> SOL debt) without
47674
+ * repaying and affecting their health during the swap.
47675
+ *
47676
+ * @param params - Swap debt transaction parameters
47677
+ * @param params.connection - Solana connection instance
47678
+ * @param params.oraclePrices - Map of current oracle prices
47679
+ * @param params.repayOpts - Repay configuration (bank, amount, tokenProgram)
47680
+ * @param params.borrowOpts - Borrow configuration (bank, tokenProgram)
47681
+ * @param params.swapOpts - Jupiter swap configuration
47682
+ * @param params.addressLookupTableAccounts - Address lookup tables
47683
+ * @param params.overrideInferAccounts - Optional account overrides
47684
+ * @param params.additionalIxs - Additional instructions to include
47685
+ * @param params.crossbarUrl - Crossbar URL for oracle updates
47686
+ *
47687
+ * @returns Object containing transactions array, action index, and swap quote
47688
+ *
47689
+ * @throws {TransactionBuildingError} If swap exceeds transaction size limits
47690
+ *
47691
+ * @see {@link makeSwapDebtTx} for detailed implementation
47692
+ */
47693
+ async makeSwapDebtTx(params) {
47694
+ return makeSwapDebtTx({
47695
+ ...params,
47696
+ marginfiAccount: this
47697
+ });
47698
+ }
47012
47699
  /**
47013
47700
  * Creates a deposit transaction.
47014
47701
  *
@@ -47436,6 +48123,50 @@ var MarginfiAccountWrapper = class {
47436
48123
  };
47437
48124
  return this.account.makeRepayWithCollatTx(fullParams);
47438
48125
  }
48126
+ /**
48127
+ * Creates a swap collateral transaction with auto-injected client data.
48128
+ *
48129
+ * Swaps one collateral type for another (e.g., JitoSOL -> mSOL) using a flash loan
48130
+ * so account health is not affected during the swap.
48131
+ *
48132
+ * Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap, addressLookupTables
48133
+ *
48134
+ * @param params - Swap collateral parameters (user provides: connection, withdrawOpts, depositOpts, swapOpts, etc.)
48135
+ */
48136
+ async makeSwapCollateralTx(params) {
48137
+ const fullParams = {
48138
+ ...params,
48139
+ program: this.client.program,
48140
+ marginfiAccount: this.account,
48141
+ bankMap: this.client.bankMap,
48142
+ oraclePrices: this.client.oraclePriceByBank,
48143
+ bankMetadataMap: this.client.bankIntegrationMap,
48144
+ addressLookupTableAccounts: this.client.addressLookupTables
48145
+ };
48146
+ return this.account.makeSwapCollateralTx(fullParams);
48147
+ }
48148
+ /**
48149
+ * Creates a swap debt transaction with auto-injected client data.
48150
+ *
48151
+ * Swaps one debt type for another (e.g., USDC debt -> SOL debt) using a flash loan
48152
+ * so account health is not affected during the swap.
48153
+ *
48154
+ * Auto-injects: program, marginfiAccount, bankMap, oraclePrices, bankMetadataMap, addressLookupTables
48155
+ *
48156
+ * @param params - Swap debt parameters (user provides: connection, repayOpts, borrowOpts, swapOpts, etc.)
48157
+ */
48158
+ async makeSwapDebtTx(params) {
48159
+ const fullParams = {
48160
+ ...params,
48161
+ program: this.client.program,
48162
+ marginfiAccount: this.account,
48163
+ bankMap: this.client.bankMap,
48164
+ oraclePrices: this.client.oraclePriceByBank,
48165
+ bankMetadataMap: this.client.bankIntegrationMap,
48166
+ addressLookupTableAccounts: this.client.addressLookupTables
48167
+ };
48168
+ return this.account.makeSwapDebtTx(fullParams);
48169
+ }
47439
48170
  /**
47440
48171
  * Creates a deposit transaction with auto-injected client data.
47441
48172
  *
@@ -47902,16 +48633,23 @@ var Project0Client = class _Project0Client {
47902
48633
  * @param accountAddress - The public key of the marginfi account
47903
48634
  * @returns A wrapped account ready to use
47904
48635
  */
47905
- async fetchAccount(accountAddress) {
47906
- const bankMap = new Map(this.banks.map((b) => [b.address.toBase58(), b]));
47907
- const { marginfiAccount } = await fetchMarginfiAccountData(
47908
- this.program,
48636
+ async fetchAccount(accountAddress, skipHealthCache) {
48637
+ const marginfiAccountRaw = await this.program.account.marginfiAccount.fetch(accountAddress);
48638
+ let marginfiAccountParsed = MarginfiAccount.fromAccountParsed(
47909
48639
  accountAddress,
47910
- bankMap,
47911
- this.bankIntegrationMap
48640
+ marginfiAccountRaw
47912
48641
  );
47913
- const account = MarginfiAccount.fromAccountType(marginfiAccount);
47914
- return new MarginfiAccountWrapper(account, this);
48642
+ if (!skipHealthCache) {
48643
+ const bankMap = new Map(this.banks.map((b) => [b.address.toBase58(), b]));
48644
+ const { account: simulatedAccount } = await marginfiAccountParsed.simulateHealthCache(
48645
+ this.program,
48646
+ bankMap,
48647
+ this.oraclePriceByBank,
48648
+ this.bankIntegrationMap
48649
+ );
48650
+ marginfiAccountParsed = simulatedAccount;
48651
+ }
48652
+ return new MarginfiAccountWrapper(marginfiAccountParsed, this);
47915
48653
  }
47916
48654
  static async initialize(connection, config) {
47917
48655
  const { groupPk, programId } = config;
@@ -48269,6 +49007,8 @@ exports.makeRepayTx = makeRepayTx;
48269
49007
  exports.makeRepayWithCollatTx = makeRepayWithCollatTx;
48270
49008
  exports.makeSetupIx = makeSetupIx;
48271
49009
  exports.makeSmartCrankSwbFeedIx = makeSmartCrankSwbFeedIx;
49010
+ exports.makeSwapCollateralTx = makeSwapCollateralTx;
49011
+ exports.makeSwapDebtTx = makeSwapDebtTx;
48272
49012
  exports.makeTxPriorityIx = makeTxPriorityIx;
48273
49013
  exports.makeUnwrapSolIx = makeUnwrapSolIx;
48274
49014
  exports.makeUpdateDriftMarketIxs = makeUpdateDriftMarketIxs;