@drift-labs/sdk 0.2.0-master.26 → 0.2.0-master.28

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 (143) hide show
  1. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +1 -0
  2. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +3 -0
  3. package/lib/accounts/types.d.ts +2 -0
  4. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +1 -0
  5. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +3 -0
  6. package/lib/admin.d.ts +5 -2
  7. package/lib/admin.js +30 -4
  8. package/lib/clearingHouse.d.ts +3 -0
  9. package/lib/clearingHouse.js +19 -1
  10. package/lib/clearingHouseUser.d.ts +11 -9
  11. package/lib/clearingHouseUser.js +184 -108
  12. package/lib/config.js +1 -1
  13. package/lib/dlob/DLOB.d.ts +73 -0
  14. package/lib/dlob/DLOB.js +557 -0
  15. package/lib/dlob/DLOBNode.d.ts +52 -0
  16. package/lib/dlob/DLOBNode.js +82 -0
  17. package/lib/dlob/NodeList.d.ts +26 -0
  18. package/lib/dlob/NodeList.js +138 -0
  19. package/lib/idl/clearing_house.json +123 -203
  20. package/lib/index.d.ts +5 -0
  21. package/lib/index.js +5 -0
  22. package/lib/math/market.d.ts +3 -2
  23. package/lib/math/market.js +17 -12
  24. package/lib/math/orders.d.ts +3 -3
  25. package/lib/math/orders.js +31 -16
  26. package/lib/math/position.d.ts +3 -3
  27. package/lib/math/position.js +23 -16
  28. package/lib/math/repeg.js +8 -0
  29. package/lib/math/spotBalance.d.ts +3 -0
  30. package/lib/math/spotBalance.js +18 -1
  31. package/lib/math/spotPosition.d.ts +5 -1
  32. package/lib/math/spotPosition.js +16 -1
  33. package/lib/types.d.ts +25 -24
  34. package/lib/types.js +9 -3
  35. package/lib/userMap/userMap.d.ts +25 -0
  36. package/lib/userMap/userMap.js +73 -0
  37. package/lib/userMap/userStatsMap.d.ts +19 -0
  38. package/lib/userMap/userStatsMap.js +68 -0
  39. package/package.json +6 -3
  40. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +4 -0
  41. package/src/accounts/types.ts +1 -0
  42. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +6 -0
  43. package/src/admin.ts +50 -8
  44. package/src/clearingHouse.ts +30 -1
  45. package/src/clearingHouseUser.ts +366 -167
  46. package/src/config.ts +1 -1
  47. package/src/dlob/DLOB.ts +884 -0
  48. package/src/dlob/DLOBNode.ts +163 -0
  49. package/src/dlob/NodeList.ts +185 -0
  50. package/src/idl/clearing_house.json +123 -203
  51. package/src/index.ts +5 -0
  52. package/src/math/market.ts +22 -13
  53. package/src/math/orders.ts +29 -21
  54. package/src/math/position.ts +36 -22
  55. package/src/math/repeg.ts +9 -0
  56. package/src/math/spotBalance.ts +26 -0
  57. package/src/math/spotPosition.ts +42 -1
  58. package/src/types.ts +26 -24
  59. package/src/userMap/userMap.ts +100 -0
  60. package/src/userMap/userStatsMap.ts +110 -0
  61. package/tests/bn/test.ts +2 -3
  62. package/tests/dlob/helpers.ts +322 -0
  63. package/tests/dlob/test.ts +2865 -0
  64. package/my-script/.env +0 -7
  65. package/my-script/getUserStats.ts +0 -106
  66. package/my-script/multiConnections.ts +0 -119
  67. package/my-script/test-regex.ts +0 -11
  68. package/my-script/utils.ts +0 -52
  69. package/src/accounts/bulkAccountLoader.js +0 -249
  70. package/src/accounts/bulkUserStatsSubscription.js +0 -75
  71. package/src/accounts/bulkUserSubscription.js +0 -75
  72. package/src/accounts/fetch.js +0 -92
  73. package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -465
  74. package/src/accounts/pollingOracleSubscriber.js +0 -156
  75. package/src/accounts/pollingTokenAccountSubscriber.js +0 -141
  76. package/src/accounts/pollingUserAccountSubscriber.js +0 -208
  77. package/src/accounts/pollingUserStatsAccountSubscriber.js +0 -208
  78. package/src/accounts/types.js +0 -28
  79. package/src/accounts/utils.js +0 -7
  80. package/src/accounts/webSocketAccountSubscriber.js +0 -138
  81. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -433
  82. package/src/accounts/webSocketUserAccountSubscriber.js +0 -113
  83. package/src/accounts/webSocketUserStatsAccountSubsriber.js +0 -113
  84. package/src/addresses/pda.js +0 -186
  85. package/src/admin.js +0 -1284
  86. package/src/assert/assert.js +0 -9
  87. package/src/clearingHouse.js +0 -3433
  88. package/src/clearingHouseConfig.js +0 -2
  89. package/src/clearingHouseUser.js +0 -874
  90. package/src/clearingHouseUserConfig.js +0 -2
  91. package/src/clearingHouseUserStats.js +0 -115
  92. package/src/clearingHouseUserStatsConfig.js +0 -2
  93. package/src/config.js +0 -80
  94. package/src/constants/numericConstants.js +0 -48
  95. package/src/constants/perpMarkets.js +0 -42
  96. package/src/constants/spotMarkets.js +0 -51
  97. package/src/events/eventList.js +0 -120
  98. package/src/events/eventSubscriber.js +0 -202
  99. package/src/events/fetchLogs.js +0 -117
  100. package/src/events/pollingLogProvider.js +0 -113
  101. package/src/events/sort.js +0 -41
  102. package/src/events/txEventCache.js +0 -74
  103. package/src/events/types.js +0 -25
  104. package/src/events/webSocketLogProvider.js +0 -76
  105. package/src/factory/bigNum.js +0 -393
  106. package/src/factory/oracleClient.js +0 -20
  107. package/src/index.js +0 -75
  108. package/src/math/amm.js +0 -422
  109. package/src/math/auction.js +0 -42
  110. package/src/math/conversion.js +0 -12
  111. package/src/math/funding.js +0 -296
  112. package/src/math/insurance.js +0 -27
  113. package/src/math/margin.js +0 -77
  114. package/src/math/market.js +0 -105
  115. package/src/math/oracles.js +0 -56
  116. package/src/math/orders.js +0 -153
  117. package/src/math/position.js +0 -172
  118. package/src/math/repeg.js +0 -128
  119. package/src/math/spotBalance.js +0 -176
  120. package/src/math/spotMarket.js +0 -8
  121. package/src/math/spotPosition.js +0 -8
  122. package/src/math/trade.js +0 -260
  123. package/src/math/utils.js +0 -27
  124. package/src/oracles/oracleClientCache.js +0 -20
  125. package/src/oracles/pythClient.js +0 -81
  126. package/src/oracles/quoteAssetOracleClient.js +0 -63
  127. package/src/oracles/switchboardClient.js +0 -101
  128. package/src/oracles/types.js +0 -2
  129. package/src/orderParams.js +0 -28
  130. package/src/serum/serumSubscriber.js +0 -102
  131. package/src/serum/types.js +0 -2
  132. package/src/slot/SlotSubscriber.js +0 -86
  133. package/src/token/index.js +0 -38
  134. package/src/tokenFaucet.js +0 -323
  135. package/src/tx/retryTxSender.js +0 -280
  136. package/src/tx/types.js +0 -2
  137. package/src/tx/utils.js +0 -18
  138. package/src/types.js +0 -216
  139. package/src/userName.js +0 -20
  140. package/src/util/computeUnits.js +0 -62
  141. package/src/util/promiseTimeout.js +0 -14
  142. package/src/util/tps.js +0 -61
  143. package/src/wallet.js +0 -72
@@ -131,9 +131,9 @@ export function standardizeBaseAssetAmount(
131
131
 
132
132
  export function getLimitPrice(
133
133
  order: Order,
134
- market: PerpMarketAccount,
135
134
  oraclePriceData: OraclePriceData,
136
- slot: number
135
+ slot: number,
136
+ perpMarket?: PerpMarketAccount
137
137
  ): BN {
138
138
  let limitPrice;
139
139
  if (!order.oraclePriceOffset.eq(ZERO)) {
@@ -143,14 +143,26 @@ export function getLimitPrice(
143
143
  limitPrice = getAuctionPrice(order, slot);
144
144
  } else if (!order.price.eq(ZERO)) {
145
145
  limitPrice = order.price;
146
- } else if (isVariant(order.direction, 'long')) {
147
- const askPrice = calculateAskPrice(market, oraclePriceData);
148
- const delta = askPrice.div(new BN(market.amm.maxSlippageRatio));
149
- limitPrice = askPrice.add(delta);
150
146
  } else {
151
- const bidPrice = calculateBidPrice(market, oraclePriceData);
152
- const delta = bidPrice.div(new BN(market.amm.maxSlippageRatio));
153
- limitPrice = bidPrice.sub(delta);
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
+ }
157
+ } 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
+ }
165
+ }
154
166
  }
155
167
  } else {
156
168
  limitPrice = order.price;
@@ -163,8 +175,7 @@ export function isFillableByVAMM(
163
175
  order: Order,
164
176
  market: PerpMarketAccount,
165
177
  oraclePriceData: OraclePriceData,
166
- slot: number,
167
- maxAuctionDuration: number
178
+ slot: number
168
179
  ): boolean {
169
180
  return (
170
181
  (isAuctionComplete(order, slot) &&
@@ -174,7 +185,7 @@ export function isFillableByVAMM(
174
185
  oraclePriceData,
175
186
  slot
176
187
  ).eq(ZERO)) ||
177
- isOrderExpired(order, slot, maxAuctionDuration)
188
+ isOrderExpired(order, slot)
178
189
  );
179
190
  }
180
191
 
@@ -191,7 +202,7 @@ export function calculateBaseAssetAmountForAmmToFulfill(
191
202
  return ZERO;
192
203
  }
193
204
 
194
- const limitPrice = getLimitPrice(order, market, oraclePriceData, slot);
205
+ const limitPrice = getLimitPrice(order, oraclePriceData, slot, market);
195
206
  const baseAssetAmount = calculateBaseAssetAmountToFillUpToLimitPrice(
196
207
  order,
197
208
  market,
@@ -246,17 +257,14 @@ function isSameDirection(
246
257
  );
247
258
  }
248
259
 
249
- export function isOrderExpired(
250
- order: Order,
251
- slot: number,
252
- maxAuctionDuration: number
253
- ): boolean {
260
+ export function isOrderExpired(order: Order, slot: number): boolean {
254
261
  if (
255
- !isVariant(order.orderType, 'market') ||
256
- !isVariant(order.status, 'open')
262
+ isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) ||
263
+ !isVariant(order.status, 'open') ||
264
+ order.timeInForce === 0
257
265
  ) {
258
266
  return false;
259
267
  }
260
268
 
261
- return new BN(slot).sub(order.slot).gt(new BN(maxAuctionDuration));
269
+ return new BN(slot).sub(order.slot).gt(new BN(order.timeInForce));
262
270
  }
@@ -1,4 +1,4 @@
1
- import { BN } from '../';
1
+ import { BN, SpotMarketAccount } from '../';
2
2
  import {
3
3
  AMM_RESERVE_PRECISION,
4
4
  AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
@@ -17,8 +17,8 @@ import {
17
17
  calculateAmmReservesAfterSwap,
18
18
  getSwapDirection,
19
19
  } from './amm';
20
-
21
20
  import { calculateBaseAssetValueWithOracle } from './margin';
21
+ import { calculateNetUserPnlImbalance } from './market';
22
22
 
23
23
  /**
24
24
  * calculateBaseAssetValue
@@ -31,7 +31,9 @@ import { calculateBaseAssetValueWithOracle } from './margin';
31
31
  export function calculateBaseAssetValue(
32
32
  market: PerpMarketAccount,
33
33
  userPosition: PerpPosition,
34
- oraclePriceData: OraclePriceData
34
+ oraclePriceData: OraclePriceData,
35
+ useSpread = true,
36
+ skipUpdate = false
35
37
  ): BN {
36
38
  if (userPosition.baseAssetAmount.eq(ZERO)) {
37
39
  return ZERO;
@@ -40,21 +42,25 @@ export function calculateBaseAssetValue(
40
42
  const directionToClose = findDirectionToClose(userPosition);
41
43
  let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
42
44
 
43
- if (market.amm.baseSpread > 0) {
44
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
45
- calculateUpdatedAMMSpreadReserves(
46
- market.amm,
47
- directionToClose,
48
- oraclePriceData
49
- );
50
- prepegAmm = {
51
- baseAssetReserve,
52
- quoteAssetReserve,
53
- sqrtK: sqrtK,
54
- pegMultiplier: newPeg,
55
- };
45
+ if (!skipUpdate) {
46
+ if (market.amm.baseSpread > 0 && useSpread) {
47
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
48
+ calculateUpdatedAMMSpreadReserves(
49
+ market.amm,
50
+ directionToClose,
51
+ oraclePriceData
52
+ );
53
+ prepegAmm = {
54
+ baseAssetReserve,
55
+ quoteAssetReserve,
56
+ sqrtK: sqrtK,
57
+ pegMultiplier: newPeg,
58
+ };
59
+ } else {
60
+ prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
61
+ }
56
62
  } else {
57
- prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
63
+ prepegAmm = market.amm;
58
64
  }
59
65
 
60
66
  const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
@@ -124,8 +130,9 @@ export function calculatePositionPNL(
124
130
  return pnl;
125
131
  }
126
132
 
127
- export function calculateUnsettledPnl(
133
+ export function calculateClaimablePnl(
128
134
  market: PerpMarketAccount,
135
+ spotMarket: SpotMarketAccount,
129
136
  perpPosition: PerpPosition,
130
137
  oraclePriceData: OraclePriceData
131
138
  ): BN {
@@ -136,16 +143,23 @@ export function calculateUnsettledPnl(
136
143
  oraclePriceData
137
144
  );
138
145
 
139
- let unsettledPnl = unrealizedPnl;
146
+ const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
147
+ PRICE_TO_QUOTE_PRECISION
148
+ );
149
+
150
+ let unsettledPnl = unrealizedPnl.add(fundingPnL);
140
151
  if (unrealizedPnl.gt(ZERO)) {
141
- const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
142
- PRICE_TO_QUOTE_PRECISION
152
+ const excessPnlPool = BN.max(
153
+ ZERO,
154
+ calculateNetUserPnlImbalance(market, spotMarket, oraclePriceData).mul(
155
+ new BN(-1)
156
+ )
143
157
  );
144
158
 
145
159
  const maxPositivePnl = BN.max(
146
160
  perpPosition.quoteAssetAmount
147
161
  .sub(perpPosition.quoteEntryAmount)
148
- .add(fundingPnL),
162
+ .add(excessPnlPool),
149
163
  ZERO
150
164
  );
151
165
 
package/src/math/repeg.ts CHANGED
@@ -98,6 +98,15 @@ export function calculateBudgetedKBN(
98
98
  .div(QUOTE_PRECISION);
99
99
  const denom2 = pegged_y_d_d;
100
100
 
101
+ // protocol is spending to increase k
102
+ if (C.lt(ZERO)) {
103
+ // thus denom1 is negative and solution is unstable
104
+ if (denom1.lt(pegged_y_d_d.abs())) {
105
+ console.log('budget cost exceeds stable K solution');
106
+ return [new BN(10000), new BN(1)];
107
+ }
108
+ }
109
+
101
110
  const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
102
111
  const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
103
112
 
@@ -19,6 +19,7 @@ import {
19
19
  calculateSizeDiscountAssetWeight,
20
20
  calculateSizePremiumLiabilityWeight,
21
21
  } from './margin';
22
+ import { OraclePriceData } from '../oracles/types';
22
23
 
23
24
  export function getBalance(
24
25
  tokenAmount: BN,
@@ -54,6 +55,31 @@ export function getTokenAmount(
54
55
  return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
55
56
  }
56
57
 
58
+ export function getSignedTokenAmount(
59
+ tokenAmount: BN,
60
+ balanceType: SpotBalanceType
61
+ ): BN {
62
+ if (isVariant(balanceType, 'deposit')) {
63
+ return tokenAmount;
64
+ } else {
65
+ return tokenAmount.abs().neg();
66
+ }
67
+ }
68
+
69
+ export function getTokenValue(
70
+ tokenAmount: BN,
71
+ spotDecimals: number,
72
+ oraclePriceData: OraclePriceData
73
+ ): BN {
74
+ if (tokenAmount.eq(ZERO)) {
75
+ return ZERO;
76
+ }
77
+
78
+ const precisionDecrease = TEN.pow(new BN(10 + spotDecimals - 6));
79
+
80
+ return tokenAmount.mul(oraclePriceData.price).div(precisionDecrease);
81
+ }
82
+
57
83
  export function calculateAssetWeight(
58
84
  balanceAmount: BN,
59
85
  spotMarket: SpotMarketAccount,
@@ -1,6 +1,47 @@
1
- import { SpotPosition } from '../types';
1
+ import { SpotMarketAccount, SpotPosition } from '../types';
2
2
  import { ZERO } from '../constants/numericConstants';
3
+ import { BN } from '@project-serum/anchor';
4
+ import {
5
+ getSignedTokenAmount,
6
+ getTokenAmount,
7
+ getTokenValue,
8
+ } from './spotBalance';
9
+ import { OraclePriceData } from '../oracles/types';
3
10
 
4
11
  export function isSpotPositionAvailable(position: SpotPosition): boolean {
5
12
  return position.balance.eq(ZERO) && position.openOrders === 0;
6
13
  }
14
+
15
+ export function getWorstCaseTokenAmounts(
16
+ spotPosition: SpotPosition,
17
+ spotMarketAccount: SpotMarketAccount,
18
+ oraclePriceData: OraclePriceData
19
+ ): [BN, BN] {
20
+ const tokenAmount = getSignedTokenAmount(
21
+ getTokenAmount(
22
+ spotPosition.balance,
23
+ spotMarketAccount,
24
+ spotPosition.balanceType
25
+ ),
26
+ spotPosition.balanceType
27
+ );
28
+
29
+ const tokenAmountAllBidsFill = tokenAmount.add(spotPosition.openBids);
30
+ const tokenAmountAllAsksFill = tokenAmount.add(spotPosition.openAsks);
31
+
32
+ if (tokenAmountAllAsksFill.abs().gt(tokenAmountAllBidsFill.abs())) {
33
+ const worstCaseQuoteTokenAmount = getTokenValue(
34
+ spotPosition.openBids.neg(),
35
+ spotMarketAccount.decimals,
36
+ oraclePriceData
37
+ );
38
+ return [tokenAmountAllBidsFill, worstCaseQuoteTokenAmount];
39
+ } else {
40
+ const worstCaseQuoteTokenAmount = getTokenValue(
41
+ spotPosition.openAsks.neg(),
42
+ spotMarketAccount.decimals,
43
+ oraclePriceData
44
+ );
45
+ return [tokenAmountAllAsksFill, worstCaseQuoteTokenAmount];
46
+ }
47
+ }
package/src/types.ts CHANGED
@@ -7,6 +7,7 @@ export class MarketStatus {
7
7
  static readonly INITIALIZED = { initialized: {} };
8
8
  static readonly REDUCEONLY = { reduceonly: {} };
9
9
  static readonly SETTLEMENT = { settlement: {} };
10
+ static readonly DELISTED = { delisted: {} };
10
11
  }
11
12
 
12
13
  export class ContractType {
@@ -47,6 +48,7 @@ export class OrderType {
47
48
  static readonly MARKET = { market: {} };
48
49
  }
49
50
 
51
+ export declare type MarketTypeStr = 'perp' | 'spot';
50
52
  export class MarketType {
51
53
  static readonly SPOT = { spot: {} };
52
54
  static readonly PERP = { perp: {} };
@@ -113,6 +115,10 @@ export function isOneOfVariant(object: unknown, types: string[]) {
113
115
  }, false);
114
116
  }
115
117
 
118
+ export function getVariant(object: unknown): string {
119
+ return Object.keys(object)[0];
120
+ }
121
+
116
122
  export enum TradeSide {
117
123
  None = 0,
118
124
  Buy = 1,
@@ -241,6 +247,7 @@ export type LiquidationRecord = {
241
247
  marginRequirement: BN;
242
248
  totalCollateral: BN;
243
249
  liquidationId: number;
250
+ canceledOrderIds: BN[];
244
251
  liquidatePerp: LiquidatePerpRecord;
245
252
  liquidateBorrow: LiquidateBorrowRecord;
246
253
  liquidateBorrowForPerpPnl: LiquidateBorrowForPerpPnlRecord;
@@ -268,17 +275,16 @@ export class LiquidationType {
268
275
 
269
276
  export type LiquidatePerpRecord = {
270
277
  marketIndex: BN;
271
- orderIds: BN[];
272
278
  oraclePrice: BN;
273
279
  baseAssetAmount: BN;
274
280
  quoteAssetAmount: BN;
275
281
  lpShares: BN;
276
282
  userPnl: BN;
277
283
  liquidatorPnl: BN;
278
- canceledOrdersFee: BN;
279
284
  userOrderId: BN;
280
285
  liquidatorOrderId: BN;
281
286
  fillRecordId: BN;
287
+ ifFee: BN;
282
288
  };
283
289
 
284
290
  export type LiquidateBorrowRecord = {
@@ -288,6 +294,7 @@ export type LiquidateBorrowRecord = {
288
294
  liabilityMarketIndex: BN;
289
295
  liabilityPrice: BN;
290
296
  liabilityTransfer: BN;
297
+ ifFee: BN;
291
298
  };
292
299
 
293
300
  export type LiquidateBorrowForPerpPnlRecord = {
@@ -378,17 +385,6 @@ export type StateAccount = {
378
385
  exchangePaused: boolean;
379
386
  adminControlsPrices: boolean;
380
387
  insuranceVault: PublicKey;
381
- marginRatioInitial: BN;
382
- marginRatioMaintenance: BN;
383
- marginRatioPartial: BN;
384
- partialLiquidationClosePercentageNumerator: BN;
385
- partialLiquidationClosePercentageDenominator: BN;
386
- partialLiquidationPenaltyPercentageNumerator: BN;
387
- partialLiquidationPenaltyPercentageDenominator: BN;
388
- fullLiquidationPenaltyPercentageNumerator: BN;
389
- fullLiquidationPenaltyPercentageDenominator: BN;
390
- partialLiquidationLiquidatorShareDenominator: BN;
391
- fullLiquidationLiquidatorShareDenominator: BN;
392
388
  perpFeeStructure: FeeStructure;
393
389
  spotFeeStructure: FeeStructure;
394
390
  totalFee: BN;
@@ -402,8 +398,9 @@ export type StateAccount = {
402
398
  minOrderQuoteAssetAmount: BN;
403
399
  signer: PublicKey;
404
400
  signerNonce: number;
405
- maxAuctionDuration: number;
406
- minAuctionDuration: number;
401
+ defaultMarketOrderTimeInForce: number;
402
+ minPerpAuctionDuration: number;
403
+ defaultSpotAuctionDuration: number;
407
404
  liquidationMarginBufferRatio: number;
408
405
  };
409
406
 
@@ -423,7 +420,8 @@ export type PerpMarketAccount = {
423
420
  marginRatioMaintenance: number;
424
421
  nextFillRecordId: BN;
425
422
  pnlPool: PoolBalance;
426
- liquidationFee: BN;
423
+ liquidatorFee: BN;
424
+ ifLiquidationFee: BN;
427
425
  imfFactor: BN;
428
426
  unrealizedImfFactor: BN;
429
427
  unrealizedMaxImbalance: BN;
@@ -451,7 +449,7 @@ export type SpotMarketAccount = {
451
449
 
452
450
  userIfFactor: BN;
453
451
  totalIfFactor: BN;
454
- liquidationIfFactor: BN;
452
+ ifLiquidationFee: BN;
455
453
 
456
454
  decimals: number;
457
455
  optimalUtilization: BN;
@@ -468,7 +466,7 @@ export type SpotMarketAccount = {
468
466
  maintenanceAssetWeight: BN;
469
467
  initialLiabilityWeight: BN;
470
468
  maintenanceLiabilityWeight: BN;
471
- liquidationFee: BN;
469
+ liquidatorFee: BN;
472
470
  imfFactor: BN;
473
471
 
474
472
  withdrawGuardThreshold: BN;
@@ -561,7 +559,7 @@ export type PerpPosition = {
561
559
  openOrders: BN;
562
560
  openBids: BN;
563
561
  openAsks: BN;
564
- realizedPnl: BN;
562
+ settledPnl: BN;
565
563
  lpShares: BN;
566
564
  lastFeePerLp: BN;
567
565
  lastNetBaseAssetAmountPerLp: BN;
@@ -600,6 +598,7 @@ export type UserAccount = {
600
598
  bankrupt: boolean;
601
599
  nextLiquidationId: number;
602
600
  nextOrderId: BN;
601
+ customMarginRatio: number;
603
602
  };
604
603
 
605
604
  export type SpotPosition = {
@@ -638,6 +637,7 @@ export type Order = {
638
637
  auctionDuration: number;
639
638
  auctionStartPrice: BN;
640
639
  auctionEndPrice: BN;
640
+ timeInForce: number;
641
641
  };
642
642
 
643
643
  export type OrderParams = {
@@ -655,8 +655,9 @@ export type OrderParams = {
655
655
  triggerCondition: OrderTriggerCondition;
656
656
  positionLimit: BN;
657
657
  oraclePriceOffset: BN;
658
- padding0: boolean;
659
- padding1: BN;
658
+ auctionDuration: number | null;
659
+ timeInForce: number | null;
660
+ auctionStartPrice: BN | null;
660
661
  };
661
662
 
662
663
  export type NecessaryOrderParams = {
@@ -685,8 +686,9 @@ export const DefaultOrderParams = {
685
686
  triggerCondition: OrderTriggerCondition.ABOVE,
686
687
  positionLimit: ZERO,
687
688
  oraclePriceOffset: ZERO,
688
- padding0: ZERO,
689
- padding1: ZERO,
689
+ auctionDuration: null,
690
+ timeInForce: null,
691
+ auctionStartPrice: null,
690
692
  };
691
693
 
692
694
  export type MakerInfo = {
@@ -748,7 +750,7 @@ export type FeeStructure = {
748
750
  makerRebateNumerator: BN;
749
751
  makerRebateDenominator: BN;
750
752
  fillerRewardStructure: OrderFillerRewardStructure;
751
- cancelOrderFee: BN;
753
+ flatFillerFee: BN;
752
754
  };
753
755
 
754
756
  export type OracleGuardRails = {
@@ -0,0 +1,100 @@
1
+ import {
2
+ ClearingHouseUser,
3
+ ClearingHouse,
4
+ UserAccount,
5
+ bulkPollingUserSubscribe,
6
+ OrderRecord,
7
+ ClearingHouseUserAccountSubscriptionConfig,
8
+ } from '..';
9
+ import { ProgramAccount } from '@project-serum/anchor';
10
+
11
+ import { PublicKey } from '@solana/web3.js';
12
+
13
+ export class UserMap {
14
+ private userMap = new Map<string, ClearingHouseUser>();
15
+ private clearingHouse: ClearingHouse;
16
+ private accountSubscription: ClearingHouseUserAccountSubscriptionConfig;
17
+
18
+ constructor(
19
+ clearingHouse: ClearingHouse,
20
+ accountSubscription: ClearingHouseUserAccountSubscriptionConfig
21
+ ) {
22
+ this.clearingHouse = clearingHouse;
23
+ this.accountSubscription = accountSubscription;
24
+ }
25
+
26
+ public async fetchAllUsers() {
27
+ const userArray: ClearingHouseUser[] = [];
28
+
29
+ const programUserAccounts =
30
+ (await this.clearingHouse.program.account.user.all()) as ProgramAccount<UserAccount>[];
31
+ for (const programUserAccount of programUserAccounts) {
32
+ if (this.userMap.has(programUserAccount.publicKey.toString())) {
33
+ continue;
34
+ }
35
+
36
+ const user = new ClearingHouseUser({
37
+ clearingHouse: this.clearingHouse,
38
+ userAccountPublicKey: programUserAccount.publicKey,
39
+ accountSubscription: this.accountSubscription,
40
+ });
41
+ userArray.push(user);
42
+ }
43
+
44
+ if (this.accountSubscription.type === 'polling') {
45
+ await bulkPollingUserSubscribe(
46
+ userArray,
47
+ this.accountSubscription.accountLoader
48
+ );
49
+ }
50
+
51
+ for (const user of userArray) {
52
+ this.userMap.set(user.getUserAccountPublicKey().toString(), user);
53
+ }
54
+ }
55
+
56
+ public async addPubkey(userAccountPublicKey: PublicKey) {
57
+ const user = new ClearingHouseUser({
58
+ clearingHouse: this.clearingHouse,
59
+ userAccountPublicKey,
60
+ accountSubscription: this.accountSubscription,
61
+ });
62
+ await user.subscribe();
63
+ this.userMap.set(userAccountPublicKey.toString(), user);
64
+ }
65
+
66
+ public has(key: string): boolean {
67
+ return this.userMap.has(key);
68
+ }
69
+
70
+ /**
71
+ * gets the ClearingHouseUser for a particular userAccountPublicKey, if no ClearingHouseUser exists, undefined is returned
72
+ * @param key userAccountPublicKey to get ClearngHouseUserFor
73
+ * @returns user ClearingHouseUser | undefined
74
+ */
75
+ public get(key: string): ClearingHouseUser | undefined {
76
+ return this.userMap.get(key);
77
+ }
78
+
79
+ /**
80
+ * gets the ClearingHouseUser for a particular userAccountPublicKey, if no ClearingHouseUser exists, new one is created
81
+ * @param key userAccountPublicKey to get ClearngHouseUserFor
82
+ * @returns ClearingHouseUser
83
+ */
84
+ public async mustGet(key: string): Promise<ClearingHouseUser> {
85
+ if (!this.has(key)) {
86
+ await this.addPubkey(new PublicKey(key));
87
+ }
88
+ const user = this.userMap.get(key);
89
+ await user.fetchAccounts();
90
+ return user;
91
+ }
92
+
93
+ public async updateWithOrderRecord(record: OrderRecord) {
94
+ await this.addPubkey(record.user);
95
+ }
96
+
97
+ public values(): IterableIterator<ClearingHouseUser> {
98
+ return this.userMap.values();
99
+ }
100
+ }
@@ -0,0 +1,110 @@
1
+ import {
2
+ ClearingHouse,
3
+ getUserStatsAccountPublicKey,
4
+ OrderRecord,
5
+ UserStatsAccount,
6
+ ClearingHouseUserStats,
7
+ ClearingHouseUserStatsAccountSubscriptionConfig,
8
+ bulkPollingUserStatsSubscribe,
9
+ } from '..';
10
+ import { ProgramAccount } from '@project-serum/anchor';
11
+ import { PublicKey } from '@solana/web3.js';
12
+
13
+ import { UserMap } from './userMap';
14
+
15
+ export class UserStatsMap {
16
+ /**
17
+ * map from authority pubkey to ClearingHouseUserStats
18
+ */
19
+ private userStatsMap = new Map<string, ClearingHouseUserStats>();
20
+ private clearingHouse: ClearingHouse;
21
+ private accountSubscription: ClearingHouseUserStatsAccountSubscriptionConfig;
22
+
23
+ constructor(
24
+ clearingHouse: ClearingHouse,
25
+ accountSubscription: ClearingHouseUserStatsAccountSubscriptionConfig
26
+ ) {
27
+ this.clearingHouse = clearingHouse;
28
+ this.accountSubscription = accountSubscription;
29
+ }
30
+
31
+ public async fetchAllUserStats() {
32
+ const userStatArray: ClearingHouseUserStats[] = [];
33
+
34
+ const programUserAccounts =
35
+ (await this.clearingHouse.program.account.userStats.all()) as ProgramAccount<UserStatsAccount>[];
36
+
37
+ for (const programUserAccount of programUserAccounts) {
38
+ const userStat: UserStatsAccount = programUserAccount.account;
39
+ if (this.userStatsMap.has(userStat.authority.toString())) {
40
+ continue;
41
+ }
42
+
43
+ const chUserStat = new ClearingHouseUserStats({
44
+ clearingHouse: this.clearingHouse,
45
+ userStatsAccountPublicKey: getUserStatsAccountPublicKey(
46
+ this.clearingHouse.program.programId,
47
+ userStat.authority
48
+ ),
49
+ accountSubscription: this.accountSubscription,
50
+ });
51
+ userStatArray.push(chUserStat);
52
+ }
53
+
54
+ if (this.accountSubscription.type === 'polling') {
55
+ await bulkPollingUserStatsSubscribe(
56
+ userStatArray,
57
+ this.accountSubscription.accountLoader
58
+ );
59
+ }
60
+
61
+ for (const userStat of userStatArray) {
62
+ this.userStatsMap.set(
63
+ userStat.getAccount().authority.toString(),
64
+ userStat
65
+ );
66
+ }
67
+ }
68
+
69
+ public async addUserStat(authority: PublicKey) {
70
+ const userStat = new ClearingHouseUserStats({
71
+ clearingHouse: this.clearingHouse,
72
+ userStatsAccountPublicKey: getUserStatsAccountPublicKey(
73
+ this.clearingHouse.program.programId,
74
+ authority
75
+ ),
76
+ accountSubscription: this.accountSubscription,
77
+ });
78
+ await userStat.subscribe();
79
+
80
+ this.userStatsMap.set(authority.toString(), userStat);
81
+ }
82
+
83
+ public async updateWithOrderRecord(record: OrderRecord, userMap: UserMap) {
84
+ if (!this.has(record.user.toString())) {
85
+ const takerUserAccount = await userMap.mustGet(record.user.toString());
86
+ this.addUserStat(takerUserAccount.getUserAccount().authority);
87
+ }
88
+ }
89
+
90
+ public has(authorityPublicKey: string): boolean {
91
+ return this.userStatsMap.has(authorityPublicKey);
92
+ }
93
+
94
+ public get(authorityPublicKey: string): ClearingHouseUserStats {
95
+ return this.userStatsMap.get(authorityPublicKey);
96
+ }
97
+
98
+ public async mustGet(
99
+ authorityPublicKey: string
100
+ ): Promise<ClearingHouseUserStats> {
101
+ if (!this.has(authorityPublicKey)) {
102
+ await this.addUserStat(new PublicKey(authorityPublicKey));
103
+ }
104
+ return this.get(authorityPublicKey);
105
+ }
106
+
107
+ public values(): IterableIterator<ClearingHouseUserStats> {
108
+ return this.userStatsMap.values();
109
+ }
110
+ }