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

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