@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.30

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 (208) hide show
  1. package/README.md +13 -13
  2. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  3. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  4. package/lib/accounts/bulkUserSubscription.js +0 -1
  5. package/lib/accounts/fetch.d.ts +2 -1
  6. package/lib/accounts/fetch.js +9 -1
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
  8. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
  9. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  10. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  11. package/lib/accounts/types.d.ts +22 -11
  12. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
  13. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  16. package/lib/addresses/marketAddresses.d.ts +1 -3
  17. package/lib/addresses/pda.d.ts +10 -4
  18. package/lib/addresses/pda.js +51 -14
  19. package/lib/admin.d.ts +34 -22
  20. package/lib/admin.js +182 -73
  21. package/lib/clearingHouse.d.ts +120 -42
  22. package/lib/clearingHouse.js +1505 -254
  23. package/lib/clearingHouseConfig.d.ts +4 -4
  24. package/lib/clearingHouseUser.d.ts +50 -38
  25. package/lib/clearingHouseUser.js +410 -190
  26. package/lib/clearingHouseUserStats.d.ts +18 -0
  27. package/lib/clearingHouseUserStats.js +49 -0
  28. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  29. package/lib/clearingHouseUserStatsConfig.js +2 -0
  30. package/lib/config.d.ts +7 -9
  31. package/lib/config.js +21 -21
  32. package/lib/constants/numericConstants.d.ts +18 -12
  33. package/lib/constants/numericConstants.js +28 -21
  34. package/lib/constants/perpMarkets.d.ts +18 -0
  35. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  36. package/lib/constants/spotMarkets.d.ts +19 -0
  37. package/lib/constants/spotMarkets.js +53 -0
  38. package/lib/dlob/DLOB.d.ts +73 -0
  39. package/lib/dlob/DLOB.js +553 -0
  40. package/lib/dlob/DLOBNode.d.ts +52 -0
  41. package/lib/dlob/DLOBNode.js +82 -0
  42. package/lib/dlob/NodeList.d.ts +26 -0
  43. package/lib/dlob/NodeList.js +138 -0
  44. package/lib/events/eventList.js +3 -0
  45. package/lib/events/eventSubscriber.d.ts +4 -2
  46. package/lib/events/eventSubscriber.js +16 -9
  47. package/lib/events/fetchLogs.d.ts +10 -1
  48. package/lib/events/fetchLogs.js +27 -7
  49. package/lib/events/pollingLogProvider.d.ts +2 -1
  50. package/lib/events/pollingLogProvider.js +6 -2
  51. package/lib/events/sort.js +8 -11
  52. package/lib/events/types.d.ts +7 -2
  53. package/lib/events/types.js +5 -0
  54. package/lib/examples/makeTradeExample.js +20 -8
  55. package/lib/factory/bigNum.d.ts +1 -0
  56. package/lib/factory/bigNum.js +34 -10
  57. package/lib/idl/clearing_house.json +4313 -1433
  58. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  59. package/lib/index.d.ts +21 -6
  60. package/lib/index.js +25 -6
  61. package/lib/math/amm.d.ts +8 -5
  62. package/lib/math/amm.js +68 -46
  63. package/lib/math/auction.js +4 -1
  64. package/lib/math/conversion.js +1 -1
  65. package/lib/math/funding.d.ts +6 -6
  66. package/lib/math/funding.js +11 -10
  67. package/lib/math/insurance.d.ts +4 -0
  68. package/lib/math/insurance.js +27 -0
  69. package/lib/math/margin.d.ts +11 -0
  70. package/lib/math/margin.js +77 -0
  71. package/lib/math/market.d.ts +14 -9
  72. package/lib/math/market.js +69 -7
  73. package/lib/math/oracles.d.ts +4 -0
  74. package/lib/math/oracles.js +36 -8
  75. package/lib/math/orders.d.ts +6 -2
  76. package/lib/math/orders.js +78 -3
  77. package/lib/math/position.d.ts +21 -13
  78. package/lib/math/position.js +76 -36
  79. package/lib/math/repeg.js +14 -5
  80. package/lib/math/spotBalance.d.ts +22 -0
  81. package/lib/math/spotBalance.js +193 -0
  82. package/lib/math/spotMarket.d.ts +4 -0
  83. package/lib/math/spotMarket.js +8 -0
  84. package/lib/math/spotPosition.d.ts +6 -0
  85. package/lib/math/spotPosition.js +23 -0
  86. package/lib/math/trade.d.ts +10 -10
  87. package/lib/math/trade.js +22 -29
  88. package/lib/oracles/pythClient.js +1 -1
  89. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  90. package/lib/oracles/switchboardClient.js +1 -1
  91. package/lib/orderParams.d.ts +14 -5
  92. package/lib/orderParams.js +12 -92
  93. package/lib/serum/serumSubscriber.d.ts +23 -0
  94. package/lib/serum/serumSubscriber.js +41 -0
  95. package/lib/serum/types.d.ts +11 -0
  96. package/lib/serum/types.js +2 -0
  97. package/lib/slot/SlotSubscriber.d.ts +7 -0
  98. package/lib/slot/SlotSubscriber.js +3 -0
  99. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  100. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  101. package/lib/tx/retryTxSender.d.ts +1 -1
  102. package/lib/tx/retryTxSender.js +13 -4
  103. package/lib/tx/types.d.ts +1 -1
  104. package/lib/tx/utils.js +1 -1
  105. package/lib/types.d.ts +474 -123
  106. package/lib/types.js +99 -5
  107. package/lib/userMap/userMap.d.ts +25 -0
  108. package/lib/userMap/userMap.js +73 -0
  109. package/lib/userMap/userStatsMap.d.ts +19 -0
  110. package/lib/userMap/userStatsMap.js +68 -0
  111. package/lib/util/computeUnits.js +1 -1
  112. package/lib/util/getTokenAddress.d.ts +2 -0
  113. package/lib/util/getTokenAddress.js +9 -0
  114. package/package.json +9 -5
  115. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  116. package/src/accounts/bulkUserSubscription.ts +0 -1
  117. package/src/accounts/fetch.ts +27 -2
  118. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
  119. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  120. package/src/accounts/types.ts +31 -11
  121. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
  122. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  123. package/src/addresses/marketAddresses.ts +1 -2
  124. package/src/addresses/pda.ts +88 -14
  125. package/src/admin.ts +333 -128
  126. package/src/assert/assert.js +9 -0
  127. package/src/clearingHouse.ts +2464 -458
  128. package/src/clearingHouseConfig.ts +4 -3
  129. package/src/clearingHouseUser.ts +747 -291
  130. package/src/clearingHouseUserStats.ts +75 -0
  131. package/src/clearingHouseUserStatsConfig.ts +18 -0
  132. package/src/config.ts +30 -31
  133. package/src/constants/numericConstants.ts +41 -25
  134. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  135. package/src/constants/spotMarkets.ts +72 -0
  136. package/src/dlob/DLOB.ts +868 -0
  137. package/src/dlob/DLOBNode.ts +162 -0
  138. package/src/dlob/NodeList.ts +185 -0
  139. package/src/events/eventList.js +77 -0
  140. package/src/events/eventList.ts +3 -0
  141. package/src/events/eventSubscriber.ts +20 -12
  142. package/src/events/fetchLogs.ts +35 -8
  143. package/src/events/pollingLogProvider.ts +10 -2
  144. package/src/events/sort.ts +11 -15
  145. package/src/events/types.ts +16 -1
  146. package/src/examples/makeTradeExample.js +157 -0
  147. package/src/examples/makeTradeExample.ts +32 -14
  148. package/src/factory/bigNum.ts +42 -13
  149. package/src/idl/clearing_house.json +4313 -1433
  150. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  151. package/src/index.ts +21 -6
  152. package/src/math/amm.ts +136 -66
  153. package/src/math/auction.ts +5 -1
  154. package/src/math/conversion.ts +2 -2
  155. package/src/math/funding.ts +20 -18
  156. package/src/math/insurance.ts +35 -0
  157. package/src/math/margin.ts +127 -0
  158. package/src/math/market.ts +138 -12
  159. package/src/math/oracles.ts +63 -9
  160. package/src/math/orders.ts +138 -4
  161. package/src/math/position.ts +119 -58
  162. package/src/math/repeg.ts +16 -6
  163. package/src/math/spotBalance.ts +316 -0
  164. package/src/math/spotMarket.ts +9 -0
  165. package/src/math/spotPosition.ts +47 -0
  166. package/src/math/trade.ts +43 -49
  167. package/src/oracles/pythClient.ts +2 -2
  168. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  169. package/src/oracles/switchboardClient.ts +2 -2
  170. package/src/orderParams.ts +24 -137
  171. package/src/serum/serumSubscriber.ts +80 -0
  172. package/src/serum/types.ts +13 -0
  173. package/src/slot/SlotSubscriber.ts +11 -1
  174. package/src/token/index.js +38 -0
  175. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  176. package/src/tx/retryTxSender.ts +16 -5
  177. package/src/tx/types.js +2 -0
  178. package/src/tx/types.ts +2 -1
  179. package/src/tx/utils.js +17 -0
  180. package/src/tx/utils.ts +1 -1
  181. package/src/types.ts +477 -125
  182. package/src/userMap/userMap.ts +100 -0
  183. package/src/userMap/userStatsMap.ts +110 -0
  184. package/src/util/computeUnits.js +21 -11
  185. package/src/util/computeUnits.ts +1 -1
  186. package/src/util/getTokenAddress.js +9 -0
  187. package/src/util/getTokenAddress.ts +18 -0
  188. package/src/util/promiseTimeout.js +14 -0
  189. package/src/util/tps.js +27 -0
  190. package/tests/bn/test.ts +12 -3
  191. package/tests/dlob/helpers.ts +374 -0
  192. package/tests/dlob/test.ts +2865 -0
  193. package/lib/constants/banks.d.ts +0 -16
  194. package/lib/constants/banks.js +0 -34
  195. package/lib/constants/markets.d.ts +0 -19
  196. package/lib/math/bankBalance.d.ts +0 -9
  197. package/lib/math/bankBalance.js +0 -75
  198. package/lib/math/state.d.ts +0 -8
  199. package/lib/math/state.js +0 -15
  200. package/lib/orders.d.ts +0 -8
  201. package/lib/orders.js +0 -134
  202. package/src/constants/banks.ts +0 -43
  203. package/src/math/bankBalance.ts +0 -112
  204. package/src/math/state.ts +0 -14
  205. package/src/math/utils.js +0 -27
  206. package/src/math/utils.js.map +0 -1
  207. package/src/orders.ts +0 -244
  208. package/src/util/computeUnits.js.map +0 -1
@@ -7,11 +7,11 @@ import {
7
7
  MarginCategory,
8
8
  Order,
9
9
  UserAccount,
10
- UserPosition,
10
+ PerpPosition,
11
11
  } from './types';
12
12
  import { calculateEntryPrice } from './math/position';
13
13
  import {
14
- MARK_PRICE_PRECISION,
14
+ PRICE_PRECISION,
15
15
  AMM_TO_QUOTE_PRECISION_RATIO,
16
16
  ZERO,
17
17
  TEN_THOUSAND,
@@ -20,7 +20,8 @@ import {
20
20
  AMM_RESERVE_PRECISION,
21
21
  PRICE_TO_QUOTE_PRECISION,
22
22
  MARGIN_PRECISION,
23
- BANK_WEIGHT_PRECISION,
23
+ SPOT_MARKET_WEIGHT_PRECISION,
24
+ QUOTE_SPOT_MARKET_INDEX,
24
25
  } from './constants/numericConstants';
25
26
  import {
26
27
  UserAccountSubscriber,
@@ -28,21 +29,35 @@ import {
28
29
  DataAndSlot,
29
30
  } from './accounts/types';
30
31
  import {
31
- calculateMarkPrice,
32
+ calculateReservePrice,
32
33
  calculateBaseAssetValue,
33
34
  calculatePositionFundingPNL,
34
35
  calculatePositionPNL,
36
+ calculateUnrealizedAssetWeight,
37
+ calculateMarketMarginRatio,
35
38
  PositionDirection,
36
39
  calculateTradeSlippage,
37
40
  BN,
38
- BankAccount,
41
+ SpotMarketAccount,
42
+ getTokenValue,
39
43
  } from '.';
40
- import { getTokenAmount } from './math/bankBalance';
44
+ import {
45
+ getTokenAmount,
46
+ calculateAssetWeight,
47
+ calculateLiabilityWeight,
48
+ } from './math/spotBalance';
49
+ import {
50
+ calculateBaseAssetValueWithOracle,
51
+ calculateWorstCaseBaseAssetAmount,
52
+ } from './math/margin';
41
53
  import { OraclePriceData } from './oracles/types';
42
54
  import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
43
55
  import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
44
56
  import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
45
-
57
+ import {
58
+ getWorstCaseTokenAmounts,
59
+ isSpotPositionAvailable,
60
+ } from './math/spotPosition';
46
61
  export class ClearingHouseUser {
47
62
  clearingHouse: ClearingHouse;
48
63
  userAccountPublicKey: PublicKey;
@@ -110,26 +125,36 @@ export class ClearingHouseUser {
110
125
  * @param marketIndex
111
126
  * @returns userPosition
112
127
  */
113
- public getUserPosition(marketIndex: BN): UserPosition | undefined {
114
- return this.getUserAccount().positions.find((position) =>
115
- position.marketIndex.eq(marketIndex)
128
+ public getUserPosition(marketIndex: number): PerpPosition | undefined {
129
+ return this.getUserAccount().perpPositions.find(
130
+ (position) => position.marketIndex === marketIndex
116
131
  );
117
132
  }
118
133
 
119
- public getEmptyPosition(marketIndex: BN): UserPosition {
134
+ public getEmptyPosition(marketIndex: number): PerpPosition {
120
135
  return {
121
136
  baseAssetAmount: ZERO,
137
+ remainderBaseAssetAmount: ZERO,
122
138
  lastCumulativeFundingRate: ZERO,
123
139
  marketIndex,
124
140
  quoteAssetAmount: ZERO,
125
141
  quoteEntryAmount: ZERO,
126
- openOrders: ZERO,
127
- unsettledPnl: ZERO,
142
+ openOrders: 0,
128
143
  openBids: ZERO,
129
144
  openAsks: ZERO,
145
+ settledPnl: ZERO,
146
+ lpShares: ZERO,
147
+ lastFeePerLp: ZERO,
148
+ lastNetBaseAssetAmountPerLp: ZERO,
149
+ lastNetQuoteAssetAmountPerLp: ZERO,
130
150
  };
131
151
  }
132
152
 
153
+ public getClonedPosition(position: PerpPosition): PerpPosition {
154
+ const clonedPosition = Object.assign({}, position);
155
+ return clonedPosition;
156
+ }
157
+
133
158
  /**
134
159
  * @param orderId
135
160
  * @returns Order
@@ -162,11 +187,117 @@ export class ClearingHouseUser {
162
187
  return userAccountRPCResponse.value !== null;
163
188
  }
164
189
 
190
+ /**
191
+ * calculates the market position if the lp position was settled
192
+ * @returns : the settled userPosition
193
+ * @returns : the dust base asset amount (ie, < stepsize)
194
+ * @returns : pnl from settle
195
+ */
196
+ public getSettledLPPosition(marketIndex: number): [PerpPosition, BN, BN] {
197
+ const _position = this.getUserPosition(marketIndex);
198
+ const position = this.getClonedPosition(_position);
199
+
200
+ const market = this.clearingHouse.getPerpMarketAccount(
201
+ position.marketIndex
202
+ );
203
+ const nShares = position.lpShares;
204
+
205
+ const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
206
+ .sub(position.lastNetBaseAssetAmountPerLp)
207
+ .mul(nShares)
208
+ .div(AMM_RESERVE_PRECISION);
209
+ const deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
210
+ .sub(position.lastNetQuoteAssetAmountPerLp)
211
+ .mul(nShares)
212
+ .div(AMM_RESERVE_PRECISION);
213
+
214
+ function sign(v: BN) {
215
+ const sign = { true: new BN(1), false: new BN(-1) }[
216
+ v.gte(ZERO).toString()
217
+ ];
218
+ return sign;
219
+ }
220
+
221
+ function standardize(amount, stepsize) {
222
+ const remainder = amount.abs().mod(stepsize).mul(sign(amount));
223
+ const standardizedAmount = amount.sub(remainder);
224
+ return [standardizedAmount, remainder];
225
+ }
226
+
227
+ const [standardizedBaa, remainderBaa] = standardize(
228
+ deltaBaa,
229
+ market.amm.baseAssetAmountStepSize
230
+ );
231
+
232
+ position.remainderBaseAssetAmount =
233
+ position.remainderBaseAssetAmount.add(remainderBaa);
234
+
235
+ if (
236
+ position.remainderBaseAssetAmount
237
+ .abs()
238
+ .gte(market.amm.baseAssetAmountStepSize)
239
+ ) {
240
+ const [newStandardizedBaa, newRemainderBaa] = standardize(
241
+ position.remainderBaseAssetAmount,
242
+ market.amm.baseAssetAmountStepSize
243
+ );
244
+ position.baseAssetAmount =
245
+ position.baseAssetAmount.add(newStandardizedBaa);
246
+ position.remainderBaseAssetAmount = newRemainderBaa;
247
+ }
248
+
249
+ let updateType;
250
+ if (position.baseAssetAmount.eq(ZERO)) {
251
+ updateType = 'open';
252
+ } else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
253
+ updateType = 'increase';
254
+ } else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
255
+ updateType = 'reduce';
256
+ } else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
257
+ updateType = 'close';
258
+ } else {
259
+ updateType = 'flip';
260
+ }
261
+
262
+ let newQuoteEntry;
263
+ let pnl;
264
+ if (updateType == 'open' || updateType == 'increase') {
265
+ newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
266
+ pnl = 0;
267
+ } else if (updateType == 'reduce' || updateType == 'close') {
268
+ newQuoteEntry = position.quoteEntryAmount.sub(
269
+ position.quoteEntryAmount
270
+ .mul(deltaBaa.abs())
271
+ .div(position.baseAssetAmount.abs())
272
+ );
273
+ pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
274
+ } else {
275
+ newQuoteEntry = deltaQaa.sub(
276
+ deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
277
+ );
278
+ pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
279
+ }
280
+ position.quoteEntryAmount = newQuoteEntry;
281
+ position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
282
+ position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
283
+
284
+ if (position.baseAssetAmount.gt(ZERO)) {
285
+ position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
286
+ } else if (position.baseAssetAmount.lt(ZERO)) {
287
+ position.lastCumulativeFundingRate =
288
+ market.amm.cumulativeFundingRateShort;
289
+ } else {
290
+ position.lastCumulativeFundingRate = ZERO;
291
+ }
292
+
293
+ return [position, remainderBaa, pnl];
294
+ }
295
+
165
296
  /**
166
297
  * calculates Buying Power = FC * MAX_LEVERAGE
167
298
  * @returns : Precision QUOTE_PRECISION
168
299
  */
169
- public getBuyingPower(marketIndex: BN | number): BN {
300
+ public getBuyingPower(marketIndex: number): BN {
170
301
  return this.getFreeCollateral()
171
302
  .mul(this.getMaxLeverage(marketIndex, 'Initial'))
172
303
  .div(TEN_THOUSAND);
@@ -183,82 +314,85 @@ export class ClearingHouseUser {
183
314
  return freeCollateral.gte(ZERO) ? freeCollateral : ZERO;
184
315
  }
185
316
 
186
- public getInitialMarginRequirement(): BN {
187
- return this.getUserAccount()
188
- .positions.reduce((marginRequirement, marketPosition) => {
189
- const market = this.clearingHouse.getMarketAccount(
190
- marketPosition.marketIndex
191
- );
192
- return marginRequirement.add(
193
- calculateBaseAssetValue(
194
- market,
195
- marketPosition,
196
- this.getOracleDataForMarket(market.marketIndex)
197
- )
198
- .mul(new BN(market.marginRatioInitial))
199
- .div(MARGIN_PRECISION)
200
- );
201
- }, ZERO)
202
- .add(this.getTotalLiability());
317
+ /**
318
+ * @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
319
+ */
320
+ public getMarginRequirement(
321
+ marginCategory: MarginCategory,
322
+ liquidationBuffer?: BN
323
+ ): BN {
324
+ return this.getTotalPerpPositionValue(
325
+ marginCategory,
326
+ liquidationBuffer,
327
+ true
328
+ ).add(
329
+ this.getSpotMarketLiabilityValue(
330
+ undefined,
331
+ marginCategory,
332
+ liquidationBuffer,
333
+ true
334
+ )
335
+ );
203
336
  }
204
337
 
205
338
  /**
206
- * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
339
+ * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
207
340
  */
208
- public getPartialMarginRequirement(): BN {
209
- return this.getUserAccount()
210
- .positions.reduce((marginRequirement, marketPosition) => {
211
- const market = this.clearingHouse.getMarketAccount(
212
- marketPosition.marketIndex
213
- );
214
- return marginRequirement.add(
215
- calculateBaseAssetValue(
216
- market,
217
- marketPosition,
218
- this.getOracleDataForMarket(market.marketIndex)
219
- )
220
- .mul(new BN(market.marginRatioPartial))
221
- .div(MARGIN_PRECISION)
222
- );
223
- }, ZERO)
224
- .add(this.getTotalLiability());
341
+ public getInitialMarginRequirement(): BN {
342
+ return this.getMarginRequirement('Initial');
225
343
  }
226
344
 
227
345
  /**
228
- * calculates unrealized position price pnl
229
- * @returns : Precision QUOTE_PRECISION
346
+ * @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
230
347
  */
231
- public getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN): BN {
232
- return this.getUserAccount()
233
- .positions.filter((pos) =>
234
- marketIndex ? pos.marketIndex === marketIndex : true
235
- )
236
- .reduce((pnl, marketPosition) => {
237
- const market = this.clearingHouse.getMarketAccount(
238
- marketPosition.marketIndex
239
- );
240
- return pnl.add(
241
- calculatePositionPNL(
242
- market,
243
- marketPosition,
244
- withFunding,
245
- this.getOracleDataForMarket(market.marketIndex)
246
- )
247
- );
248
- }, ZERO);
348
+ public getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN {
349
+ return this.getMarginRequirement('Maintenance', liquidationBuffer);
249
350
  }
250
351
 
251
352
  /**
252
353
  * calculates unrealized position price pnl
253
354
  * @returns : Precision QUOTE_PRECISION
254
355
  */
255
- public getUnsettledPNL(marketIndex?: BN): BN {
356
+ public getUnrealizedPNL(
357
+ withFunding?: boolean,
358
+ marketIndex?: number,
359
+ withWeightMarginCategory?: MarginCategory
360
+ ): BN {
361
+ const quoteSpotMarket = this.clearingHouse.getQuoteSpotMarketAccount();
256
362
  return this.getUserAccount()
257
- .positions.filter((pos) =>
363
+ .perpPositions.filter((pos) =>
258
364
  marketIndex ? pos.marketIndex === marketIndex : true
259
365
  )
260
- .reduce((pnl, marketPosition) => {
261
- return pnl.add(marketPosition.unsettledPnl);
366
+ .reduce((unrealizedPnl, perpPosition) => {
367
+ const market = this.clearingHouse.getPerpMarketAccount(
368
+ perpPosition.marketIndex
369
+ );
370
+ const oraclePriceData = this.getOracleDataForMarket(market.marketIndex);
371
+
372
+ let positionUnrealizedPnl = calculatePositionPNL(
373
+ market,
374
+ perpPosition,
375
+ withFunding,
376
+ oraclePriceData
377
+ );
378
+
379
+ if (withWeightMarginCategory !== undefined) {
380
+ if (positionUnrealizedPnl.gt(ZERO)) {
381
+ positionUnrealizedPnl = positionUnrealizedPnl
382
+ .mul(
383
+ calculateUnrealizedAssetWeight(
384
+ market,
385
+ quoteSpotMarket,
386
+ positionUnrealizedPnl,
387
+ withWeightMarginCategory,
388
+ oraclePriceData
389
+ )
390
+ )
391
+ .div(new BN(SPOT_MARKET_WEIGHT_PRECISION));
392
+ }
393
+ }
394
+
395
+ return unrealizedPnl.add(positionUnrealizedPnl);
262
396
  }, ZERO);
263
397
  }
264
398
 
@@ -266,163 +400,426 @@ export class ClearingHouseUser {
266
400
  * calculates unrealized funding payment pnl
267
401
  * @returns : Precision QUOTE_PRECISION
268
402
  */
269
- public getUnrealizedFundingPNL(marketIndex?: BN): BN {
403
+ public getUnrealizedFundingPNL(marketIndex?: number): BN {
270
404
  return this.getUserAccount()
271
- .positions.filter((pos) =>
405
+ .perpPositions.filter((pos) =>
272
406
  marketIndex ? pos.marketIndex === marketIndex : true
273
407
  )
274
- .reduce((pnl, marketPosition) => {
275
- const market = this.clearingHouse.getMarketAccount(
276
- marketPosition.marketIndex
408
+ .reduce((pnl, perpPosition) => {
409
+ const market = this.clearingHouse.getPerpMarketAccount(
410
+ perpPosition.marketIndex
277
411
  );
278
- return pnl.add(calculatePositionFundingPNL(market, marketPosition));
412
+ return pnl.add(calculatePositionFundingPNL(market, perpPosition));
279
413
  }, ZERO);
280
414
  }
281
415
 
282
- public getTotalLiability(): BN {
283
- return this.getUserAccount().bankBalances.reduce(
284
- (totalAssetValue, bankBalance) => {
416
+ public getSpotMarketLiabilityValue(
417
+ marketIndex?: number,
418
+ marginCategory?: MarginCategory,
419
+ liquidationBuffer?: BN,
420
+ includeOpenOrders?: boolean
421
+ ): BN {
422
+ return this.getUserAccount().spotPositions.reduce(
423
+ (totalLiabilityValue, spotPosition) => {
285
424
  if (
286
- bankBalance.balance.eq(ZERO) ||
287
- isVariant(bankBalance.balanceType, 'deposit')
425
+ isSpotPositionAvailable(spotPosition) ||
426
+ (marketIndex !== undefined &&
427
+ spotPosition.marketIndex !== marketIndex)
288
428
  ) {
289
- return totalAssetValue;
429
+ return totalLiabilityValue;
290
430
  }
291
431
 
292
- // Todo this needs to account for whether it's based on initial or maintenance requirements
293
- const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
294
- bankBalance.bankIndex
295
- );
432
+ const spotMarketAccount: SpotMarketAccount =
433
+ this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
296
434
 
297
- const tokenAmount = getTokenAmount(
298
- bankBalance.balance,
299
- bankAccount,
300
- bankBalance.balanceType
301
- );
302
- return totalAssetValue.add(
303
- tokenAmount
304
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
305
- .mul(bankAccount.initialLiabilityWeight)
306
- .div(BANK_WEIGHT_PRECISION)
307
- .div(MARK_PRICE_PRECISION)
435
+ if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
436
+ if (isVariant(spotPosition.balanceType, 'borrow')) {
437
+ const tokenAmount = getTokenAmount(
438
+ spotPosition.balance,
439
+ spotMarketAccount,
440
+ spotPosition.balanceType
441
+ );
442
+
443
+ let weight = SPOT_MARKET_WEIGHT_PRECISION;
444
+ if (marginCategory === 'Initial') {
445
+ weight = BN.max(
446
+ weight,
447
+ new BN(this.getUserAccount().customMarginRatio)
448
+ );
449
+ }
450
+
451
+ const weightedTokenValue = tokenAmount
452
+ .mul(weight)
453
+ .div(SPOT_MARKET_WEIGHT_PRECISION);
454
+
455
+ return totalLiabilityValue.add(weightedTokenValue);
456
+ } else {
457
+ return totalLiabilityValue;
458
+ }
459
+ }
460
+
461
+ const oraclePriceData = this.getOracleDataForSpotMarket(
462
+ spotPosition.marketIndex
308
463
  );
464
+
465
+ if (!includeOpenOrders) {
466
+ if (isVariant(spotPosition.balanceType, 'borrow')) {
467
+ const tokenAmount = getTokenAmount(
468
+ spotPosition.balance,
469
+ spotMarketAccount,
470
+ spotPosition.balanceType
471
+ );
472
+ const liabilityValue = this.getSpotLiabilityValue(
473
+ tokenAmount,
474
+ oraclePriceData,
475
+ spotMarketAccount,
476
+ marginCategory,
477
+ liquidationBuffer
478
+ );
479
+ return totalLiabilityValue.add(liabilityValue);
480
+ } else {
481
+ return totalLiabilityValue;
482
+ }
483
+ }
484
+
485
+ const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
486
+ getWorstCaseTokenAmounts(
487
+ spotPosition,
488
+ spotMarketAccount,
489
+ this.getOracleDataForSpotMarket(spotPosition.marketIndex)
490
+ );
491
+
492
+ let newTotalLiabilityValue = totalLiabilityValue;
493
+ if (worstCaseTokenAmount.lt(ZERO)) {
494
+ const baseLiabilityValue = this.getSpotLiabilityValue(
495
+ worstCaseTokenAmount,
496
+ oraclePriceData,
497
+ spotMarketAccount,
498
+ marginCategory,
499
+ liquidationBuffer
500
+ );
501
+
502
+ newTotalLiabilityValue =
503
+ newTotalLiabilityValue.add(baseLiabilityValue);
504
+ }
505
+
506
+ if (worstCaseQuoteTokenAmount.lt(ZERO)) {
507
+ let weight = SPOT_MARKET_WEIGHT_PRECISION;
508
+ if (marginCategory === 'Initial') {
509
+ weight = BN.max(
510
+ weight,
511
+ new BN(this.getUserAccount().customMarginRatio)
512
+ );
513
+ }
514
+
515
+ const weightedTokenValue = worstCaseQuoteTokenAmount
516
+ .mul(weight)
517
+ .div(SPOT_MARKET_WEIGHT_PRECISION);
518
+
519
+ newTotalLiabilityValue =
520
+ newTotalLiabilityValue.add(weightedTokenValue);
521
+ }
522
+
523
+ return newTotalLiabilityValue;
309
524
  },
310
525
  ZERO
311
526
  );
312
527
  }
313
528
 
314
- public getCollateralValue(bankIndex?: BN): BN {
315
- return this.getUserAccount().bankBalances.reduce(
316
- (totalAssetValue, bankBalance) => {
529
+ getSpotLiabilityValue(
530
+ tokenAmount: BN,
531
+ oraclePriceData: OraclePriceData,
532
+ spotMarketAccount: SpotMarketAccount,
533
+ marginCategory?: MarginCategory,
534
+ liquidationBuffer?: BN
535
+ ): BN {
536
+ let liabilityValue = getTokenValue(
537
+ tokenAmount,
538
+ spotMarketAccount.decimals,
539
+ oraclePriceData
540
+ );
541
+
542
+ if (marginCategory !== undefined) {
543
+ let weight = calculateLiabilityWeight(
544
+ tokenAmount,
545
+ spotMarketAccount,
546
+ marginCategory
547
+ );
548
+
549
+ if (marginCategory === 'Initial') {
550
+ weight = BN.max(
551
+ weight,
552
+ new BN(this.getUserAccount().customMarginRatio)
553
+ );
554
+ }
555
+
556
+ if (liquidationBuffer !== undefined) {
557
+ weight = weight.add(liquidationBuffer);
558
+ }
559
+
560
+ liabilityValue = liabilityValue
561
+ .mul(weight)
562
+ .div(SPOT_MARKET_WEIGHT_PRECISION);
563
+ }
564
+
565
+ return liabilityValue;
566
+ }
567
+
568
+ public getSpotMarketAssetValue(
569
+ marketIndex?: number,
570
+ marginCategory?: MarginCategory,
571
+ includeOpenOrders?: boolean
572
+ ): BN {
573
+ return this.getUserAccount().spotPositions.reduce(
574
+ (totalAssetValue, spotPosition) => {
317
575
  if (
318
- bankBalance.balance.eq(ZERO) ||
319
- (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
576
+ isSpotPositionAvailable(spotPosition) ||
577
+ (marketIndex !== undefined &&
578
+ spotPosition.marketIndex !== marketIndex)
320
579
  ) {
321
580
  return totalAssetValue;
322
581
  }
323
582
 
324
583
  // Todo this needs to account for whether it's based on initial or maintenance requirements
325
- const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
326
- bankBalance.bankIndex
327
- );
584
+ const spotMarketAccount: SpotMarketAccount =
585
+ this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
586
+
587
+ if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
588
+ if (isVariant(spotPosition.balanceType, 'deposit')) {
589
+ const tokenAmount = getTokenAmount(
590
+ spotPosition.balance,
591
+ spotMarketAccount,
592
+ spotPosition.balanceType
593
+ );
594
+
595
+ return totalAssetValue.add(tokenAmount);
596
+ } else {
597
+ return totalAssetValue;
598
+ }
599
+ }
328
600
 
329
- let tokenAmount = getTokenAmount(
330
- bankBalance.balance,
331
- bankAccount,
332
- bankBalance.balanceType
601
+ const oraclePriceData = this.getOracleDataForSpotMarket(
602
+ spotPosition.marketIndex
333
603
  );
334
604
 
335
- if (isVariant(bankBalance.balanceType, 'borrow')) {
336
- tokenAmount = tokenAmount.mul(new BN(-1));
605
+ if (!includeOpenOrders) {
606
+ if (isVariant(spotPosition.balanceType, 'deposit')) {
607
+ const tokenAmount = getTokenAmount(
608
+ spotPosition.balance,
609
+ spotMarketAccount,
610
+ spotPosition.balanceType
611
+ );
612
+ const assetValue = this.getSpotAssetValue(
613
+ tokenAmount,
614
+ oraclePriceData,
615
+ spotMarketAccount,
616
+ marginCategory
617
+ );
618
+ return totalAssetValue.add(assetValue);
619
+ } else {
620
+ return totalAssetValue;
621
+ }
337
622
  }
338
623
 
339
- return totalAssetValue.add(
340
- tokenAmount
341
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
342
- .div(MARK_PRICE_PRECISION)
343
- );
624
+ const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
625
+ getWorstCaseTokenAmounts(
626
+ spotPosition,
627
+ spotMarketAccount,
628
+ this.getOracleDataForSpotMarket(spotPosition.marketIndex)
629
+ );
630
+
631
+ let newTotalAssetValue = totalAssetValue;
632
+ if (worstCaseTokenAmount.gt(ZERO)) {
633
+ const baseAssetValue = this.getSpotAssetValue(
634
+ worstCaseTokenAmount,
635
+ oraclePriceData,
636
+ spotMarketAccount,
637
+ marginCategory
638
+ );
639
+
640
+ newTotalAssetValue = newTotalAssetValue.add(baseAssetValue);
641
+ }
642
+
643
+ if (worstCaseQuoteTokenAmount.gt(ZERO)) {
644
+ newTotalAssetValue = newTotalAssetValue.add(
645
+ worstCaseQuoteTokenAmount
646
+ );
647
+ }
648
+
649
+ return newTotalAssetValue;
344
650
  },
345
651
  ZERO
346
652
  );
347
653
  }
348
654
 
655
+ getSpotAssetValue(
656
+ tokenAmount: BN,
657
+ oraclePriceData: OraclePriceData,
658
+ spotMarketAccount: SpotMarketAccount,
659
+ marginCategory?: MarginCategory
660
+ ): BN {
661
+ let assetValue = getTokenValue(
662
+ tokenAmount,
663
+ spotMarketAccount.decimals,
664
+ oraclePriceData
665
+ );
666
+
667
+ if (marginCategory !== undefined) {
668
+ const weight = calculateAssetWeight(
669
+ tokenAmount,
670
+ spotMarketAccount,
671
+ marginCategory
672
+ );
673
+
674
+ assetValue = assetValue.mul(weight).div(SPOT_MARKET_WEIGHT_PRECISION);
675
+ }
676
+
677
+ return assetValue;
678
+ }
679
+
680
+ public getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN {
681
+ return this.getSpotMarketAssetValue(
682
+ undefined,
683
+ withWeightMarginCategory
684
+ ).sub(
685
+ this.getSpotMarketLiabilityValue(undefined, withWeightMarginCategory)
686
+ );
687
+ }
688
+
349
689
  /**
350
690
  * calculates TotalCollateral: collateral + unrealized pnl
351
- * TODO: rename to total equity (for perpetuals swaps)
352
691
  * @returns : Precision QUOTE_PRECISION
353
692
  */
354
- public getTotalCollateral(): BN {
355
- return this.getUserAccount()
356
- .bankBalances.reduce((totalAssetValue, bankBalance) => {
357
- if (
358
- bankBalance.balance.eq(ZERO) ||
359
- isVariant(bankBalance.balanceType, 'borrow')
360
- ) {
361
- return totalAssetValue;
362
- }
363
-
364
- // Todo this needs to account for whether it's based on initial or maintenance requirements
365
- const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
366
- bankBalance.bankIndex
367
- );
368
-
369
- const tokenAmount = getTokenAmount(
370
- bankBalance.balance,
371
- bankAccount,
372
- bankBalance.balanceType
373
- );
374
- return totalAssetValue.add(
375
- tokenAmount
376
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
377
- .mul(bankAccount.initialAssetWeight)
378
- .div(BANK_WEIGHT_PRECISION)
379
- .div(MARK_PRICE_PRECISION)
380
- );
381
- }, ZERO)
382
- .add(this.getUnrealizedPNL(true))
383
- .add(this.getUnsettledPNL());
693
+ public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
694
+ return this.getSpotMarketAssetValue(undefined, marginCategory, true).add(
695
+ this.getUnrealizedPNL(true, undefined, marginCategory)
696
+ );
384
697
  }
385
698
 
386
699
  /**
387
- * calculates sum of position value across all positions
700
+ * calculates sum of position value across all positions in margin system
388
701
  * @returns : Precision QUOTE_PRECISION
389
702
  */
390
- getTotalPositionValue(): BN {
391
- return this.getUserAccount().positions.reduce(
392
- (positionValue, marketPosition) => {
393
- const market = this.clearingHouse.getMarketAccount(
394
- marketPosition.marketIndex
395
- );
396
- return positionValue.add(
397
- calculateBaseAssetValue(
398
- market,
399
- marketPosition,
400
- this.getOracleDataForMarket(market.marketIndex)
401
- )
703
+ getTotalPerpPositionValue(
704
+ marginCategory?: MarginCategory,
705
+ liquidationBuffer?: BN,
706
+ includeOpenOrders?: boolean
707
+ ): BN {
708
+ return this.getUserAccount().perpPositions.reduce(
709
+ (totalPerpValue, perpPosition) => {
710
+ const market = this.clearingHouse.getPerpMarketAccount(
711
+ perpPosition.marketIndex
402
712
  );
713
+
714
+ if (perpPosition.lpShares.gt(ZERO)) {
715
+ // is an lp
716
+ // clone so we dont mutate the position
717
+ perpPosition = this.getClonedPosition(perpPosition);
718
+
719
+ // settle position
720
+ const [settledPosition, dustBaa, _] = this.getSettledLPPosition(
721
+ market.marketIndex
722
+ );
723
+ perpPosition.baseAssetAmount =
724
+ settledPosition.baseAssetAmount.add(dustBaa);
725
+ perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
726
+
727
+ // open orders
728
+ let openAsks;
729
+ if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
730
+ openAsks = market.amm.maxBaseAssetReserve
731
+ .sub(market.amm.baseAssetReserve)
732
+ .mul(perpPosition.lpShares)
733
+ .div(market.amm.sqrtK)
734
+ .mul(new BN(-1));
735
+ } else {
736
+ openAsks = ZERO;
737
+ }
738
+
739
+ let openBids;
740
+ if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
741
+ openBids = market.amm.baseAssetReserve
742
+ .sub(market.amm.minBaseAssetReserve)
743
+ .mul(perpPosition.lpShares)
744
+ .div(market.amm.sqrtK);
745
+ } else {
746
+ openBids = ZERO;
747
+ }
748
+
749
+ perpPosition.openAsks = perpPosition.openAsks.add(openAsks);
750
+ perpPosition.openBids = perpPosition.openBids.add(openBids);
751
+ }
752
+
753
+ let valuationPrice = this.getOracleDataForMarket(
754
+ market.marketIndex
755
+ ).price;
756
+
757
+ if (isVariant(market.status, 'settlement')) {
758
+ valuationPrice = market.settlementPrice;
759
+ }
760
+
761
+ const baseAssetAmount = includeOpenOrders
762
+ ? calculateWorstCaseBaseAssetAmount(perpPosition)
763
+ : perpPosition.baseAssetAmount;
764
+
765
+ let baseAssetValue = baseAssetAmount
766
+ .abs()
767
+ .mul(valuationPrice)
768
+ .div(AMM_TO_QUOTE_PRECISION_RATIO.mul(PRICE_PRECISION));
769
+
770
+ if (marginCategory) {
771
+ let marginRatio = new BN(
772
+ calculateMarketMarginRatio(
773
+ market,
774
+ baseAssetAmount.abs(),
775
+ marginCategory
776
+ )
777
+ );
778
+
779
+ if (marginCategory === 'Initial') {
780
+ marginRatio = BN.max(
781
+ marginRatio,
782
+ new BN(this.getUserAccount().customMarginRatio)
783
+ );
784
+ }
785
+
786
+ if (liquidationBuffer !== undefined) {
787
+ marginRatio = marginRatio.add(liquidationBuffer);
788
+ }
789
+
790
+ baseAssetValue = baseAssetValue
791
+ .mul(marginRatio)
792
+ .div(MARGIN_PRECISION);
793
+ }
794
+
795
+ return totalPerpValue.add(baseAssetValue);
403
796
  },
404
797
  ZERO
405
798
  );
406
799
  }
407
800
 
408
801
  /**
409
- * calculates position value from closing 100%
802
+ * calculates position value in margin system
410
803
  * @returns : Precision QUOTE_PRECISION
411
804
  */
412
- public getPositionValue(
413
- marketIndex: BN,
805
+ public getPerpPositionValue(
806
+ marketIndex: number,
414
807
  oraclePriceData: OraclePriceData
415
808
  ): BN {
416
809
  const userPosition =
417
810
  this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
418
- const market = this.clearingHouse.getMarketAccount(
811
+ const market = this.clearingHouse.getPerpMarketAccount(
419
812
  userPosition.marketIndex
420
813
  );
421
- return calculateBaseAssetValue(market, userPosition, oraclePriceData);
814
+ return calculateBaseAssetValueWithOracle(
815
+ market,
816
+ userPosition,
817
+ oraclePriceData
818
+ );
422
819
  }
423
820
 
424
821
  public getPositionSide(
425
- currentPosition: Pick<UserPosition, 'baseAssetAmount'>
822
+ currentPosition: Pick<PerpPosition, 'baseAssetAmount'>
426
823
  ): PositionDirection | undefined {
427
824
  if (currentPosition.baseAssetAmount.gt(ZERO)) {
428
825
  return PositionDirection.LONG;
@@ -434,14 +831,17 @@ export class ClearingHouseUser {
434
831
  }
435
832
 
436
833
  /**
437
- * calculates average exit price for closing 100% of position
438
- * @returns : Precision MARK_PRICE_PRECISION
834
+ * calculates average exit price (optionally for closing up to 100% of position)
835
+ * @returns : Precision PRICE_PRECISION
439
836
  */
440
837
  public getPositionEstimatedExitPriceAndPnl(
441
- position: UserPosition,
442
- amountToClose?: BN
838
+ position: PerpPosition,
839
+ amountToClose?: BN,
840
+ useAMMClose = false
443
841
  ): [BN, BN] {
444
- const market = this.clearingHouse.getMarketAccount(position.marketIndex);
842
+ const market = this.clearingHouse.getPerpMarketAccount(
843
+ position.marketIndex
844
+ );
445
845
 
446
846
  const entryPrice = calculateEntryPrice(position);
447
847
 
@@ -449,34 +849,44 @@ export class ClearingHouseUser {
449
849
 
450
850
  if (amountToClose) {
451
851
  if (amountToClose.eq(ZERO)) {
452
- return [calculateMarkPrice(market, oraclePriceData), ZERO];
852
+ return [calculateReservePrice(market, oraclePriceData), ZERO];
453
853
  }
454
854
  position = {
455
855
  baseAssetAmount: amountToClose,
456
856
  lastCumulativeFundingRate: position.lastCumulativeFundingRate,
457
857
  marketIndex: position.marketIndex,
458
858
  quoteAssetAmount: position.quoteAssetAmount,
459
- } as UserPosition;
859
+ } as PerpPosition;
460
860
  }
461
861
 
462
- const baseAssetValue = calculateBaseAssetValue(
463
- market,
464
- position,
465
- oraclePriceData
466
- );
862
+ let baseAssetValue: BN;
863
+
864
+ if (useAMMClose) {
865
+ baseAssetValue = calculateBaseAssetValue(
866
+ market,
867
+ position,
868
+ oraclePriceData
869
+ );
870
+ } else {
871
+ baseAssetValue = calculateBaseAssetValueWithOracle(
872
+ market,
873
+ position,
874
+ oraclePriceData
875
+ );
876
+ }
467
877
  if (position.baseAssetAmount.eq(ZERO)) {
468
878
  return [ZERO, ZERO];
469
879
  }
470
880
 
471
881
  const exitPrice = baseAssetValue
472
882
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)
473
- .mul(MARK_PRICE_PRECISION)
883
+ .mul(PRICE_PRECISION)
474
884
  .div(position.baseAssetAmount.abs());
475
885
 
476
886
  const pnlPerBase = exitPrice.sub(entryPrice);
477
887
  const pnl = pnlPerBase
478
888
  .mul(position.baseAssetAmount)
479
- .div(MARK_PRICE_PRECISION)
889
+ .div(PRICE_PRECISION)
480
890
  .div(AMM_TO_QUOTE_PRECISION_RATIO);
481
891
 
482
892
  return [exitPrice, pnl];
@@ -486,13 +896,31 @@ export class ClearingHouseUser {
486
896
  * calculates current user leverage across all positions
487
897
  * @returns : Precision TEN_THOUSAND
488
898
  */
489
- public getLeverage(): BN {
490
- const totalCollateral = this.getTotalCollateral();
491
- const totalPositionValue = this.getTotalPositionValue();
492
- if (totalPositionValue.eq(ZERO) && totalCollateral.eq(ZERO)) {
899
+ public getLeverage(marginCategory?: MarginCategory): BN {
900
+ const totalLiabilityValue = this.getTotalPerpPositionValue(
901
+ marginCategory,
902
+ undefined,
903
+ true
904
+ ).add(
905
+ this.getSpotMarketLiabilityValue(
906
+ undefined,
907
+ marginCategory,
908
+ undefined,
909
+ true
910
+ )
911
+ );
912
+
913
+ const totalAssetValue = this.getSpotMarketAssetValue(
914
+ undefined,
915
+ marginCategory,
916
+ true
917
+ ).add(this.getUnrealizedPNL(true, undefined, marginCategory));
918
+
919
+ if (totalAssetValue.eq(ZERO) && totalLiabilityValue.eq(ZERO)) {
493
920
  return ZERO;
494
921
  }
495
- return totalPositionValue.mul(TEN_THOUSAND).div(totalCollateral);
922
+
923
+ return totalLiabilityValue.mul(TEN_THOUSAND).div(totalAssetValue);
496
924
  }
497
925
 
498
926
  /**
@@ -501,26 +929,17 @@ export class ClearingHouseUser {
501
929
  * @returns : Precision TEN_THOUSAND
502
930
  */
503
931
  public getMaxLeverage(
504
- marketIndex: BN | number,
932
+ marketIndex: number,
505
933
  category: MarginCategory = 'Initial'
506
934
  ): BN {
507
- const market = this.clearingHouse.getMarketAccount(marketIndex);
508
- let marginRatioCategory: number;
509
-
510
- switch (category) {
511
- case 'Initial':
512
- marginRatioCategory = market.marginRatioInitial;
513
- break;
514
- case 'Maintenance':
515
- marginRatioCategory = market.marginRatioMaintenance;
516
- break;
517
- case 'Partial':
518
- marginRatioCategory = market.marginRatioPartial;
519
- break;
520
- default:
521
- marginRatioCategory = market.marginRatioInitial;
522
- break;
523
- }
935
+ const market = this.clearingHouse.getPerpMarketAccount(marketIndex);
936
+
937
+ const marginRatioCategory = calculateMarketMarginRatio(
938
+ market,
939
+ // worstCaseBaseAssetAmount.abs(),
940
+ ZERO, // todo
941
+ category
942
+ );
524
943
  const maxLeverage = TEN_THOUSAND.mul(TEN_THOUSAND).div(
525
944
  new BN(marginRatioCategory)
526
945
  );
@@ -531,22 +950,46 @@ export class ClearingHouseUser {
531
950
  * calculates margin ratio: total collateral / |total position value|
532
951
  * @returns : Precision TEN_THOUSAND
533
952
  */
534
- public getMarginRatio(): BN {
535
- const totalPositionValue = this.getTotalPositionValue();
953
+ public getMarginRatio(marginCategory?: MarginCategory): BN {
954
+ const totalLiabilityValue = this.getTotalPerpPositionValue(
955
+ marginCategory,
956
+ undefined,
957
+ true
958
+ ).add(
959
+ this.getSpotMarketLiabilityValue(
960
+ undefined,
961
+ marginCategory,
962
+ undefined,
963
+ true
964
+ )
965
+ );
536
966
 
537
- if (totalPositionValue.eq(ZERO)) {
967
+ if (totalLiabilityValue.eq(ZERO)) {
538
968
  return BN_MAX;
539
969
  }
540
970
 
541
- return this.getTotalCollateral().mul(TEN_THOUSAND).div(totalPositionValue);
971
+ const totalAssetValue = this.getSpotMarketAssetValue(
972
+ undefined,
973
+ marginCategory,
974
+ true
975
+ ).add(this.getUnrealizedPNL(true, undefined, marginCategory));
976
+
977
+ return totalAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
542
978
  }
543
979
 
544
- public canBeLiquidated(): [boolean, BN] {
980
+ public canBeLiquidated(): boolean {
545
981
  const totalCollateral = this.getTotalCollateral();
546
- const partialMaintenanceRequirement = this.getPartialMarginRequirement();
547
- const marginRatio = this.getMarginRatio();
548
- const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
549
- return [canLiquidate, marginRatio];
982
+
983
+ // if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
984
+ let liquidationBuffer = undefined;
985
+ if (this.getUserAccount().beingLiquidated) {
986
+ liquidationBuffer = new BN(
987
+ this.clearingHouse.getStateAccount().liquidationMarginBufferRatio
988
+ );
989
+ }
990
+ const maintenanceRequirement =
991
+ this.getMaintenanceMarginRequirement(liquidationBuffer);
992
+ return totalCollateral.lt(maintenanceRequirement);
550
993
  }
551
994
 
552
995
  /**
@@ -554,12 +997,12 @@ export class ClearingHouseUser {
554
997
  * @returns
555
998
  */
556
999
  public needsToSettleFundingPayment(): boolean {
557
- for (const userPosition of this.getUserAccount().positions) {
1000
+ for (const userPosition of this.getUserAccount().perpPositions) {
558
1001
  if (userPosition.baseAssetAmount.eq(ZERO)) {
559
1002
  continue;
560
1003
  }
561
1004
 
562
- const market = this.clearingHouse.getMarketAccount(
1005
+ const market = this.clearingHouse.getPerpMarketAccount(
563
1006
  userPosition.marketIndex
564
1007
  );
565
1008
  if (
@@ -580,15 +1023,14 @@ export class ClearingHouseUser {
580
1023
 
581
1024
  /**
582
1025
  * Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
583
- * @param marketPosition
1026
+ * @param PerpPosition
584
1027
  * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
585
1028
  * @param partial
586
- * @returns Precision : MARK_PRICE_PRECISION
1029
+ * @returns Precision : PRICE_PRECISION
587
1030
  */
588
1031
  public liquidationPrice(
589
- marketPosition: Pick<UserPosition, 'marketIndex'>,
590
- positionBaseSizeChange: BN = ZERO,
591
- partial = false
1032
+ perpPosition: Pick<PerpPosition, 'marketIndex'>,
1033
+ positionBaseSizeChange: BN = ZERO
592
1034
  ): BN {
593
1035
  // solves formula for example canBeLiquidated below
594
1036
 
@@ -606,65 +1048,73 @@ export class ClearingHouseUser {
606
1048
 
607
1049
  // calculate the total position value ignoring any value from the target market of the trade
608
1050
  const totalPositionValueExcludingTargetMarket =
609
- this.getTotalPositionValueExcludingMarket(marketPosition.marketIndex);
1051
+ this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex);
610
1052
 
611
- const currentMarketPosition =
612
- this.getUserPosition(marketPosition.marketIndex) ||
613
- this.getEmptyPosition(marketPosition.marketIndex);
1053
+ const currentPerpPosition =
1054
+ this.getUserPosition(perpPosition.marketIndex) ||
1055
+ this.getEmptyPosition(perpPosition.marketIndex);
614
1056
 
615
- const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
1057
+ const currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
616
1058
 
617
- const proposedBaseAssetAmount = currentMarketPositionBaseSize.add(
1059
+ const proposedBaseAssetAmount = currentPerpPositionBaseSize.add(
618
1060
  positionBaseSizeChange
619
1061
  );
620
1062
 
621
1063
  // calculate position for current market after trade
622
- const proposedMarketPosition: UserPosition = {
623
- marketIndex: marketPosition.marketIndex,
1064
+ const proposedPerpPosition: PerpPosition = {
1065
+ marketIndex: perpPosition.marketIndex,
624
1066
  baseAssetAmount: proposedBaseAssetAmount,
625
- lastCumulativeFundingRate:
626
- currentMarketPosition.lastCumulativeFundingRate,
1067
+ remainderBaseAssetAmount: ZERO,
627
1068
  quoteAssetAmount: new BN(0),
1069
+ lastCumulativeFundingRate: ZERO,
628
1070
  quoteEntryAmount: new BN(0),
629
- openOrders: new BN(0),
630
- unsettledPnl: new BN(0),
1071
+ openOrders: 0,
631
1072
  openBids: new BN(0),
632
1073
  openAsks: new BN(0),
1074
+ settledPnl: ZERO,
1075
+ lpShares: ZERO,
1076
+ lastFeePerLp: ZERO,
1077
+ lastNetBaseAssetAmountPerLp: ZERO,
1078
+ lastNetQuoteAssetAmountPerLp: ZERO,
633
1079
  };
634
1080
 
635
1081
  if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
636
1082
 
637
- const market = this.clearingHouse.getMarketAccount(
638
- proposedMarketPosition.marketIndex
1083
+ const market = this.clearingHouse.getPerpMarketAccount(
1084
+ proposedPerpPosition.marketIndex
639
1085
  );
640
1086
 
641
- const proposedMarketPositionValue = calculateBaseAssetValue(
1087
+ const proposedPerpPositionValue = calculateBaseAssetValueWithOracle(
642
1088
  market,
643
- proposedMarketPosition,
1089
+ proposedPerpPosition,
644
1090
  this.getOracleDataForMarket(market.marketIndex)
645
1091
  );
646
1092
 
647
1093
  // total position value after trade
648
1094
  const totalPositionValueAfterTrade =
649
- totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
1095
+ totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
650
1096
 
651
1097
  const marginRequirementExcludingTargetMarket =
652
- this.getUserAccount().positions.reduce(
1098
+ this.getUserAccount().perpPositions.reduce(
653
1099
  (totalMarginRequirement, position) => {
654
- if (!position.marketIndex.eq(marketPosition.marketIndex)) {
655
- const market = this.clearingHouse.getMarketAccount(
1100
+ if (position.marketIndex !== perpPosition.marketIndex) {
1101
+ const market = this.clearingHouse.getPerpMarketAccount(
656
1102
  position.marketIndex
657
1103
  );
658
- const positionValue = calculateBaseAssetValue(
1104
+ const positionValue = calculateBaseAssetValueWithOracle(
659
1105
  market,
660
1106
  position,
661
1107
  this.getOracleDataForMarket(market.marketIndex)
662
1108
  );
663
1109
  const marketMarginRequirement = positionValue
664
1110
  .mul(
665
- partial
666
- ? new BN(market.marginRatioPartial)
667
- : new BN(market.marginRatioMaintenance)
1111
+ new BN(
1112
+ calculateMarketMarginRatio(
1113
+ market,
1114
+ position.baseAssetAmount.abs(),
1115
+ 'Maintenance'
1116
+ )
1117
+ )
668
1118
  )
669
1119
  .div(MARGIN_PRECISION);
670
1120
  totalMarginRequirement = totalMarginRequirement.add(
@@ -683,18 +1133,22 @@ export class ClearingHouseUser {
683
1133
  // if the position value after the trade is less than free collateral, there is no liq price
684
1134
  if (
685
1135
  totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
686
- proposedMarketPosition.baseAssetAmount.abs().gt(ZERO)
1136
+ proposedPerpPosition.baseAssetAmount.abs().gt(ZERO)
687
1137
  ) {
688
1138
  return new BN(-1);
689
1139
  }
690
1140
 
691
1141
  const marginRequirementAfterTrade =
692
1142
  marginRequirementExcludingTargetMarket.add(
693
- proposedMarketPositionValue
1143
+ proposedPerpPositionValue
694
1144
  .mul(
695
- partial
696
- ? new BN(market.marginRatioPartial)
697
- : new BN(market.marginRatioMaintenance)
1145
+ new BN(
1146
+ calculateMarketMarginRatio(
1147
+ market,
1148
+ proposedPerpPosition.baseAssetAmount.abs(),
1149
+ 'Maintenance'
1150
+ )
1151
+ )
698
1152
  )
699
1153
  .div(MARGIN_PRECISION)
700
1154
  );
@@ -702,9 +1156,10 @@ export class ClearingHouseUser {
702
1156
  marginRequirementAfterTrade
703
1157
  );
704
1158
 
705
- const marketMaxLeverage = partial
706
- ? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
707
- : this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
1159
+ const marketMaxLeverage = this.getMaxLeverage(
1160
+ proposedPerpPosition.marketIndex,
1161
+ 'Maintenance'
1162
+ );
708
1163
 
709
1164
  let priceDelta;
710
1165
  if (proposedBaseAssetAmount.lt(ZERO)) {
@@ -725,9 +1180,9 @@ export class ClearingHouseUser {
725
1180
 
726
1181
  let markPriceAfterTrade;
727
1182
  if (positionBaseSizeChange.eq(ZERO)) {
728
- markPriceAfterTrade = calculateMarkPrice(
729
- this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
730
- this.getOracleDataForMarket(marketPosition.marketIndex)
1183
+ markPriceAfterTrade = calculateReservePrice(
1184
+ this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex),
1185
+ this.getOracleDataForMarket(perpPosition.marketIndex)
731
1186
  );
732
1187
  } else {
733
1188
  const direction = positionBaseSizeChange.gt(ZERO)
@@ -736,9 +1191,9 @@ export class ClearingHouseUser {
736
1191
  markPriceAfterTrade = calculateTradeSlippage(
737
1192
  direction,
738
1193
  positionBaseSizeChange.abs(),
739
- this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
1194
+ this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex),
740
1195
  'base',
741
- this.getOracleDataForMarket(marketPosition.marketIndex)
1196
+ this.getOracleDataForMarket(perpPosition.marketIndex)
742
1197
  )[3]; // newPrice after swap
743
1198
  }
744
1199
 
@@ -753,10 +1208,10 @@ export class ClearingHouseUser {
753
1208
  * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
754
1209
  * @param positionMarketIndex
755
1210
  * @param closeQuoteAmount
756
- * @returns : Precision MARK_PRICE_PRECISION
1211
+ * @returns : Precision PRICE_PRECISION
757
1212
  */
758
1213
  public liquidationPriceAfterClose(
759
- positionMarketIndex: BN,
1214
+ positionMarketIndex: number,
760
1215
  closeQuoteAmount: BN
761
1216
  ): BN {
762
1217
  const currentPosition =
@@ -765,11 +1220,11 @@ export class ClearingHouseUser {
765
1220
 
766
1221
  const closeBaseAmount = currentPosition.baseAssetAmount
767
1222
  .mul(closeQuoteAmount)
768
- .div(currentPosition.quoteAssetAmount)
1223
+ .div(currentPosition.quoteAssetAmount.abs())
769
1224
  .add(
770
1225
  currentPosition.baseAssetAmount
771
1226
  .mul(closeQuoteAmount)
772
- .mod(currentPosition.quoteAssetAmount)
1227
+ .mod(currentPosition.quoteAssetAmount.abs())
773
1228
  )
774
1229
  .neg();
775
1230
 
@@ -777,8 +1232,7 @@ export class ClearingHouseUser {
777
1232
  {
778
1233
  marketIndex: positionMarketIndex,
779
1234
  },
780
- closeBaseAmount,
781
- true
1235
+ closeBaseAmount
782
1236
  );
783
1237
  }
784
1238
 
@@ -804,7 +1258,7 @@ export class ClearingHouseUser {
804
1258
  * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
805
1259
  */
806
1260
  public getMaxTradeSizeUSDC(
807
- targetMarketIndex: BN,
1261
+ targetMarketIndex: number,
808
1262
  tradeSide: PositionDirection
809
1263
  ): BN {
810
1264
  const currentPosition =
@@ -826,7 +1280,7 @@ export class ClearingHouseUser {
826
1280
  // add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
827
1281
  const oppositeSizeValueUSDC = targetingSameSide
828
1282
  ? ZERO
829
- : this.getPositionValue(targetMarketIndex, oracleData);
1283
+ : this.getPerpPositionValue(targetMarketIndex, oracleData);
830
1284
 
831
1285
  let maxPositionSize = this.getBuyingPower(targetMarketIndex);
832
1286
  if (maxPositionSize.gte(ZERO)) {
@@ -843,21 +1297,22 @@ export class ClearingHouseUser {
843
1297
  // current leverage is greater than max leverage - can only reduce position size
844
1298
 
845
1299
  if (!targetingSameSide) {
846
- const market = this.clearingHouse.getMarketAccount(targetMarketIndex);
847
- const marketPositionValue = this.getPositionValue(
1300
+ const market =
1301
+ this.clearingHouse.getPerpMarketAccount(targetMarketIndex);
1302
+ const perpPositionValue = this.getPerpPositionValue(
848
1303
  targetMarketIndex,
849
1304
  oracleData
850
1305
  );
851
1306
  const totalCollateral = this.getTotalCollateral();
852
1307
  const marginRequirement = this.getInitialMarginRequirement();
853
- const marginFreedByClosing = marketPositionValue
1308
+ const marginFreedByClosing = perpPositionValue
854
1309
  .mul(new BN(market.marginRatioInitial))
855
1310
  .div(MARGIN_PRECISION);
856
1311
  const marginRequirementAfterClosing =
857
1312
  marginRequirement.sub(marginFreedByClosing);
858
1313
 
859
1314
  if (marginRequirementAfterClosing.gt(totalCollateral)) {
860
- maxPositionSize = marketPositionValue;
1315
+ maxPositionSize = perpPositionValue;
861
1316
  } else {
862
1317
  const freeCollateralAfterClose = totalCollateral.sub(
863
1318
  marginRequirementAfterClosing
@@ -865,7 +1320,7 @@ export class ClearingHouseUser {
865
1320
  const buyingPowerAfterClose = freeCollateralAfterClose
866
1321
  .mul(this.getMaxLeverage(targetMarketIndex))
867
1322
  .div(TEN_THOUSAND);
868
- maxPositionSize = marketPositionValue.add(buyingPowerAfterClose);
1323
+ maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
869
1324
  }
870
1325
  } else {
871
1326
  // do nothing if targetting same side
@@ -888,7 +1343,7 @@ export class ClearingHouseUser {
888
1343
  * @returns leverageRatio : Precision TEN_THOUSAND
889
1344
  */
890
1345
  public accountLeverageRatioAfterTrade(
891
- targetMarketIndex: BN,
1346
+ targetMarketIndex: number,
892
1347
  tradeQuoteAmount: BN,
893
1348
  tradeSide: PositionDirection
894
1349
  ): BN {
@@ -898,7 +1353,7 @@ export class ClearingHouseUser {
898
1353
 
899
1354
  const oracleData = this.getOracleDataForMarket(targetMarketIndex);
900
1355
 
901
- let currentPositionQuoteAmount = this.getPositionValue(
1356
+ let currentPositionQuoteAmount = this.getPerpPositionValue(
902
1357
  targetMarketIndex,
903
1358
  oracleData
904
1359
  );
@@ -914,16 +1369,16 @@ export class ClearingHouseUser {
914
1369
  if (tradeSide === PositionDirection.SHORT)
915
1370
  tradeQuoteAmount = tradeQuoteAmount.neg();
916
1371
 
917
- const currentMarketPositionAfterTrade = currentPositionQuoteAmount
1372
+ const currentPerpPositionAfterTrade = currentPositionQuoteAmount
918
1373
  .add(tradeQuoteAmount)
919
1374
  .abs();
920
1375
 
921
1376
  const totalPositionAfterTradeExcludingTargetMarket =
922
- this.getTotalPositionValueExcludingMarket(targetMarketIndex);
1377
+ this.getTotalPerpPositionValueExcludingMarket(targetMarketIndex);
923
1378
 
924
1379
  const totalCollateral = this.getTotalCollateral();
925
1380
  if (totalCollateral.gt(ZERO)) {
926
- const newLeverage = currentMarketPositionAfterTrade
1381
+ const newLeverage = currentPerpPositionAfterTrade
927
1382
  .add(totalPositionAfterTradeExcludingTargetMarket)
928
1383
  .abs()
929
1384
  .mul(TEN_THOUSAND)
@@ -940,11 +1395,11 @@ export class ClearingHouseUser {
940
1395
  * @returns feeForQuote : Precision QUOTE_PRECISION
941
1396
  */
942
1397
  public calculateFeeForQuoteAmount(quoteAmount: BN): BN {
943
- const feeStructure = this.clearingHouse.getStateAccount().feeStructure;
944
-
1398
+ const feeTier =
1399
+ this.clearingHouse.getStateAccount().perpFeeStructure.feeTiers[0];
945
1400
  return quoteAmount
946
- .mul(feeStructure.feeNumerator)
947
- .div(feeStructure.feeDenominator);
1401
+ .mul(new BN(feeTier.feeNumerator))
1402
+ .div(new BN(feeTier.feeDenominator));
948
1403
  }
949
1404
 
950
1405
  /**
@@ -952,34 +1407,35 @@ export class ClearingHouseUser {
952
1407
  * @param marketToIgnore
953
1408
  * @returns positionValue : Precision QUOTE_PRECISION
954
1409
  */
955
- private getTotalPositionValueExcludingMarket(marketToIgnore: BN): BN {
956
- const currentMarketPosition =
1410
+ private getTotalPerpPositionValueExcludingMarket(marketToIgnore: number): BN {
1411
+ const currentPerpPosition =
957
1412
  this.getUserPosition(marketToIgnore) ||
958
1413
  this.getEmptyPosition(marketToIgnore);
959
1414
 
960
1415
  const oracleData = this.getOracleDataForMarket(marketToIgnore);
961
1416
 
962
- let currentMarketPositionValueUSDC = ZERO;
963
- if (currentMarketPosition) {
964
- currentMarketPositionValueUSDC = this.getPositionValue(
1417
+ let currentPerpPositionValueUSDC = ZERO;
1418
+ if (currentPerpPosition) {
1419
+ currentPerpPositionValueUSDC = this.getPerpPositionValue(
965
1420
  marketToIgnore,
966
1421
  oracleData
967
1422
  );
968
1423
  }
969
1424
 
970
- return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
1425
+ return this.getTotalPerpPositionValue().sub(currentPerpPositionValueUSDC);
971
1426
  }
972
1427
 
973
- private getOracleDataForMarket(marketIndex: BN): OraclePriceData {
1428
+ private getOracleDataForMarket(marketIndex: number): OraclePriceData {
974
1429
  const oracleKey =
975
- this.clearingHouse.getMarketAccount(marketIndex).amm.oracle;
1430
+ this.clearingHouse.getPerpMarketAccount(marketIndex).amm.oracle;
976
1431
  const oracleData =
977
1432
  this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
978
1433
 
979
1434
  return oracleData;
980
1435
  }
981
- private getOracleDataForBank(bankIndex: BN): OraclePriceData {
982
- const oracleKey = this.clearingHouse.getBankAccount(bankIndex).oracle;
1436
+ private getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
1437
+ const oracleKey =
1438
+ this.clearingHouse.getSpotMarketAccount(marketIndex).oracle;
983
1439
 
984
1440
  const oracleData =
985
1441
  this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;