@0dotxyz/p0-ts-sdk 2.10.0 → 2.10.1-alpha.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
  */
@@ -78587,6 +78601,162 @@ function exceedsCostlyPositionLimit(balances, bankMap, bank) {
78587
78601
  }).length;
78588
78602
  return held >= MAX_COSTLY_POSITIONS;
78589
78603
  }
78604
+ function buildOrderTrigger(params) {
78605
+ const { stopLossUsd, takeProfitUsd } = params;
78606
+ const maxSlippage = percentToMaxSlippageU32(params.maxSlippagePercent);
78607
+ const invalidTrigger = (reason) => TransactionBuildingError.orderInvalidTrigger(
78608
+ reason,
78609
+ takeProfitUsd?.toString(),
78610
+ stopLossUsd?.toString()
78611
+ );
78612
+ if (stopLossUsd && !stopLossUsd.gt(0)) {
78613
+ throw invalidTrigger(`stop-loss threshold (${stopLossUsd}) must be above 0`);
78614
+ }
78615
+ if (takeProfitUsd && !takeProfitUsd.gt(0)) {
78616
+ throw invalidTrigger(`take-profit threshold (${takeProfitUsd}) must be above 0`);
78617
+ }
78618
+ if (stopLossUsd && takeProfitUsd) {
78619
+ if (takeProfitUsd.lte(stopLossUsd)) {
78620
+ throw invalidTrigger(
78621
+ `take-profit threshold (${takeProfitUsd}) must be above stop-loss threshold (${stopLossUsd})`
78622
+ );
78623
+ }
78624
+ return {
78625
+ both: {
78626
+ stopLoss: bigNumberToWrappedI80F48(stopLossUsd),
78627
+ takeProfit: bigNumberToWrappedI80F48(takeProfitUsd),
78628
+ maxSlippage
78629
+ }
78630
+ };
78631
+ }
78632
+ if (stopLossUsd) {
78633
+ return { stopLoss: { threshold: bigNumberToWrappedI80F48(stopLossUsd), maxSlippage } };
78634
+ }
78635
+ if (takeProfitUsd) {
78636
+ return { takeProfit: { threshold: bigNumberToWrappedI80F48(takeProfitUsd), maxSlippage } };
78637
+ }
78638
+ throw invalidTrigger("an order needs a stop-loss threshold, a take-profit threshold, or both");
78639
+ }
78640
+ async function makePlaceOrderIx2(params) {
78641
+ const { program, marginfiAccount, collateralBank, debtBank, trigger, feePayer } = params;
78642
+ const [order] = deriveOrderPda(program.programId, marginfiAccount.address, [
78643
+ collateralBank,
78644
+ debtBank
78645
+ ]);
78646
+ const globalFeeWallet = params.globalFeeWallet ?? (await program.account.feeState.fetch(deriveFeeState(program.programId)[0])).globalFeeWallet;
78647
+ const placeOrderIx = await instructions_default3.makePlaceOrderIx(
78648
+ program,
78649
+ {
78650
+ marginfiAccount: marginfiAccount.address,
78651
+ feePayer: feePayer ?? marginfiAccount.authority,
78652
+ authority: marginfiAccount.authority,
78653
+ order,
78654
+ globalFeeWallet,
78655
+ group: marginfiAccount.group
78656
+ },
78657
+ { bankKeys: [collateralBank, debtBank], trigger: buildOrderTrigger(trigger) }
78658
+ );
78659
+ return { instructions: [placeOrderIx], keys: [] };
78660
+ }
78661
+ async function makeCloseOrderIx2(params) {
78662
+ const { program, marginfiAccount, order, feeRecipient } = params;
78663
+ const closeOrderIx = await instructions_default3.makeCloseOrderIx(program, {
78664
+ marginfiAccount: marginfiAccount.address,
78665
+ authority: marginfiAccount.authority,
78666
+ order,
78667
+ feeRecipient: feeRecipient ?? marginfiAccount.authority,
78668
+ group: marginfiAccount.group
78669
+ });
78670
+ return { instructions: [closeOrderIx], keys: [] };
78671
+ }
78672
+ async function compileOrderTx(params, payerKey, ixs, type) {
78673
+ const blockhash = params.blockhash ?? (await params.connection.getLatestBlockhashAndContext("confirmed")).value.blockhash;
78674
+ return addTransactionMetadata(
78675
+ new web3_js.VersionedTransaction(
78676
+ new web3_js.TransactionMessage({
78677
+ instructions: ixs.flatMap((ix) => ix.instructions),
78678
+ payerKey,
78679
+ recentBlockhash: blockhash
78680
+ }).compileToV0Message(params.luts)
78681
+ ),
78682
+ { type, signers: ixs.flatMap((ix) => ix.keys), addressLookupTables: params.luts }
78683
+ );
78684
+ }
78685
+ async function makePlaceOrderTx(params) {
78686
+ const placeIxs = await makePlaceOrderIx2(params);
78687
+ const payerKey = params.feePayer ?? params.marginfiAccount.authority;
78688
+ return compileOrderTx(params, payerKey, [placeIxs], "PLACE_ORDER" /* PLACE_ORDER */);
78689
+ }
78690
+ async function makeCloseOrderTx(params) {
78691
+ const closeIxs = await makeCloseOrderIx2(params);
78692
+ return compileOrderTx(
78693
+ params,
78694
+ params.marginfiAccount.authority,
78695
+ [closeIxs],
78696
+ "CLOSE_ORDER" /* CLOSE_ORDER */
78697
+ );
78698
+ }
78699
+ async function makeUpdateOrderTx(params) {
78700
+ const [order] = deriveOrderPda(params.program.programId, params.marginfiAccount.address, [
78701
+ params.collateralBank,
78702
+ params.debtBank
78703
+ ]);
78704
+ const closeIxs = await makeCloseOrderIx2({ ...params, order, feeRecipient: params.feePayer });
78705
+ const placeIxs = await makePlaceOrderIx2(params);
78706
+ const payerKey = params.feePayer ?? params.marginfiAccount.authority;
78707
+ return compileOrderTx(params, payerKey, [closeIxs, placeIxs], "UPDATE_ORDER" /* UPDATE_ORDER */);
78708
+ }
78709
+ var SEND_PIPELINE_MARGINS = {
78710
+ sizeMargin: PRIORITY_TX_SIZE + BUNDLE_TX_SIZE,
78711
+ maxAccountLocks: MAX_ACCOUNT_LOCKS - 3
78712
+ };
78713
+ async function makeOrderChangesIxs(params) {
78714
+ const { program, marginfiAccount, ordersToClose = [], placeOrder } = params;
78715
+ const wrappers = await Promise.all([
78716
+ ...ordersToClose.map((order) => makeCloseOrderIx2({ program, marginfiAccount, order })),
78717
+ ...placeOrder ? [makePlaceOrderIx2({ ...placeOrder, program, marginfiAccount })] : []
78718
+ ]);
78719
+ return wrappers.flatMap((wrapper) => wrapper.instructions);
78720
+ }
78721
+ async function prependOrderCloses(params, actionIxs, luts) {
78722
+ const { program, marginfiAccount, ordersToClose = [] } = params;
78723
+ if (ordersToClose.length === 0) return actionIxs;
78724
+ const closeIxs = await makeOrderChangesIxs({ program, marginfiAccount, ordersToClose });
78725
+ const withCloses = [...closeIxs, ...actionIxs];
78726
+ if (!fitsInOneTransaction(withCloses, {
78727
+ payerKey: params.authority,
78728
+ luts,
78729
+ ...SEND_PIPELINE_MARGINS
78730
+ })) {
78731
+ throw TransactionBuildingError.orderClosesDontFit(
78732
+ ordersToClose.map((order) => order.toBase58())
78733
+ );
78734
+ }
78735
+ return withCloses;
78736
+ }
78737
+ async function makeOrderChangesTx(params) {
78738
+ const { program, marginfiAccount, ordersToClose = [], placeOrder, luts } = params;
78739
+ const ixs = await makeOrderChangesIxs(params);
78740
+ if (ixs.length === 0) return void 0;
78741
+ if (!fitsInOneTransaction(ixs, {
78742
+ payerKey: marginfiAccount.authority,
78743
+ luts,
78744
+ ...SEND_PIPELINE_MARGINS
78745
+ })) {
78746
+ throw TransactionBuildingError.orderClosesDontFit(
78747
+ ordersToClose.map((order) => order.toBase58())
78748
+ );
78749
+ }
78750
+ let type = "CLOSE_ORDER" /* CLOSE_ORDER */;
78751
+ if (placeOrder) {
78752
+ const [placedOrder] = deriveOrderPda(program.programId, marginfiAccount.address, [
78753
+ placeOrder.collateralBank,
78754
+ placeOrder.debtBank
78755
+ ]);
78756
+ type = ordersToClose.some((order) => order.equals(placedOrder)) ? "UPDATE_ORDER" /* UPDATE_ORDER */ : "PLACE_ORDER" /* PLACE_ORDER */;
78757
+ }
78758
+ return compileOrderTx(params, marginfiAccount.authority, [{ instructions: ixs, keys: [] }], type);
78759
+ }
78590
78760
  var KAMINO_PROGRAM_ID = new web3_js.PublicKey("KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD");
78591
78761
  var FARMS_PROGRAM_ID2 = new web3_js.PublicKey("FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr");
78592
78762
  function encodeU642(value) {
@@ -79310,13 +79480,18 @@ async function makeBorrowTx(params) {
79310
79480
  params.bankMetadataMap
79311
79481
  );
79312
79482
  const borrowIxs = await makeBorrowIx3(borrowIxParams);
79483
+ const ixs = await prependOrderCloses(
79484
+ params,
79485
+ [...refreshIntegrationIxs.instructions, ...borrowIxs.instructions],
79486
+ selectedLuts
79487
+ );
79313
79488
  const {
79314
79489
  value: { blockhash }
79315
79490
  } = await connection.getLatestBlockhashAndContext("confirmed");
79316
79491
  const borrowTx = addTransactionMetadata(
79317
79492
  new web3_js.VersionedTransaction(
79318
79493
  new web3_js.TransactionMessage({
79319
- instructions: [...refreshIntegrationIxs.instructions, ...borrowIxs.instructions],
79494
+ instructions: ixs,
79320
79495
  payerKey: params.authority,
79321
79496
  recentBlockhash: blockhash
79322
79497
  }).compileToV0Message(selectedLuts)
@@ -79415,9 +79590,14 @@ async function makeDriftDepositTx(params) {
79415
79590
  amount,
79416
79591
  ...depositIxParams
79417
79592
  });
79418
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79593
+ const actionIxs = await prependOrderCloses(
79419
79594
  params,
79420
79595
  depositIxs.instructions,
79596
+ selectLutsForBanks(luts, [params.bank])
79597
+ );
79598
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79599
+ params,
79600
+ actionIxs,
79421
79601
  [params.bank.address],
79422
79602
  []
79423
79603
  );
@@ -79558,9 +79738,14 @@ async function makeKaminoDepositTx(params) {
79558
79738
  amount,
79559
79739
  ...depositIxParams
79560
79740
  });
79561
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79741
+ const actionIxs = await prependOrderCloses(
79562
79742
  params,
79563
79743
  [...refreshIxs, ...depositIxs.instructions],
79744
+ selectLutsForBanks(luts, [params.bank])
79745
+ );
79746
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79747
+ params,
79748
+ actionIxs,
79564
79749
  [params.bank.address],
79565
79750
  []
79566
79751
  );
@@ -79649,9 +79834,14 @@ async function makeDepositTx(params) {
79649
79834
  throw TransactionBuildingError.costlyPositionLimitExceeded(params.bank.address.toBase58());
79650
79835
  }
79651
79836
  const ixs = await makeDepositIx3(depositIxParams);
79652
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79837
+ const actionIxs = await prependOrderCloses(
79653
79838
  params,
79654
79839
  ixs.instructions,
79840
+ selectLutsForBanks(luts, [params.bank])
79841
+ );
79842
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79843
+ params,
79844
+ actionIxs,
79655
79845
  [params.bank.address],
79656
79846
  []
79657
79847
  );
@@ -79741,9 +79931,14 @@ async function makeJuplendDepositTx(params) {
79741
79931
  amount,
79742
79932
  ...depositIxParams
79743
79933
  });
79744
- const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79934
+ const actionIxs = await prependOrderCloses(
79745
79935
  params,
79746
79936
  depositIxs.instructions,
79937
+ selectLutsForBanks(luts, [params.bank])
79938
+ );
79939
+ const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
79940
+ params,
79941
+ actionIxs,
79747
79942
  [params.bank.address],
79748
79943
  []
79749
79944
  );
@@ -80519,13 +80714,18 @@ async function makeDriftWithdrawTx(params) {
80519
80714
  [withdrawIxParams.bank.address],
80520
80715
  params.bankMetadataMap
80521
80716
  );
80717
+ const ixs = await prependOrderCloses(
80718
+ params,
80719
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80720
+ selectedLuts
80721
+ );
80522
80722
  const {
80523
80723
  value: { blockhash }
80524
80724
  } = await connection.getLatestBlockhashAndContext("confirmed");
80525
80725
  const withdrawTx = addTransactionMetadata(
80526
80726
  new web3_js.VersionedTransaction(
80527
80727
  new web3_js.TransactionMessage({
80528
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80728
+ instructions: ixs,
80529
80729
  payerKey: params.authority,
80530
80730
  recentBlockhash: blockhash
80531
80731
  }).compileToV0Message(selectedLuts)
@@ -80772,13 +80972,18 @@ async function makeWithdrawTx(params) {
80772
80972
  [withdrawIxParams.bank.address],
80773
80973
  params.bankMetadataMap
80774
80974
  );
80975
+ const ixs = await prependOrderCloses(
80976
+ params,
80977
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80978
+ selectedLuts
80979
+ );
80775
80980
  const {
80776
80981
  value: { blockhash }
80777
80982
  } = await connection.getLatestBlockhashAndContext("confirmed");
80778
80983
  const withdrawTx = addTransactionMetadata(
80779
80984
  new web3_js.VersionedTransaction(
80780
80985
  new web3_js.TransactionMessage({
80781
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
80986
+ instructions: ixs,
80782
80987
  payerKey: params.authority,
80783
80988
  recentBlockhash: blockhash
80784
80989
  }).compileToV0Message(selectedLuts)
@@ -80816,13 +81021,18 @@ async function makeKaminoWithdrawTx(params) {
80816
81021
  cTokenAmount: adjustedAmount,
80817
81022
  ...withdrawIxParams
80818
81023
  });
81024
+ const ixs = await prependOrderCloses(
81025
+ params,
81026
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81027
+ selectedLuts
81028
+ );
80819
81029
  const {
80820
81030
  value: { blockhash }
80821
81031
  } = await connection.getLatestBlockhashAndContext("confirmed");
80822
81032
  const withdrawTx = addTransactionMetadata(
80823
81033
  new web3_js.VersionedTransaction(
80824
81034
  new web3_js.TransactionMessage({
80825
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81035
+ instructions: ixs,
80826
81036
  payerKey: params.authority,
80827
81037
  recentBlockhash: blockhash
80828
81038
  }).compileToV0Message(selectedLuts)
@@ -80946,13 +81156,18 @@ async function makeJuplendWithdrawTx(params) {
80946
81156
  [withdrawIxParams.bank.address],
80947
81157
  params.bankMetadataMap
80948
81158
  );
81159
+ const ixs = await prependOrderCloses(
81160
+ params,
81161
+ [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81162
+ selectedLuts
81163
+ );
80949
81164
  const {
80950
81165
  value: { blockhash }
80951
81166
  } = await connection.getLatestBlockhashAndContext("confirmed");
80952
81167
  const withdrawTx = addTransactionMetadata(
80953
81168
  new web3_js.VersionedTransaction(
80954
81169
  new web3_js.TransactionMessage({
80955
- instructions: [...refreshIntegrationIxs.instructions, ...withdrawIxs.instructions],
81170
+ instructions: ixs,
80956
81171
  payerKey: params.authority,
80957
81172
  recentBlockhash: blockhash
80958
81173
  }).compileToV0Message(selectedLuts)
@@ -81022,10 +81237,15 @@ async function makeRepayIx3({
81022
81237
  async function makeRepayTx(params) {
81023
81238
  const { luts, ...repayIxParams } = params;
81024
81239
  const ixs = await makeRepayIx3(repayIxParams);
81240
+ const actionIxs = await prependOrderCloses(
81241
+ params,
81242
+ ixs.instructions,
81243
+ selectLutsForBanks(luts, [params.bank])
81244
+ );
81025
81245
  const closedBanks = params.repayAll ? [params.bank.address] : [];
81026
81246
  const { instructions: instructions2, luts: selectedLuts } = await appendPremiumRefresh(
81027
81247
  params,
81028
- ixs.instructions,
81248
+ actionIxs,
81029
81249
  [],
81030
81250
  closedBanks
81031
81251
  );
@@ -81092,12 +81312,18 @@ async function makeRepayWithCollatTx(params) {
81092
81312
  payerKey: marginfiAccount.authority,
81093
81313
  luts: addressLookupTableAccounts ?? []
81094
81314
  });
81315
+ const orderTx = await makeOrderChangesTx({
81316
+ ...params,
81317
+ luts: addressLookupTableAccounts ?? [],
81318
+ blockhash
81319
+ });
81095
81320
  const transactions = [...additionalTxs, flashloanTx];
81321
+ if (orderTx) transactions.push(orderTx);
81096
81322
  return {
81097
81323
  transactions,
81098
81324
  swapQuote,
81099
81325
  amountToRepay,
81100
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
81326
+ mustBeAtomicBundle: transactions.length > 1
81101
81327
  };
81102
81328
  }
81103
81329
  async function buildRepayWithCollatFlashloanTx({
@@ -83593,7 +83819,8 @@ async function composeBridgedSwap(params) {
83593
83819
  banksMap,
83594
83820
  assetShareValueMultiplierByBank,
83595
83821
  feePayer,
83596
- maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS
83822
+ maxBundleTxs = MAX_BRIDGED_BUNDLE_TXS,
83823
+ reservedTxs = 0
83597
83824
  } = params;
83598
83825
  if (!firstLeg.quoteResponse) return null;
83599
83826
  const projectedAccount = projectAccountAfterFirstLeg(
@@ -83610,7 +83837,7 @@ async function composeBridgedSwap(params) {
83610
83837
  secondLeg.transactions,
83611
83838
  feePayer,
83612
83839
  blockhashOf(firstLeg),
83613
- maxBundleTxs
83840
+ maxBundleTxs - reservedTxs
83614
83841
  );
83615
83842
  if (!transactions) return null;
83616
83843
  return {
@@ -83672,12 +83899,18 @@ async function makeSwapDebtTx(params) {
83672
83899
  luts: addressLookupTableAccounts ?? []
83673
83900
  }
83674
83901
  );
83902
+ const orderTx = await makeOrderChangesTx({
83903
+ ...params,
83904
+ luts: addressLookupTableAccounts ?? [],
83905
+ blockhash
83906
+ });
83675
83907
  const transactions = [...additionalTxs, flashloanTx];
83908
+ if (orderTx) transactions.push(orderTx);
83676
83909
  return {
83677
83910
  transactions,
83678
- actionTxIndex: transactions.length - 1,
83911
+ actionTxIndex: additionalTxs.length,
83679
83912
  quoteResponse: swapQuote,
83680
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
83913
+ mustBeAtomicBundle: transactions.length > 1
83681
83914
  };
83682
83915
  }
83683
83916
  async function buildSwapDebtFlashloanTx({
@@ -83884,6 +84117,10 @@ async function tryBridgedDebtSwap(params, bridgeOpts) {
83884
84117
  bridgeTokenSide: "borrow",
83885
84118
  bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
83886
84119
  });
84120
+ const orderTx = await makeOrderChangesTx({
84121
+ ...params,
84122
+ luts: params.addressLookupTableAccounts ?? []
84123
+ });
83887
84124
  const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
83888
84125
  return tryBridgeCandidates({
83889
84126
  usableBridgeBanks,
@@ -83937,11 +84174,12 @@ async function tryBridgedDebtSwap(params, bridgeOpts) {
83937
84174
  banksMap: params.bankMap,
83938
84175
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
83939
84176
  feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
83940
- maxBundleTxs: bridgeOpts?.maxBundleTxs
84177
+ maxBundleTxs: bridgeOpts?.maxBundleTxs,
84178
+ reservedTxs: orderTx ? 1 : 0
83941
84179
  });
83942
84180
  if (!result) return null;
83943
84181
  return {
83944
- transactions: result.transactions,
84182
+ transactions: orderTx ? [...result.transactions, orderTx] : result.transactions,
83945
84183
  actionTxIndex: result.transactions.length - 1,
83946
84184
  quoteResponse: mergeBridgeQuotesDebt(result.firstLegQuote, result.secondLegQuote),
83947
84185
  bridgeMint: bridgeBank.mint,
@@ -84020,12 +84258,23 @@ async function makeLoopTx(params) {
84020
84258
  luts: addressLookupTableAccounts ?? []
84021
84259
  }
84022
84260
  );
84261
+ const orderTx = await makeOrderChangesTx({
84262
+ ...params,
84263
+ placeOrder: params.placeOrder && {
84264
+ collateralBank: depositOpts.depositBank.address,
84265
+ debtBank: borrowOpts.borrowBank.address,
84266
+ trigger: params.placeOrder
84267
+ },
84268
+ luts: addressLookupTableAccounts ?? [],
84269
+ blockhash
84270
+ });
84023
84271
  const transactions = [...additionalTxs, flashloanTx];
84272
+ if (orderTx) transactions.push(orderTx);
84024
84273
  return {
84025
84274
  transactions,
84026
- actionTxIndex: transactions.length - 1,
84275
+ actionTxIndex: additionalTxs.length,
84027
84276
  quoteResponse: swapQuote,
84028
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
84277
+ mustBeAtomicBundle: transactions.length > 1
84029
84278
  };
84030
84279
  }
84031
84280
  async function buildLoopFlashloanTx(params) {
@@ -84356,6 +84605,15 @@ async function tryBridgedLoop(params, bridgeOpts) {
84356
84605
  const oraclePriceOf = (bank) => params.oraclePrices.get(bank.address.toBase58())?.priceRealtime.price.toNumber() ?? 0;
84357
84606
  const borrowBankPrice = oraclePriceOf(borrowBank);
84358
84607
  if (borrowBankPrice <= 0) return null;
84608
+ const orderTx = await makeOrderChangesTx({
84609
+ ...params,
84610
+ placeOrder: params.placeOrder && {
84611
+ collateralBank: depositBank.address,
84612
+ debtBank: borrowBank.address,
84613
+ trigger: params.placeOrder
84614
+ },
84615
+ luts: params.addressLookupTableAccounts ?? []
84616
+ });
84359
84617
  const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
84360
84618
  return tryBridgeCandidates({
84361
84619
  usableBridgeBanks,
@@ -84374,6 +84632,9 @@ async function tryBridgedLoop(params, bridgeOpts) {
84374
84632
  );
84375
84633
  const firstLeg = await makeLoopTx({
84376
84634
  ...params,
84635
+ // The order changes run after the second leg, once the loop's final debt exists
84636
+ ordersToClose: void 0,
84637
+ placeOrder: void 0,
84377
84638
  depositOpts: {
84378
84639
  ...params.depositOpts,
84379
84640
  marketPrice: oraclePriceOf(depositBank)
@@ -84411,11 +84672,12 @@ async function tryBridgedLoop(params, bridgeOpts) {
84411
84672
  banksMap: params.bankMap,
84412
84673
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
84413
84674
  feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
84414
- maxBundleTxs: bridgeOpts?.maxBundleTxs
84675
+ maxBundleTxs: bridgeOpts?.maxBundleTxs,
84676
+ reservedTxs: orderTx ? 1 : 0
84415
84677
  });
84416
84678
  if (!result) return null;
84417
84679
  return {
84418
- transactions: result.transactions,
84680
+ transactions: orderTx ? [...result.transactions, orderTx] : result.transactions,
84419
84681
  actionTxIndex: result.transactions.length - 1,
84420
84682
  quoteResponse: mergeBridgeQuotesLoop(result.firstLegQuote, result.secondLegQuote),
84421
84683
  bridgeMint: bridgeBank.mint,
@@ -84471,12 +84733,18 @@ async function makeSwapCollateralTx(params) {
84471
84733
  payerKey: marginfiAccount.authority,
84472
84734
  luts: addressLookupTableAccounts ?? []
84473
84735
  });
84736
+ const orderTx = await makeOrderChangesTx({
84737
+ ...params,
84738
+ luts: addressLookupTableAccounts ?? [],
84739
+ blockhash
84740
+ });
84474
84741
  const transactions = [...additionalTxs, flashloanTx];
84742
+ if (orderTx) transactions.push(orderTx);
84475
84743
  return {
84476
84744
  transactions,
84477
- actionTxIndex: transactions.length - 1,
84745
+ actionTxIndex: additionalTxs.length,
84478
84746
  quoteResponse: swapQuote,
84479
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
84747
+ mustBeAtomicBundle: transactions.length > 1
84480
84748
  };
84481
84749
  }
84482
84750
  async function buildSwapCollateralFlashloanTx({
@@ -84837,6 +85105,10 @@ async function tryBridgedCollateralSwap(params, bridgeOpts) {
84837
85105
  bridgeTokenSide: "deposit",
84838
85106
  bridgeCandidateMints: bridgeOpts?.bridgeCandidateMints
84839
85107
  });
85108
+ const orderTx = await makeOrderChangesTx({
85109
+ ...params,
85110
+ luts: params.addressLookupTableAccounts ?? []
85111
+ });
84840
85112
  const tokenProgramCache = new Map(bridgeOpts?.tokenProgramByMint);
84841
85113
  return tryBridgeCandidates({
84842
85114
  usableBridgeBanks,
@@ -84886,11 +85158,12 @@ async function tryBridgedCollateralSwap(params, bridgeOpts) {
84886
85158
  banksMap: params.bankMap,
84887
85159
  assetShareValueMultiplierByBank: params.assetShareValueMultiplierByBank,
84888
85160
  feePayer: params.overrideInferAccounts?.authority ?? params.marginfiAccount.authority,
84889
- maxBundleTxs: bridgeOpts?.maxBundleTxs
85161
+ maxBundleTxs: bridgeOpts?.maxBundleTxs,
85162
+ reservedTxs: orderTx ? 1 : 0
84890
85163
  });
84891
85164
  if (!result) return null;
84892
85165
  return {
84893
- transactions: result.transactions,
85166
+ transactions: orderTx ? [...result.transactions, orderTx] : result.transactions,
84894
85167
  actionTxIndex: result.transactions.length - 1,
84895
85168
  quoteResponse: mergeBridgeQuotes(result.firstLegQuote, result.secondLegQuote),
84896
85169
  bridgeMint: bridgeBank.mint,
@@ -84958,12 +85231,18 @@ async function makeRollPtTx(params) {
84958
85231
  payerKey: marginfiAccount.authority,
84959
85232
  luts: addressLookupTableAccounts ?? []
84960
85233
  });
85234
+ const orderTx = await makeOrderChangesTx({
85235
+ ...params,
85236
+ luts: addressLookupTableAccounts ?? [],
85237
+ blockhash
85238
+ });
84961
85239
  const transactions = [...additionalTxs, flashloanTx];
85240
+ if (orderTx) transactions.push(orderTx);
84962
85241
  return {
84963
85242
  transactions,
84964
- actionTxIndex: transactions.length - 1,
85243
+ actionTxIndex: additionalTxs.length,
84965
85244
  quoteResponse: swapQuote,
84966
- mustBeAtomicBundle: refreshIntegrationIxs.instructions.length > 0
85245
+ mustBeAtomicBundle: transactions.length > 1
84967
85246
  };
84968
85247
  }
84969
85248
  async function buildRollPtFlashloanTx({
@@ -85658,12 +85937,22 @@ async function makeTransferPositionsTx(params) {
85658
85937
  payerKey: accountA.authority,
85659
85938
  luts
85660
85939
  });
85940
+ const sourceOrderTx = await makeOrderChangesTx({ ...params, luts, blockhash });
85941
+ const destinationOrderTx = await makeOrderChangesTx({
85942
+ ...params,
85943
+ marginfiAccount: accountB,
85944
+ ordersToClose: params.destinationOrdersToClose,
85945
+ luts,
85946
+ blockhash
85947
+ });
85661
85948
  const transactions = [...additionalTxs, flashloanTx];
85949
+ if (sourceOrderTx) transactions.push(sourceOrderTx);
85950
+ if (destinationOrderTx) transactions.push(destinationOrderTx);
85662
85951
  return {
85663
85952
  transactions,
85664
85953
  actionTxIndex: additionalTxs.length,
85665
85954
  destinationAccount: accountB,
85666
- mustBeAtomicBundle: refreshIxs.length > 0
85955
+ mustBeAtomicBundle: transactions.length > 1
85667
85956
  };
85668
85957
  }
85669
85958
 
@@ -85786,8 +86075,10 @@ async function makeBulkWithdrawTx(params) {
85786
86075
  if (setupTokens.some((t) => t.mint.equals(NATIVE_MINT))) {
85787
86076
  withdrawIxs.push(makeUnwrapSolIx(authority));
85788
86077
  }
86078
+ const closeIxs = await makeOrderChangesIxs(params);
86079
+ const actionIxs = [...closeIxs, ...withdrawIxs];
85789
86080
  const { blockhash } = await connection.getLatestBlockhash("confirmed");
85790
- const withdrawTxs = splitInstructionsToFitTransactions([], withdrawIxs, {
86081
+ const withdrawTxs = splitInstructionsToFitTransactions([], actionIxs, {
85791
86082
  blockhash,
85792
86083
  payerKey: authority,
85793
86084
  luts: selectedLuts,
@@ -85818,7 +86109,8 @@ async function makeBulkWithdrawTx(params) {
85818
86109
  return {
85819
86110
  transactions: [...additionalTxs, ...withdrawTxs],
85820
86111
  actionTxIndex: additionalTxs.length,
85821
- mustBeAtomicBundle: refreshIxs.length > 0
86112
+ // Order closes must land with every withdraw
86113
+ mustBeAtomicBundle: refreshIxs.length > 0 || closeIxs.length > 0 && withdrawTxs.length > 1
85822
86114
  };
85823
86115
  }
85824
86116
  async function makeBulkRepayTx(params) {
@@ -85865,8 +86157,10 @@ async function makeBulkRepayTx(params) {
85865
86157
  [],
85866
86158
  bankAddresses
85867
86159
  ) : [];
86160
+ const closeIxs = await makeOrderChangesIxs(params);
86161
+ const actionIxs = [...closeIxs, ...repayIxs, ...premiumIxs];
85868
86162
  const { blockhash } = await connection.getLatestBlockhash("confirmed");
85869
- const transactions = splitInstructionsToFitTransactions([], [...repayIxs, ...premiumIxs], {
86163
+ const transactions = splitInstructionsToFitTransactions([], actionIxs, {
85870
86164
  blockhash,
85871
86165
  payerKey: authority,
85872
86166
  luts,
@@ -85881,115 +86175,11 @@ async function makeBulkRepayTx(params) {
85881
86175
  return {
85882
86176
  transactions,
85883
86177
  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
86178
+ // Venue refreshes only count in the pulse's slot, and the pulse must follow every repay;
86179
+ // order closes must land with every repay
86180
+ mustBeAtomicBundle: (premiumIxs.length > 0 || closeIxs.length > 0) && transactions.length > 1
85886
86181
  };
85887
86182
  }
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
86183
 
85994
86184
  // src/services/account/services/account-simulation.service.ts
85995
86185
  async function simulateAccountHealthCacheWithFallback(params) {
@@ -90068,6 +90258,8 @@ exports.makeLoopTx = makeLoopTx;
90068
90258
  exports.makeMergeStakeAccountsTx = makeMergeStakeAccountsTx;
90069
90259
  exports.makeMintStakedLstIx = makeMintStakedLstIx;
90070
90260
  exports.makeMintStakedLstTx = makeMintStakedLstTx;
90261
+ exports.makeOrderChangesIxs = makeOrderChangesIxs;
90262
+ exports.makeOrderChangesTx = makeOrderChangesTx;
90071
90263
  exports.makePlaceOrderIx = makePlaceOrderIx2;
90072
90264
  exports.makePlaceOrderTx = makePlaceOrderTx;
90073
90265
  exports.makePoolAddBankIx = makePoolAddBankIx2;
@@ -90132,6 +90324,7 @@ exports.parseRiskTier = parseRiskTier;
90132
90324
  exports.parseRpcPythPriceData = parseRpcPythPriceData;
90133
90325
  exports.patchDepositAmount = patchDepositAmount;
90134
90326
  exports.percentToMaxSlippageU32 = percentToMaxSlippageU32;
90327
+ exports.prependOrderCloses = prependOrderCloses;
90135
90328
  exports.rateFromU32 = rateFromU32;
90136
90329
  exports.requireBank = requireBank;
90137
90330
  exports.requireTokenProgram = requireTokenProgram;