@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.
@@ -5,6 +5,7 @@ import {
5
5
  MarginCategory,
6
6
  SpotMarketAccount,
7
7
  SpotBalanceType,
8
+ MarketType,
8
9
  } from '../types';
9
10
  import {
10
11
  calculateAmmReservesAfterSwap,
@@ -12,6 +13,7 @@ import {
12
13
  calculateUpdatedAMMSpreadReserves,
13
14
  getSwapDirection,
14
15
  calculateUpdatedAMM,
16
+ calculateMarketOpenBidAsk,
15
17
  } from './amm';
16
18
  import {
17
19
  calculateSizeDiscountAssetWeight,
@@ -25,6 +27,7 @@ import {
25
27
  ZERO,
26
28
  } from '../constants/numericConstants';
27
29
  import { getTokenAmount } from './spotBalance';
30
+ import { DLOB } from '../dlob/DLOB';
28
31
 
29
32
  /**
30
33
  * Calculates market mark price
@@ -232,3 +235,51 @@ export function calculateNetUserPnlImbalance(
232
235
 
233
236
  return imbalance;
234
237
  }
238
+
239
+ export function calculateAvailablePerpLiquidity(
240
+ market: PerpMarketAccount,
241
+ oraclePriceData: OraclePriceData,
242
+ dlob: DLOB,
243
+ slot: number
244
+ ): { bids: BN; asks: BN } {
245
+ let [bids, asks] = calculateMarketOpenBidAsk(
246
+ market.amm.baseAssetReserve,
247
+ market.amm.minBaseAssetReserve,
248
+ market.amm.maxBaseAssetReserve,
249
+ market.amm.orderStepSize
250
+ );
251
+
252
+ asks = asks.abs();
253
+
254
+ const bidPrice = calculateBidPrice(market, oraclePriceData);
255
+ const askPrice = calculateAskPrice(market, oraclePriceData);
256
+
257
+ for (const bid of dlob.getMakerLimitBids(
258
+ market.marketIndex,
259
+ slot,
260
+ MarketType.PERP,
261
+ oraclePriceData,
262
+ askPrice
263
+ )) {
264
+ bids = bids.add(
265
+ bid.order.baseAssetAmount.sub(bid.order.baseAssetAmountFilled)
266
+ );
267
+ }
268
+
269
+ for (const ask of dlob.getMakerLimitAsks(
270
+ market.marketIndex,
271
+ slot,
272
+ MarketType.PERP,
273
+ oraclePriceData,
274
+ bidPrice
275
+ )) {
276
+ asks = asks.add(
277
+ ask.order.baseAssetAmount.sub(ask.order.baseAssetAmountFilled)
278
+ );
279
+ }
280
+
281
+ return {
282
+ bids: bids,
283
+ asks: asks,
284
+ };
285
+ }
@@ -6,8 +6,9 @@ import {
6
6
  PRICE_PRECISION,
7
7
  ONE,
8
8
  ZERO,
9
+ FIVE_MINUTE,
9
10
  } from '../constants/numericConstants';
10
- import { BN, PerpMarketAccount } from '../index';
11
+ import { BN, HistoricalOracleData, PerpMarketAccount } from '../index';
11
12
  import { assert } from '../assert/assert';
12
13
 
13
14
  export function oraclePriceBands(
@@ -68,7 +69,7 @@ export function isOracleTooDivergent(
68
69
  const sinceLastUpdate = now.sub(
69
70
  amm.historicalOracleData.lastOraclePriceTwapTs
70
71
  );
71
- const sinceStart = BN.max(ZERO, new BN(60 * 5).sub(sinceLastUpdate));
72
+ const sinceStart = BN.max(ZERO, FIVE_MINUTE.sub(sinceLastUpdate));
72
73
  const oracleTwap5min = amm.historicalOracleData.lastOraclePriceTwap5Min
73
74
  .mul(sinceStart)
74
75
  .add(oraclePriceData.price)
@@ -90,29 +91,34 @@ export function isOracleTooDivergent(
90
91
  }
91
92
 
92
93
  export function calculateLiveOracleTwap(
93
- amm: AMM,
94
+ histOracleData: HistoricalOracleData,
94
95
  oraclePriceData: OraclePriceData,
95
- now: BN
96
+ now: BN,
97
+ period: BN
96
98
  ): BN {
99
+ let oracleTwap = undefined;
100
+ if (period.eq(FIVE_MINUTE)) {
101
+ oracleTwap = histOracleData.lastOraclePriceTwap5Min;
102
+ } else {
103
+ //todo: assumes its fundingPeriod (1hr)
104
+ // period = amm.fundingPeriod;
105
+ oracleTwap = histOracleData.lastOraclePriceTwap;
106
+ }
107
+
97
108
  const sinceLastUpdate = BN.max(
98
109
  ONE,
99
- now.sub(amm.historicalOracleData.lastOraclePriceTwapTs)
110
+ now.sub(histOracleData.lastOraclePriceTwapTs)
100
111
  );
101
- const sinceStart = BN.max(ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
112
+ const sinceStart = BN.max(ZERO, period.sub(sinceLastUpdate));
102
113
 
103
- const clampRange = amm.historicalOracleData.lastOraclePriceTwap.div(
104
- new BN(3)
105
- );
114
+ const clampRange = oracleTwap.div(new BN(3));
106
115
 
107
116
  const clampedOraclePrice = BN.min(
108
- amm.historicalOracleData.lastOraclePriceTwap.add(clampRange),
109
- BN.max(
110
- oraclePriceData.price,
111
- amm.historicalOracleData.lastOraclePriceTwap.sub(clampRange)
112
- )
117
+ oracleTwap.add(clampRange),
118
+ BN.max(oraclePriceData.price, oracleTwap.sub(clampRange))
113
119
  );
114
120
 
115
- const newOracleTwap = amm.historicalOracleData.lastOraclePriceTwap
121
+ const newOracleTwap = oracleTwap
116
122
  .mul(sinceStart)
117
123
  .add(clampedOraclePrice.mul(sinceLastUpdate))
118
124
  .div(sinceStart.add(sinceLastUpdate));
@@ -131,7 +137,12 @@ export function calculateLiveOracleStd(
131
137
  );
132
138
  const sinceStart = BN.max(ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
133
139
 
134
- const liveOracleTwap = calculateLiveOracleTwap(amm, oraclePriceData, now);
140
+ const liveOracleTwap = calculateLiveOracleTwap(
141
+ amm.historicalOracleData,
142
+ oraclePriceData,
143
+ now,
144
+ amm.fundingPeriod
145
+ );
135
146
 
136
147
  const priceDeltaVsTwap = oraclePriceData.price.sub(liveOracleTwap).abs();
137
148
 
@@ -165,12 +165,12 @@ export function isFillableByVAMM(
165
165
  ): boolean {
166
166
  return (
167
167
  (isAuctionComplete(order, slot) &&
168
- !calculateBaseAssetAmountForAmmToFulfill(
168
+ calculateBaseAssetAmountForAmmToFulfill(
169
169
  order,
170
170
  market,
171
171
  oraclePriceData,
172
172
  slot
173
- ).eq(ZERO)) ||
173
+ ).gte(market.amm.minOrderSize)) ||
174
174
  isOrderExpired(order, ts)
175
175
  );
176
176
  }
@@ -67,6 +67,28 @@ export function getSignedTokenAmount(
67
67
  }
68
68
  }
69
69
 
70
+ export function getStrictTokenValue(
71
+ tokenAmount: BN,
72
+ spotDecimals: number,
73
+ oraclePriceData: OraclePriceData,
74
+ oraclePriceTwap: BN
75
+ ): BN {
76
+ if (tokenAmount.eq(ZERO)) {
77
+ return ZERO;
78
+ }
79
+
80
+ let price = oraclePriceData.price;
81
+ if (tokenAmount.gt(ZERO)) {
82
+ price = BN.min(oraclePriceData.price, oraclePriceTwap);
83
+ } else {
84
+ price = BN.max(oraclePriceData.price, oraclePriceTwap);
85
+ }
86
+
87
+ const precisionDecrease = TEN.pow(new BN(spotDecimals));
88
+
89
+ return tokenAmount.mul(price).div(precisionDecrease);
90
+ }
91
+
70
92
  export function getTokenValue(
71
93
  tokenAmount: BN,
72
94
  spotDecimals: number,
@@ -268,7 +290,14 @@ export function calculateInterestAccumulated(
268
290
  export function calculateWithdrawLimit(
269
291
  spotMarket: SpotMarketAccount,
270
292
  now: BN
271
- ): { borrowLimit: BN; withdrawLimit: BN } {
293
+ ): {
294
+ borrowLimit: BN;
295
+ withdrawLimit: BN;
296
+ minDepositAmount: BN;
297
+ maxBorrowAmount: BN;
298
+ currentDepositAmount;
299
+ currentBorrowAmount;
300
+ } {
272
301
  const marketDepositTokenAmount = getTokenAmount(
273
302
  spotMarket.depositBalance,
274
303
  spotMarket,
@@ -311,8 +340,27 @@ export function calculateWithdrawLimit(
311
340
  )
312
341
  );
313
342
 
343
+ let withdrawLimit = BN.max(
344
+ marketDepositTokenAmount.sub(minDepositTokens),
345
+ ZERO
346
+ );
347
+
348
+ let borrowLimit = BN.max(maxBorrowTokens.sub(marketBorrowTokenAmount), ZERO);
349
+
350
+ if (borrowLimit.eq(ZERO)) {
351
+ withdrawLimit = ZERO;
352
+ }
353
+
354
+ if (withdrawLimit.eq(ZERO)) {
355
+ borrowLimit = ZERO;
356
+ }
357
+
314
358
  return {
315
- borrowLimit: maxBorrowTokens.sub(marketBorrowTokenAmount),
316
- withdrawLimit: marketDepositTokenAmount.sub(minDepositTokens),
359
+ borrowLimit,
360
+ withdrawLimit,
361
+ maxBorrowAmount: maxBorrowTokens,
362
+ minDepositAmount: minDepositTokens,
363
+ currentDepositAmount: marketDepositTokenAmount,
364
+ currentBorrowAmount: marketBorrowTokenAmount,
317
365
  };
318
366
  }
package/src/math/trade.ts CHANGED
@@ -529,7 +529,11 @@ export function calculateEstimatedPerpEntryPrice(
529
529
  }
530
530
  }
531
531
 
532
- if (limitOrder && usersToSkip.has(limitOrder.userAccount)) {
532
+ if (!limitOrder) {
533
+ continue;
534
+ }
535
+
536
+ if (usersToSkip.has(limitOrder.userAccount)) {
533
537
  continue;
534
538
  }
535
539
 
@@ -615,7 +619,11 @@ export function calculateEstimatedPerpEntryPrice(
615
619
  }
616
620
  }
617
621
 
618
- if (limitOrder && usersToSkip.has(limitOrder.userAccount)) {
622
+ if (!limitOrder) {
623
+ continue;
624
+ }
625
+
626
+ if (usersToSkip.has(limitOrder.userAccount)) {
619
627
  continue;
620
628
  }
621
629
 
package/src/math/utils.ts CHANGED
@@ -1,10 +1,14 @@
1
- import { BN } from '../';
1
+ import { BN, ZERO } from '../';
2
2
 
3
3
  export function clampBN(x: BN, min: BN, max: BN): BN {
4
4
  return BN.max(min, BN.min(x, max));
5
5
  }
6
6
 
7
7
  export const squareRootBN = (n, closeness = new BN(1)): BN => {
8
+ if (n.lt(ZERO)) {
9
+ throw new Error('square root of negative number');
10
+ }
11
+
8
12
  // Assuming the sqrt of n as n only
9
13
  let x = n;
10
14