@drift-labs/sdk 0.2.0-master.2 → 0.2.0-master.20

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 (152) hide show
  1. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  2. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  3. package/lib/accounts/bulkUserSubscription.js +0 -1
  4. package/lib/accounts/fetch.d.ts +2 -1
  5. package/lib/accounts/fetch.js +9 -1
  6. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  7. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  8. package/lib/accounts/types.d.ts +14 -1
  9. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  10. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  11. package/lib/addresses/pda.d.ts +1 -0
  12. package/lib/addresses/pda.js +8 -1
  13. package/lib/admin.d.ts +9 -5
  14. package/lib/admin.js +52 -11
  15. package/lib/clearingHouse.d.ts +52 -23
  16. package/lib/clearingHouse.js +727 -197
  17. package/lib/clearingHouseConfig.d.ts +1 -0
  18. package/lib/clearingHouseUser.d.ts +17 -17
  19. package/lib/clearingHouseUser.js +186 -101
  20. package/lib/clearingHouseUserStats.d.ts +18 -0
  21. package/lib/clearingHouseUserStats.js +49 -0
  22. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  23. package/lib/clearingHouseUserStatsConfig.js +2 -0
  24. package/lib/config.js +1 -1
  25. package/lib/constants/banks.d.ts +2 -2
  26. package/lib/constants/banks.js +12 -4
  27. package/lib/constants/numericConstants.d.ts +5 -0
  28. package/lib/constants/numericConstants.js +8 -3
  29. package/lib/events/eventList.js +3 -0
  30. package/lib/events/types.d.ts +3 -1
  31. package/lib/events/types.js +2 -0
  32. package/lib/factory/bigNum.d.ts +1 -0
  33. package/lib/factory/bigNum.js +34 -10
  34. package/lib/idl/clearing_house.json +1609 -388
  35. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  36. package/lib/index.d.ts +9 -3
  37. package/lib/index.js +13 -3
  38. package/lib/math/amm.d.ts +1 -0
  39. package/lib/math/amm.js +22 -38
  40. package/lib/math/auction.js +4 -1
  41. package/lib/math/bankBalance.d.ts +7 -1
  42. package/lib/math/bankBalance.js +77 -2
  43. package/lib/math/margin.d.ts +11 -0
  44. package/lib/math/margin.js +72 -0
  45. package/lib/math/market.d.ts +4 -1
  46. package/lib/math/market.js +35 -1
  47. package/lib/math/oracles.d.ts +3 -0
  48. package/lib/math/oracles.js +25 -5
  49. package/lib/math/orders.d.ts +5 -2
  50. package/lib/math/orders.js +53 -12
  51. package/lib/math/position.d.ts +8 -0
  52. package/lib/math/position.js +45 -12
  53. package/lib/math/trade.d.ts +1 -1
  54. package/lib/math/trade.js +7 -10
  55. package/lib/orderParams.d.ts +14 -5
  56. package/lib/orderParams.js +8 -96
  57. package/lib/slot/SlotSubscriber.d.ts +7 -0
  58. package/lib/slot/SlotSubscriber.js +3 -0
  59. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  60. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  61. package/lib/tx/retryTxSender.js +9 -2
  62. package/lib/tx/utils.js +1 -1
  63. package/lib/types.d.ts +233 -26
  64. package/lib/types.js +64 -1
  65. package/lib/util/computeUnits.js +1 -1
  66. package/lib/util/getTokenAddress.d.ts +2 -0
  67. package/lib/util/getTokenAddress.js +9 -0
  68. package/package.json +3 -3
  69. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  70. package/src/accounts/bulkUserSubscription.ts +0 -1
  71. package/src/accounts/fetch.ts +27 -2
  72. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  73. package/src/accounts/types.ts +18 -0
  74. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  75. package/src/addresses/marketAddresses.js +26 -0
  76. package/src/addresses/pda.ts +13 -0
  77. package/src/admin.ts +82 -15
  78. package/src/assert/assert.js +9 -0
  79. package/src/clearingHouse.ts +1224 -319
  80. package/src/clearingHouseConfig.ts +1 -0
  81. package/src/clearingHouseUser.ts +311 -148
  82. package/src/clearingHouseUserStats.ts +75 -0
  83. package/src/clearingHouseUserStatsConfig.ts +18 -0
  84. package/src/config.ts +1 -1
  85. package/src/constants/banks.js +42 -0
  86. package/src/constants/banks.ts +14 -4
  87. package/src/constants/markets.js +42 -0
  88. package/src/constants/numericConstants.js +41 -0
  89. package/src/constants/numericConstants.ts +14 -2
  90. package/src/events/eventList.js +77 -0
  91. package/src/events/eventList.ts +3 -0
  92. package/src/events/eventSubscriber.js +139 -0
  93. package/src/events/fetchLogs.js +50 -0
  94. package/src/events/pollingLogProvider.js +64 -0
  95. package/src/events/sort.js +44 -0
  96. package/src/events/txEventCache.js +71 -0
  97. package/src/events/types.ts +6 -0
  98. package/src/events/webSocketLogProvider.js +41 -0
  99. package/src/examples/makeTradeExample.js +80 -0
  100. package/src/factory/bigNum.js +390 -0
  101. package/src/factory/bigNum.ts +42 -13
  102. package/src/factory/oracleClient.js +20 -0
  103. package/src/idl/clearing_house.json +1609 -388
  104. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  105. package/src/index.ts +9 -3
  106. package/src/math/amm.ts +54 -55
  107. package/src/math/auction.js +42 -0
  108. package/src/math/auction.ts +5 -1
  109. package/src/math/bankBalance.ts +148 -2
  110. package/src/math/conversion.js +11 -0
  111. package/src/math/funding.js +248 -0
  112. package/src/math/margin.ts +124 -0
  113. package/src/math/market.ts +66 -1
  114. package/src/math/oracles.js +26 -0
  115. package/src/math/oracles.ts +42 -5
  116. package/src/math/orders.ts +112 -13
  117. package/src/math/position.ts +64 -9
  118. package/src/math/repeg.js +128 -0
  119. package/src/math/state.js +15 -0
  120. package/src/math/trade.js +253 -0
  121. package/src/math/trade.ts +23 -25
  122. package/src/math/utils.js +0 -1
  123. package/src/oracles/oracleClientCache.js +19 -0
  124. package/src/oracles/pythClient.js +46 -0
  125. package/src/oracles/quoteAssetOracleClient.js +32 -0
  126. package/src/oracles/switchboardClient.js +69 -0
  127. package/src/oracles/types.js +2 -0
  128. package/src/orderParams.js +20 -0
  129. package/src/orderParams.ts +20 -141
  130. package/src/slot/SlotSubscriber.js +39 -0
  131. package/src/slot/SlotSubscriber.ts +11 -1
  132. package/src/token/index.js +38 -0
  133. package/src/tokenFaucet.js +189 -0
  134. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  135. package/src/tx/retryTxSender.ts +11 -3
  136. package/src/tx/types.js +2 -0
  137. package/src/tx/utils.js +17 -0
  138. package/src/tx/utils.ts +1 -1
  139. package/src/types.ts +236 -27
  140. package/src/userName.js +20 -0
  141. package/src/util/computeUnits.js +21 -11
  142. package/src/util/computeUnits.ts +1 -1
  143. package/src/util/getTokenAddress.js +9 -0
  144. package/src/util/getTokenAddress.ts +18 -0
  145. package/src/util/promiseTimeout.js +14 -0
  146. package/src/util/tps.js +27 -0
  147. package/src/wallet.js +35 -0
  148. package/tests/bn/test.ts +10 -0
  149. package/lib/orders.d.ts +0 -8
  150. package/lib/orders.js +0 -142
  151. package/src/orders.ts +0 -251
  152. package/src/util/computeUnits.js.map +0 -1
@@ -21,6 +21,7 @@ import {
21
21
  PRICE_TO_QUOTE_PRECISION,
22
22
  MARGIN_PRECISION,
23
23
  BANK_WEIGHT_PRECISION,
24
+ BANK_BALANCE_PRECISION_EXP,
24
25
  } from './constants/numericConstants';
25
26
  import {
26
27
  UserAccountSubscriber,
@@ -32,17 +33,26 @@ import {
32
33
  calculateBaseAssetValue,
33
34
  calculatePositionFundingPNL,
34
35
  calculatePositionPNL,
36
+ calculateUnrealizedAssetWeight,
37
+ calculateMarketMarginRatio,
35
38
  PositionDirection,
36
39
  calculateTradeSlippage,
37
40
  BN,
38
41
  BankAccount,
39
42
  } from '.';
40
- import { getTokenAmount } from './math/bankBalance';
43
+ import {
44
+ getTokenAmount,
45
+ calculateAssetWeight,
46
+ calculateLiabilityWeight,
47
+ } from './math/bankBalance';
48
+ import {
49
+ calculateMarginBaseAssetValue,
50
+ calculateWorstCaseBaseAssetAmount,
51
+ } from './math/margin';
41
52
  import { OraclePriceData } from './oracles/types';
42
53
  import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
43
54
  import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
44
55
  import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
45
-
46
56
  export class ClearingHouseUser {
47
57
  clearingHouse: ClearingHouse;
48
58
  userAccountPublicKey: PublicKey;
@@ -124,9 +134,13 @@ export class ClearingHouseUser {
124
134
  quoteAssetAmount: ZERO,
125
135
  quoteEntryAmount: ZERO,
126
136
  openOrders: ZERO,
127
- unsettledPnl: ZERO,
128
137
  openBids: ZERO,
129
138
  openAsks: ZERO,
139
+ realizedPnl: ZERO,
140
+ lpShares: ZERO,
141
+ lastFeePerLp: ZERO,
142
+ lastNetBaseAssetAmountPerLp: ZERO,
143
+ lastNetQuoteAssetAmountPerLp: ZERO,
130
144
  };
131
145
  }
132
146
 
@@ -162,6 +176,98 @@ export class ClearingHouseUser {
162
176
  return userAccountRPCResponse.value !== null;
163
177
  }
164
178
 
179
+ /**
180
+ * calculates the market position if the lp position was settled
181
+ * @returns : userPosition
182
+ */
183
+ public getSettledLPPosition(marketIndex: BN): [UserPosition, BN] {
184
+ const position = this.getUserPosition(marketIndex);
185
+ const market = this.clearingHouse.getMarketAccount(position.marketIndex);
186
+ const nShares = position.lpShares;
187
+
188
+ const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
189
+ .sub(position.lastNetBaseAssetAmountPerLp)
190
+ .mul(nShares)
191
+ .div(AMM_RESERVE_PRECISION);
192
+ const deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
193
+ .sub(position.lastNetQuoteAssetAmountPerLp)
194
+ .mul(nShares)
195
+ .div(AMM_RESERVE_PRECISION);
196
+
197
+ function sign(v: BN) {
198
+ const sign = { true: new BN(1), false: new BN(-1) }[
199
+ v.gte(ZERO).toString()
200
+ ];
201
+ return sign;
202
+ }
203
+
204
+ const remainder = deltaBaa
205
+ .abs()
206
+ .mod(market.amm.baseAssetAmountStepSize)
207
+ .mul(sign(deltaBaa));
208
+ const _standardizedBaa = deltaBaa.sub(remainder);
209
+
210
+ let remainderBaa;
211
+ if (_standardizedBaa.abs().gte(market.amm.baseAssetAmountStepSize)) {
212
+ remainderBaa = remainder;
213
+ } else {
214
+ remainderBaa = deltaBaa;
215
+ }
216
+ const standardizedBaa = deltaBaa.sub(remainderBaa);
217
+
218
+ const reaminderPerLP = remainderBaa.mul(AMM_RESERVE_PRECISION).div(nShares);
219
+
220
+ position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
221
+ position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
222
+
223
+ position.lastNetBaseAssetAmountPerLp =
224
+ market.amm.marketPositionPerLp.baseAssetAmount.sub(reaminderPerLP);
225
+
226
+ let updateType;
227
+ if (position.baseAssetAmount.eq(ZERO)) {
228
+ updateType = 'open';
229
+ } else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
230
+ updateType = 'increase';
231
+ } else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
232
+ updateType = 'reduce';
233
+ } else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
234
+ updateType = 'close';
235
+ } else {
236
+ updateType = 'flip';
237
+ }
238
+
239
+ let newQuoteEntry;
240
+ let pnl;
241
+ if (updateType == 'open' || updateType == 'increase') {
242
+ newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
243
+ pnl = 0;
244
+ } else if (updateType == 'reduce' || updateType == 'close') {
245
+ newQuoteEntry = position.quoteEntryAmount.sub(
246
+ position.quoteEntryAmount
247
+ .mul(deltaBaa.abs())
248
+ .div(position.baseAssetAmount.abs())
249
+ );
250
+ pnl = position.quoteEntryAmount.sub(newQuoteEntry);
251
+ } else {
252
+ newQuoteEntry = deltaQaa.sub(
253
+ deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
254
+ );
255
+ pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
256
+ }
257
+ position.quoteEntryAmount = newQuoteEntry;
258
+
259
+ if (position.baseAssetAmount.gt(ZERO)) {
260
+ position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
261
+ } else if (position.baseAssetAmount.lt(ZERO)) {
262
+ position.lastCumulativeFundingRate =
263
+ market.amm.cumulativeFundingRateShort;
264
+ } else {
265
+ position.lastCumulativeFundingRate = ZERO;
266
+ }
267
+
268
+ return [position, pnl];
269
+ }
270
+
165
271
  /**
166
272
  * calculates Buying Power = FC * MAX_LEVERAGE
167
273
  * @returns : Precision QUOTE_PRECISION
@@ -184,81 +290,114 @@ export class ClearingHouseUser {
184
290
  }
185
291
 
186
292
  public getInitialMarginRequirement(): BN {
187
- return this.getUserAccount()
188
- .positions.reduce((marginRequirement, marketPosition) => {
293
+ const postionMarginRequirement = this.getUserAccount().positions.reduce(
294
+ (marginRequirement, marketPosition) => {
189
295
  const market = this.clearingHouse.getMarketAccount(
190
296
  marketPosition.marketIndex
191
297
  );
192
- return marginRequirement.add(
193
- calculateBaseAssetValue(
298
+ const worstCaseBaseAssetAmount =
299
+ calculateWorstCaseBaseAssetAmount(marketPosition);
300
+
301
+ const worstCaseAssetValue = worstCaseBaseAssetAmount
302
+ .abs()
303
+ .mul(this.getOracleDataForMarket(market.marketIndex).price)
304
+ .div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
305
+
306
+ const marketMarginRatio = new BN(
307
+ calculateMarketMarginRatio(
194
308
  market,
195
- marketPosition,
196
- this.getOracleDataForMarket(market.marketIndex)
309
+ worstCaseBaseAssetAmount.abs(),
310
+ 'Initial'
197
311
  )
198
- .mul(new BN(market.marginRatioInitial))
199
- .div(MARGIN_PRECISION)
200
312
  );
201
- }, ZERO)
202
- .add(this.getTotalLiability());
313
+ return marginRequirement.add(
314
+ worstCaseAssetValue.mul(marketMarginRatio).div(MARGIN_PRECISION)
315
+ );
316
+ },
317
+ ZERO
318
+ );
319
+
320
+ const bankMarginRequirement = this.getBankLiabilityValue(
321
+ undefined,
322
+ 'Initial'
323
+ );
324
+
325
+ return bankMarginRequirement.add(postionMarginRequirement);
203
326
  }
204
327
 
205
328
  /**
206
- * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
329
+ * @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
207
330
  */
208
- public getPartialMarginRequirement(): BN {
331
+ public getMaintenanceMarginRequirement(): BN {
209
332
  return this.getUserAccount()
210
333
  .positions.reduce((marginRequirement, marketPosition) => {
211
334
  const market = this.clearingHouse.getMarketAccount(
212
335
  marketPosition.marketIndex
213
336
  );
337
+ const worstCaseBaseAssetAmount =
338
+ calculateWorstCaseBaseAssetAmount(marketPosition);
339
+
340
+ const worstCaseAssetValue = worstCaseBaseAssetAmount
341
+ .abs()
342
+ .mul(this.getOracleDataForMarket(market.marketIndex).price)
343
+ .div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
344
+
214
345
  return marginRequirement.add(
215
- calculateBaseAssetValue(
216
- market,
217
- marketPosition,
218
- this.getOracleDataForMarket(market.marketIndex)
219
- )
220
- .mul(new BN(market.marginRatioPartial))
346
+ worstCaseAssetValue
347
+ .mul(
348
+ new BN(
349
+ calculateMarketMarginRatio(
350
+ market,
351
+ worstCaseBaseAssetAmount.abs(),
352
+ 'Maintenance'
353
+ )
354
+ )
355
+ )
221
356
  .div(MARGIN_PRECISION)
222
357
  );
223
358
  }, ZERO)
224
- .add(this.getTotalLiability());
359
+ .add(this.getBankLiabilityValue(undefined, 'Maintenance'));
225
360
  }
226
361
 
227
362
  /**
228
363
  * calculates unrealized position price pnl
229
364
  * @returns : Precision QUOTE_PRECISION
230
365
  */
231
- public getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN): BN {
366
+ public getUnrealizedPNL(
367
+ withFunding?: boolean,
368
+ marketIndex?: BN,
369
+ withWeightMarginCategory?: MarginCategory
370
+ ): BN {
232
371
  return this.getUserAccount()
233
372
  .positions.filter((pos) =>
234
373
  marketIndex ? pos.marketIndex === marketIndex : true
235
374
  )
236
- .reduce((pnl, marketPosition) => {
375
+ .reduce((unrealizedPnl, marketPosition) => {
237
376
  const market = this.clearingHouse.getMarketAccount(
238
377
  marketPosition.marketIndex
239
378
  );
240
- return pnl.add(
241
- calculatePositionPNL(
242
- market,
243
- marketPosition,
244
- withFunding,
245
- this.getOracleDataForMarket(market.marketIndex)
246
- )
379
+ let positionUnrealizedPnl = calculatePositionPNL(
380
+ market,
381
+ marketPosition,
382
+ withFunding,
383
+ this.getOracleDataForMarket(market.marketIndex)
247
384
  );
248
- }, ZERO);
249
- }
250
385
 
251
- /**
252
- * calculates unrealized position price pnl
253
- * @returns : Precision QUOTE_PRECISION
254
- */
255
- public getUnsettledPNL(marketIndex?: BN): BN {
256
- return this.getUserAccount()
257
- .positions.filter((pos) =>
258
- marketIndex ? pos.marketIndex === marketIndex : true
259
- )
260
- .reduce((pnl, marketPosition) => {
261
- return pnl.add(marketPosition.unsettledPnl);
386
+ if (withWeightMarginCategory !== undefined) {
387
+ if (positionUnrealizedPnl.gt(ZERO)) {
388
+ positionUnrealizedPnl = positionUnrealizedPnl
389
+ .mul(
390
+ calculateUnrealizedAssetWeight(
391
+ market,
392
+ positionUnrealizedPnl,
393
+ withWeightMarginCategory
394
+ )
395
+ )
396
+ .div(new BN(BANK_WEIGHT_PRECISION));
397
+ }
398
+ }
399
+
400
+ return unrealizedPnl.add(positionUnrealizedPnl);
262
401
  }, ZERO);
263
402
  }
264
403
 
@@ -279,14 +418,18 @@ export class ClearingHouseUser {
279
418
  }, ZERO);
280
419
  }
281
420
 
282
- public getTotalLiability(): BN {
421
+ public getBankLiabilityValue(
422
+ bankIndex?: BN,
423
+ withWeightMarginCategory?: MarginCategory
424
+ ): BN {
283
425
  return this.getUserAccount().bankBalances.reduce(
284
- (totalAssetValue, bankBalance) => {
426
+ (totalLiabilityValue, bankBalance) => {
285
427
  if (
286
428
  bankBalance.balance.eq(ZERO) ||
287
- isVariant(bankBalance.balanceType, 'deposit')
429
+ isVariant(bankBalance.balanceType, 'deposit') ||
430
+ (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
288
431
  ) {
289
- return totalAssetValue;
432
+ return totalLiabilityValue;
290
433
  }
291
434
 
292
435
  // Todo this needs to account for whether it's based on initial or maintenance requirements
@@ -299,23 +442,42 @@ export class ClearingHouseUser {
299
442
  bankAccount,
300
443
  bankBalance.balanceType
301
444
  );
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)
308
- );
445
+
446
+ let liabilityValue = tokenAmount
447
+ .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
448
+ .div(MARK_PRICE_PRECISION)
449
+ .div(
450
+ new BN(10).pow(
451
+ new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
452
+ )
453
+ );
454
+
455
+ if (withWeightMarginCategory !== undefined) {
456
+ const weight = calculateLiabilityWeight(
457
+ tokenAmount,
458
+ bankAccount,
459
+ withWeightMarginCategory
460
+ );
461
+ liabilityValue = liabilityValue
462
+ .mul(weight)
463
+ .div(BANK_WEIGHT_PRECISION);
464
+ }
465
+
466
+ return totalLiabilityValue.add(liabilityValue);
309
467
  },
310
468
  ZERO
311
469
  );
312
470
  }
313
471
 
314
- public getCollateralValue(bankIndex?: BN): BN {
472
+ public getBankAssetValue(
473
+ bankIndex?: BN,
474
+ withWeightMarginCategory?: MarginCategory
475
+ ): BN {
315
476
  return this.getUserAccount().bankBalances.reduce(
316
477
  (totalAssetValue, bankBalance) => {
317
478
  if (
318
479
  bankBalance.balance.eq(ZERO) ||
480
+ isVariant(bankBalance.balanceType, 'borrow') ||
319
481
  (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
320
482
  ) {
321
483
  return totalAssetValue;
@@ -326,65 +488,53 @@ export class ClearingHouseUser {
326
488
  bankBalance.bankIndex
327
489
  );
328
490
 
329
- let tokenAmount = getTokenAmount(
491
+ const tokenAmount = getTokenAmount(
330
492
  bankBalance.balance,
331
493
  bankAccount,
332
494
  bankBalance.balanceType
333
495
  );
334
496
 
335
- if (isVariant(bankBalance.balanceType, 'borrow')) {
336
- tokenAmount = tokenAmount.mul(new BN(-1));
497
+ let assetValue = tokenAmount
498
+ .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
499
+ .div(MARK_PRICE_PRECISION)
500
+ .div(
501
+ new BN(10).pow(
502
+ new BN(bankAccount.decimals).sub(BANK_BALANCE_PRECISION_EXP)
503
+ )
504
+ );
505
+ if (withWeightMarginCategory !== undefined) {
506
+ const weight = calculateAssetWeight(
507
+ tokenAmount,
508
+ bankAccount,
509
+ withWeightMarginCategory
510
+ );
511
+ assetValue = assetValue.mul(weight).div(BANK_WEIGHT_PRECISION);
337
512
  }
338
513
 
339
- return totalAssetValue.add(
340
- tokenAmount
341
- .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
342
- .div(MARK_PRICE_PRECISION)
343
- );
514
+ return totalAssetValue.add(assetValue);
344
515
  },
345
516
  ZERO
346
517
  );
347
518
  }
348
519
 
520
+ public getNetBankValue(withWeightMarginCategory?: MarginCategory): BN {
521
+ return this.getBankAssetValue(undefined, withWeightMarginCategory).sub(
522
+ this.getBankLiabilityValue(undefined, withWeightMarginCategory)
523
+ );
524
+ }
525
+
349
526
  /**
350
527
  * calculates TotalCollateral: collateral + unrealized pnl
351
- * TODO: rename to total equity (for perpetuals swaps)
352
528
  * @returns : Precision QUOTE_PRECISION
353
529
  */
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());
530
+ public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
531
+ return this.getBankAssetValue(undefined, marginCategory).add(
532
+ this.getUnrealizedPNL(true, undefined, marginCategory)
533
+ );
384
534
  }
385
535
 
386
536
  /**
387
- * calculates sum of position value across all positions
537
+ * calculates sum of position value across all positions in margin system
388
538
  * @returns : Precision QUOTE_PRECISION
389
539
  */
390
540
  getTotalPositionValue(): BN {
@@ -393,20 +543,20 @@ export class ClearingHouseUser {
393
543
  const market = this.clearingHouse.getMarketAccount(
394
544
  marketPosition.marketIndex
395
545
  );
396
- return positionValue.add(
397
- calculateBaseAssetValue(
398
- market,
399
- marketPosition,
400
- this.getOracleDataForMarket(market.marketIndex)
401
- )
546
+ const posVal = calculateMarginBaseAssetValue(
547
+ market,
548
+ marketPosition,
549
+ this.getOracleDataForMarket(market.marketIndex)
402
550
  );
551
+
552
+ return positionValue.add(posVal);
403
553
  },
404
554
  ZERO
405
555
  );
406
556
  }
407
557
 
408
558
  /**
409
- * calculates position value from closing 100%
559
+ * calculates position value in margin system
410
560
  * @returns : Precision QUOTE_PRECISION
411
561
  */
412
562
  public getPositionValue(
@@ -418,7 +568,7 @@ export class ClearingHouseUser {
418
568
  const market = this.clearingHouse.getMarketAccount(
419
569
  userPosition.marketIndex
420
570
  );
421
- return calculateBaseAssetValue(market, userPosition, oraclePriceData);
571
+ return calculateMarginBaseAssetValue(market, userPosition, oraclePriceData);
422
572
  }
423
573
 
424
574
  public getPositionSide(
@@ -434,12 +584,13 @@ export class ClearingHouseUser {
434
584
  }
435
585
 
436
586
  /**
437
- * calculates average exit price for closing 100% of position
587
+ * calculates average exit price (optionally for closing up to 100% of position)
438
588
  * @returns : Precision MARK_PRICE_PRECISION
439
589
  */
440
590
  public getPositionEstimatedExitPriceAndPnl(
441
591
  position: UserPosition,
442
- amountToClose?: BN
592
+ amountToClose?: BN,
593
+ useAMMClose = false
443
594
  ): [BN, BN] {
444
595
  const market = this.clearingHouse.getMarketAccount(position.marketIndex);
445
596
 
@@ -459,11 +610,21 @@ export class ClearingHouseUser {
459
610
  } as UserPosition;
460
611
  }
461
612
 
462
- const baseAssetValue = calculateBaseAssetValue(
463
- market,
464
- position,
465
- oraclePriceData
466
- );
613
+ let baseAssetValue: BN;
614
+
615
+ if (useAMMClose) {
616
+ baseAssetValue = calculateBaseAssetValue(
617
+ market,
618
+ position,
619
+ oraclePriceData
620
+ );
621
+ } else {
622
+ baseAssetValue = calculateMarginBaseAssetValue(
623
+ market,
624
+ position,
625
+ oraclePriceData
626
+ );
627
+ }
467
628
  if (position.baseAssetAmount.eq(ZERO)) {
468
629
  return [ZERO, ZERO];
469
630
  }
@@ -505,22 +666,13 @@ export class ClearingHouseUser {
505
666
  category: MarginCategory = 'Initial'
506
667
  ): BN {
507
668
  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
- }
669
+
670
+ const marginRatioCategory = calculateMarketMarginRatio(
671
+ market,
672
+ // worstCaseBaseAssetAmount.abs(),
673
+ ZERO, // todo
674
+ category
675
+ );
524
676
  const maxLeverage = TEN_THOUSAND.mul(TEN_THOUSAND).div(
525
677
  new BN(marginRatioCategory)
526
678
  );
@@ -543,7 +695,8 @@ export class ClearingHouseUser {
543
695
 
544
696
  public canBeLiquidated(): [boolean, BN] {
545
697
  const totalCollateral = this.getTotalCollateral();
546
- const partialMaintenanceRequirement = this.getPartialMarginRequirement();
698
+ const partialMaintenanceRequirement =
699
+ this.getMaintenanceMarginRequirement();
547
700
  const marginRatio = this.getMarginRatio();
548
701
  const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
549
702
  return [canLiquidate, marginRatio];
@@ -587,8 +740,7 @@ export class ClearingHouseUser {
587
740
  */
588
741
  public liquidationPrice(
589
742
  marketPosition: Pick<UserPosition, 'marketIndex'>,
590
- positionBaseSizeChange: BN = ZERO,
591
- partial = false
743
+ positionBaseSizeChange: BN = ZERO
592
744
  ): BN {
593
745
  // solves formula for example canBeLiquidated below
594
746
 
@@ -622,14 +774,17 @@ export class ClearingHouseUser {
622
774
  const proposedMarketPosition: UserPosition = {
623
775
  marketIndex: marketPosition.marketIndex,
624
776
  baseAssetAmount: proposedBaseAssetAmount,
625
- lastCumulativeFundingRate:
626
- currentMarketPosition.lastCumulativeFundingRate,
627
777
  quoteAssetAmount: new BN(0),
778
+ lastCumulativeFundingRate: ZERO,
628
779
  quoteEntryAmount: new BN(0),
629
780
  openOrders: new BN(0),
630
- unsettledPnl: new BN(0),
631
781
  openBids: new BN(0),
632
782
  openAsks: new BN(0),
783
+ realizedPnl: ZERO,
784
+ lpShares: ZERO,
785
+ lastFeePerLp: ZERO,
786
+ lastNetBaseAssetAmountPerLp: ZERO,
787
+ lastNetQuoteAssetAmountPerLp: ZERO,
633
788
  };
634
789
 
635
790
  if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
@@ -638,7 +793,7 @@ export class ClearingHouseUser {
638
793
  proposedMarketPosition.marketIndex
639
794
  );
640
795
 
641
- const proposedMarketPositionValue = calculateBaseAssetValue(
796
+ const proposedMarketPositionValue = calculateMarginBaseAssetValue(
642
797
  market,
643
798
  proposedMarketPosition,
644
799
  this.getOracleDataForMarket(market.marketIndex)
@@ -655,16 +810,20 @@ export class ClearingHouseUser {
655
810
  const market = this.clearingHouse.getMarketAccount(
656
811
  position.marketIndex
657
812
  );
658
- const positionValue = calculateBaseAssetValue(
813
+ const positionValue = calculateMarginBaseAssetValue(
659
814
  market,
660
815
  position,
661
816
  this.getOracleDataForMarket(market.marketIndex)
662
817
  );
663
818
  const marketMarginRequirement = positionValue
664
819
  .mul(
665
- partial
666
- ? new BN(market.marginRatioPartial)
667
- : new BN(market.marginRatioMaintenance)
820
+ new BN(
821
+ calculateMarketMarginRatio(
822
+ market,
823
+ position.baseAssetAmount.abs(),
824
+ 'Maintenance'
825
+ )
826
+ )
668
827
  )
669
828
  .div(MARGIN_PRECISION);
670
829
  totalMarginRequirement = totalMarginRequirement.add(
@@ -692,9 +851,13 @@ export class ClearingHouseUser {
692
851
  marginRequirementExcludingTargetMarket.add(
693
852
  proposedMarketPositionValue
694
853
  .mul(
695
- partial
696
- ? new BN(market.marginRatioPartial)
697
- : new BN(market.marginRatioMaintenance)
854
+ new BN(
855
+ calculateMarketMarginRatio(
856
+ market,
857
+ proposedMarketPosition.baseAssetAmount.abs(),
858
+ 'Maintenance'
859
+ )
860
+ )
698
861
  )
699
862
  .div(MARGIN_PRECISION)
700
863
  );
@@ -702,9 +865,10 @@ export class ClearingHouseUser {
702
865
  marginRequirementAfterTrade
703
866
  );
704
867
 
705
- const marketMaxLeverage = partial
706
- ? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
707
- : this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
868
+ const marketMaxLeverage = this.getMaxLeverage(
869
+ proposedMarketPosition.marketIndex,
870
+ 'Maintenance'
871
+ );
708
872
 
709
873
  let priceDelta;
710
874
  if (proposedBaseAssetAmount.lt(ZERO)) {
@@ -765,11 +929,11 @@ export class ClearingHouseUser {
765
929
 
766
930
  const closeBaseAmount = currentPosition.baseAssetAmount
767
931
  .mul(closeQuoteAmount)
768
- .div(currentPosition.quoteAssetAmount)
932
+ .div(currentPosition.quoteAssetAmount.abs())
769
933
  .add(
770
934
  currentPosition.baseAssetAmount
771
935
  .mul(closeQuoteAmount)
772
- .mod(currentPosition.quoteAssetAmount)
936
+ .mod(currentPosition.quoteAssetAmount.abs())
773
937
  )
774
938
  .neg();
775
939
 
@@ -777,8 +941,7 @@ export class ClearingHouseUser {
777
941
  {
778
942
  marketIndex: positionMarketIndex,
779
943
  },
780
- closeBaseAmount,
781
- true
944
+ closeBaseAmount
782
945
  );
783
946
  }
784
947