@drift-labs/sdk 0.2.0-master.31 → 0.2.0-master.33

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.
Files changed (99) hide show
  1. package/lib/accounts/bulkAccountLoader.js +2 -1
  2. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +2 -2
  3. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +8 -8
  4. package/lib/accounts/types.d.ts +1 -0
  5. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +2 -2
  6. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +7 -7
  7. package/lib/addresses/marketAddresses.js +1 -1
  8. package/lib/addresses/pda.d.ts +4 -4
  9. package/lib/addresses/pda.js +23 -22
  10. package/lib/admin.d.ts +30 -32
  11. package/lib/admin.js +111 -119
  12. package/lib/clearingHouse.d.ts +43 -34
  13. package/lib/clearingHouse.js +353 -193
  14. package/lib/clearingHouseConfig.d.ts +2 -2
  15. package/lib/clearingHouseUser.d.ts +26 -5
  16. package/lib/clearingHouseUser.js +151 -51
  17. package/lib/config.d.ts +2 -0
  18. package/lib/config.js +5 -1
  19. package/lib/constants/numericConstants.d.ts +1 -0
  20. package/lib/constants/numericConstants.js +3 -2
  21. package/lib/dlob/DLOB.d.ts +19 -11
  22. package/lib/dlob/DLOB.js +208 -107
  23. package/lib/dlob/DLOBNode.js +2 -10
  24. package/lib/dlob/NodeList.d.ts +1 -0
  25. package/lib/dlob/NodeList.js +6 -1
  26. package/lib/events/eventSubscriber.d.ts +1 -0
  27. package/lib/events/eventSubscriber.js +11 -4
  28. package/lib/events/fetchLogs.d.ts +3 -1
  29. package/lib/events/fetchLogs.js +13 -5
  30. package/lib/events/pollingLogProvider.js +1 -1
  31. package/lib/events/types.d.ts +1 -1
  32. package/lib/events/webSocketLogProvider.js +1 -1
  33. package/lib/factory/bigNum.d.ts +5 -4
  34. package/lib/factory/bigNum.js +36 -6
  35. package/lib/idl/clearing_house.json +1527 -1242
  36. package/lib/index.d.ts +3 -0
  37. package/lib/index.js +3 -0
  38. package/lib/math/amm.js +9 -9
  39. package/lib/math/exchangeStatus.d.ts +4 -0
  40. package/lib/math/exchangeStatus.js +18 -0
  41. package/lib/math/funding.js +10 -10
  42. package/lib/math/margin.js +6 -1
  43. package/lib/math/market.js +9 -9
  44. package/lib/math/orders.d.ts +7 -3
  45. package/lib/math/orders.js +39 -31
  46. package/lib/math/repeg.js +3 -3
  47. package/lib/math/spotBalance.js +3 -3
  48. package/lib/math/spotPosition.js +2 -2
  49. package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
  50. package/lib/serum/serumFulfillmentConfigMap.js +17 -0
  51. package/lib/serum/serumSubscriber.d.ts +4 -0
  52. package/lib/serum/serumSubscriber.js +16 -1
  53. package/lib/types.d.ts +70 -85
  54. package/lib/types.js +12 -11
  55. package/lib/userMap/userMap.d.ts +17 -1
  56. package/lib/userMap/userMap.js +12 -0
  57. package/lib/userName.d.ts +1 -0
  58. package/lib/userName.js +3 -2
  59. package/package.json +1 -1
  60. package/src/accounts/bulkAccountLoader.ts +5 -1
  61. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +9 -9
  62. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +8 -8
  63. package/src/addresses/marketAddresses.ts +2 -2
  64. package/src/addresses/pda.ts +20 -20
  65. package/src/admin.ts +246 -221
  66. package/src/clearingHouse.ts +556 -236
  67. package/src/clearingHouseConfig.ts +2 -2
  68. package/src/clearingHouseUser.ts +237 -87
  69. package/src/config.ts +8 -1
  70. package/src/constants/numericConstants.ts +5 -1
  71. package/src/dlob/DLOB.ts +290 -120
  72. package/src/dlob/DLOBNode.ts +2 -14
  73. package/src/dlob/NodeList.ts +7 -1
  74. package/src/events/eventSubscriber.ts +18 -4
  75. package/src/events/fetchLogs.ts +20 -5
  76. package/src/events/pollingLogProvider.ts +1 -1
  77. package/src/events/types.ts +2 -1
  78. package/src/events/webSocketLogProvider.ts +1 -1
  79. package/src/factory/bigNum.ts +59 -6
  80. package/src/idl/clearing_house.json +1527 -1242
  81. package/src/idl/pyth.json +98 -2
  82. package/src/index.ts +3 -0
  83. package/src/math/amm.ts +9 -9
  84. package/src/math/exchangeStatus.ts +31 -0
  85. package/src/math/funding.ts +20 -10
  86. package/src/math/margin.ts +7 -1
  87. package/src/math/market.ts +9 -9
  88. package/src/math/orders.ts +44 -29
  89. package/src/math/repeg.ts +3 -3
  90. package/src/math/spotBalance.ts +4 -4
  91. package/src/math/spotPosition.ts +2 -2
  92. package/src/serum/serumFulfillmentConfigMap.ts +26 -0
  93. package/src/serum/serumSubscriber.ts +20 -1
  94. package/src/types.ts +75 -61
  95. package/src/userMap/userMap.ts +25 -1
  96. package/src/userName.ts +2 -1
  97. package/tests/bn/test.ts +22 -1
  98. package/tests/dlob/helpers.ts +252 -81
  99. package/tests/dlob/test.ts +1115 -215
package/src/idl/pyth.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.0",
2
+ "version": "0.1.0",
3
3
  "name": "pyth",
4
4
  "instructions": [
5
5
  {
@@ -41,6 +41,102 @@
41
41
  "type": "i64"
42
42
  }
43
43
  ]
44
+ },
45
+ {
46
+ "name": "setPriceInfo",
47
+ "accounts": [
48
+ {
49
+ "name": "price",
50
+ "isMut": true,
51
+ "isSigner": false
52
+ }
53
+ ],
54
+ "args": [
55
+ {
56
+ "name": "price",
57
+ "type": "i64"
58
+ },
59
+ {
60
+ "name": "conf",
61
+ "type": "u64"
62
+ },
63
+ {
64
+ "name": "slot",
65
+ "type": "u64"
66
+ }
67
+ ]
68
+ },
69
+ {
70
+ "name": "setTwap",
71
+ "accounts": [
72
+ {
73
+ "name": "price",
74
+ "isMut": true,
75
+ "isSigner": false
76
+ }
77
+ ],
78
+ "args": [
79
+ {
80
+ "name": "twap",
81
+ "type": "i64"
82
+ }
83
+ ]
84
+ }
85
+ ],
86
+ "types": [
87
+ {
88
+ "name": "PriceStatus",
89
+ "type": {
90
+ "kind": "enum",
91
+ "variants": [
92
+ {
93
+ "name": "Unknown"
94
+ },
95
+ {
96
+ "name": "Trading"
97
+ },
98
+ {
99
+ "name": "Halted"
100
+ },
101
+ {
102
+ "name": "Auction"
103
+ }
104
+ ]
105
+ }
106
+ },
107
+ {
108
+ "name": "CorpAction",
109
+ "type": {
110
+ "kind": "enum",
111
+ "variants": [
112
+ {
113
+ "name": "NoCorpAct"
114
+ }
115
+ ]
116
+ }
117
+ },
118
+ {
119
+ "name": "PriceType",
120
+ "type": {
121
+ "kind": "enum",
122
+ "variants": [
123
+ {
124
+ "name": "Unknown"
125
+ },
126
+ {
127
+ "name": "Price"
128
+ },
129
+ {
130
+ "name": "TWAP"
131
+ },
132
+ {
133
+ "name": "Volatility"
134
+ }
135
+ ]
136
+ }
44
137
  }
45
- ]
138
+ ],
139
+ "metadata": {
140
+ "address": "gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s"
141
+ }
46
142
  }
package/src/index.ts CHANGED
@@ -34,6 +34,7 @@ export * from './events/fetchLogs';
34
34
  export * from './math/auction';
35
35
  export * from './math/spotMarket';
36
36
  export * from './math/conversion';
37
+ export * from './math/exchangeStatus';
37
38
  export * from './math/funding';
38
39
  export * from './math/market';
39
40
  export * from './math/position';
@@ -52,9 +53,11 @@ export * from './math/utils';
52
53
  export * from './config';
53
54
  export * from './constants/numericConstants';
54
55
  export * from './serum/serumSubscriber';
56
+ export * from './serum/serumFulfillmentConfigMap';
55
57
  export * from './tx/retryTxSender';
56
58
  export * from './util/computeUnits';
57
59
  export * from './util/tps';
60
+ export * from './util/promiseTimeout';
58
61
  export * from './math/spotBalance';
59
62
  export * from './constants/spotMarkets';
60
63
  export * from './clearingHouseConfig';
package/src/math/amm.ts CHANGED
@@ -117,7 +117,7 @@ export function calculateNewAmm(
117
117
  newAmm.sqrtK = newAmm.sqrtK.mul(pKNumer).div(pKDenom);
118
118
  const invariant = newAmm.sqrtK.mul(newAmm.sqrtK);
119
119
  newAmm.quoteAssetReserve = invariant.div(newAmm.baseAssetReserve);
120
- const directionToClose = amm.netBaseAssetAmount.gt(ZERO)
120
+ const directionToClose = amm.baseAssetAmountWithAmm.gt(ZERO)
121
121
  ? PositionDirection.SHORT
122
122
  : PositionDirection.LONG;
123
123
 
@@ -125,7 +125,7 @@ export function calculateNewAmm(
125
125
  calculateAmmReservesAfterSwap(
126
126
  newAmm,
127
127
  'base',
128
- amm.netBaseAssetAmount.abs(),
128
+ amm.baseAssetAmountWithAmm.abs(),
129
129
  getSwapDirection('base', directionToClose)
130
130
  );
131
131
 
@@ -157,7 +157,7 @@ export function calculateUpdatedAMM(
157
157
  newAmm.quoteAssetReserve = invariant.div(newAmm.baseAssetReserve);
158
158
  newAmm.pegMultiplier = newPeg;
159
159
 
160
- const directionToClose = amm.netBaseAssetAmount.gt(ZERO)
160
+ const directionToClose = amm.baseAssetAmountWithAmm.gt(ZERO)
161
161
  ? PositionDirection.SHORT
162
162
  : PositionDirection.LONG;
163
163
 
@@ -165,7 +165,7 @@ export function calculateUpdatedAMM(
165
165
  calculateAmmReservesAfterSwap(
166
166
  newAmm,
167
167
  'base',
168
- amm.netBaseAssetAmount.abs(),
168
+ amm.baseAssetAmountWithAmm.abs(),
169
169
  getSwapDirection('base', directionToClose)
170
170
  );
171
171
 
@@ -522,7 +522,7 @@ export function calculateSpread(
522
522
  amm.quoteAssetReserve,
523
523
  amm.terminalQuoteAssetReserve,
524
524
  amm.pegMultiplier,
525
- amm.netBaseAssetAmount,
525
+ amm.baseAssetAmountWithAmm,
526
526
  reservePrice,
527
527
  amm.totalFeeMinusDistributions,
528
528
  amm.baseAssetReserve,
@@ -629,7 +629,7 @@ export function getSwapDirection(
629
629
  * @returns cost : Precision PRICE_PRECISION
630
630
  */
631
631
  export function calculateTerminalPrice(market: PerpMarketAccount) {
632
- const directionToClose = market.amm.netBaseAssetAmount.gt(ZERO)
632
+ const directionToClose = market.amm.baseAssetAmountWithAmm.gt(ZERO)
633
633
  ? PositionDirection.SHORT
634
634
  : PositionDirection.LONG;
635
635
 
@@ -637,7 +637,7 @@ export function calculateTerminalPrice(market: PerpMarketAccount) {
637
637
  calculateAmmReservesAfterSwap(
638
638
  market.amm,
639
639
  'base',
640
- market.amm.netBaseAssetAmount.abs(),
640
+ market.amm.baseAssetAmountWithAmm.abs(),
641
641
  getSwapDirection('base', directionToClose)
642
642
  );
643
643
 
@@ -713,7 +713,7 @@ export function calculateMaxBaseAssetAmountFillable(
713
713
  orderDirection: PositionDirection
714
714
  ): BN {
715
715
  const maxFillSize = amm.baseAssetReserve.div(
716
- new BN(amm.maxBaseAssetAmountRatio)
716
+ new BN(amm.maxFillReserveFraction)
717
717
  );
718
718
  let maxBaseAssetAmountOnSide: BN;
719
719
  if (isVariant(orderDirection, 'long')) {
@@ -730,6 +730,6 @@ export function calculateMaxBaseAssetAmountFillable(
730
730
 
731
731
  return standardizeBaseAssetAmount(
732
732
  BN.min(maxFillSize, maxBaseAssetAmountOnSide),
733
- amm.baseAssetAmountStepSize
733
+ amm.orderStepSize
734
734
  );
735
735
  }
@@ -0,0 +1,31 @@
1
+ import {
2
+ isOneOfVariant,
3
+ isVariant,
4
+ PerpMarketAccount,
5
+ SpotMarketAccount,
6
+ StateAccount,
7
+ } from '../types';
8
+
9
+ export function exchangePaused(state: StateAccount): boolean {
10
+ return isVariant(state.exchangeStatus, 'paused');
11
+ }
12
+
13
+ export function fillPaused(
14
+ state: StateAccount,
15
+ market: PerpMarketAccount | SpotMarketAccount
16
+ ): boolean {
17
+ return (
18
+ isOneOfVariant(state.exchangeStatus, ['paused', 'fillPaused']) ||
19
+ isOneOfVariant(market.status, ['paused', 'fillPaused'])
20
+ );
21
+ }
22
+
23
+ export function ammPaused(
24
+ state: StateAccount,
25
+ market: PerpMarketAccount | SpotMarketAccount
26
+ ): boolean {
27
+ return (
28
+ isOneOfVariant(state.exchangeStatus, ['paused', 'ammPaused']) ||
29
+ isOneOfVariant(market.status, ['paused', 'ammPaused'])
30
+ );
31
+ }
@@ -137,9 +137,11 @@ export async function calculateAllEstimatedFundingRate(
137
137
  let cappedAltEst: BN;
138
138
  let largerSide: BN;
139
139
  let smallerSide: BN;
140
- if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())) {
141
- largerSide = market.baseAssetAmountLong.abs();
142
- smallerSide = market.baseAssetAmountShort.abs();
140
+ if (
141
+ market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort.abs())
142
+ ) {
143
+ largerSide = market.amm.baseAssetAmountLong.abs();
144
+ smallerSide = market.amm.baseAssetAmountShort.abs();
143
145
  if (twapSpread.gt(new BN(0))) {
144
146
  return [
145
147
  markTwapWithMantissa,
@@ -149,9 +151,11 @@ export async function calculateAllEstimatedFundingRate(
149
151
  interpEst,
150
152
  ];
151
153
  }
152
- } else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())) {
153
- largerSide = market.baseAssetAmountShort.abs();
154
- smallerSide = market.baseAssetAmountLong.abs();
154
+ } else if (
155
+ market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort.abs())
156
+ ) {
157
+ largerSide = market.amm.baseAssetAmountShort.abs();
158
+ smallerSide = market.amm.baseAssetAmountLong.abs();
155
159
  if (twapSpread.lt(new BN(0))) {
156
160
  return [
157
161
  markTwapWithMantissa,
@@ -251,9 +255,11 @@ export async function calculateLongShortFundingRate(
251
255
  periodAdjustment
252
256
  );
253
257
 
254
- if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
258
+ if (market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort)) {
255
259
  return [cappedAltEst, interpEst];
256
- } else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort)) {
260
+ } else if (
261
+ market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort)
262
+ ) {
257
263
  return [interpEst, cappedAltEst];
258
264
  } else {
259
265
  return [interpEst, interpEst];
@@ -279,9 +285,13 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
279
285
  periodAdjustment
280
286
  );
281
287
 
282
- if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort.abs())) {
288
+ if (
289
+ market.amm.baseAssetAmountLong.gt(market.amm.baseAssetAmountShort.abs())
290
+ ) {
283
291
  return [markTwapLive, oracleTwapLive, cappedAltEst, interpEst];
284
- } else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort.abs())) {
292
+ } else if (
293
+ market.amm.baseAssetAmountLong.lt(market.amm.baseAssetAmountShort.abs())
294
+ ) {
285
295
  return [markTwapLive, oracleTwapLive, interpEst, cappedAltEst];
286
296
  } else {
287
297
  return [markTwapLive, oracleTwapLive, interpEst, interpEst];
@@ -9,6 +9,7 @@ import {
9
9
  import { BN } from '@project-serum/anchor';
10
10
  import { OraclePriceData } from '../oracles/types';
11
11
  import { PerpMarketAccount, PerpPosition } from '..';
12
+ import { isVariant } from '../types';
12
13
  import { assert } from '../assert/assert';
13
14
 
14
15
  export function calculateSizePremiumLiabilityWeight(
@@ -107,9 +108,14 @@ export function calculateBaseAssetValueWithOracle(
107
108
  perpPosition: PerpPosition,
108
109
  oraclePriceData: OraclePriceData
109
110
  ): BN {
111
+ let price = oraclePriceData.price;
112
+ if (isVariant(market.status, 'settlement')) {
113
+ price = market.expiryPrice;
114
+ }
115
+
110
116
  return perpPosition.baseAssetAmount
111
117
  .abs()
112
- .mul(oraclePriceData.price)
118
+ .mul(price)
113
119
  .div(AMM_RESERVE_PRECISION);
114
120
  }
115
121
 
@@ -159,29 +159,29 @@ export function calculateUnrealizedAssetWeight(
159
159
  let assetWeight: BN;
160
160
  switch (marginCategory) {
161
161
  case 'Initial':
162
- assetWeight = new BN(market.unrealizedInitialAssetWeight);
162
+ assetWeight = new BN(market.unrealizedPnlInitialAssetWeight);
163
163
 
164
- if (market.unrealizedMaxImbalance.gt(ZERO)) {
164
+ if (market.unrealizedPnlMaxImbalance.gt(ZERO)) {
165
165
  const netUnsettledPnl = calculateNetUserPnlImbalance(
166
166
  market,
167
167
  quoteSpotMarket,
168
168
  oraclePriceData
169
169
  );
170
- if (netUnsettledPnl.gt(market.unrealizedMaxImbalance)) {
170
+ if (netUnsettledPnl.gt(market.unrealizedPnlMaxImbalance)) {
171
171
  assetWeight = assetWeight
172
- .mul(market.unrealizedMaxImbalance)
172
+ .mul(market.unrealizedPnlMaxImbalance)
173
173
  .div(netUnsettledPnl);
174
174
  }
175
175
  }
176
176
 
177
177
  assetWeight = calculateSizeDiscountAssetWeight(
178
178
  unrealizedPnl,
179
- market.unrealizedImfFactor,
179
+ market.unrealizedPnlImfFactor,
180
180
  assetWeight
181
181
  );
182
182
  break;
183
183
  case 'Maintenance':
184
- assetWeight = new BN(market.unrealizedMaintenanceAssetWeight);
184
+ assetWeight = new BN(market.unrealizedPnlMaintenanceAssetWeight);
185
185
  break;
186
186
  }
187
187
 
@@ -193,7 +193,7 @@ export function calculateMarketAvailablePNL(
193
193
  spotMarket: SpotMarketAccount
194
194
  ): BN {
195
195
  return getTokenAmount(
196
- perpMarket.pnlPool.balance,
196
+ perpMarket.pnlPool.scaledBalance,
197
197
  spotMarket,
198
198
  SpotBalanceType.DEPOSIT
199
199
  );
@@ -203,7 +203,7 @@ export function calculateNetUserPnl(
203
203
  perpMarket: PerpMarketAccount,
204
204
  oraclePriceData: OraclePriceData
205
205
  ): BN {
206
- const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
206
+ const netUserPositionValue = perpMarket.amm.baseAssetAmountWithAmm
207
207
  .mul(oraclePriceData.price)
208
208
  .div(BASE_PRECISION)
209
209
  .div(PRICE_TO_QUOTE_PRECISION);
@@ -225,7 +225,7 @@ export function calculateNetUserPnlImbalance(
225
225
  const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
226
226
 
227
227
  const pnlPool = getTokenAmount(
228
- perpMarket.pnlPool.balance,
228
+ perpMarket.pnlPool.scaledBalance,
229
229
  spotMarket,
230
230
  SpotBalanceType.DEPOSIT
231
231
  );
@@ -10,7 +10,6 @@ import { ZERO, TWO } from '../constants/numericConstants';
10
10
  import { BN } from '@project-serum/anchor';
11
11
  import { OraclePriceData } from '../oracles/types';
12
12
  import { getAuctionPrice, isAuctionComplete } from './auction';
13
- import { calculateAskPrice, calculateBidPrice } from './market';
14
13
  import {
15
14
  calculateMaxBaseAssetAmountFillable,
16
15
  calculateMaxBaseAssetAmountToTrade,
@@ -132,36 +131,23 @@ export function standardizeBaseAssetAmount(
132
131
  export function getLimitPrice(
133
132
  order: Order,
134
133
  oraclePriceData: OraclePriceData,
135
- slot: number,
136
- perpMarket?: PerpMarketAccount
134
+ slot: number
137
135
  ): BN {
138
136
  let limitPrice;
139
- if (!order.oraclePriceOffset.eq(ZERO)) {
140
- limitPrice = oraclePriceData.price.add(order.oraclePriceOffset);
137
+ if (order.oraclePriceOffset !== 0) {
138
+ limitPrice = oraclePriceData.price.add(new BN(order.oraclePriceOffset));
141
139
  } else if (isOneOfVariant(order.orderType, ['market', 'triggerMarket'])) {
142
140
  if (!isAuctionComplete(order, slot)) {
143
141
  limitPrice = getAuctionPrice(order, slot);
144
142
  } else if (!order.price.eq(ZERO)) {
145
143
  limitPrice = order.price;
146
144
  } else {
147
- if (perpMarket) {
148
- if (isVariant(order.direction, 'long')) {
149
- const askPrice = calculateAskPrice(perpMarket, oraclePriceData);
150
- const delta = askPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
151
- limitPrice = askPrice.add(delta);
152
- } else {
153
- const bidPrice = calculateBidPrice(perpMarket, oraclePriceData);
154
- const delta = bidPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
155
- limitPrice = bidPrice.sub(delta);
156
- }
145
+ // check oracle validity?
146
+ const oraclePrice1Pct = oraclePriceData.price.div(new BN(100));
147
+ if (isVariant(order.direction, 'long')) {
148
+ limitPrice = oraclePriceData.price.add(oraclePrice1Pct);
157
149
  } else {
158
- // check oracle validity?
159
- const oraclePrice1Pct = oraclePriceData.price.div(new BN(100));
160
- if (isVariant(order.direction, 'long')) {
161
- limitPrice = oraclePriceData.price.add(oraclePrice1Pct);
162
- } else {
163
- limitPrice = oraclePriceData.price.sub(oraclePrice1Pct);
164
- }
150
+ limitPrice = oraclePriceData.price.sub(oraclePrice1Pct);
165
151
  }
166
152
  }
167
153
  } else {
@@ -171,11 +157,32 @@ export function getLimitPrice(
171
157
  return limitPrice;
172
158
  }
173
159
 
160
+ export function getOptionalLimitPrice(
161
+ order: Order,
162
+ oraclePriceData: OraclePriceData,
163
+ slot: number
164
+ ): BN | undefined {
165
+ if (hasLimitPrice(order, slot)) {
166
+ return getLimitPrice(order, oraclePriceData, slot);
167
+ } else {
168
+ return undefined;
169
+ }
170
+ }
171
+
172
+ export function hasLimitPrice(order: Order, slot: number): boolean {
173
+ return (
174
+ order.price.gt(ZERO) ||
175
+ order.oraclePriceOffset != 0 ||
176
+ !isAuctionComplete(order, slot)
177
+ );
178
+ }
179
+
174
180
  export function isFillableByVAMM(
175
181
  order: Order,
176
182
  market: PerpMarketAccount,
177
183
  oraclePriceData: OraclePriceData,
178
- slot: number
184
+ slot: number,
185
+ ts: number
179
186
  ): boolean {
180
187
  return (
181
188
  (isAuctionComplete(order, slot) &&
@@ -185,7 +192,7 @@ export function isFillableByVAMM(
185
192
  oraclePriceData,
186
193
  slot
187
194
  ).eq(ZERO)) ||
188
- isOrderExpired(order, slot)
195
+ isOrderExpired(order, ts)
189
196
  );
190
197
  }
191
198
 
@@ -202,7 +209,7 @@ export function calculateBaseAssetAmountForAmmToFulfill(
202
209
  return ZERO;
203
210
  }
204
211
 
205
- const limitPrice = getLimitPrice(order, oraclePriceData, slot, market);
212
+ const limitPrice = getLimitPrice(order, oraclePriceData, slot);
206
213
  const baseAssetAmount = calculateBaseAssetAmountToFillUpToLimitPrice(
207
214
  order,
208
215
  market,
@@ -233,7 +240,7 @@ export function calculateBaseAssetAmountToFillUpToLimitPrice(
233
240
 
234
241
  const baseAssetAmount = standardizeBaseAssetAmount(
235
242
  maxAmountToTrade,
236
- market.amm.baseAssetAmountStepSize
243
+ market.amm.orderStepSize
237
244
  );
238
245
 
239
246
  // Check that directions are the same
@@ -257,14 +264,22 @@ function isSameDirection(
257
264
  );
258
265
  }
259
266
 
260
- export function isOrderExpired(order: Order, slot: number): boolean {
267
+ export function isOrderExpired(order: Order, ts: number): boolean {
261
268
  if (
262
269
  isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) ||
263
270
  !isVariant(order.status, 'open') ||
264
- order.timeInForce === 0
271
+ order.maxTs.eq(ZERO)
265
272
  ) {
266
273
  return false;
267
274
  }
268
275
 
269
- return new BN(slot).sub(order.slot).gt(new BN(order.timeInForce));
276
+ return new BN(ts).gt(order.maxTs);
277
+ }
278
+
279
+ export function isMarketOrder(order: Order): boolean {
280
+ return isOneOfVariant(order.orderType, ['market', 'triggerMarket']);
281
+ }
282
+
283
+ export function isLimitOrder(order: Order): boolean {
284
+ return isOneOfVariant(order.orderType, ['limit', 'triggerLimit']);
270
285
  }
package/src/math/repeg.ts CHANGED
@@ -26,7 +26,7 @@ export function calculateAdjustKCost(
26
26
  const x = amm.baseAssetReserve;
27
27
  const y = amm.quoteAssetReserve;
28
28
 
29
- const d = amm.netBaseAssetAmount;
29
+ const d = amm.baseAssetAmountWithAmm;
30
30
  const Q = amm.pegMultiplier;
31
31
 
32
32
  const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
@@ -135,7 +135,7 @@ export function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN] {
135
135
  const x = amm.baseAssetReserve;
136
136
  const y = amm.quoteAssetReserve;
137
137
 
138
- const d = amm.netBaseAssetAmount;
138
+ const d = amm.baseAssetAmountWithAmm;
139
139
  const Q = amm.pegMultiplier;
140
140
 
141
141
  const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
@@ -159,7 +159,7 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
159
159
  const x = amm.baseAssetReserve;
160
160
  const y = amm.quoteAssetReserve;
161
161
 
162
- const d = amm.netBaseAssetAmount;
162
+ const d = amm.baseAssetAmountWithAmm;
163
163
  const Q = amm.pegMultiplier;
164
164
 
165
165
  const C = cost.mul(new BN(-1));
@@ -287,20 +287,20 @@ export function calculateWithdrawLimit(
287
287
  const borrowTokenTwapLive = spotMarket.borrowTokenTwap
288
288
  .mul(sinceStart)
289
289
  .add(marketBorrowTokenAmount.mul(sinceLast))
290
- .div(sinceLast.add(sinceLast));
290
+ .div(sinceLast.add(sinceStart));
291
291
 
292
292
  const depositTokenTwapLive = spotMarket.depositTokenTwap
293
293
  .mul(sinceStart)
294
294
  .add(marketDepositTokenAmount.mul(sinceLast))
295
- .div(sinceLast.add(sinceLast));
295
+ .div(sinceLast.add(sinceStart));
296
296
 
297
297
  const maxBorrowTokens = BN.min(
298
298
  BN.max(
299
299
  marketDepositTokenAmount.div(new BN(6)),
300
300
  borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
301
301
  ),
302
- marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(10)))
303
- ); // between ~15-90% utilization with friction on twap
302
+ marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(5)))
303
+ ); // between ~15-80% utilization with friction on twap
304
304
 
305
305
  const minDepositTokens = depositTokenTwapLive.sub(
306
306
  BN.min(
@@ -9,7 +9,7 @@ import {
9
9
  import { OraclePriceData } from '../oracles/types';
10
10
 
11
11
  export function isSpotPositionAvailable(position: SpotPosition): boolean {
12
- return position.balance.eq(ZERO) && position.openOrders === 0;
12
+ return position.scaledBalance.eq(ZERO) && position.openOrders === 0;
13
13
  }
14
14
 
15
15
  export function getWorstCaseTokenAmounts(
@@ -19,7 +19,7 @@ export function getWorstCaseTokenAmounts(
19
19
  ): [BN, BN] {
20
20
  const tokenAmount = getSignedTokenAmount(
21
21
  getTokenAmount(
22
- spotPosition.balance,
22
+ spotPosition.scaledBalance,
23
23
  spotMarketAccount,
24
24
  spotPosition.balanceType
25
25
  ),
@@ -0,0 +1,26 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { SerumV3FulfillmentConfigAccount } from '../types';
3
+ import { ClearingHouse } from '../clearingHouse';
4
+
5
+ export class SerumFulfillmentConfigMap {
6
+ clearingHouse: ClearingHouse;
7
+ map = new Map<number, SerumV3FulfillmentConfigAccount>();
8
+
9
+ public constructor(clearingHouse: ClearingHouse) {
10
+ this.clearingHouse = clearingHouse;
11
+ }
12
+
13
+ public async add(
14
+ marketIndex: number,
15
+ serumMarketAddress: PublicKey
16
+ ): Promise<void> {
17
+ const account = await this.clearingHouse.getSerumV3FulfillmentConfig(
18
+ serumMarketAddress
19
+ );
20
+ this.map.set(marketIndex, account);
21
+ }
22
+
23
+ public get(marketIndex: number): SerumV3FulfillmentConfigAccount {
24
+ return this.map.get(marketIndex);
25
+ }
26
+ }
@@ -2,6 +2,8 @@ import { Connection, PublicKey } from '@solana/web3.js';
2
2
  import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
3
  import { Market, Orderbook } from '@project-serum/serum';
4
4
  import { SerumMarketSubscriberConfig } from './types';
5
+ import { BN } from '@project-serum/anchor';
6
+ import { PRICE_PRECISION } from '../constants/numericConstants';
5
7
 
6
8
  export class SerumSubscriber {
7
9
  connection: Connection;
@@ -49,7 +51,6 @@ export class SerumSubscriber {
49
51
  (buffer, slot) => {
50
52
  this.lastAsksSlot = slot;
51
53
  this.asks = Orderbook.decode(this.market, buffer);
52
- console.log(this.asks.getL2(3));
53
54
  }
54
55
  );
55
56
 
@@ -67,6 +68,24 @@ export class SerumSubscriber {
67
68
  this.subscribed = true;
68
69
  }
69
70
 
71
+ public getBestBid(): BN | undefined {
72
+ const bestBid = this.bids.getL2(1)[0];
73
+ if (!bestBid) {
74
+ return undefined;
75
+ }
76
+
77
+ return new BN(bestBid[0] * PRICE_PRECISION.toNumber());
78
+ }
79
+
80
+ public getBestAsk(): BN | undefined {
81
+ const bestAsk = this.asks.getL2(1)[0];
82
+ if (!bestAsk) {
83
+ return undefined;
84
+ }
85
+
86
+ return new BN(bestAsk[0] * PRICE_PRECISION.toNumber());
87
+ }
88
+
70
89
  public async unsubscribe(): Promise<void> {
71
90
  if (!this.subscribed) {
72
91
  return;