@0dotxyz/p0-ts-sdk 2.9.0-alpha.1 → 2.9.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
@@ -125,6 +125,8 @@ var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCod
125
125
  TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSUPPORTED_BANK"] = "TRANSFER_POSITIONS_UNSUPPORTED_BANK";
126
126
  TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSPLITTABLE"] = "TRANSFER_POSITIONS_UNSPLITTABLE";
127
127
  TransactionBuildingErrorCode2["BRIDGE_CONFLICT"] = "BRIDGE_CONFLICT";
128
+ TransactionBuildingErrorCode2["ORDER_INVALID_TRIGGER"] = "ORDER_INVALID_TRIGGER";
129
+ TransactionBuildingErrorCode2["ORDER_INVALID_SLIPPAGE"] = "ORDER_INVALID_SLIPPAGE";
128
130
  return TransactionBuildingErrorCode2;
129
131
  })(TransactionBuildingErrorCode || {});
130
132
  var TransactionBuildingError = class _TransactionBuildingError extends Error {
@@ -258,6 +260,28 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
258
260
  { conflictingBanks, bridgeTokenSide }
259
261
  );
260
262
  }
263
+ /**
264
+ * The order trigger can't be placed: no threshold set, a threshold not above 0, or take-profit
265
+ * at or below stop-loss (the program rejects all three with `InvalidOrderTakeProfitOrStopLoss`).
266
+ */
267
+ static orderInvalidTrigger(reason, takeProfitUsd, stopLossUsd) {
268
+ return new _TransactionBuildingError(
269
+ "ORDER_INVALID_TRIGGER" /* ORDER_INVALID_TRIGGER */,
270
+ `Invalid order trigger: ${reason}`,
271
+ { reason, takeProfitUsd, stopLossUsd }
272
+ );
273
+ }
274
+ /**
275
+ * The order's max slippage is outside (0, cap]. The program accepts 0, but a keeper can't
276
+ * execute an order that allows no slippage, so the SDK rejects it.
277
+ */
278
+ static orderInvalidSlippage(maxSlippagePercent, maxAllowedPercent) {
279
+ return new _TransactionBuildingError(
280
+ "ORDER_INVALID_SLIPPAGE" /* ORDER_INVALID_SLIPPAGE */,
281
+ `Max slippage percent must be in (0, ${maxAllowedPercent}], got ${maxSlippagePercent}`,
282
+ { maxSlippagePercent, maxAllowedPercent }
283
+ );
284
+ }
261
285
  /**
262
286
  * Generic escape hatch for custom errors
263
287
  */
@@ -535,9 +559,7 @@ var U32_MAX = 4294967295;
535
559
  var MAX_ORDER_SLIPPAGE_PERCENT = 10;
536
560
  function percentToMaxSlippageU32(percent) {
537
561
  if (!(percent > 0) || percent > MAX_ORDER_SLIPPAGE_PERCENT) {
538
- throw new Error(
539
- `Max slippage percent must be in (0, ${MAX_ORDER_SLIPPAGE_PERCENT}], got ${percent}`
540
- );
562
+ throw TransactionBuildingError.orderInvalidSlippage(percent, MAX_ORDER_SLIPPAGE_PERCENT);
541
563
  }
542
564
  return Math.floor(percent / 100 * U32_MAX);
543
565
  }
@@ -72911,6 +72933,18 @@ function getActiveBalances(balances) {
72911
72933
  function getBalance(bankAddress, balances) {
72912
72934
  return balances.filter((b) => b.active).find((b) => b.bankPk.equals(bankAddress)) ?? createEmptyBalance(bankAddress);
72913
72935
  }
72936
+ var EMPTY_BALANCE_THRESHOLD = 1;
72937
+ function resolveOrderLegs(marginfiAccount, order) {
72938
+ const taggedBalances = marginfiAccount.balances.filter(
72939
+ (balance) => balance.active && balance.tag !== 0 && order.tags.includes(balance.tag)
72940
+ );
72941
+ return {
72942
+ collateralBank: taggedBalances.find(
72943
+ (balance) => balance.liabilityShares.lt(EMPTY_BALANCE_THRESHOLD) && balance.assetShares.gte(EMPTY_BALANCE_THRESHOLD)
72944
+ )?.bankPk ?? null,
72945
+ debtBank: taggedBalances.find((balance) => balance.liabilityShares.gte(EMPTY_BALANCE_THRESHOLD))?.bankPk ?? null
72946
+ };
72947
+ }
72914
72948
  function computeAccountValue(marginfiAccount) {
72915
72949
  const { assets, liabilities } = computeHealthComponentsFromCache(
72916
72950
  marginfiAccount,
@@ -73474,11 +73508,6 @@ var fetchMarginfiAccountData = async (program, marginfiAccountPk, banksMap, bank
73474
73508
  return { marginfiAccount };
73475
73509
  }
73476
73510
  };
73477
- var fetchOrder = async (program, orderAddress) => {
73478
- const orderRaw = await program.account.order.fetchNullable(orderAddress);
73479
- if (!orderRaw) return null;
73480
- return parseOrderRaw(orderAddress, orderRaw);
73481
- };
73482
73511
  var fetchOrdersForAccount = async (program, marginfiAccount) => {
73483
73512
  const orders = await program.account.order.all([
73484
73513
  {
@@ -73491,24 +73520,6 @@ var fetchOrdersForAccount = async (program, marginfiAccount) => {
73491
73520
  ]);
73492
73521
  return orders.map(({ publicKey: publicKey5, account }) => parseOrderRaw(publicKey5, account));
73493
73522
  };
73494
- var resolveOrderLegs = (marginfiAccount, order) => {
73495
- const taggedBalances = marginfiAccount.balances.filter(
73496
- (balance) => balance.active && balance.tag !== 0 && order.tags.includes(balance.tag)
73497
- );
73498
- return {
73499
- collateralBank: taggedBalances.find((balance) => balance.assetShares.gt(0))?.bankPk ?? null,
73500
- debtBank: taggedBalances.find((balance) => balance.liabilityShares.gt(0))?.bankPk ?? null
73501
- };
73502
- };
73503
- var resolveOrderBanks = (marginfiAccount, order) => {
73504
- const { collateralBank, debtBank } = resolveOrderLegs(marginfiAccount, order);
73505
- if (!collateralBank || !debtBank) {
73506
- throw new Error(
73507
- `Could not resolve banks for order ${order.address.toBase58()}: tagged balances are missing or closed`
73508
- );
73509
- }
73510
- return { collateralBank, debtBank };
73511
- };
73512
73523
  var fetchOrderFees = async (program) => {
73513
73524
  const [feeStateAddress] = deriveFeeState(program.programId);
73514
73525
  const feeState = await program.account.feeState.fetch(feeStateAddress);
@@ -73640,18 +73651,27 @@ function computeMaxBorrowForBank(params) {
73640
73651
  BigNumber3__default.default.min(healthMaxBorrow, borrowCapRemaining, availableLiquidity, rateLimitRemaining)
73641
73652
  );
73642
73653
  }
73643
- function computeOutflowRateLimitRemaining(bank, oraclePrice, groupRateLimiter, assetShareValueMultiplier) {
73654
+ function computeBankOutflowRateLimit(bank, assetShareValueMultiplier) {
73655
+ if (!bank.rateLimiter) return null;
73644
73656
  const nowSeconds = Date.now() / 1e3;
73645
- let remaining = new BigNumber3__default.default(Infinity);
73646
- let bankRemaining = computeBankRateLimitRemaining(bank, nowSeconds);
73647
- if (bankRemaining !== null) {
73648
- const limiterInBankMintUnits = bank.config.assetTag === 3 /* KAMINO */ || bank.config.assetTag === 2 /* STAKED */;
73649
- if (limiterInBankMintUnits && assetShareValueMultiplier?.gt(0)) {
73650
- bankRemaining = bankRemaining.times(assetShareValueMultiplier);
73651
- }
73652
- remaining = BigNumber3__default.default.min(remaining, bankRemaining);
73657
+ const limiterToUnderlying = bank.config.assetTag === 2 /* STAKED */ && assetShareValueMultiplier?.gt(0) ? assetShareValueMultiplier : new BigNumber3__default.default(1);
73658
+ let tightest = null;
73659
+ for (const window of ["hourly", "daily"]) {
73660
+ const remainingNative = computeRateLimitWindowRemainingCapacity(
73661
+ bank.rateLimiter[window],
73662
+ nowSeconds
73663
+ );
73664
+ if (!remainingNative) continue;
73665
+ const remaining = BigNumber3__default.default.max(0, nativeToUi(remainingNative, bank.mintDecimals)).times(
73666
+ limiterToUnderlying
73667
+ );
73668
+ if (!tightest || remaining.lt(tightest.remaining)) tightest = { window, remaining };
73653
73669
  }
73654
- const groupRemainingUsd = computeGroupRateLimitRemainingUsd(groupRateLimiter, nowSeconds);
73670
+ return tightest;
73671
+ }
73672
+ function computeOutflowRateLimitRemaining(bank, oraclePrice, groupRateLimiter, assetShareValueMultiplier) {
73673
+ let remaining = computeBankOutflowRateLimit(bank, assetShareValueMultiplier)?.remaining ?? new BigNumber3__default.default(Infinity);
73674
+ const groupRemainingUsd = computeGroupRateLimitRemainingUsd(groupRateLimiter);
73655
73675
  if (groupRemainingUsd !== null) {
73656
73676
  const price = getPrice(oraclePrice, 1 /* None */, false);
73657
73677
  if (price.gt(0)) remaining = BigNumber3__default.default.min(remaining, groupRemainingUsd.div(price));
@@ -79295,6 +79315,14 @@ var MarginfiAccount = class _MarginfiAccount {
79295
79315
  async makePlaceOrderTx(params) {
79296
79316
  return makePlaceOrderTx({ ...params, marginfiAccount: this });
79297
79317
  }
79318
+ /**
79319
+ * Creates a close-order instruction for this marginfi account.
79320
+ *
79321
+ * @see {@link makeCloseOrderIx} for detailed implementation
79322
+ */
79323
+ async makeCloseOrderIx(params) {
79324
+ return makeCloseOrderIx2({ ...params, marginfiAccount: this });
79325
+ }
79298
79326
  /**
79299
79327
  * Creates a transaction closing an existing order.
79300
79328
  *
@@ -81875,10 +81903,21 @@ async function makeBulkRepayTx(params) {
81875
81903
  function buildOrderTrigger(params) {
81876
81904
  const { stopLossUsd, takeProfitUsd } = params;
81877
81905
  const maxSlippage = percentToMaxSlippageU32(params.maxSlippagePercent);
81906
+ const invalidTrigger = (reason) => TransactionBuildingError.orderInvalidTrigger(
81907
+ reason,
81908
+ takeProfitUsd?.toString(),
81909
+ stopLossUsd?.toString()
81910
+ );
81911
+ if (stopLossUsd && !stopLossUsd.gt(0)) {
81912
+ throw invalidTrigger(`stop-loss threshold (${stopLossUsd}) must be above 0`);
81913
+ }
81914
+ if (takeProfitUsd && !takeProfitUsd.gt(0)) {
81915
+ throw invalidTrigger(`take-profit threshold (${takeProfitUsd}) must be above 0`);
81916
+ }
81878
81917
  if (stopLossUsd && takeProfitUsd) {
81879
81918
  if (takeProfitUsd.lte(stopLossUsd)) {
81880
- throw new Error(
81881
- `Take-profit threshold (${takeProfitUsd}) must be above stop-loss threshold (${stopLossUsd})`
81919
+ throw invalidTrigger(
81920
+ `take-profit threshold (${takeProfitUsd}) must be above stop-loss threshold (${stopLossUsd})`
81882
81921
  );
81883
81922
  }
81884
81923
  return {
@@ -81895,7 +81934,7 @@ function buildOrderTrigger(params) {
81895
81934
  if (takeProfitUsd) {
81896
81935
  return { takeProfit: { threshold: bigNumberToWrappedI80F48(takeProfitUsd), maxSlippage } };
81897
81936
  }
81898
- throw new Error("An order needs a stop-loss threshold, a take-profit threshold, or both");
81937
+ throw invalidTrigger("an order needs a stop-loss threshold, a take-profit threshold, or both");
81899
81938
  }
81900
81939
  async function makePlaceOrderIx2(params) {
81901
81940
  const { program, marginfiAccount, collateralBank, debtBank, trigger, feePayer } = params;
@@ -84829,6 +84868,29 @@ var MarginfiAccountWrapper = class {
84829
84868
  // ----------------------------------------------------------------------------
84830
84869
  // Orders (take-profit / stop-loss)
84831
84870
  // ----------------------------------------------------------------------------
84871
+ /**
84872
+ * Creates a place-order instruction, for composing into a larger transaction.
84873
+ *
84874
+ * @param collateralBank - Bank of the asset-side balance
84875
+ * @param debtBank - Bank of the liability-side balance
84876
+ * @param trigger - USD pair-equity thresholds and max slippage
84877
+ */
84878
+ async makePlaceOrderIx(collateralBank, debtBank, trigger) {
84879
+ return this.account.makePlaceOrderIx({
84880
+ program: this.client.program,
84881
+ collateralBank,
84882
+ debtBank,
84883
+ trigger
84884
+ });
84885
+ }
84886
+ /**
84887
+ * Creates a close-order instruction, for composing into a larger transaction.
84888
+ *
84889
+ * @param order - The order PDA (from `fetchOrdersForAccount` or `deriveOrderPda`)
84890
+ */
84891
+ async makeCloseOrderIx(order) {
84892
+ return this.account.makeCloseOrderIx({ program: this.client.program, order });
84893
+ }
84832
84894
  /**
84833
84895
  * Creates a transaction placing a take-profit / stop-loss order on a collateral/debt pair.
84834
84896
  *
@@ -85689,6 +85751,7 @@ exports.computeBankBorrowApy = computeBankBorrowApy;
85689
85751
  exports.computeBankBorrowCapRemaining = computeBankBorrowCapRemaining;
85690
85752
  exports.computeBankDepositCapRemaining = computeBankDepositCapRemaining;
85691
85753
  exports.computeBankMetrics = computeBankMetrics;
85754
+ exports.computeBankOutflowRateLimit = computeBankOutflowRateLimit;
85692
85755
  exports.computeBankPoolSize = computeBankPoolSize;
85693
85756
  exports.computeBankProjectedAvailableLiquidity = computeBankProjectedAvailableLiquidity;
85694
85757
  exports.computeBankRateLimitRemaining = computeBankRateLimitRemaining;
@@ -85800,7 +85863,6 @@ exports.fetchOracleData = fetchOracleData;
85800
85863
  exports.fetchOracleMultipliers = fetchOracleMultipliers;
85801
85864
  exports.fetchOracleMultipliersFromAPI = fetchOracleMultipliersFromAPI;
85802
85865
  exports.fetchOracleMultipliersFromChain = fetchOracleMultipliersFromChain;
85803
- exports.fetchOrder = fetchOrder;
85804
85866
  exports.fetchOrderFees = fetchOrderFees;
85805
85867
  exports.fetchOrdersForAccount = fetchOrdersForAccount;
85806
85868
  exports.fetchProgramForMints = fetchProgramForMints;
@@ -85991,7 +86053,6 @@ exports.requireBank = requireBank;
85991
86053
  exports.requireTokenProgram = requireTokenProgram;
85992
86054
  exports.resolveAmount = resolveAmount;
85993
86055
  exports.resolveBridgeCandidateBanks = resolveBridgeCandidateBanks;
85994
- exports.resolveOrderBanks = resolveOrderBanks;
85995
86056
  exports.resolveOrderLegs = resolveOrderLegs;
85996
86057
  exports.resolvePinnedSwapRoute = resolvePinnedSwapRoute;
85997
86058
  exports.resolveTokenProgramForMint = resolveTokenProgramForMint;