@drift-labs/sdk 2.13.0-beta.0 → 2.13.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,6 +51,8 @@ export declare const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO: BN;
51
51
  export declare const MARGIN_PRECISION: BN;
52
52
  export declare const BID_ASK_SPREAD_PRECISION: BN;
53
53
  export declare const LIQUIDATION_PCT_PRECISION: BN;
54
+ export declare const FIVE_MINUTE: BN;
55
+ export declare const ONE_HOUR: BN;
54
56
  export declare const ONE_YEAR: BN;
55
57
  export declare const QUOTE_SPOT_MARKET_INDEX = 0;
56
58
  export declare const LAMPORTS_PRECISION: BN;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BID_ASK_SPREAD_PRECISION = exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.PRICE_DIV_PEG = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION_EXP = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_RATE_BUFFER_PRECISION = exports.FUNDING_RATE_PRECISION = exports.PRICE_PRECISION = exports.QUOTE_PRECISION = exports.LIQUIDATION_FEE_PRECISION = exports.SPOT_MARKET_IMF_PRECISION = exports.SPOT_MARKET_IMF_PRECISION_EXP = exports.SPOT_MARKET_BALANCE_PRECISION = exports.SPOT_MARKET_BALANCE_PRECISION_EXP = exports.SPOT_MARKET_WEIGHT_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION_EXP = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION_EXP = exports.SPOT_MARKET_RATE_PRECISION = exports.SPOT_MARKET_RATE_PRECISION_EXP = exports.AMM_RESERVE_PRECISION_EXP = exports.PEG_PRECISION_EXP = exports.FUNDING_RATE_PRECISION_EXP = exports.PRICE_PRECISION_EXP = exports.FUNDING_RATE_BUFFER_PRECISION_EXP = exports.QUOTE_PRECISION_EXP = exports.CONCENTRATION_PRECISION = exports.PERCENTAGE_PRECISION = exports.PERCENTAGE_PRECISION_EXP = exports.MAX_LEVERAGE = exports.TEN_MILLION = exports.BN_MAX = exports.TEN_THOUSAND = exports.TEN = exports.NINE = exports.EIGHT = exports.SEVEN = exports.SIX = exports.FIVE = exports.FOUR = exports.THREE = exports.TWO = exports.ONE = exports.ZERO = void 0;
4
- exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.LIQUIDATION_PCT_PRECISION = void 0;
4
+ exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.ONE_HOUR = exports.FIVE_MINUTE = exports.LIQUIDATION_PCT_PRECISION = void 0;
5
5
  const web3_js_1 = require("@solana/web3.js");
6
6
  const __1 = require("../");
7
7
  exports.ZERO = new __1.BN(0);
@@ -55,6 +55,8 @@ exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.AMM_RESERVE_PRECISION.m
55
55
  exports.MARGIN_PRECISION = exports.TEN_THOUSAND;
56
56
  exports.BID_ASK_SPREAD_PRECISION = new __1.BN(1000000); // 10^6
57
57
  exports.LIQUIDATION_PCT_PRECISION = exports.TEN_THOUSAND;
58
+ exports.FIVE_MINUTE = new __1.BN(60 * 5);
59
+ exports.ONE_HOUR = new __1.BN(60 * 60);
58
60
  exports.ONE_YEAR = new __1.BN(31536000);
59
61
  exports.QUOTE_SPOT_MARKET_INDEX = 0;
60
62
  exports.LAMPORTS_PRECISION = new __1.BN(web3_js_1.LAMPORTS_PER_SOL);
@@ -219,6 +219,15 @@ export declare class DriftClient {
219
219
  * @returns
220
220
  */
221
221
  modifyPerpOrder(orderId: number, newBaseAmount?: BN, newLimitPrice?: BN, newOraclePriceOffset?: number): Promise<TransactionSignature>;
222
+ /**
223
+ * Modifies an open order by closing it and replacing it with a new order.
224
+ * @param userOrderId: The open order to modify
225
+ * @param newBaseAmount: The new base amount for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
226
+ * @param newLimitPice: The new limit price for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
227
+ * @param newOraclePriceOffset: The new oracle price offset for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
228
+ * @returns
229
+ */
230
+ modifyPerpOrderByUserOrderId(userOrderId: number, newBaseAmount?: BN, newLimitPrice?: BN, newOraclePriceOffset?: number): Promise<TransactionSignature>;
222
231
  settlePNLs(users: {
223
232
  settleeUserAccountPublicKey: PublicKey;
224
233
  settleeUserAccount: UserAccount;
@@ -1777,6 +1777,55 @@ class DriftClient {
1777
1777
  maxTs: openOrder.maxTs,
1778
1778
  auctionStartPrice: openOrder.auctionStartPrice,
1779
1779
  auctionEndPrice: openOrder.auctionEndPrice,
1780
+ userOrderId: openOrder.userOrderId,
1781
+ };
1782
+ const placeOrderIx = await this.getPlacePerpOrderIx(newOrderParams);
1783
+ const tx = new web3_js_1.Transaction();
1784
+ tx.add(web3_js_1.ComputeBudgetProgram.requestUnits({
1785
+ units: 1000000,
1786
+ additionalFee: 0,
1787
+ }));
1788
+ tx.add(cancelOrderIx);
1789
+ tx.add(placeOrderIx);
1790
+ const { txSig, slot } = await this.sendTransaction(tx, [], this.opts);
1791
+ this.perpMarketLastSlotCache.set(newOrderParams.marketIndex, slot);
1792
+ return txSig;
1793
+ }
1794
+ /**
1795
+ * Modifies an open order by closing it and replacing it with a new order.
1796
+ * @param userOrderId: The open order to modify
1797
+ * @param newBaseAmount: The new base amount for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
1798
+ * @param newLimitPice: The new limit price for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
1799
+ * @param newOraclePriceOffset: The new oracle price offset for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
1800
+ * @returns
1801
+ */
1802
+ async modifyPerpOrderByUserOrderId(userOrderId, newBaseAmount, newLimitPrice, newOraclePriceOffset) {
1803
+ if (!newBaseAmount && !newLimitPrice && !newOraclePriceOffset) {
1804
+ throw new Error(`Must provide newBaseAmount or newLimitPrice or newOraclePriceOffset to modify order`);
1805
+ }
1806
+ const openOrder = this.getUser().getOrderByUserOrderId(userOrderId);
1807
+ if (!openOrder) {
1808
+ throw new Error(`No open order with user order id ${userOrderId.toString()}`);
1809
+ }
1810
+ const cancelOrderIx = await this.getCancelOrderIx(openOrder.orderId);
1811
+ const newOrderParams = {
1812
+ orderType: openOrder.orderType,
1813
+ marketType: openOrder.marketType,
1814
+ direction: openOrder.direction,
1815
+ baseAssetAmount: newBaseAmount || openOrder.baseAssetAmount,
1816
+ price: newLimitPrice || openOrder.price,
1817
+ marketIndex: openOrder.marketIndex,
1818
+ reduceOnly: openOrder.reduceOnly,
1819
+ postOnly: openOrder.postOnly,
1820
+ immediateOrCancel: openOrder.immediateOrCancel,
1821
+ triggerPrice: openOrder.triggerPrice,
1822
+ triggerCondition: openOrder.triggerCondition,
1823
+ oraclePriceOffset: newOraclePriceOffset || openOrder.oraclePriceOffset,
1824
+ auctionDuration: openOrder.auctionDuration,
1825
+ maxTs: openOrder.maxTs,
1826
+ auctionStartPrice: openOrder.auctionStartPrice,
1827
+ auctionEndPrice: openOrder.auctionEndPrice,
1828
+ userOrderId: openOrder.userOrderId,
1780
1829
  };
1781
1830
  const placeOrderIx = await this.getPlacePerpOrderIx(newOrderParams);
1782
1831
  const tx = new web3_js_1.Transaction();
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.13.0-beta.0",
2
+ "version": "2.13.0-beta.2",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -7,5 +7,5 @@ imfFactor: BN, liabilityWeight: BN, precision: BN): BN;
7
7
  export declare function calculateSizeDiscountAssetWeight(size: BN, // AMM_RESERVE_PRECISION
8
8
  imfFactor: BN, assetWeight: BN): BN;
9
9
  export declare function calculateOraclePriceForPerpMargin(perpPosition: PerpPosition, market: PerpMarketAccount, oraclePriceData: OraclePriceData): BN;
10
- export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
10
+ export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
11
11
  export declare function calculateWorstCaseBaseAssetAmount(perpPosition: PerpPosition): BN;
@@ -11,7 +11,7 @@ imfFactor, liabilityWeight, precision) {
11
11
  if (imfFactor.eq(numericConstants_1.ZERO)) {
12
12
  return liabilityWeight;
13
13
  }
14
- const sizeSqrt = utils_1.squareRootBN(size.mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
14
+ const sizeSqrt = utils_1.squareRootBN(size.abs().mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
15
15
  const denom0 = anchor_1.BN.max(new anchor_1.BN(1), numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(imfFactor));
16
16
  assert_1.assert(denom0.gt(numericConstants_1.ZERO));
17
17
  const liabilityWeightNumerator = liabilityWeight.sub(liabilityWeight.div(anchor_1.BN.max(new anchor_1.BN(1), numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(imfFactor))));
@@ -30,7 +30,7 @@ imfFactor, assetWeight) {
30
30
  if (imfFactor.eq(numericConstants_1.ZERO)) {
31
31
  return assetWeight;
32
32
  }
33
- const sizeSqrt = utils_1.squareRootBN(size.mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
33
+ const sizeSqrt = utils_1.squareRootBN(size.abs().mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
34
34
  const imfNumerator = numericConstants_1.SPOT_MARKET_IMF_PRECISION.add(numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(new anchor_1.BN(10)));
35
35
  const sizeDiscountAssetWeight = imfNumerator
36
36
  .mul(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
@@ -58,15 +58,15 @@ function calculateOraclePriceForPerpMargin(perpPosition, market, oraclePriceData
58
58
  return marginPrice;
59
59
  }
60
60
  exports.calculateOraclePriceForPerpMargin = calculateOraclePriceForPerpMargin;
61
- function calculateBaseAssetValueWithOracle(market, perpPosition, oraclePriceData) {
61
+ function calculateBaseAssetValueWithOracle(market, perpPosition, oraclePriceData, includeOpenOrders = false) {
62
62
  let price = oraclePriceData.price;
63
63
  if (types_1.isVariant(market.status, 'settlement')) {
64
64
  price = market.expiryPrice;
65
65
  }
66
- return perpPosition.baseAssetAmount
67
- .abs()
68
- .mul(price)
69
- .div(numericConstants_1.AMM_RESERVE_PRECISION);
66
+ const baseAssetAmount = includeOpenOrders
67
+ ? calculateWorstCaseBaseAssetAmount(perpPosition)
68
+ : perpPosition.baseAssetAmount;
69
+ return baseAssetAmount.abs().mul(price).div(numericConstants_1.AMM_RESERVE_PRECISION);
70
70
  }
71
71
  exports.calculateBaseAssetValueWithOracle = calculateBaseAssetValueWithOracle;
72
72
  function calculateWorstCaseBaseAssetAmount(perpPosition) {
@@ -2,6 +2,7 @@
2
2
  import { BN } from '@project-serum/anchor';
3
3
  import { PerpMarketAccount, PositionDirection, MarginCategory, SpotMarketAccount } from '../types';
4
4
  import { OraclePriceData } from '../oracles/types';
5
+ import { DLOB } from '../dlob/DLOB';
5
6
  /**
6
7
  * Calculates market mark price
7
8
  *
@@ -31,3 +32,7 @@ export declare function calculateUnrealizedAssetWeight(market: PerpMarketAccount
31
32
  export declare function calculateMarketAvailablePNL(perpMarket: PerpMarketAccount, spotMarket: SpotMarketAccount): BN;
32
33
  export declare function calculateNetUserPnl(perpMarket: PerpMarketAccount, oraclePriceData: OraclePriceData): BN;
33
34
  export declare function calculateNetUserPnlImbalance(perpMarket: PerpMarketAccount, spotMarket: SpotMarketAccount, oraclePriceData: OraclePriceData): BN;
35
+ export declare function calculateAvailablePerpLiquidity(market: PerpMarketAccount, oraclePriceData: OraclePriceData, dlob: DLOB, slot: number): {
36
+ bids: BN;
37
+ asks: BN;
38
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateNetUserPnlImbalance = exports.calculateNetUserPnl = exports.calculateMarketAvailablePNL = exports.calculateUnrealizedAssetWeight = exports.calculateMarketMarginRatio = exports.calculateOracleSpread = exports.calculateOracleReserveSpread = exports.calculateNewMarketAfterTrade = exports.calculateAskPrice = exports.calculateBidPrice = exports.calculateReservePrice = void 0;
3
+ exports.calculateAvailablePerpLiquidity = exports.calculateNetUserPnlImbalance = exports.calculateNetUserPnl = exports.calculateMarketAvailablePNL = exports.calculateUnrealizedAssetWeight = exports.calculateMarketMarginRatio = exports.calculateOracleSpread = exports.calculateOracleReserveSpread = exports.calculateNewMarketAfterTrade = exports.calculateAskPrice = exports.calculateBidPrice = exports.calculateReservePrice = void 0;
4
4
  const anchor_1 = require("@project-serum/anchor");
5
5
  const types_1 = require("../types");
6
6
  const amm_1 = require("./amm");
@@ -115,3 +115,20 @@ function calculateNetUserPnlImbalance(perpMarket, spotMarket, oraclePriceData) {
115
115
  return imbalance;
116
116
  }
117
117
  exports.calculateNetUserPnlImbalance = calculateNetUserPnlImbalance;
118
+ function calculateAvailablePerpLiquidity(market, oraclePriceData, dlob, slot) {
119
+ let [bids, asks] = amm_1.calculateMarketOpenBidAsk(market.amm.baseAssetReserve, market.amm.minBaseAssetReserve, market.amm.maxBaseAssetReserve, market.amm.orderStepSize);
120
+ asks = asks.abs();
121
+ const bidPrice = calculateBidPrice(market, oraclePriceData);
122
+ const askPrice = calculateAskPrice(market, oraclePriceData);
123
+ for (const bid of dlob.getMakerLimitBids(market.marketIndex, slot, types_1.MarketType.PERP, oraclePriceData, askPrice)) {
124
+ bids = bids.add(bid.order.baseAssetAmount.sub(bid.order.baseAssetAmountFilled));
125
+ }
126
+ for (const ask of dlob.getMakerLimitAsks(market.marketIndex, slot, types_1.MarketType.PERP, oraclePriceData, bidPrice)) {
127
+ asks = asks.add(ask.order.baseAssetAmount.sub(ask.order.baseAssetAmountFilled));
128
+ }
129
+ return {
130
+ bids: bids,
131
+ asks: asks,
132
+ };
133
+ }
134
+ exports.calculateAvailablePerpLiquidity = calculateAvailablePerpLiquidity;
@@ -1,9 +1,9 @@
1
1
  /// <reference types="bn.js" />
2
2
  import { AMM, OracleGuardRails } from '../types';
3
3
  import { OraclePriceData } from '../oracles/types';
4
- import { BN, PerpMarketAccount } from '../index';
4
+ import { BN, HistoricalOracleData, PerpMarketAccount } from '../index';
5
5
  export declare function oraclePriceBands(market: PerpMarketAccount, oraclePriceData: OraclePriceData): [BN, BN];
6
6
  export declare function isOracleValid(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, slot: number): boolean;
7
7
  export declare function isOracleTooDivergent(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, now: BN): boolean;
8
- export declare function calculateLiveOracleTwap(amm: AMM, oraclePriceData: OraclePriceData, now: BN): BN;
8
+ export declare function calculateLiveOracleTwap(histOracleData: HistoricalOracleData, oraclePriceData: OraclePriceData, now: BN, period: BN): BN;
9
9
  export declare function calculateLiveOracleStd(amm: AMM, oraclePriceData: OraclePriceData, now: BN): BN;
@@ -38,7 +38,7 @@ function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
38
38
  exports.isOracleValid = isOracleValid;
39
39
  function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
40
40
  const sinceLastUpdate = now.sub(amm.historicalOracleData.lastOraclePriceTwapTs);
41
- const sinceStart = index_1.BN.max(numericConstants_1.ZERO, new index_1.BN(60 * 5).sub(sinceLastUpdate));
41
+ const sinceStart = index_1.BN.max(numericConstants_1.ZERO, numericConstants_1.FIVE_MINUTE.sub(sinceLastUpdate));
42
42
  const oracleTwap5min = amm.historicalOracleData.lastOraclePriceTwap5Min
43
43
  .mul(sinceStart)
44
44
  .add(oraclePriceData.price)
@@ -52,12 +52,21 @@ function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
52
52
  return tooDivergent;
53
53
  }
54
54
  exports.isOracleTooDivergent = isOracleTooDivergent;
55
- function calculateLiveOracleTwap(amm, oraclePriceData, now) {
56
- const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(amm.historicalOracleData.lastOraclePriceTwapTs));
57
- const sinceStart = index_1.BN.max(numericConstants_1.ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
58
- const clampRange = amm.historicalOracleData.lastOraclePriceTwap.div(new index_1.BN(3));
59
- const clampedOraclePrice = index_1.BN.min(amm.historicalOracleData.lastOraclePriceTwap.add(clampRange), index_1.BN.max(oraclePriceData.price, amm.historicalOracleData.lastOraclePriceTwap.sub(clampRange)));
60
- const newOracleTwap = amm.historicalOracleData.lastOraclePriceTwap
55
+ function calculateLiveOracleTwap(histOracleData, oraclePriceData, now, period) {
56
+ let oracleTwap = undefined;
57
+ if (period.eq(numericConstants_1.FIVE_MINUTE)) {
58
+ oracleTwap = histOracleData.lastOraclePriceTwap5Min;
59
+ }
60
+ else {
61
+ //todo: assumes its fundingPeriod (1hr)
62
+ // period = amm.fundingPeriod;
63
+ oracleTwap = histOracleData.lastOraclePriceTwap;
64
+ }
65
+ const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(histOracleData.lastOraclePriceTwapTs));
66
+ const sinceStart = index_1.BN.max(numericConstants_1.ZERO, period.sub(sinceLastUpdate));
67
+ const clampRange = oracleTwap.div(new index_1.BN(3));
68
+ const clampedOraclePrice = index_1.BN.min(oracleTwap.add(clampRange), index_1.BN.max(oraclePriceData.price, oracleTwap.sub(clampRange)));
69
+ const newOracleTwap = oracleTwap
61
70
  .mul(sinceStart)
62
71
  .add(clampedOraclePrice.mul(sinceLastUpdate))
63
72
  .div(sinceStart.add(sinceLastUpdate));
@@ -67,7 +76,7 @@ exports.calculateLiveOracleTwap = calculateLiveOracleTwap;
67
76
  function calculateLiveOracleStd(amm, oraclePriceData, now) {
68
77
  const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(amm.historicalOracleData.lastOraclePriceTwapTs));
69
78
  const sinceStart = index_1.BN.max(numericConstants_1.ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
70
- const liveOracleTwap = calculateLiveOracleTwap(amm, oraclePriceData, now);
79
+ const liveOracleTwap = calculateLiveOracleTwap(amm.historicalOracleData, oraclePriceData, now, amm.fundingPeriod);
71
80
  const priceDeltaVsTwap = oraclePriceData.price.sub(liveOracleTwap).abs();
72
81
  const oracleStd = priceDeltaVsTwap.add(amm.oracleStd.mul(sinceStart).div(sinceStart.add(sinceLastUpdate)));
73
82
  return oracleStd;
@@ -108,7 +108,7 @@ function hasAuctionPrice(order, slot) {
108
108
  exports.hasAuctionPrice = hasAuctionPrice;
109
109
  function isFillableByVAMM(order, market, oraclePriceData, slot, ts) {
110
110
  return ((auction_1.isAuctionComplete(order, slot) &&
111
- !calculateBaseAssetAmountForAmmToFulfill(order, market, oraclePriceData, slot).eq(numericConstants_1.ZERO)) ||
111
+ calculateBaseAssetAmountForAmmToFulfill(order, market, oraclePriceData, slot).gte(market.amm.minOrderSize)) ||
112
112
  isOrderExpired(order, ts));
113
113
  }
114
114
  exports.isFillableByVAMM = isFillableByVAMM;
@@ -5,6 +5,7 @@ import { OraclePriceData } from '../oracles/types';
5
5
  export declare function getBalance(tokenAmount: BN, spotMarket: SpotMarketAccount, balanceType: SpotBalanceType): BN;
6
6
  export declare function getTokenAmount(balanceAmount: BN, spotMarket: SpotMarketAccount, balanceType: SpotBalanceType): BN;
7
7
  export declare function getSignedTokenAmount(tokenAmount: BN, balanceType: SpotBalanceType): BN;
8
+ export declare function getStrictTokenValue(tokenAmount: BN, spotDecimals: number, oraclePriceData: OraclePriceData, oraclePriceTwap: BN): BN;
8
9
  export declare function getTokenValue(tokenAmount: BN, spotDecimals: number, oraclePriceData: OraclePriceData): BN;
9
10
  export declare function calculateAssetWeight(balanceAmount: BN, spotMarket: SpotMarketAccount, marginCategory: MarginCategory): BN;
10
11
  export declare function calculateLiabilityWeight(balanceAmount: BN, spotMarket: SpotMarketAccount, marginCategory: MarginCategory): BN;
@@ -19,4 +20,8 @@ export declare function calculateInterestAccumulated(bank: SpotMarketAccount, no
19
20
  export declare function calculateWithdrawLimit(spotMarket: SpotMarketAccount, now: BN): {
20
21
  borrowLimit: BN;
21
22
  withdrawLimit: BN;
23
+ minDepositAmount: BN;
24
+ maxBorrowAmount: BN;
25
+ currentDepositAmount: any;
26
+ currentBorrowAmount: any;
22
27
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateWithdrawLimit = exports.calculateInterestAccumulated = exports.calculateBorrowRate = exports.calculateDepositRate = exports.calculateInterestRate = exports.calculateUtilization = exports.calculateLiabilityWeight = exports.calculateAssetWeight = exports.getTokenValue = exports.getSignedTokenAmount = exports.getTokenAmount = exports.getBalance = void 0;
3
+ exports.calculateWithdrawLimit = exports.calculateInterestAccumulated = exports.calculateBorrowRate = exports.calculateDepositRate = exports.calculateInterestRate = exports.calculateUtilization = exports.calculateLiabilityWeight = exports.calculateAssetWeight = exports.getTokenValue = exports.getStrictTokenValue = exports.getSignedTokenAmount = exports.getTokenAmount = exports.getBalance = void 0;
4
4
  const types_1 = require("../types");
5
5
  const anchor_1 = require("@project-serum/anchor");
6
6
  const numericConstants_1 = require("../constants/numericConstants");
@@ -35,6 +35,21 @@ function getSignedTokenAmount(tokenAmount, balanceType) {
35
35
  }
36
36
  }
37
37
  exports.getSignedTokenAmount = getSignedTokenAmount;
38
+ function getStrictTokenValue(tokenAmount, spotDecimals, oraclePriceData, oraclePriceTwap) {
39
+ if (tokenAmount.eq(numericConstants_1.ZERO)) {
40
+ return numericConstants_1.ZERO;
41
+ }
42
+ let price = oraclePriceData.price;
43
+ if (tokenAmount.gt(numericConstants_1.ZERO)) {
44
+ price = anchor_1.BN.min(oraclePriceData.price, oraclePriceTwap);
45
+ }
46
+ else {
47
+ price = anchor_1.BN.max(oraclePriceData.price, oraclePriceTwap);
48
+ }
49
+ const precisionDecrease = numericConstants_1.TEN.pow(new anchor_1.BN(spotDecimals));
50
+ return tokenAmount.mul(price).div(precisionDecrease);
51
+ }
52
+ exports.getStrictTokenValue = getStrictTokenValue;
38
53
  function getTokenValue(tokenAmount, spotDecimals, oraclePriceData) {
39
54
  if (tokenAmount.eq(numericConstants_1.ZERO)) {
40
55
  return numericConstants_1.ZERO;
@@ -187,9 +202,21 @@ function calculateWithdrawLimit(spotMarket, now) {
187
202
  .div(sinceLast.add(sinceStart));
188
203
  const maxBorrowTokens = anchor_1.BN.min(anchor_1.BN.max(marketDepositTokenAmount.div(new anchor_1.BN(6)), borrowTokenTwapLive.add(borrowTokenTwapLive.div(new anchor_1.BN(5)))), marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new anchor_1.BN(5)))); // between ~15-80% utilization with friction on twap
189
204
  const minDepositTokens = depositTokenTwapLive.sub(anchor_1.BN.min(anchor_1.BN.max(depositTokenTwapLive.div(new anchor_1.BN(5)), spotMarket.withdrawGuardThreshold), depositTokenTwapLive));
205
+ let withdrawLimit = anchor_1.BN.max(marketDepositTokenAmount.sub(minDepositTokens), numericConstants_1.ZERO);
206
+ let borrowLimit = anchor_1.BN.max(maxBorrowTokens.sub(marketBorrowTokenAmount), numericConstants_1.ZERO);
207
+ if (borrowLimit.eq(numericConstants_1.ZERO)) {
208
+ withdrawLimit = numericConstants_1.ZERO;
209
+ }
210
+ if (withdrawLimit.eq(numericConstants_1.ZERO)) {
211
+ borrowLimit = numericConstants_1.ZERO;
212
+ }
190
213
  return {
191
- borrowLimit: maxBorrowTokens.sub(marketBorrowTokenAmount),
192
- withdrawLimit: marketDepositTokenAmount.sub(minDepositTokens),
214
+ borrowLimit,
215
+ withdrawLimit,
216
+ maxBorrowAmount: maxBorrowTokens,
217
+ minDepositAmount: minDepositTokens,
218
+ currentDepositAmount: marketDepositTokenAmount,
219
+ currentBorrowAmount: marketBorrowTokenAmount,
193
220
  };
194
221
  }
195
222
  exports.calculateWithdrawLimit = calculateWithdrawLimit;
package/lib/math/trade.js CHANGED
@@ -338,7 +338,10 @@ function calculateEstimatedPerpEntryPrice(assetType, amount, direction, market,
338
338
  break;
339
339
  }
340
340
  }
341
- if (limitOrder && usersToSkip.has(limitOrder.userAccount)) {
341
+ if (!limitOrder) {
342
+ continue;
343
+ }
344
+ if (usersToSkip.has(limitOrder.userAccount)) {
342
345
  continue;
343
346
  }
344
347
  const baseFilled = anchor_1.BN.min(limitOrder.order.baseAssetAmount.sub(limitOrder.order.baseAssetAmountFilled), amount.sub(cumulativeBaseFilled));
@@ -388,7 +391,10 @@ function calculateEstimatedPerpEntryPrice(assetType, amount, direction, market,
388
391
  break;
389
392
  }
390
393
  }
391
- if (limitOrder && usersToSkip.has(limitOrder.userAccount)) {
394
+ if (!limitOrder) {
395
+ continue;
396
+ }
397
+ if (usersToSkip.has(limitOrder.userAccount)) {
392
398
  continue;
393
399
  }
394
400
  const quoteFilled = anchor_1.BN.min(limitOrder.order.baseAssetAmount
package/lib/math/utils.js CHANGED
@@ -7,6 +7,9 @@ function clampBN(x, min, max) {
7
7
  }
8
8
  exports.clampBN = clampBN;
9
9
  const squareRootBN = (n, closeness = new __1.BN(1)) => {
10
+ if (n.lt(__1.ZERO)) {
11
+ throw new Error('square root of negative number');
12
+ }
10
13
  // Assuming the sqrt of n as n only
11
14
  let x = n;
12
15
  // The closed guess will be stored in the root
package/lib/user.d.ts CHANGED
@@ -77,10 +77,11 @@ export declare class User {
77
77
  */
78
78
  getSettledLPPosition(marketIndex: number): [PerpPosition, BN, BN];
79
79
  /**
80
- * calculates Buying Power = FC * MAX_LEVERAGE
80
+ * calculates Buying Power = free collateral / initial margin ratio
81
81
  * @returns : Precision QUOTE_PRECISION
82
82
  */
83
83
  getBuyingPower(marketIndex: number): BN;
84
+ getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN): BN;
84
85
  /**
85
86
  * calculates Free Collateral = Total collateral - initial margin requirement
86
87
  * @returns : Precision QUOTE_PRECISION
@@ -89,7 +90,7 @@ export declare class User {
89
90
  /**
90
91
  * @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
91
92
  */
92
- getMarginRequirement(marginCategory: MarginCategory, liquidationBuffer?: BN): BN;
93
+ getMarginRequirement(marginCategory: MarginCategory, liquidationBuffer?: BN, strict?: boolean): BN;
93
94
  /**
94
95
  * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
95
96
  */
@@ -109,10 +110,10 @@ export declare class User {
109
110
  * @returns : Precision QUOTE_PRECISION
110
111
  */
111
112
  getUnrealizedFundingPNL(marketIndex?: number): BN;
112
- getSpotMarketLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean): BN;
113
- getSpotLiabilityValue(tokenAmount: BN, oraclePriceData: OraclePriceData, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory, liquidationBuffer?: BN): BN;
114
- getSpotMarketAssetValue(marketIndex?: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean): BN;
115
- getSpotAssetValue(tokenAmount: BN, oraclePriceData: OraclePriceData, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory): BN;
113
+ getSpotMarketLiabilityValue(marketIndex?: number, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean, now?: BN): BN;
114
+ getSpotLiabilityValue(tokenAmount: BN, oraclePriceData: OraclePriceData, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory, liquidationBuffer?: BN, strict?: boolean, now?: BN): BN;
115
+ getSpotMarketAssetValue(marketIndex?: number, marginCategory?: MarginCategory, includeOpenOrders?: boolean, strict?: boolean, now?: BN): BN;
116
+ getSpotAssetValue(tokenAmount: BN, oraclePriceData: OraclePriceData, spotMarketAccount: SpotMarketAccount, marginCategory?: MarginCategory, strict?: boolean, now?: BN): BN;
116
117
  getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN;
117
118
  /**
118
119
  * calculates TotalCollateral: collateral + unrealized pnl
@@ -133,7 +134,7 @@ export declare class User {
133
134
  * calculates position value in margin system
134
135
  * @returns : Precision QUOTE_PRECISION
135
136
  */
136
- getPerpPositionValue(marketIndex: number, oraclePriceData: OraclePriceData): BN;
137
+ getPerpPositionValue(marketIndex: number, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
137
138
  getPositionSide(currentPosition: Pick<PerpPosition, 'baseAssetAmount'>): PositionDirection | undefined;
138
139
  /**
139
140
  * calculates average exit price (optionally for closing up to 100% of position)
@@ -141,7 +142,7 @@ export declare class User {
141
142
  */
142
143
  getPositionEstimatedExitPriceAndPnl(position: PerpPosition, amountToClose?: BN, useAMMClose?: boolean): [BN, BN];
143
144
  /**
144
- * calculates current user leverage across all positions
145
+ * calculates current user leverage which is (total liability size) / (net asset value)
145
146
  * @returns : Precision TEN_THOUSAND
146
147
  */
147
148
  getLeverage(): BN;
@@ -232,6 +233,12 @@ export declare class User {
232
233
  * @returns withdrawalLimit : Precision is the token precision for the chosen SpotMarket
233
234
  */
234
235
  getWithdrawalLimit(marketIndex: number, reduceOnly?: boolean): BN;
236
+ canBypassWithdrawLimits(marketIndex: number): {
237
+ canBypass: boolean;
238
+ netDeposits: BN;
239
+ depositAmount: BN;
240
+ maxDepositAmount: BN;
241
+ };
235
242
  /**
236
243
  * Get the total position value, excluding any position coming from the given target market
237
244
  * @param marketToIgnore