@0dotxyz/p0-ts-sdk 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -216,6 +216,7 @@ var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCod
216
216
  TransactionBuildingErrorCode2["BRIDGE_CONFLICT"] = "BRIDGE_CONFLICT";
217
217
  TransactionBuildingErrorCode2["ORDER_INVALID_TRIGGER"] = "ORDER_INVALID_TRIGGER";
218
218
  TransactionBuildingErrorCode2["ORDER_INVALID_SLIPPAGE"] = "ORDER_INVALID_SLIPPAGE";
219
+ TransactionBuildingErrorCode2["ORDER_CLOSES_DONT_FIT"] = "ORDER_CLOSES_DONT_FIT";
219
220
  TransactionBuildingErrorCode2["COSTLY_POSITION_LIMIT_EXCEEDED"] = "COSTLY_POSITION_LIMIT_EXCEEDED";
220
221
  TransactionBuildingErrorCode2["ACCOUNT_DISABLED"] = "ACCOUNT_DISABLED";
221
222
  return TransactionBuildingErrorCode2;
@@ -384,6 +385,19 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
384
385
  { maxSlippagePercent, maxAllowedPercent }
385
386
  );
386
387
  }
388
+ /**
389
+ * Closing the orders an action touches doesn't fit in one transaction: next to the action, or in
390
+ * the one order transaction after a multi-transaction action. Builders throw rather than leave the
391
+ * closes out, since an order on a changed position can still fire: close the orders on their own
392
+ * first, then retry the action.
393
+ */
394
+ static orderClosesDontFit(orderAddresses) {
395
+ return new _TransactionBuildingError(
396
+ "ORDER_CLOSES_DONT_FIT" /* ORDER_CLOSES_DONT_FIT */,
397
+ `Closing ${orderAddresses.length} order(s) doesn't fit in one transaction`,
398
+ { orderAddresses }
399
+ );
400
+ }
387
401
  /**
388
402
  * The marginfi account is disabled (e.g. already transferred to a new account), so it can't act.
389
403
  */
@@ -76840,18 +76854,12 @@ function computeHealthComponentsFromBalances(params) {
76840
76854
  let totalLiabilities = new BigNumber3__default.default(0);
76841
76855
  for (const accountBalance of filteredBalances) {
76842
76856
  const bankKey = accountBalance.bankPk.toBase58();
76843
- const bank = banksMap.get(bankKey);
76844
- if (!bank) {
76845
- console.warn(
76846
- `Bank ${shortenAddress(accountBalance.bankPk)} not found, excluding from health computation`
76847
- );
76848
- continue;
76849
- }
76857
+ const bank = requireBank(banksMap, accountBalance.bankPk);
76850
76858
  const oraclePrice = oraclePricesByBank.get(bankKey);
76851
76859
  if (!oraclePrice) {
76852
- console.warn(
76853
- `Price info for bank ${shortenAddress(accountBalance.bankPk)} not found, excluding from health computation`
76854
- );
76860
+ if (accountBalance.liabilityShares.gt(0)) {
76861
+ throw Error(`Oracle price for ${bankKey} not found`);
76862
+ }
76855
76863
  continue;
76856
76864
  }
76857
76865
  const emodeWeight = activeEmodeWeightsByBank?.get(bankKey);
@@ -77060,7 +77068,7 @@ function computeLiquidationPriceForBank(params) {
77060
77068
  const { bank, oraclePrice, marginfiAccount, assetShareValueMultiplier, activeEmodeWeights } = params;
77061
77069
  const balance = getBalance(bank.address, marginfiAccount.balances);
77062
77070
  if (!balance.active) return null;
77063
- const { assets: assetBank, liabilities: liabilitiesBank } = computeBalanceUsdValue({
77071
+ const { assets: assetBank, liabilities: liabilitiesBank } = getBalanceUsdValueWithPriceBias({
77064
77072
  balance,
77065
77073
  bank,
77066
77074
  oraclePrice,
@@ -77074,7 +77082,8 @@ function computeLiquidationPriceForBank(params) {
77074
77082
  const isLending = balance.liabilityShares.isZero();
77075
77083
  const { assets: assetQuantityUi, liabilities: liabQuantitiesUi } = computeQuantityUi(
77076
77084
  balance,
77077
- bank
77085
+ bank,
77086
+ assetShareValueMultiplier
77078
77087
  );
77079
77088
  let liquidationPrice;
77080
77089
  if (isLending) {
@@ -77180,6 +77189,8 @@ function computeBankRiskAccountKeys(bank) {
77180
77189
  } else if (bank.stakedOracleUsesOnramp && bank.stakedIntegrationAccounts && !bank.stakedIntegrationAccounts.validatorVoteAccount.equals(web3_js.PublicKey.default)) {
77181
77190
  const pool = findPoolAddress(bank.stakedIntegrationAccounts.validatorVoteAccount);
77182
77191
  keys.push(findPoolOnRampAddress(pool));
77192
+ } else {
77193
+ keys.push(web3_js.PublicKey.default);
77183
77194
  }
77184
77195
  }
77185
77196
  return keys;
@@ -78218,7 +78229,6 @@ function createJupiterClient(config = {}) {
78218
78229
  // src/services/account/utils/swap.utils.ts
78219
78230
  function resolvePinnedSwapRoute(swapIxs, expectedInAmountNative) {
78220
78231
  const { quoteResponse } = swapIxs;
78221
- const expectedIn = new BN8__default.default(expectedInAmountNative);
78222
78232
  let minOut;
78223
78233
  try {
78224
78234
  minOut = new BN8__default.default(quoteResponse.otherAmountThreshold);
@@ -78231,15 +78241,15 @@ function resolvePinnedSwapRoute(swapIxs, expectedInAmountNative) {
78231
78241
  );
78232
78242
  }
78233
78243
  const pinnedIn = new BN8__default.default(quoteResponse.inAmount);
78234
- if (!pinnedIn.eq(expectedIn)) {
78244
+ if (expectedInAmountNative !== void 0 && !pinnedIn.eq(new BN8__default.default(expectedInAmountNative))) {
78235
78245
  throw new Error(
78236
- `Pinned swap route (swapOpts.swapIxs) was quoted for a different input amount than the flow will swap: quote inAmount=${pinnedIn.toString()}, flow swap input=${expectedIn.toString()} (native units). Re-quote the pinned route for the exact flow amount.`
78246
+ `Pinned swap route (swapOpts.swapIxs) was quoted for a different input amount than the flow will swap: quote inAmount=${pinnedIn.toString()}, flow swap input=${expectedInAmountNative.toString()} (native units). Re-quote the pinned route for the exact flow amount.`
78237
78247
  );
78238
78248
  }
78239
78249
  return {
78240
78250
  swapInstructions: swapIxs.instructions,
78241
78251
  setupInstructions: [],
78242
- lookupTables: swapIxs.lookupTables,
78252
+ swapLuts: swapIxs.lookupTables,
78243
78253
  quoteResponse,
78244
78254
  outputAmountNative: minOut
78245
78255
  };
@@ -78353,7 +78363,7 @@ var getSwapIxsForFlashloan = async (params) => {
78353
78363
  return {
78354
78364
  swapInstructions: pinned.swapInstructions,
78355
78365
  setupInstructions: pinned.setupInstructions,
78356
- addressLookupTableAddresses: pinned.lookupTables,
78366
+ addressLookupTableAddresses: pinned.swapLuts,
78357
78367
  quoteResponse: pinned.quoteResponse
78358
78368
  };
78359
78369
  }
@@ -78551,17 +78561,8 @@ var getJupiterSwapIxsForFlashloan = async ({
78551
78561
  quoteResponse: mapJupiterQuoteToSwapQuoteResult(swapQuote)
78552
78562
  };
78553
78563
  };
78554
-
78555
- // src/services/account/utils/misc.utils.ts
78556
- function floor(value, decimals) {
78557
- return Math.floor(value * 10 ** decimals) / 10 ** decimals;
78558
- }
78559
- function ceil(value, decimals) {
78560
- return Math.ceil(value * 10 ** decimals) / 10 ** decimals;
78561
- }
78562
78564
  function computeClosePositionTokenAmount(position, mintDecimals) {
78563
- const closePositionTokenAmount = position.isLending ? floor(position.amount, mintDecimals) : ceil(position.amount, mintDecimals);
78564
- return closePositionTokenAmount;
78565
+ return new BigNumber3.BigNumber(position.amount).decimalPlaces(mintDecimals, position.isLending ? BigNumber3.BigNumber.ROUND_FLOOR : BigNumber3.BigNumber.ROUND_CEIL).toNumber();
78565
78566
  }
78566
78567
  function isWholePosition(position, amount, mintDecimals) {
78567
78568
  const closePositionTokenAmount = computeClosePositionTokenAmount(position, mintDecimals);
@@ -78587,6 +78588,162 @@ function exceedsCostlyPositionLimit(balances, bankMap, bank) {
78587
78588
  }).length;
78588
78589
  return held >= MAX_COSTLY_POSITIONS;
78589
78590
  }
78591
+ function buildOrderTrigger(params) {
78592
+ const { stopLossUsd, takeProfitUsd } = params;
78593
+ const maxSlippage = percentToMaxSlippageU32(params.maxSlippagePercent);
78594
+ const invalidTrigger = (reason) => TransactionBuildingError.orderInvalidTrigger(
78595
+ reason,
78596
+ takeProfitUsd?.toString(),
78597
+ stopLossUsd?.toString()
78598
+ );
78599
+ if (stopLossUsd && !stopLossUsd.gt(0)) {
78600
+ throw invalidTrigger(`stop-loss threshold (${stopLossUsd}) must be above 0`);
78601
+ }
78602
+ if (takeProfitUsd && !takeProfitUsd.gt(0)) {
78603
+ throw invalidTrigger(`take-profit threshold (${takeProfitUsd}) must be above 0`);
78604
+ }
78605
+ if (stopLossUsd && takeProfitUsd) {
78606
+ if (takeProfitUsd.lte(stopLossUsd)) {
78607
+ throw invalidTrigger(
78608
+ `take-profit threshold (${takeProfitUsd}) must be above stop-loss threshold (${stopLossUsd})`
78609
+ );
78610
+ }
78611
+ return {
78612
+ both: {
78613
+ stopLoss: bigNumberToWrappedI80F48(stopLossUsd),
78614
+ takeProfit: bigNumberToWrappedI80F48(takeProfitUsd),
78615
+ maxSlippage
78616
+ }
78617
+ };
78618
+ }
78619
+ if (stopLossUsd) {
78620
+ return { stopLoss: { threshold: bigNumberToWrappedI80F48(stopLossUsd), maxSlippage } };
78621
+ }
78622
+ if (takeProfitUsd) {
78623
+ return { takeProfit: { threshold: bigNumberToWrappedI80F48(takeProfitUsd), maxSlippage } };
78624
+ }
78625
+ throw invalidTrigger("an order needs a stop-loss threshold, a take-profit threshold, or both");
78626
+ }
78627
+ async function makePlaceOrderIx2(params) {
78628
+ const { program, marginfiAccount, collateralBank, debtBank, trigger, feePayer } = params;
78629
+ const [order] = deriveOrderPda(program.programId, marginfiAccount.address, [
78630
+ collateralBank,
78631
+ debtBank
78632
+ ]);
78633
+ const globalFeeWallet = params.globalFeeWallet ?? (await program.account.feeState.fetch(deriveFeeState(program.programId)[0])).globalFeeWallet;
78634
+ const placeOrderIx = await instructions_default3.makePlaceOrderIx(
78635
+ program,
78636
+ {
78637
+ marginfiAccount: marginfiAccount.address,
78638
+ feePayer: feePayer ?? marginfiAccount.authority,
78639
+ authority: marginfiAccount.authority,
78640
+ order,
78641
+ globalFeeWallet,
78642
+ group: marginfiAccount.group
78643
+ },
78644
+ { bankKeys: [collateralBank, debtBank], trigger: buildOrderTrigger(trigger) }
78645
+ );
78646
+ return { instructions: [placeOrderIx], keys: [] };
78647
+ }
78648
+ async function makeCloseOrderIx2(params) {
78649
+ const { program, marginfiAccount, order, feeRecipient } = params;
78650
+ const closeOrderIx = await instructions_default3.makeCloseOrderIx(program, {
78651
+ marginfiAccount: marginfiAccount.address,
78652
+ authority: marginfiAccount.authority,
78653
+ order,
78654
+ feeRecipient: feeRecipient ?? marginfiAccount.authority,
78655
+ group: marginfiAccount.group
78656
+ });
78657
+ return { instructions: [closeOrderIx], keys: [] };
78658
+ }
78659
+ async function compileOrderTx(params, payerKey, ixs, type) {
78660
+ const blockhash = params.blockhash ?? (await params.connection.getLatestBlockhashAndContext("confirmed")).value.blockhash;
78661
+ return addTransactionMetadata(
78662
+ new web3_js.VersionedTransaction(
78663
+ new web3_js.TransactionMessage({
78664
+ instructions: ixs.flatMap((ix) => ix.instructions),
78665
+ payerKey,
78666
+ recentBlockhash: blockhash
78667
+ }).compileToV0Message(params.luts)
78668
+ ),
78669
+ { type, signers: ixs.flatMap((ix) => ix.keys), addressLookupTables: params.luts }
78670
+ );
78671
+ }
78672
+ async function makePlaceOrderTx(params) {
78673
+ const placeIxs = await makePlaceOrderIx2(params);
78674
+ const payerKey = params.feePayer ?? params.marginfiAccount.authority;
78675
+ return compileOrderTx(params, payerKey, [placeIxs], "PLACE_ORDER" /* PLACE_ORDER */);
78676
+ }
78677
+ async function makeCloseOrderTx(params) {
78678
+ const closeIxs = await makeCloseOrderIx2(params);
78679
+ return compileOrderTx(
78680
+ params,
78681
+ params.marginfiAccount.authority,
78682
+ [closeIxs],
78683
+ "CLOSE_ORDER" /* CLOSE_ORDER */
78684
+ );
78685
+ }
78686
+ async function makeUpdateOrderTx(params) {
78687
+ const [order] = deriveOrderPda(params.program.programId, params.marginfiAccount.address, [
78688
+ params.collateralBank,
78689
+ params.debtBank
78690
+ ]);
78691
+ const closeIxs = await makeCloseOrderIx2({ ...params, order, feeRecipient: params.feePayer });
78692
+ const placeIxs = await makePlaceOrderIx2(params);
78693
+ const payerKey = params.feePayer ?? params.marginfiAccount.authority;
78694
+ return compileOrderTx(params, payerKey, [closeIxs, placeIxs], "UPDATE_ORDER" /* UPDATE_ORDER */);
78695
+ }
78696
+ var SEND_PIPELINE_MARGINS = {
78697
+ sizeMargin: PRIORITY_TX_SIZE + BUNDLE_TX_SIZE,
78698
+ maxAccountLocks: MAX_ACCOUNT_LOCKS - 3
78699
+ };
78700
+ async function makeOrderChangesIxs(params) {
78701
+ const { program, marginfiAccount, ordersToClose = [], placeOrder } = params;
78702
+ const wrappers = await Promise.all([
78703
+ ...ordersToClose.map((order) => makeCloseOrderIx2({ program, marginfiAccount, order })),
78704
+ ...placeOrder ? [makePlaceOrderIx2({ ...placeOrder, program, marginfiAccount })] : []
78705
+ ]);
78706
+ return wrappers.flatMap((wrapper) => wrapper.instructions);
78707
+ }
78708
+ async function prependOrderCloses(params, actionIxs, luts) {
78709
+ const { program, marginfiAccount, ordersToClose = [] } = params;
78710
+ if (ordersToClose.length === 0) return actionIxs;
78711
+ const closeIxs = await makeOrderChangesIxs({ program, marginfiAccount, ordersToClose });
78712
+ const withCloses = [...closeIxs, ...actionIxs];
78713
+ if (!fitsInOneTransaction(withCloses, {
78714
+ payerKey: params.authority,
78715
+ luts,
78716
+ ...SEND_PIPELINE_MARGINS
78717
+ })) {
78718
+ throw TransactionBuildingError.orderClosesDontFit(
78719
+ ordersToClose.map((order) => order.toBase58())
78720
+ );
78721
+ }
78722
+ return withCloses;
78723
+ }
78724
+ async function makeOrderChangesTx(params) {
78725
+ const { program, marginfiAccount, ordersToClose = [], placeOrder, luts } = params;
78726
+ const ixs = await makeOrderChangesIxs(params);
78727
+ if (ixs.length === 0) return void 0;
78728
+ if (!fitsInOneTransaction(ixs, {
78729
+ payerKey: marginfiAccount.authority,
78730
+ luts,
78731
+ ...SEND_PIPELINE_MARGINS
78732
+ })) {
78733
+ throw TransactionBuildingError.orderClosesDontFit(
78734
+ ordersToClose.map((order) => order.toBase58())
78735
+ );
78736
+ }
78737
+ let type = "CLOSE_ORDER" /* CLOSE_ORDER */;
78738
+ if (placeOrder) {
78739
+ const [placedOrder] = deriveOrderPda(program.programId, marginfiAccount.address, [
78740
+ placeOrder.collateralBank,
78741
+ placeOrder.debtBank
78742
+ ]);
78743
+ type = ordersToClose.some((order) => order.equals(placedOrder)) ? "UPDATE_ORDER" /* UPDATE_ORDER */ : "PLACE_ORDER" /* PLACE_ORDER */;
78744
+ }
78745
+ return compileOrderTx(params, marginfiAccount.authority, [{ instructions: ixs, keys: [] }], type);
78746
+ }
78590
78747
  var KAMINO_PROGRAM_ID = new web3_js.PublicKey("KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD");
78591
78748
  var FARMS_PROGRAM_ID2 = new web3_js.PublicKey("FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr");
78592
78749
  function encodeU642(value) {
@@ -79310,13 +79467,18 @@ async function makeBorrowTx(params) {
79310
79467
  params.bankMetadataMap
79311
79468
  );
79312
79469
  const borrowIxs = await makeBorrowIx3(borrowIxParams);
79470
+ const ixs = await prependOrderCloses(
79471
+ params,
79472
+ [...refreshIntegrationIxs.instructions, ...borrowIxs.instructions],
79473
+ selectedLuts
79474
+ );
79313
79475
  const {
79314
79476
  value: { blockhash }
79315
79477
  } = await connection.getLatestBlockhashAndContext("confirmed");
79316
79478
  const borrowTx = addTransactionMetadata(
79317
79479
  new web3_js.VersionedTransaction(
79318
79480
  new web3_js.TransactionMessage({
79319
- instructions: [...refreshIntegrationIxs.instructions, ...borrowIxs.instructions],
79481
+ instructions: ixs,
79320
79482
  payerKey: params.authority,
79321
79483
  recentBlockhash: blockhash
79322
79484
  }).compileToV0Message(selectedLuts)
@@ -79415,9 +79577,14 @@ async function makeDriftDepositTx(params) {
79415
79577
  amount,
79416
79578
  ...depositIxParams
79417
79579
  });
79418
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79580
+ const actionIxs = await prependOrderCloses(
79419
79581
  params,
79420
79582
  depositIxs.instructions,
79583
+ selectLutsForBanks(luts, [params.bank])
79584
+ );
79585
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79586
+ params,
79587
+ actionIxs,
79421
79588
  [params.bank.address],
79422
79589
  []
79423
79590
  );
@@ -79558,9 +79725,14 @@ async function makeKaminoDepositTx(params) {
79558
79725
  amount,
79559
79726
  ...depositIxParams
79560
79727
  });
79561
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79728
+ const actionIxs = await prependOrderCloses(
79562
79729
  params,
79563
79730
  [...refreshIxs, ...depositIxs.instructions],
79731
+ selectLutsForBanks(luts, [params.bank])
79732
+ );
79733
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79734
+ params,
79735
+ actionIxs,
79564
79736
  [params.bank.address],
79565
79737
  []
79566
79738
  );
@@ -79649,9 +79821,14 @@ async function makeDepositTx(params) {
79649
79821
  throw TransactionBuildingError.costlyPositionLimitExceeded(params.bank.address.toBase58());
79650
79822
  }
79651
79823
  const ixs = await makeDepositIx3(depositIxParams);
79652
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79824
+ const actionIxs = await prependOrderCloses(
79653
79825
  params,
79654
79826
  ixs.instructions,
79827
+ selectLutsForBanks(luts, [params.bank])
79828
+ );
79829
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79830
+ params,
79831
+ actionIxs,
79655
79832
  [params.bank.address],
79656
79833
  []
79657
79834
  );
@@ -79741,9 +79918,14 @@ async function makeJuplendDepositTx(params) {
79741
79918
  amount,
79742
79919
  ...depositIxParams
79743
79920
  });
79744
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79921
+ const actionIxs = await prependOrderCloses(
79745
79922
  params,
79746
79923
  depositIxs.instructions,
79924
+ selectLutsForBanks(luts, [params.bank])
79925
+ );
79926
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79927
+ params,
79928
+ actionIxs,
79747
79929
  [params.bank.address],
79748
79930
  []
79749
79931
  );
@@ -80519,13 +80701,18 @@ async function makeDriftWithdrawTx(params) {
80519
80701
  [withdrawIxParams.bank.address],
80520
80702
  params.bankMetadataMap
80521
80703
  );
80704
+ const ixs = await prependOrderCloses(
80705
+ params,
80706
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80707
+ selectedLuts
80708
+ );
80522
80709
  const {
80523
80710
  value: { blockhash }
80524
80711
  } = await connection.getLatestBlockhashAndContext("confirmed");
80525
80712
  const withdrawTx = addTransactionMetadata(
80526
80713
  new web3_js.VersionedTransaction(
80527
80714
  new web3_js.TransactionMessage({
80528
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80715
+ instructions: ixs,
80529
80716
  payerKey: params.authority,
80530
80717
  recentBlockhash: blockhash
80531
80718
  }).compileToV0Message(selectedLuts)
@@ -80772,13 +80959,18 @@ async function makeWithdrawTx(params) {
80772
80959
  [withdrawIxParams.bank.address],
80773
80960
  params.bankMetadataMap
80774
80961
  );
80962
+ const ixs = await prependOrderCloses(
80963
+ params,
80964
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80965
+ selectedLuts
80966
+ );
80775
80967
  const {
80776
80968
  value: { blockhash }
80777
80969
  } = await connection.getLatestBlockhashAndContext("confirmed");
80778
80970
  const withdrawTx = addTransactionMetadata(
80779
80971
  new web3_js.VersionedTransaction(
80780
80972
  new web3_js.TransactionMessage({
80781
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80973
+ instructions: ixs,
80782
80974
  payerKey: params.authority,
80783
80975
  recentBlockhash: blockhash
80784
80976
  }).compileToV0Message(selectedLuts)
@@ -80816,13 +81008,18 @@ async function makeKaminoWithdrawTx(params) {
80816
81008
  cTokenAmount: adjustedAmount,
80817
81009
  ...withdrawIxParams
80818
81010
  });
81011
+ const ixs = await prependOrderCloses(
81012
+ params,
81013
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81014
+ selectedLuts
81015
+ );
80819
81016
  const {
80820
81017
  value: { blockhash }
80821
81018
  } = await connection.getLatestBlockhashAndContext("confirmed");
80822
81019
  const withdrawTx = addTransactionMetadata(
80823
81020
  new web3_js.VersionedTransaction(
80824
81021
  new web3_js.TransactionMessage({
80825
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81022
+ instructions: ixs,
80826
81023
  payerKey: params.authority,
80827
81024
  recentBlockhash: blockhash
80828
81025
  }).compileToV0Message(selectedLuts)
@@ -80946,13 +81143,18 @@ async function makeJuplendWithdrawTx(params) {
80946
81143
  [withdrawIxParams.bank.address],
80947
81144
  params.bankMetadataMap
80948
81145
  );
81146
+ const ixs = await prependOrderCloses(
81147
+ params,
81148
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81149
+ selectedLuts
81150
+ );
80949
81151
  const {
80950
81152
  value: { blockhash }
80951
81153
  } = await connection.getLatestBlockhashAndContext("confirmed");
80952
81154
  const withdrawTx = addTransactionMetadata(
80953
81155
  new web3_js.VersionedTransaction(
80954
81156
  new web3_js.TransactionMessage({
80955
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81157
+ instructions: ixs,
80956
81158
  payerKey: params.authority,
80957
81159
  recentBlockhash: blockhash
80958
81160
  }).compileToV0Message(selectedLuts)
@@ -81022,10 +81224,15 @@ async function makeRepayIx3({
81022
81224
  async function makeRepayTx(params) {
81023
81225
  const { luts, ...repayIxParams } = params;
81024
81226
  const ixs = await makeRepayIx3(repayIxParams);
81227
+ const actionIxs = await prependOrderCloses(
81228
+ params,
81229
+ ixs.instructions,
81230
+ selectLutsForBanks(luts, [params.bank])
81231
+ );
81025
81232
  const closedBanks = params.repayAll ? [params.bank.address] : [];
81026
81233
  const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
81027
81234
  params,
81028
- ixs.instructions,
81235
+ actionIxs,
81029
81236
  [],
81030
81237
  closedBanks
81031
81238
  );
@@ -81092,12 +81299,18 @@ async function makeRepayWithCollatTx(params) {
81092
81299
  payerKey: marginfiAccount.authority,
81093
81300
  luts: addressLookupTableAccounts ?? []
81094
81301
  });
81302
+ const orderTx = await makeOrderChangesTx({
81303
+ ...params,
81304
+ luts: addressLookupTableAccounts ?? [],
81305
+ blockhash
81306
+ });
81095
81307
  const transactions = [...additionalTxs, flashloanTx];
81308
+ if (orderTx) transactions.push(orderTx);
81096
81309
  return {
81097
81310
  transactions,
81098
81311
  swapQuote,
81099
81312
  amountToRepay,
81100
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
81313
+ mustBeAtomicBundle: transactions.length > 1
81101
81314
  };
81102
81315
  }
81103
81316
  async function buildRepayWithCollatFlashloanTx({
@@ -83593,7 +83806,8 @@ async function composeBridgedSwap(params) {
83593
83806
  banksMap,
83594
83807
  assetShareValueMultiplierByBank,
83595
83808
  feePayer,
83596
- maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS
83809
+ maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS,
83810
+ reservedTxs = 0
83597
83811
  } = params;
83598
83812
  if (!firstLeg.quoteResponse) return null;
83599
83813
  const projectedAccount = projectAccountAfterFirstLeg(
@@ -83610,7 +83824,7 @@ async function composeBridgedSwap(params) {
83610
83824
  secondLeg.transactions,
83611
83825
  feePayer,
83612
83826
  blockhashOf(firstLeg),
83613
- maxBundleTxs
83827
+ maxBundleTxs - reservedTxs
83614
83828
  );
83615
83829
  if (!transactions) return null;
83616
83830
  return {
@@ -83672,12 +83886,18 @@ async function makeSwapDebtTx(params) {
83672
83886
  luts: addressLookupTableAccounts ?? []
83673
83887
  }
83674
83888
  );
83889
+ const orderTx = await makeOrderChangesTx({
83890
+ ...params,
83891
+ luts: addressLookupTableAccounts ?? [],
83892
+ blockhash
83893
+ });
83675
83894
  const transactions = [...additionalTxs, flashloanTx];
83895
+ if (orderTx) transactions.push(orderTx);
83676
83896
  return {
83677
83897
  transactions,
83678
- actionTxIndex: transactions.length - 1,
83898
+ actionTxIndex: additionalTxs.length,
83679
83899
  quoteResponse: swapQuote,
83680
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
83900
+ mustBeAtomicBundle: transactions.length > 1
83681
83901
  };
83682
83902
  }
83683
83903
  async function buildSwapDebtFlashloanTx({
@@ -83754,7 +83974,7 @@ async function buildSwapDebtFlashloanTx({
83754
83974
  opts: { wrapAndUnwrapSol: false, overrideInferAccounts }
83755
83975
  });
83756
83976
  const runEngine = swapEngineRunner ?? runSwapEngine;
83757
- const engineResult = await runEngine({
83977
+ const engineResult = swapOpts.swapIxs ? resolvePinnedSwapRoute(swapOpts.swapIxs) : await runEngine({
83758
83978
  inputMint: borrowBank.mint.toBase58(),
83759
83979
  outputMint: repayBank.mint.toBase58(),
83760
83980
  amountNative: uiToNative(estimatedBorrowAmount, borrowBank.mintDecimals).toNumber(),
@@ -83780,7 +84000,8 @@ async function buildSwapDebtFlashloanTx({
83780
84000
  const quoteResponse = engineResult.quoteResponse;
83781
84001
  const outAmount = nativeToUi(quoteResponse.outAmount, repayBank.mintDecimals);
83782
84002
  const outAmountThreshold = nativeToUi(quoteResponse.otherAmountThreshold, repayBank.mintDecimals);
83783
- const amountToRepay = outAmount > totalPositionAmount ? totalPositionAmount : outAmountThreshold;
84003
+ const repayAll = outAmount > totalPositionAmount;
84004
+ const amountToRepay = repayAll ? totalPositionAmount : outAmountThreshold;
83784
84005
  const borrowAmount = nativeToUi(quoteResponse.inAmount, borrowBank.mintDecimals);
83785
84006
  const borrowIxs = await makeBorrowIx3({
83786
84007
  program,
@@ -83804,14 +84025,7 @@ async function buildSwapDebtFlashloanTx({
83804
84025
  amount: amountToRepay,
83805
84026
  accountAddress: marginfiAccount.address,
83806
84027
  authority: marginfiAccount.authority,
83807
- repayAll: isWholePosition(
83808
- {
83809
- amount: totalPositionAmount,
83810
- isLending: false
83811
- },
83812
- amountToRepay,
83813
- repayBank.mintDecimals
83814
- ),
84028
+ repayAll,
83815
84029
  isSync: true,
83816
84030
  opts: {
83817
84031
  wrapAndUnwrapSol: false,
@@ -83884,6 +84098,10 @@ async function tryBridgedDebtSwap(params, bridgeOpts) {
83884
84098
  bridgeTokenSide: "borrow",
83885
84099
  bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
83886
84100
  });
84101
+ const orderTx = await makeOrderChangesTx({
84102
+ ...params,
84103
+ luts: params.addressLookupTableAccounts ?? []
84104
+ });
83887
84105
  const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
83888
84106
  return tryBridgeCandidates({
83889
84107
  usableBridgeBanks,
@@ -83937,11 +84155,12 @@ async function tryBridgedDebtSwap(params, bridgeOpts) {
83937
84155
  banksMap: params.bankMap,
83938
84156
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
83939
84157
  feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
83940
- maxBundleTxs: bridgeOpts?.maxBundleTxs
84158
+ maxBundleTxs: bridgeOpts?.maxBundleTxs,
84159
+ reservedTxs: orderTx ? 1 : 0
83941
84160
  });
83942
84161
  if (!result) return null;
83943
84162
  return {
83944
- transactions: result.transactions,
84163
+ transactions: orderTx ? [...result.transactions, orderTx] : result.transactions,
83945
84164
  actionTxIndex: result.transactions.length - 1,
83946
84165
  quoteResponse: mergeBridgeQuotesDebt(result.firstLegQuote, result.secondLegQuote),
83947
84166
  bridgeMint: bridgeBank.mint,
@@ -84020,12 +84239,23 @@ async function makeLoopTx(params) {
84020
84239
  luts: addressLookupTableAccounts ?? []
84021
84240
  }
84022
84241
  );
84242
+ const orderTx = await makeOrderChangesTx({
84243
+ ...params,
84244
+ placeOrder: params.placeOrder && {
84245
+ collateralBank: depositOpts.depositBank.address,
84246
+ debtBank: borrowOpts.borrowBank.address,
84247
+ trigger: params.placeOrder
84248
+ },
84249
+ luts: addressLookupTableAccounts ?? [],
84250
+ blockhash
84251
+ });
84023
84252
  const transactions = [...additionalTxs, flashloanTx];
84253
+ if (orderTx) transactions.push(orderTx);
84024
84254
  return {
84025
84255
  transactions,
84026
- actionTxIndex: transactions.length - 1,
84256
+ actionTxIndex: additionalTxs.length,
84027
84257
  quoteResponse: swapQuote,
84028
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
84258
+ mustBeAtomicBundle: transactions.length > 1
84029
84259
  };
84030
84260
  }
84031
84261
  async function buildLoopFlashloanTx(params) {
@@ -84254,16 +84484,7 @@ async function buildDepositIxs(params, amountUi) {
84254
84484
  }
84255
84485
  async function runLoopSwapEngine(descriptor, params) {
84256
84486
  const { connection, swapOpts, marginfiAccount, swapEngineRunner } = params;
84257
- if (swapOpts.swapIxs) {
84258
- const pinned = resolvePinnedSwapRoute(swapOpts.swapIxs, descriptor.inAmountNative);
84259
- return {
84260
- swapInstructions: pinned.swapInstructions,
84261
- setupInstructions: pinned.setupInstructions,
84262
- swapLuts: pinned.lookupTables,
84263
- quoteResponse: pinned.quoteResponse,
84264
- outputAmountNative: pinned.outputAmountNative
84265
- };
84266
- }
84487
+ if (swapOpts.swapIxs) return resolvePinnedSwapRoute(swapOpts.swapIxs, descriptor.inAmountNative);
84267
84488
  const runEngine = swapEngineRunner ?? runSwapEngine;
84268
84489
  const engineResult = await runEngine({
84269
84490
  inputMint: descriptor.inputMint,
@@ -84356,6 +84577,15 @@ async function tryBridgedLoop(params, bridgeOpts) {
84356
84577
  const oraclePriceOf = (bank) => params.oraclePrices.get(bank.address.toBase58())?.priceRealtime.price.toNumber() ?? 0;
84357
84578
  const borrowBankPrice = oraclePriceOf(borrowBank);
84358
84579
  if (borrowBankPrice <= 0) return null;
84580
+ const orderTx = await makeOrderChangesTx({
84581
+ ...params,
84582
+ placeOrder: params.placeOrder && {
84583
+ collateralBank: depositBank.address,
84584
+ debtBank: borrowBank.address,
84585
+ trigger: params.placeOrder
84586
+ },
84587
+ luts: params.addressLookupTableAccounts ?? []
84588
+ });
84359
84589
  const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
84360
84590
  return tryBridgeCandidates({
84361
84591
  usableBridgeBanks,
@@ -84374,6 +84604,9 @@ async function tryBridgedLoop(params, bridgeOpts) {
84374
84604
  );
84375
84605
  const firstLeg = await makeLoopTx({
84376
84606
  ...params,
84607
+ // The order changes run after the second leg, once the loop's final debt exists
84608
+ ordersToClose: void 0,
84609
+ placeOrder: void 0,
84377
84610
  depositOpts: {
84378
84611
  ...params.depositOpts,
84379
84612
  marketPrice: oraclePriceOf(depositBank)
@@ -84411,11 +84644,12 @@ async function tryBridgedLoop(params, bridgeOpts) {
84411
84644
  banksMap: params.bankMap,
84412
84645
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
84413
84646
  feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
84414
- maxBundleTxs: bridgeOpts?.maxBundleTxs
84647
+ maxBundleTxs: bridgeOpts?.maxBundleTxs,
84648
+ reservedTxs: orderTx ? 1 : 0
84415
84649
  });
84416
84650
  if (!result) return null;
84417
84651
  return {
84418
- transactions: result.transactions,
84652
+ transactions: orderTx ? [...result.transactions, orderTx] : result.transactions,
84419
84653
  actionTxIndex: result.transactions.length - 1,
84420
84654
  quoteResponse: mergeBridgeQuotesLoop(result.firstLegQuote, result.secondLegQuote),
84421
84655
  bridgeMint: bridgeBank.mint,
@@ -84471,12 +84705,18 @@ async function makeSwapCollateralTx(params) {
84471
84705
  payerKey: marginfiAccount.authority,
84472
84706
  luts: addressLookupTableAccounts ?? []
84473
84707
  });
84708
+ const orderTx = await makeOrderChangesTx({
84709
+ ...params,
84710
+ luts: addressLookupTableAccounts ?? [],
84711
+ blockhash
84712
+ });
84474
84713
  const transactions = [...additionalTxs, flashloanTx];
84714
+ if (orderTx) transactions.push(orderTx);
84475
84715
  return {
84476
84716
  transactions,
84477
- actionTxIndex: transactions.length - 1,
84717
+ actionTxIndex: additionalTxs.length,
84478
84718
  quoteResponse: swapQuote,
84479
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
84719
+ mustBeAtomicBundle: transactions.length > 1
84480
84720
  };
84481
84721
  }
84482
84722
  async function buildSwapCollateralFlashloanTx({
@@ -84740,10 +84980,11 @@ async function buildSwapCollateralFlashloanTx({
84740
84980
  });
84741
84981
  sizeConstraintUsed = swapConstraints.sizeConstraint;
84742
84982
  const runEngine = swapEngineRunner ?? runSwapEngine;
84743
- const engineResult = await runEngine({
84983
+ const amountNative = uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals);
84984
+ const engineResult = swapOpts.swapIxs ? resolvePinnedSwapRoute(swapOpts.swapIxs, amountNative) : await runEngine({
84744
84985
  inputMint: withdrawBank.mint.toBase58(),
84745
84986
  outputMint: depositBank.mint.toBase58(),
84746
- amountNative: uiToNative(actualWithdrawAmount, withdrawBank.mintDecimals).toNumber(),
84987
+ amountNative: amountNative.toNumber(),
84747
84988
  inputDecimals: withdrawBank.mintDecimals,
84748
84989
  outputDecimals: depositBank.mintDecimals,
84749
84990
  ...swapEngineQuoteFieldsFromOpts(swapOpts),
@@ -84751,7 +84992,11 @@ async function buildSwapCollateralFlashloanTx({
84751
84992
  destinationTokenAccount,
84752
84993
  connection,
84753
84994
  footprint: {
84754
- instructions: [...cuRequestIxs, ...withdrawIxs.instructions, ...depositIxs.instructions],
84995
+ instructions: [
84996
+ ...cuRequestIxs,
84997
+ ...withdrawIxs.instructions,
84998
+ ...depositIxs.instructions
84999
+ ],
84755
85000
  luts: addressLookupTableAccounts ?? [],
84756
85001
  payer: marginfiAccount.authority,
84757
85002
  sizeConstraint: swapConstraints.sizeConstraint,
@@ -84837,6 +85082,10 @@ async function tryBridgedCollateralSwap(params, bridgeOpts) {
84837
85082
  bridgeTokenSide: "deposit",
84838
85083
  bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
84839
85084
  });
85085
+ const orderTx = await makeOrderChangesTx({
85086
+ ...params,
85087
+ luts: params.addressLookupTableAccounts ?? []
85088
+ });
84840
85089
  const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
84841
85090
  return tryBridgeCandidates({
84842
85091
  usableBridgeBanks,
@@ -84886,11 +85135,12 @@ async function tryBridgedCollateralSwap(params, bridgeOpts) {
84886
85135
  banksMap: params.bankMap,
84887
85136
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
84888
85137
  feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
84889
- maxBundleTxs: bridgeOpts?.maxBundleTxs
85138
+ maxBundleTxs: bridgeOpts?.maxBundleTxs,
85139
+ reservedTxs: orderTx ? 1 : 0
84890
85140
  });
84891
85141
  if (!result) return null;
84892
85142
  return {
84893
- transactions: result.transactions,
85143
+ transactions: orderTx ? [...result.transactions, orderTx] : result.transactions,
84894
85144
  actionTxIndex: result.transactions.length - 1,
84895
85145
  quoteResponse: mergeBridgeQuotes(result.firstLegQuote, result.secondLegQuote),
84896
85146
  bridgeMint: bridgeBank.mint,
@@ -84958,12 +85208,18 @@ async function makeRollPtTx(params) {
84958
85208
  payerKey: marginfiAccount.authority,
84959
85209
  luts: addressLookupTableAccounts ?? []
84960
85210
  });
85211
+ const orderTx = await makeOrderChangesTx({
85212
+ ...params,
85213
+ luts: addressLookupTableAccounts ?? [],
85214
+ blockhash
85215
+ });
84961
85216
  const transactions = [...additionalTxs, flashloanTx];
85217
+ if (orderTx) transactions.push(orderTx);
84962
85218
  return {
84963
85219
  transactions,
84964
- actionTxIndex: transactions.length - 1,
85220
+ actionTxIndex: additionalTxs.length,
84965
85221
  quoteResponse: swapQuote,
84966
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
85222
+ mustBeAtomicBundle: transactions.length > 1
84967
85223
  };
84968
85224
  }
84969
85225
  async function buildRollPtFlashloanTx({
@@ -85658,12 +85914,22 @@ async function makeTransferPositionsTx(params) {
85658
85914
  payerKey: accountA.authority,
85659
85915
  luts
85660
85916
  });
85917
+ const sourceOrderTx = await makeOrderChangesTx({ ...params, luts, blockhash });
85918
+ const destinationOrderTx = await makeOrderChangesTx({
85919
+ ...params,
85920
+ marginfiAccount: accountB,
85921
+ ordersToClose: params.destinationOrdersToClose,
85922
+ luts,
85923
+ blockhash
85924
+ });
85661
85925
  const transactions = [...additionalTxs, flashloanTx];
85926
+ if (sourceOrderTx) transactions.push(sourceOrderTx);
85927
+ if (destinationOrderTx) transactions.push(destinationOrderTx);
85662
85928
  return {
85663
85929
  transactions,
85664
85930
  actionTxIndex: additionalTxs.length,
85665
85931
  destinationAccount: accountB,
85666
- mustBeAtomicBundle: refreshIxs.length > 0
85932
+ mustBeAtomicBundle: transactions.length > 1
85667
85933
  };
85668
85934
  }
85669
85935
 
@@ -85786,8 +86052,10 @@ async function makeBulkWithdrawTx(params) {
85786
86052
  if (setupTokens.some((t) => t.mint.equals(NATIVE_MINT))) {
85787
86053
  withdrawIxs.push(makeUnwrapSolIx(authority));
85788
86054
  }
86055
+ const closeIxs = await makeOrderChangesIxs(params);
86056
+ const actionIxs = [...closeIxs, ...withdrawIxs];
85789
86057
  const { blockhash } = await connection.getLatestBlockhash("confirmed");
85790
- const withdrawTxs = splitInstructionsToFitTransactions([], withdrawIxs, {
86058
+ const withdrawTxs = splitInstructionsToFitTransactions([], actionIxs, {
85791
86059
  blockhash,
85792
86060
  payerKey: authority,
85793
86061
  luts: selectedLuts,
@@ -85818,7 +86086,8 @@ async function makeBulkWithdrawTx(params) {
85818
86086
  return {
85819
86087
  transactions: [...additionalTxs, ...withdrawTxs],
85820
86088
  actionTxIndex: additionalTxs.length,
85821
- mustBeAtomicBundle: refreshIxs.length > 0
86089
+ // Order closes must land with every withdraw
86090
+ mustBeAtomicBundle: refreshIxs.length > 0 || closeIxs.length > 0 && withdrawTxs.length > 1
85822
86091
  };
85823
86092
  }
85824
86093
  async function makeBulkRepayTx(params) {
@@ -85865,8 +86134,10 @@ async function makeBulkRepayTx(params) {
85865
86134
  [],
85866
86135
  bankAddresses
85867
86136
  ) : [];
86137
+ const closeIxs = await makeOrderChangesIxs(params);
86138
+ const actionIxs = [...closeIxs, ...repayIxs, ...premiumIxs];
85868
86139
  const { blockhash } = await connection.getLatestBlockhash("confirmed");
85869
- const transactions = splitInstructionsToFitTransactions([], [...repayIxs, ...premiumIxs], {
86140
+ const transactions = splitInstructionsToFitTransactions([], actionIxs, {
85870
86141
  blockhash,
85871
86142
  payerKey: authority,
85872
86143
  luts,
@@ -85881,115 +86152,11 @@ async function makeBulkRepayTx(params) {
85881
86152
  return {
85882
86153
  transactions,
85883
86154
  actionTxIndex: 0,
85884
- // Venue refreshes only count in the pulse's slot, and the pulse must follow every repay
85885
- mustBeAtomicBundle: premiumIxs.length > 0 && transactions.length > 1
86155
+ // Venue refreshes only count in the pulse's slot, and the pulse must follow every repay;
86156
+ // order closes must land with every repay
86157
+ mustBeAtomicBundle: (premiumIxs.length > 0 || closeIxs.length > 0) && transactions.length > 1
85886
86158
  };
85887
86159
  }
85888
- function buildOrderTrigger(params) {
85889
- const { stopLossUsd, takeProfitUsd } = params;
85890
- const maxSlippage = percentToMaxSlippageU32(params.maxSlippagePercent);
85891
- const invalidTrigger = (reason) => TransactionBuildingError.orderInvalidTrigger(
85892
- reason,
85893
- takeProfitUsd?.toString(),
85894
- stopLossUsd?.toString()
85895
- );
85896
- if (stopLossUsd && !stopLossUsd.gt(0)) {
85897
- throw invalidTrigger(`stop-loss threshold (${stopLossUsd}) must be above 0`);
85898
- }
85899
- if (takeProfitUsd && !takeProfitUsd.gt(0)) {
85900
- throw invalidTrigger(`take-profit threshold (${takeProfitUsd}) must be above 0`);
85901
- }
85902
- if (stopLossUsd && takeProfitUsd) {
85903
- if (takeProfitUsd.lte(stopLossUsd)) {
85904
- throw invalidTrigger(
85905
- `take-profit threshold (${takeProfitUsd}) must be above stop-loss threshold (${stopLossUsd})`
85906
- );
85907
- }
85908
- return {
85909
- both: {
85910
- stopLoss: bigNumberToWrappedI80F48(stopLossUsd),
85911
- takeProfit: bigNumberToWrappedI80F48(takeProfitUsd),
85912
- maxSlippage
85913
- }
85914
- };
85915
- }
85916
- if (stopLossUsd) {
85917
- return { stopLoss: { threshold: bigNumberToWrappedI80F48(stopLossUsd), maxSlippage } };
85918
- }
85919
- if (takeProfitUsd) {
85920
- return { takeProfit: { threshold: bigNumberToWrappedI80F48(takeProfitUsd), maxSlippage } };
85921
- }
85922
- throw invalidTrigger("an order needs a stop-loss threshold, a take-profit threshold, or both");
85923
- }
85924
- async function makePlaceOrderIx2(params) {
85925
- const { program, marginfiAccount, collateralBank, debtBank, trigger, feePayer } = params;
85926
- const [order] = deriveOrderPda(program.programId, marginfiAccount.address, [
85927
- collateralBank,
85928
- debtBank
85929
- ]);
85930
- const globalFeeWallet = params.globalFeeWallet ?? (await program.account.feeState.fetch(deriveFeeState(program.programId)[0])).globalFeeWallet;
85931
- const placeOrderIx = await instructions_default3.makePlaceOrderIx(
85932
- program,
85933
- {
85934
- marginfiAccount: marginfiAccount.address,
85935
- feePayer: feePayer ?? marginfiAccount.authority,
85936
- authority: marginfiAccount.authority,
85937
- order,
85938
- globalFeeWallet,
85939
- group: marginfiAccount.group
85940
- },
85941
- { bankKeys: [collateralBank, debtBank], trigger: buildOrderTrigger(trigger) }
85942
- );
85943
- return { instructions: [placeOrderIx], keys: [] };
85944
- }
85945
- async function makeCloseOrderIx2(params) {
85946
- const { program, marginfiAccount, order, feeRecipient } = params;
85947
- const closeOrderIx = await instructions_default3.makeCloseOrderIx(program, {
85948
- marginfiAccount: marginfiAccount.address,
85949
- authority: marginfiAccount.authority,
85950
- order,
85951
- feeRecipient: feeRecipient ?? marginfiAccount.authority,
85952
- group: marginfiAccount.group
85953
- });
85954
- return { instructions: [closeOrderIx], keys: [] };
85955
- }
85956
- async function compileOrderTx(params, payerKey, ixs, type) {
85957
- const blockhash = params.blockhash ?? (await params.connection.getLatestBlockhashAndContext("confirmed")).value.blockhash;
85958
- return addTransactionMetadata(
85959
- new web3_js.VersionedTransaction(
85960
- new web3_js.TransactionMessage({
85961
- instructions: ixs.flatMap((ix) => ix.instructions),
85962
- payerKey,
85963
- recentBlockhash: blockhash
85964
- }).compileToV0Message(params.luts)
85965
- ),
85966
- { type, signers: ixs.flatMap((ix) => ix.keys), addressLookupTables: params.luts }
85967
- );
85968
- }
85969
- async function makePlaceOrderTx(params) {
85970
- const placeIxs = await makePlaceOrderIx2(params);
85971
- const payerKey = params.feePayer ?? params.marginfiAccount.authority;
85972
- return compileOrderTx(params, payerKey, [placeIxs], "PLACE_ORDER" /* PLACE_ORDER */);
85973
- }
85974
- async function makeCloseOrderTx(params) {
85975
- const closeIxs = await makeCloseOrderIx2(params);
85976
- return compileOrderTx(
85977
- params,
85978
- params.marginfiAccount.authority,
85979
- [closeIxs],
85980
- "CLOSE_ORDER" /* CLOSE_ORDER */
85981
- );
85982
- }
85983
- async function makeUpdateOrderTx(params) {
85984
- const [order] = deriveOrderPda(params.program.programId, params.marginfiAccount.address, [
85985
- params.collateralBank,
85986
- params.debtBank
85987
- ]);
85988
- const closeIxs = await makeCloseOrderIx2({ ...params, order, feeRecipient: params.feePayer });
85989
- const placeIxs = await makePlaceOrderIx2(params);
85990
- const payerKey = params.feePayer ?? params.marginfiAccount.authority;
85991
- return compileOrderTx(params, payerKey, [closeIxs, placeIxs], "UPDATE_ORDER" /* UPDATE_ORDER */);
85992
- }
85993
86160
 
85994
86161
  // src/services/account/services/account-simulation.service.ts
85995
86162
  async function simulateAccountHealthCacheWithFallback(params) {
@@ -86528,7 +86695,7 @@ var fetchStakePoolActiveStates = async (connection, validatorVoteAccounts) => {
86528
86695
  });
86529
86696
  const poolStakeAddressKeys = Object.keys(poolStakeAddressRecord);
86530
86697
  const poolStakeAccounts = Object.fromEntries(
86531
- (await chunkedGetRawMultipleAccountInfoOrdered(connection, poolStakeAddressKeys)).map((ai, index) => {
86698
+ (await chunkedGetRawMultipleAccountInfoOrderedWithNulls(connection, poolStakeAddressKeys)).map((ai, index) => {
86532
86699
  const key = poolStakeAddressKeys[index];
86533
86700
  const validatorVote = key ? poolStakeAddressRecord[key] : void 0;
86534
86701
  return [validatorVote, ai?.data || null];
@@ -86536,7 +86703,8 @@ var fetchStakePoolActiveStates = async (connection, validatorVoteAccounts) => {
86536
86703
  );
86537
86704
  validatorVoteAccounts.map((validatorVoteAccount) => {
86538
86705
  const voteAccountKey = validatorVoteAccount.toBase58();
86539
- const stakeAccount = fetchStakeAccount(poolStakeAccounts[voteAccountKey]);
86706
+ const stakeData = poolStakeAccounts[voteAccountKey];
86707
+ const stakeAccount = stakeData ? fetchStakeAccount(stakeData) : null;
86540
86708
  const poolMintAddress = poolMintAddressRecord[voteAccountKey];
86541
86709
  if (!poolMintAddress) {
86542
86710
  return;
@@ -86623,26 +86791,28 @@ var fetchStakePoolMev = async (connection, validatorVoteAccounts) => {
86623
86791
  const allAddresses = [...poolStakeAddresses, ...onRampAddresses].map(
86624
86792
  (address) => address.toBase58()
86625
86793
  );
86626
- return chunkedGetRawMultipleAccountInfoOrdered(connection, allAddresses).then((accountInfos) => {
86627
- const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
86628
- const onRampInfos = accountInfos.slice(poolStakeAddresses.length);
86629
- const rent = 2282280;
86630
- validatorVoteAccounts.forEach((validatorVoteAccount, index) => {
86631
- const poolStakeInfo = poolStakeInfos[index];
86632
- const onRampInfo = onRampInfos[index];
86633
- if (poolStakeInfo && onRampInfo) {
86634
- const stakeDecoded = fetchStakeAccount(poolStakeInfo.data);
86635
- const onrampDecoded = fetchStakeAccount(onRampInfo.data);
86636
- const poolLamps = poolStakeInfo.lamports - rent - Number(stakeDecoded.stake.delegation.stake.toString());
86637
- const onrampStake = Number(onrampDecoded.stake.delegation.stake.toString());
86638
- mev.set(validatorVoteAccount.toBase58(), {
86639
- pool: poolLamps >= 1e3 ? poolLamps : 0,
86640
- onramp: onrampStake
86641
- });
86642
- }
86643
- });
86644
- return mev;
86645
- });
86794
+ return chunkedGetRawMultipleAccountInfoOrderedWithNulls(connection, allAddresses).then(
86795
+ (accountInfos) => {
86796
+ const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
86797
+ const onRampInfos = accountInfos.slice(poolStakeAddresses.length);
86798
+ const rent = 2282280;
86799
+ validatorVoteAccounts.forEach((validatorVoteAccount, index) => {
86800
+ const poolStakeInfo = poolStakeInfos[index];
86801
+ const onRampInfo = onRampInfos[index];
86802
+ if (poolStakeInfo && onRampInfo) {
86803
+ const stakeDecoded = fetchStakeAccount(poolStakeInfo.data);
86804
+ const onrampDecoded = fetchStakeAccount(onRampInfo.data);
86805
+ const poolLamps = poolStakeInfo.lamports - rent - Number(stakeDecoded.stake.delegation.stake.toString());
86806
+ const onrampStake = Number(onrampDecoded.stake.delegation.stake.toString());
86807
+ mev.set(validatorVoteAccount.toBase58(), {
86808
+ pool: poolLamps >= 1e3 ? poolLamps : 0,
86809
+ onramp: onrampStake
86810
+ });
86811
+ }
86812
+ });
86813
+ return mev;
86814
+ }
86815
+ );
86646
86816
  };
86647
86817
 
86648
86818
  // src/services/native-stake/utils/serialize.utils.ts
@@ -87082,55 +87252,67 @@ function getValidatorVoteAccountByBank() {
87082
87252
  }
87083
87253
  return _voteAccountByBank;
87084
87254
  }
87255
+ var POOL_BOOTSTRAP_LAMPORTS = 1000000000n;
87256
+ var STAKE_STATE_DELEGATED = 2;
87085
87257
  async function computeStakedBankMultipliers(stakedBanks, connection) {
87086
87258
  const multiplierByBank = /* @__PURE__ */ new Map();
87087
87259
  if (stakedBanks.length === 0) {
87088
87260
  return multiplierByBank;
87089
87261
  }
87090
87262
  const metadataMap = getStakedBankMetadataMap();
87091
- const stakedBankAddresses = [];
87263
+ const resolvedBanks = [];
87092
87264
  const poolStakeAddresses = [];
87093
87265
  const lstMintAddresses = [];
87266
+ const onrampAddresses = [];
87094
87267
  for (const bank of stakedBanks) {
87095
87268
  const metadata = metadataMap.get(bank.address.toBase58());
87096
87269
  if (!metadata) {
87097
- multiplierByBank.set(bank.address.toBase58(), new BigNumber3__default.default(1));
87270
+ multiplierByBank.set(bank.address.toBase58(), new BigNumber3.BigNumber(1));
87098
87271
  continue;
87099
87272
  }
87100
87273
  const pool = findPoolAddress(new web3_js.PublicKey(metadata.validatorVoteAccount));
87101
- stakedBankAddresses.push(bank.address.toBase58());
87274
+ resolvedBanks.push(bank);
87102
87275
  poolStakeAddresses.push(findPoolStakeAddress(pool));
87103
87276
  lstMintAddresses.push(findPoolMintAddress(pool));
87277
+ onrampAddresses.push(findPoolOnRampAddress(pool));
87104
87278
  }
87105
- if (stakedBankAddresses.length === 0) {
87279
+ if (resolvedBanks.length === 0) {
87106
87280
  return multiplierByBank;
87107
87281
  }
87108
- const allAddresses = [
87109
- ...poolStakeAddresses.map((a) => a.toBase58()),
87110
- ...lstMintAddresses.map((a) => a.toBase58())
87111
- ];
87112
- const accountInfos = await chunkedGetRawMultipleAccountInfoOrdered(connection, allAddresses);
87113
- const poolStakeInfos = accountInfos.slice(0, poolStakeAddresses.length);
87114
- const lstMintInfos = accountInfos.slice(poolStakeAddresses.length);
87115
- for (let i = 0; i < stakedBankAddresses.length; i++) {
87116
- const bankAddr = stakedBankAddresses[i];
87117
- const poolStakeInfo = poolStakeInfos[i];
87118
- const lstMintInfo = lstMintInfos[i];
87119
- if (!poolStakeInfo || !lstMintInfo) {
87120
- multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
87121
- continue;
87282
+ const allAddresses = [...poolStakeAddresses, ...lstMintAddresses, ...onrampAddresses].map(
87283
+ (a) => a.toBase58()
87284
+ );
87285
+ const [accountInfos, stakeRent] = await Promise.all([
87286
+ chunkedGetRawMultipleAccountInfoOrderedWithNulls(connection, allAddresses),
87287
+ resolvedBanks.some((bank) => bank.stakedOracleUsesOnramp) ? connection.getMinimumBalanceForRentExemption(web3_js.StakeProgram.space) : 0
87288
+ ]);
87289
+ const count = resolvedBanks.length;
87290
+ const aboveRent = (lamports) => Math.max(lamports - stakeRent, 0);
87291
+ resolvedBanks.forEach((bank, i) => {
87292
+ const bankAddr = bank.address.toBase58();
87293
+ const poolStakeInfo = accountInfos[i];
87294
+ const lstMintInfo = accountInfos[count + i];
87295
+ const onrampInfo = accountInfos[2 * count + i];
87296
+ const lstMintSupply = lstMintInfo ? buffer.Buffer.from(lstMintInfo.data.subarray(36, 44)).readBigUInt64LE(0) : 0n;
87297
+ if (!poolStakeInfo || lstMintSupply === 0n) {
87298
+ multiplierByBank.set(bankAddr, new BigNumber3.BigNumber(1));
87299
+ return;
87122
87300
  }
87123
- const stakeLamports = poolStakeInfo.lamports;
87124
- const supplyBuffer = lstMintInfo.data.slice(36, 44);
87125
- const lstMintSupply = Number(buffer.Buffer.from(supplyBuffer).readBigUInt64LE(0));
87126
- if (lstMintSupply === 0) {
87127
- multiplierByBank.set(bankAddr, new BigNumber3__default.default(1));
87128
- continue;
87301
+ if (bank.stakedOracleUsesOnramp) {
87302
+ const value = aboveRent(poolStakeInfo.lamports) + (onrampInfo ? aboveRent(onrampInfo.lamports) : 0);
87303
+ multiplierByBank.set(
87304
+ bankAddr,
87305
+ new BigNumber3.BigNumber(value).dividedBy((lstMintSupply + POOL_BOOTSTRAP_LAMPORTS).toString())
87306
+ );
87307
+ return;
87129
87308
  }
87130
- const adjustedStake = Math.max(stakeLamports - web3_js.LAMPORTS_PER_SOL, 0);
87131
- const multiplier = new BigNumber3__default.default(adjustedStake).dividedBy(lstMintSupply);
87132
- multiplierByBank.set(bankAddr, multiplier);
87133
- }
87309
+ const delegated = poolStakeInfo.data.readUInt32LE(0) === STAKE_STATE_DELEGATED ? fetchStakeAccount(poolStakeInfo.data).stake.delegation.stake : 0n;
87310
+ const delegatedAboveBootstrap = delegated > POOL_BOOTSTRAP_LAMPORTS ? delegated - POOL_BOOTSTRAP_LAMPORTS : 0n;
87311
+ multiplierByBank.set(
87312
+ bankAddr,
87313
+ new BigNumber3.BigNumber(delegatedAboveBootstrap.toString()).dividedBy(lstMintSupply.toString())
87314
+ );
87315
+ });
87134
87316
  return multiplierByBank;
87135
87317
  }
87136
87318
  var SYSVAR_CLOCK_ID2 = new web3_js.PublicKey("SysvarC1ock11111111111111111111111111111111");
@@ -87959,7 +88141,7 @@ async function fetchBankIntegrationMetadata(options) {
87959
88141
 
87960
88142
  // src/models/bank.ts
87961
88143
  var Bank = class _Bank {
87962
- constructor(address, mint, mintDecimals, group, assetShareValue, liabilityShareValue, liquidityVault, liquidityVaultBump, liquidityVaultAuthorityBump, insuranceVault, insuranceVaultBump, insuranceVaultAuthorityBump, collectedInsuranceFeesOutstanding, feeVault, feeVaultBump, feeVaultAuthorityBump, collectedGroupFeesOutstanding, lastUpdate, config, totalAssetShares, totalLiabilityShares, emissionsActiveBorrowing, emissionsActiveLending, emissionsRate, emissionsMint, emissionsRemaining, collectedProgramFeesOutstanding, oracleKey, emode, premiumTag, premiumActive, premiumActivatedAt, kaminoEmergency, rateLimiter, kaminoIntegrationAccounts, driftIntegrationAccounts, solendIntegrationAccounts, jupLendIntegrationAccounts, feesDestinationAccount, lendingPositionCount, borrowingPositionCount, tokenSymbol) {
88144
+ constructor(address, mint, mintDecimals, group, assetShareValue, liabilityShareValue, liquidityVault, liquidityVaultBump, liquidityVaultAuthorityBump, insuranceVault, insuranceVaultBump, insuranceVaultAuthorityBump, collectedInsuranceFeesOutstanding, feeVault, feeVaultBump, feeVaultAuthorityBump, collectedGroupFeesOutstanding, lastUpdate, config, totalAssetShares, totalLiabilityShares, emissionsActiveBorrowing, emissionsActiveLending, emissionsRate, emissionsMint, emissionsRemaining, collectedProgramFeesOutstanding, oracleKey, emode, premiumTag, premiumActive, premiumActivatedAt, kaminoEmergency, rateLimiter, kaminoIntegrationAccounts, driftIntegrationAccounts, solendIntegrationAccounts, jupLendIntegrationAccounts, feesDestinationAccount, lendingPositionCount, borrowingPositionCount, tokenSymbol, stakedOracleDisabled, stakedOracleUsesOnramp, stakedIntegrationAccounts) {
87963
88145
  this.address = address;
87964
88146
  this.mint = mint;
87965
88147
  this.mintDecimals = mintDecimals;
@@ -88002,6 +88184,9 @@ var Bank = class _Bank {
88002
88184
  this.lendingPositionCount = lendingPositionCount;
88003
88185
  this.borrowingPositionCount = borrowingPositionCount;
88004
88186
  this.tokenSymbol = tokenSymbol;
88187
+ this.stakedOracleDisabled = stakedOracleDisabled;
88188
+ this.stakedOracleUsesOnramp = stakedOracleUsesOnramp;
88189
+ this.stakedIntegrationAccounts = stakedIntegrationAccounts;
88005
88190
  }
88006
88191
  static async fetch(address, program, bankMetadata) {
88007
88192
  const data = await program.account.bank.fetch(address);
@@ -88077,7 +88262,10 @@ var Bank = class _Bank {
88077
88262
  bankType.feesDestinationAccount,
88078
88263
  bankType.lendingPositionCount,
88079
88264
  bankType.borrowingPositionCount,
88080
- bankType.tokenSymbol
88265
+ bankType.tokenSymbol,
88266
+ bankType.stakedOracleDisabled,
88267
+ bankType.stakedOracleUsesOnramp,
88268
+ bankType.stakedIntegrationAccounts
88081
88269
  );
88082
88270
  }
88083
88271
  static fromAccountParsed(address, accountParsed, bankMetadata) {
@@ -88124,7 +88312,10 @@ var Bank = class _Bank {
88124
88312
  props.feesDestinationAccount,
88125
88313
  props.lendingPositionCount,
88126
88314
  props.borrowingPositionCount,
88127
- props.tokenSymbol
88315
+ props.tokenSymbol,
88316
+ props.stakedOracleDisabled,
88317
+ props.stakedOracleUsesOnramp,
88318
+ props.stakedIntegrationAccounts
88128
88319
  );
88129
88320
  }
88130
88321
  static withEmodeWeights(bank, emodeWeights) {
@@ -90068,6 +90259,8 @@ exports.makeLoopTx = makeLoopTx;
90068
90259
  exports.makeMergeStakeAccountsTx = makeMergeStakeAccountsTx;
90069
90260
  exports.makeMintStakedLstIx = makeMintStakedLstIx;
90070
90261
  exports.makeMintStakedLstTx = makeMintStakedLstTx;
90262
+ exports.makeOrderChangesIxs = makeOrderChangesIxs;
90263
+ exports.makeOrderChangesTx = makeOrderChangesTx;
90071
90264
  exports.makePlaceOrderIx = makePlaceOrderIx2;
90072
90265
  exports.makePlaceOrderTx = makePlaceOrderTx;
90073
90266
  exports.makePoolAddBankIx = makePoolAddBankIx2;
@@ -90132,6 +90325,7 @@ exports.parseRiskTier = parseRiskTier;
90132
90325
  exports.parseRpcPythPriceData = parseRpcPythPriceData;
90133
90326
  exports.patchDepositAmount = patchDepositAmount;
90134
90327
  exports.percentToMaxSlippageU32 = percentToMaxSlippageU32;
90328
+ exports.prependOrderCloses = prependOrderCloses;
90135
90329
  exports.rateFromU32 = rateFromU32;
90136
90330
  exports.requireBank = requireBank;
90137
90331
  exports.requireTokenProgram = requireTokenProgram;