@drift-labs/sdk 0.2.0-master.10 → 0.2.0-master.13

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 (82) hide show
  1. package/lib/admin.d.ts +3 -3
  2. package/lib/admin.js +6 -6
  3. package/lib/clearingHouse.d.ts +22 -6
  4. package/lib/clearingHouse.js +357 -74
  5. package/lib/clearingHouseUser.d.ts +12 -17
  6. package/lib/clearingHouseUser.js +97 -88
  7. package/lib/config.js +1 -1
  8. package/lib/constants/banks.d.ts +2 -2
  9. package/lib/constants/banks.js +5 -4
  10. package/lib/constants/numericConstants.d.ts +3 -0
  11. package/lib/constants/numericConstants.js +4 -1
  12. package/lib/events/eventList.js +3 -0
  13. package/lib/events/types.d.ts +2 -1
  14. package/lib/factory/bigNum.d.ts +1 -0
  15. package/lib/factory/bigNum.js +37 -11
  16. package/lib/idl/clearing_house.json +611 -146
  17. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  18. package/lib/index.d.ts +2 -1
  19. package/lib/index.js +2 -1
  20. package/lib/math/amm.js +2 -2
  21. package/lib/math/bankBalance.d.ts +3 -1
  22. package/lib/math/bankBalance.js +54 -1
  23. package/lib/math/margin.d.ts +11 -0
  24. package/lib/math/margin.js +72 -0
  25. package/lib/math/market.d.ts +4 -1
  26. package/lib/math/market.js +35 -1
  27. package/lib/math/position.d.ts +8 -0
  28. package/lib/math/position.js +42 -12
  29. package/lib/orders.d.ts +1 -2
  30. package/lib/orders.js +2 -77
  31. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  32. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  33. package/lib/tx/retryTxSender.js +9 -2
  34. package/lib/types.d.ts +86 -16
  35. package/lib/types.js +18 -1
  36. package/lib/util/computeUnits.js +1 -1
  37. package/lib/util/getTokenAddress.d.ts +2 -0
  38. package/lib/util/getTokenAddress.js +9 -0
  39. package/package.json +1 -1
  40. package/src/admin.ts +7 -7
  41. package/src/clearingHouse.ts +636 -94
  42. package/src/clearingHouseConfig.js +2 -0
  43. package/src/clearingHouseUser.ts +219 -121
  44. package/src/clearingHouseUserConfig.js +2 -0
  45. package/src/config.ts +1 -1
  46. package/src/constants/banks.js +42 -0
  47. package/src/constants/banks.ts +7 -4
  48. package/src/constants/markets.js +42 -0
  49. package/src/constants/numericConstants.js +41 -0
  50. package/src/constants/numericConstants.ts +4 -0
  51. package/src/events/eventList.ts +3 -0
  52. package/src/events/types.ts +2 -0
  53. package/src/factory/bigNum.js +37 -11
  54. package/src/factory/bigNum.ts +43 -13
  55. package/src/idl/clearing_house.json +611 -146
  56. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  57. package/src/index.js +1 -1
  58. package/src/index.ts +2 -1
  59. package/src/math/amm.ts +8 -5
  60. package/src/math/bankBalance.ts +98 -1
  61. package/src/math/margin.ts +124 -0
  62. package/src/math/market.ts +66 -1
  63. package/src/math/position.ts +59 -9
  64. package/src/mockUSDCFaucet.js +276 -167
  65. package/src/orders.ts +4 -157
  66. package/src/tokenFaucet.js +189 -0
  67. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  68. package/src/tx/retryTxSender.ts +11 -3
  69. package/src/types.js +12 -1
  70. package/src/types.ts +88 -16
  71. package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
  72. package/src/util/computeUnits.ts +1 -1
  73. package/src/util/getTokenAddress.js +9 -0
  74. package/src/util/getTokenAddress.ts +18 -0
  75. package/tests/bn/test.ts +2 -0
  76. package/src/addresses/pda.js +0 -104
  77. package/src/math/bankBalance.js +0 -75
  78. package/src/math/market.js +0 -57
  79. package/src/math/orders.js +0 -110
  80. package/src/math/position.js +0 -140
  81. package/src/orders.js +0 -134
  82. package/src/tx/retryTxSender.js +0 -188
@@ -6,6 +6,7 @@ const position_1 = require("./math/position");
6
6
  const numericConstants_1 = require("./constants/numericConstants");
7
7
  const _1 = require(".");
8
8
  const bankBalance_1 = require("./math/bankBalance");
9
+ const margin_1 = require("./math/margin");
9
10
  const pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSubscriber");
10
11
  const webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
11
12
  class ClearingHouseUser {
@@ -68,7 +69,6 @@ class ClearingHouseUser {
68
69
  quoteAssetAmount: numericConstants_1.ZERO,
69
70
  quoteEntryAmount: numericConstants_1.ZERO,
70
71
  openOrders: numericConstants_1.ZERO,
71
- unsettledPnl: numericConstants_1.ZERO,
72
72
  openBids: numericConstants_1.ZERO,
73
73
  openAsks: numericConstants_1.ZERO,
74
74
  };
@@ -114,49 +114,55 @@ class ClearingHouseUser {
114
114
  return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
115
115
  }
116
116
  getInitialMarginRequirement() {
117
- return this.getUserAccount()
118
- .positions.reduce((marginRequirement, marketPosition) => {
117
+ const postionMarginRequirement = this.getUserAccount().positions.reduce((marginRequirement, marketPosition) => {
119
118
  const market = this.clearingHouse.getMarketAccount(marketPosition.marketIndex);
120
- return marginRequirement.add((0, _1.calculateBaseAssetValue)(market, marketPosition, this.getOracleDataForMarket(market.marketIndex))
121
- .mul(new _1.BN(market.marginRatioInitial))
122
- .div(numericConstants_1.MARGIN_PRECISION));
123
- }, numericConstants_1.ZERO)
124
- .add(this.getTotalLiability());
119
+ const worstCaseBaseAssetAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(marketPosition);
120
+ const worstCaseAssetValue = worstCaseBaseAssetAmount
121
+ .abs()
122
+ .mul(this.getOracleDataForMarket(market.marketIndex).price)
123
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.MARK_PRICE_PRECISION));
124
+ const marketMarginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(market, worstCaseBaseAssetAmount.abs(), 'Initial'));
125
+ return marginRequirement.add(worstCaseAssetValue.mul(marketMarginRatio).div(numericConstants_1.MARGIN_PRECISION));
126
+ }, numericConstants_1.ZERO);
127
+ const bankMarginRequirement = this.getBankLiabilityValue(undefined, 'Initial');
128
+ return bankMarginRequirement.add(postionMarginRequirement);
125
129
  }
126
130
  /**
127
- * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
131
+ * @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
128
132
  */
129
- getPartialMarginRequirement() {
133
+ getMaintenanceMarginRequirement() {
130
134
  return this.getUserAccount()
131
135
  .positions.reduce((marginRequirement, marketPosition) => {
132
136
  const market = this.clearingHouse.getMarketAccount(marketPosition.marketIndex);
133
- return marginRequirement.add((0, _1.calculateBaseAssetValue)(market, marketPosition, this.getOracleDataForMarket(market.marketIndex))
134
- .mul(new _1.BN(market.marginRatioPartial))
137
+ const worstCaseBaseAssetAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(marketPosition);
138
+ const worstCaseAssetValue = worstCaseBaseAssetAmount
139
+ .abs()
140
+ .mul(this.getOracleDataForMarket(market.marketIndex).price)
141
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.MARK_PRICE_PRECISION));
142
+ return marginRequirement.add(worstCaseAssetValue
143
+ .mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, worstCaseBaseAssetAmount.abs(), 'Maintenance')))
135
144
  .div(numericConstants_1.MARGIN_PRECISION));
136
145
  }, numericConstants_1.ZERO)
137
- .add(this.getTotalLiability());
146
+ .add(this.getBankLiabilityValue(undefined, 'Maintenance'));
138
147
  }
139
148
  /**
140
149
  * calculates unrealized position price pnl
141
150
  * @returns : Precision QUOTE_PRECISION
142
151
  */
143
- getUnrealizedPNL(withFunding, marketIndex) {
152
+ getUnrealizedPNL(withFunding, marketIndex, withWeightMarginCategory) {
144
153
  return this.getUserAccount()
145
154
  .positions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
146
155
  .reduce((pnl, marketPosition) => {
147
156
  const market = this.clearingHouse.getMarketAccount(marketPosition.marketIndex);
148
- return pnl.add((0, _1.calculatePositionPNL)(market, marketPosition, withFunding, this.getOracleDataForMarket(market.marketIndex)));
149
- }, numericConstants_1.ZERO);
150
- }
151
- /**
152
- * calculates unrealized position price pnl
153
- * @returns : Precision QUOTE_PRECISION
154
- */
155
- getUnsettledPNL(marketIndex) {
156
- return this.getUserAccount()
157
- .positions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
158
- .reduce((pnl, marketPosition) => {
159
- return pnl.add(marketPosition.unsettledPnl);
157
+ let pnl0 = (0, _1.calculatePositionPNL)(market, marketPosition, withFunding, this.getOracleDataForMarket(market.marketIndex));
158
+ if (withWeightMarginCategory !== undefined) {
159
+ if (pnl0.gt(numericConstants_1.ZERO)) {
160
+ pnl0 = pnl0
161
+ .mul((0, _1.calculateUnsettledAssetWeight)(market, pnl0, withWeightMarginCategory))
162
+ .div(new _1.BN(numericConstants_1.BANK_WEIGHT_PRECISION));
163
+ }
164
+ }
165
+ return pnl.add(pnl0);
160
166
  }, numericConstants_1.ZERO);
161
167
  }
162
168
  /**
@@ -171,45 +177,58 @@ class ClearingHouseUser {
171
177
  return pnl.add((0, _1.calculatePositionFundingPNL)(market, marketPosition));
172
178
  }, numericConstants_1.ZERO);
173
179
  }
174
- getTotalLiability() {
175
- return this.getUserAccount().bankBalances.reduce((totalAssetValue, bankBalance) => {
180
+ getBankLiabilityValue(bankIndex, withWeightMarginCategory) {
181
+ return this.getUserAccount().bankBalances.reduce((totalLiabilityValue, bankBalance) => {
176
182
  if (bankBalance.balance.eq(numericConstants_1.ZERO) ||
177
- (0, types_1.isVariant)(bankBalance.balanceType, 'deposit')) {
178
- return totalAssetValue;
183
+ (0, types_1.isVariant)(bankBalance.balanceType, 'deposit') ||
184
+ (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))) {
185
+ return totalLiabilityValue;
179
186
  }
180
187
  // Todo this needs to account for whether it's based on initial or maintenance requirements
181
188
  const bankAccount = this.clearingHouse.getBankAccount(bankBalance.bankIndex);
182
189
  const tokenAmount = (0, bankBalance_1.getTokenAmount)(bankBalance.balance, bankAccount, bankBalance.balanceType);
183
- return totalAssetValue.add(tokenAmount
190
+ let liabilityValue = tokenAmount
184
191
  .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
185
- .mul(bankAccount.initialLiabilityWeight)
186
- .div(numericConstants_1.BANK_WEIGHT_PRECISION)
187
- .div(numericConstants_1.MARK_PRICE_PRECISION));
192
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
193
+ .div(new _1.BN(10).pow(new _1.BN(bankAccount.decimals).sub(numericConstants_1.BANK_BALANCE_PRECISION_EXP)));
194
+ if (withWeightMarginCategory !== undefined) {
195
+ const weight = (0, bankBalance_1.calculateLiabilityWeight)(tokenAmount, bankAccount, withWeightMarginCategory);
196
+ liabilityValue = liabilityValue
197
+ .mul(weight)
198
+ .div(numericConstants_1.BANK_WEIGHT_PRECISION);
199
+ }
200
+ return totalLiabilityValue.add(liabilityValue);
188
201
  }, numericConstants_1.ZERO);
189
202
  }
190
- getCollateralValue(bankIndex) {
203
+ getBankAssetValue(bankIndex, withWeightMarginCategory) {
191
204
  return this.getUserAccount().bankBalances.reduce((totalAssetValue, bankBalance) => {
192
205
  if (bankBalance.balance.eq(numericConstants_1.ZERO) ||
206
+ (0, types_1.isVariant)(bankBalance.balanceType, 'borrow') ||
193
207
  (bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))) {
194
208
  return totalAssetValue;
195
209
  }
196
210
  // Todo this needs to account for whether it's based on initial or maintenance requirements
197
211
  const bankAccount = this.clearingHouse.getBankAccount(bankBalance.bankIndex);
198
- let tokenAmount = (0, bankBalance_1.getTokenAmount)(bankBalance.balance, bankAccount, bankBalance.balanceType);
199
- if ((0, types_1.isVariant)(bankBalance.balanceType, 'borrow')) {
200
- tokenAmount = tokenAmount.mul(new _1.BN(-1));
201
- }
202
- return totalAssetValue.add(tokenAmount
212
+ const tokenAmount = (0, bankBalance_1.getTokenAmount)(bankBalance.balance, bankAccount, bankBalance.balanceType);
213
+ let assetValue = tokenAmount
203
214
  .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
204
- .div(numericConstants_1.MARK_PRICE_PRECISION));
215
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
216
+ .div(new _1.BN(10).pow(new _1.BN(bankAccount.decimals).sub(numericConstants_1.BANK_BALANCE_PRECISION_EXP)));
217
+ if (withWeightMarginCategory !== undefined) {
218
+ const weight = (0, bankBalance_1.calculateAssetWeight)(tokenAmount, bankAccount, withWeightMarginCategory);
219
+ assetValue = assetValue.mul(weight).div(numericConstants_1.BANK_WEIGHT_PRECISION);
220
+ }
221
+ return totalAssetValue.add(assetValue);
205
222
  }, numericConstants_1.ZERO);
206
223
  }
224
+ getNetBankValue(withWeightMarginCategory) {
225
+ return this.getBankAssetValue(undefined, withWeightMarginCategory).sub(this.getBankLiabilityValue(undefined, withWeightMarginCategory));
226
+ }
207
227
  /**
208
228
  * calculates TotalCollateral: collateral + unrealized pnl
209
- * TODO: rename to total equity (for perpetuals swaps)
210
229
  * @returns : Precision QUOTE_PRECISION
211
230
  */
212
- getTotalCollateral() {
231
+ getTotalCollateral(marginCategory = 'Initial') {
213
232
  return this.getUserAccount()
214
233
  .bankBalances.reduce((totalAssetValue, bankBalance) => {
215
234
  if (bankBalance.balance.eq(numericConstants_1.ZERO) ||
@@ -219,33 +238,36 @@ class ClearingHouseUser {
219
238
  // Todo this needs to account for whether it's based on initial or maintenance requirements
220
239
  const bankAccount = this.clearingHouse.getBankAccount(bankBalance.bankIndex);
221
240
  const tokenAmount = (0, bankBalance_1.getTokenAmount)(bankBalance.balance, bankAccount, bankBalance.balanceType);
241
+ const weight = (0, bankBalance_1.calculateAssetWeight)(tokenAmount, bankAccount, marginCategory);
222
242
  return totalAssetValue.add(tokenAmount
223
243
  .mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
224
- .mul(bankAccount.initialAssetWeight)
244
+ .mul(weight)
225
245
  .div(numericConstants_1.BANK_WEIGHT_PRECISION)
226
- .div(numericConstants_1.MARK_PRICE_PRECISION));
246
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
247
+ // Adjust for decimals of bank account
248
+ .div(new _1.BN(10).pow(new _1.BN(bankAccount.decimals).sub(numericConstants_1.BANK_BALANCE_PRECISION_EXP))));
227
249
  }, numericConstants_1.ZERO)
228
- .add(this.getUnrealizedPNL(true))
229
- .add(this.getUnsettledPNL());
250
+ .add(this.getUnrealizedPNL(true, undefined, marginCategory));
230
251
  }
231
252
  /**
232
- * calculates sum of position value across all positions
253
+ * calculates sum of position value across all positions in margin system
233
254
  * @returns : Precision QUOTE_PRECISION
234
255
  */
235
256
  getTotalPositionValue() {
236
257
  return this.getUserAccount().positions.reduce((positionValue, marketPosition) => {
237
258
  const market = this.clearingHouse.getMarketAccount(marketPosition.marketIndex);
238
- return positionValue.add((0, _1.calculateBaseAssetValue)(market, marketPosition, this.getOracleDataForMarket(market.marketIndex)));
259
+ const posVal = (0, margin_1.calculateMarginBaseAssetValue)(market, marketPosition, this.getOracleDataForMarket(market.marketIndex));
260
+ return positionValue.add(posVal);
239
261
  }, numericConstants_1.ZERO);
240
262
  }
241
263
  /**
242
- * calculates position value from closing 100%
264
+ * calculates position value in margin system
243
265
  * @returns : Precision QUOTE_PRECISION
244
266
  */
245
267
  getPositionValue(marketIndex, oraclePriceData) {
246
268
  const userPosition = this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
247
269
  const market = this.clearingHouse.getMarketAccount(userPosition.marketIndex);
248
- return (0, _1.calculateBaseAssetValue)(market, userPosition, oraclePriceData);
270
+ return (0, margin_1.calculateMarginBaseAssetValue)(market, userPosition, oraclePriceData);
249
271
  }
250
272
  getPositionSide(currentPosition) {
251
273
  if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
@@ -259,10 +281,10 @@ class ClearingHouseUser {
259
281
  }
260
282
  }
261
283
  /**
262
- * calculates average exit price for closing 100% of position
284
+ * calculates average exit price (optionally for closing up to 100% of position)
263
285
  * @returns : Precision MARK_PRICE_PRECISION
264
286
  */
265
- getPositionEstimatedExitPriceAndPnl(position, amountToClose) {
287
+ getPositionEstimatedExitPriceAndPnl(position, amountToClose, useAMMClose = false) {
266
288
  const market = this.clearingHouse.getMarketAccount(position.marketIndex);
267
289
  const entryPrice = (0, position_1.calculateEntryPrice)(position);
268
290
  const oraclePriceData = this.getOracleDataForMarket(position.marketIndex);
@@ -277,7 +299,13 @@ class ClearingHouseUser {
277
299
  quoteAssetAmount: position.quoteAssetAmount,
278
300
  };
279
301
  }
280
- const baseAssetValue = (0, _1.calculateBaseAssetValue)(market, position, oraclePriceData);
302
+ let baseAssetValue;
303
+ if (useAMMClose) {
304
+ baseAssetValue = (0, _1.calculateBaseAssetValue)(market, position, oraclePriceData);
305
+ }
306
+ else {
307
+ baseAssetValue = (0, margin_1.calculateMarginBaseAssetValue)(market, position, oraclePriceData);
308
+ }
281
309
  if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
282
310
  return [numericConstants_1.ZERO, numericConstants_1.ZERO];
283
311
  }
@@ -311,21 +339,10 @@ class ClearingHouseUser {
311
339
  */
312
340
  getMaxLeverage(marketIndex, category = 'Initial') {
313
341
  const market = this.clearingHouse.getMarketAccount(marketIndex);
314
- let marginRatioCategory;
315
- switch (category) {
316
- case 'Initial':
317
- marginRatioCategory = market.marginRatioInitial;
318
- break;
319
- case 'Maintenance':
320
- marginRatioCategory = market.marginRatioMaintenance;
321
- break;
322
- case 'Partial':
323
- marginRatioCategory = market.marginRatioPartial;
324
- break;
325
- default:
326
- marginRatioCategory = market.marginRatioInitial;
327
- break;
328
- }
342
+ const marginRatioCategory = (0, _1.calculateMarketMarginRatio)(market,
343
+ // worstCaseBaseAssetAmount.abs(),
344
+ numericConstants_1.ZERO, // todo
345
+ category);
329
346
  const maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(new _1.BN(marginRatioCategory));
330
347
  return maxLeverage;
331
348
  }
@@ -342,7 +359,7 @@ class ClearingHouseUser {
342
359
  }
343
360
  canBeLiquidated() {
344
361
  const totalCollateral = this.getTotalCollateral();
345
- const partialMaintenanceRequirement = this.getPartialMarginRequirement();
362
+ const partialMaintenanceRequirement = this.getMaintenanceMarginRequirement();
346
363
  const marginRatio = this.getMarginRatio();
347
364
  const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
348
365
  return [canLiquidate, marginRatio];
@@ -372,7 +389,7 @@ class ClearingHouseUser {
372
389
  * @param partial
373
390
  * @returns Precision : MARK_PRICE_PRECISION
374
391
  */
375
- liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
392
+ liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO) {
376
393
  // solves formula for example canBeLiquidated below
377
394
  /* example: assume BTC price is $40k (examine 10% up/down)
378
395
 
@@ -398,25 +415,21 @@ class ClearingHouseUser {
398
415
  quoteAssetAmount: new _1.BN(0),
399
416
  quoteEntryAmount: new _1.BN(0),
400
417
  openOrders: new _1.BN(0),
401
- unsettledPnl: new _1.BN(0),
402
418
  openBids: new _1.BN(0),
403
419
  openAsks: new _1.BN(0),
404
420
  };
405
421
  if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
406
422
  return new _1.BN(-1);
407
423
  const market = this.clearingHouse.getMarketAccount(proposedMarketPosition.marketIndex);
408
- const proposedMarketPositionValue = (0, _1.calculateBaseAssetValue)(market, proposedMarketPosition, this.getOracleDataForMarket(market.marketIndex));
424
+ const proposedMarketPositionValue = (0, margin_1.calculateMarginBaseAssetValue)(market, proposedMarketPosition, this.getOracleDataForMarket(market.marketIndex));
409
425
  // total position value after trade
410
426
  const totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
411
427
  const marginRequirementExcludingTargetMarket = this.getUserAccount().positions.reduce((totalMarginRequirement, position) => {
412
428
  if (!position.marketIndex.eq(marketPosition.marketIndex)) {
413
429
  const market = this.clearingHouse.getMarketAccount(position.marketIndex);
414
- const positionValue = (0, _1.calculateBaseAssetValue)(market, position, this.getOracleDataForMarket(market.marketIndex));
415
- const marketMarginRequirement = positionValue
416
- .mul(partial
417
- ? new _1.BN(market.marginRatioPartial)
418
- : new _1.BN(market.marginRatioMaintenance))
419
- .div(numericConstants_1.MARGIN_PRECISION);
430
+ const positionValue = (0, margin_1.calculateMarginBaseAssetValue)(market, position, this.getOracleDataForMarket(market.marketIndex));
431
+ const marketMarginRequirement = positionValue;
432
+ new _1.BN((0, _1.calculateMarketMarginRatio)(market, position.baseAssetAmount.abs(), 'Maintenance')).div(numericConstants_1.MARGIN_PRECISION);
420
433
  totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
421
434
  }
422
435
  return totalMarginRequirement;
@@ -428,14 +441,10 @@ class ClearingHouseUser {
428
441
  return new _1.BN(-1);
429
442
  }
430
443
  const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedMarketPositionValue
431
- .mul(partial
432
- ? new _1.BN(market.marginRatioPartial)
433
- : new _1.BN(market.marginRatioMaintenance))
444
+ .mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, proposedMarketPosition.baseAssetAmount.abs(), 'Maintenance')))
434
445
  .div(numericConstants_1.MARGIN_PRECISION));
435
446
  const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
436
- const marketMaxLeverage = partial
437
- ? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
438
- : this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
447
+ const marketMaxLeverage = this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
439
448
  let priceDelta;
440
449
  if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
441
450
  priceDelta = freeCollateralAfterTrade
@@ -479,14 +488,14 @@ class ClearingHouseUser {
479
488
  this.getEmptyPosition(positionMarketIndex);
480
489
  const closeBaseAmount = currentPosition.baseAssetAmount
481
490
  .mul(closeQuoteAmount)
482
- .div(currentPosition.quoteAssetAmount)
491
+ .div(currentPosition.quoteAssetAmount.abs())
483
492
  .add(currentPosition.baseAssetAmount
484
493
  .mul(closeQuoteAmount)
485
- .mod(currentPosition.quoteAssetAmount))
494
+ .mod(currentPosition.quoteAssetAmount.abs()))
486
495
  .neg();
487
496
  return this.liquidationPrice({
488
497
  marketIndex: positionMarketIndex,
489
- }, closeBaseAmount, true);
498
+ }, closeBaseAmount);
490
499
  }
491
500
  /**
492
501
  * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
package/lib/config.js CHANGED
@@ -7,7 +7,7 @@ exports.configs = {
7
7
  devnet: {
8
8
  ENV: 'devnet',
9
9
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
10
- CLEARING_HOUSE_PROGRAM_ID: 'BMow898PH56jD8z4EaqxicoGXkR1HhN17qrER6Uc4AYq',
10
+ CLEARING_HOUSE_PROGRAM_ID: '7HDuhZ94TVTWpH3vba3dJhGWyHvQuy2zBjniRxE7PU88',
11
11
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
12
12
  MARKETS: markets_1.DevnetMarkets,
13
13
  BANKS: banks_1.DevnetBanks,
@@ -1,7 +1,6 @@
1
1
  /// <reference types="bn.js" />
2
- import { BN, OracleSource } from '../';
3
- import { DriftEnv } from '../';
4
2
  import { PublicKey } from '@solana/web3.js';
3
+ import { BN, DriftEnv, OracleSource } from '../';
5
4
  export declare type BankConfig = {
6
5
  symbol: string;
7
6
  bankIndex: BN;
@@ -9,6 +8,7 @@ export declare type BankConfig = {
9
8
  mint: PublicKey;
10
9
  oracleSource: OracleSource;
11
10
  };
11
+ export declare const WRAPPED_SOL_MINT: PublicKey;
12
12
  export declare const DevnetBanks: BankConfig[];
13
13
  export declare const MainnetBanks: BankConfig[];
14
14
  export declare const Banks: {
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Banks = exports.MainnetBanks = exports.DevnetBanks = void 0;
4
- const __1 = require("../");
3
+ exports.Banks = exports.MainnetBanks = exports.DevnetBanks = exports.WRAPPED_SOL_MINT = void 0;
5
4
  const web3_js_1 = require("@solana/web3.js");
5
+ const __1 = require("../");
6
+ exports.WRAPPED_SOL_MINT = new web3_js_1.PublicKey('So11111111111111111111111111111111111111112');
6
7
  exports.DevnetBanks = [
7
8
  {
8
9
  symbol: 'USDC',
@@ -16,14 +17,14 @@ exports.DevnetBanks = [
16
17
  bankIndex: new __1.BN(1),
17
18
  oracle: new web3_js_1.PublicKey('J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'),
18
19
  oracleSource: __1.OracleSource.PYTH,
19
- mint: new web3_js_1.PublicKey('So11111111111111111111111111111111111111112'),
20
+ mint: new web3_js_1.PublicKey(exports.WRAPPED_SOL_MINT),
20
21
  },
21
22
  {
22
23
  symbol: 'BTC',
23
24
  bankIndex: new __1.BN(2),
24
25
  oracle: new web3_js_1.PublicKey('HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'),
25
26
  oracleSource: __1.OracleSource.PYTH,
26
- mint: new web3_js_1.PublicKey('Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr'),
27
+ mint: new web3_js_1.PublicKey('3BZPwbcqB5kKScF3TEXxwNfx5ipV13kbRVDvfVp5c6fv'),
27
28
  },
28
29
  ];
29
30
  exports.MainnetBanks = [
@@ -21,6 +21,9 @@ export declare const BANK_RATE_PRECISION: BN;
21
21
  export declare const BANK_WEIGHT_PRECISION: BN;
22
22
  export declare const BANK_BALANCE_PRECISION_EXP: BN;
23
23
  export declare const BANK_BALANCE_PRECISION: BN;
24
+ export declare const BANK_IMF_PRECISION_EXP: BN;
25
+ export declare const BANK_IMF_PRECISION: BN;
26
+ export declare const LIQUIDATION_FEE_PRECISION: BN;
24
27
  export declare const QUOTE_PRECISION: BN;
25
28
  export declare const MARK_PRICE_PRECISION: BN;
26
29
  export declare const FUNDING_PAYMENT_PRECISION: BN;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QUOTE_ASSET_BANK_INDEX = exports.ONE_YEAR = exports.BID_ASK_SPREAD_PRECISION = exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.PRICE_DIV_PEG = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION_EXP = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_PAYMENT_PRECISION = exports.MARK_PRICE_PRECISION = exports.QUOTE_PRECISION = exports.BANK_BALANCE_PRECISION = exports.BANK_BALANCE_PRECISION_EXP = exports.BANK_WEIGHT_PRECISION = exports.BANK_RATE_PRECISION = exports.BANK_UTILIZATION_PRECISION = exports.BANK_CUMULATIVE_INTEREST_PRECISION = exports.BANK_INTEREST_PRECISION = exports.AMM_RESERVE_PRECISION_EXP = exports.PEG_PRECISION_EXP = exports.FUNDING_RATE_PRECISION_EXP = exports.MARK_PRICE_PRECISION_EXP = exports.FUNDING_PAYMENT_PRECISION_EXP = exports.QUOTE_PRECISION_EXP = exports.MAX_LEVERAGE = exports.TEN_MILLION = exports.BN_MAX = exports.TEN_THOUSAND = exports.TEN = exports.TWO = exports.ONE = exports.ZERO = void 0;
3
+ exports.QUOTE_ASSET_BANK_INDEX = exports.ONE_YEAR = exports.BID_ASK_SPREAD_PRECISION = exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.PRICE_DIV_PEG = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION_EXP = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_PAYMENT_PRECISION = exports.MARK_PRICE_PRECISION = exports.QUOTE_PRECISION = exports.LIQUIDATION_FEE_PRECISION = exports.BANK_IMF_PRECISION = exports.BANK_IMF_PRECISION_EXP = exports.BANK_BALANCE_PRECISION = exports.BANK_BALANCE_PRECISION_EXP = exports.BANK_WEIGHT_PRECISION = exports.BANK_RATE_PRECISION = exports.BANK_UTILIZATION_PRECISION = exports.BANK_CUMULATIVE_INTEREST_PRECISION = exports.BANK_INTEREST_PRECISION = exports.AMM_RESERVE_PRECISION_EXP = exports.PEG_PRECISION_EXP = exports.FUNDING_RATE_PRECISION_EXP = exports.MARK_PRICE_PRECISION_EXP = exports.FUNDING_PAYMENT_PRECISION_EXP = exports.QUOTE_PRECISION_EXP = exports.MAX_LEVERAGE = exports.TEN_MILLION = exports.BN_MAX = exports.TEN_THOUSAND = exports.TEN = exports.TWO = exports.ONE = exports.ZERO = void 0;
4
4
  const __1 = require("../");
5
5
  exports.ZERO = new __1.BN(0);
6
6
  exports.ONE = new __1.BN(1);
@@ -23,6 +23,9 @@ exports.BANK_RATE_PRECISION = new __1.BN(1000000);
23
23
  exports.BANK_WEIGHT_PRECISION = new __1.BN(100);
24
24
  exports.BANK_BALANCE_PRECISION_EXP = new __1.BN(6);
25
25
  exports.BANK_BALANCE_PRECISION = new __1.BN(10).pow(exports.BANK_BALANCE_PRECISION_EXP);
26
+ exports.BANK_IMF_PRECISION_EXP = new __1.BN(6);
27
+ exports.BANK_IMF_PRECISION = new __1.BN(10).pow(exports.BANK_IMF_PRECISION_EXP);
28
+ exports.LIQUIDATION_FEE_PRECISION = new __1.BN(1000000);
26
29
  exports.QUOTE_PRECISION = new __1.BN(10).pow(exports.QUOTE_PRECISION_EXP);
27
30
  exports.MARK_PRICE_PRECISION = new __1.BN(10).pow(exports.MARK_PRICE_PRECISION_EXP);
28
31
  exports.FUNDING_PAYMENT_PRECISION = new __1.BN(10).pow(exports.FUNDING_PAYMENT_PRECISION_EXP);
@@ -40,6 +40,9 @@ class EventList {
40
40
  if (currentNode.next !== undefined) {
41
41
  newNode.next.prev = newNode;
42
42
  }
43
+ else {
44
+ this.tail = newNode;
45
+ }
43
46
  currentNode.next = newNode;
44
47
  newNode.prev = currentNode;
45
48
  }
@@ -1,5 +1,5 @@
1
1
  import { Commitment, TransactionSignature } from '@solana/web3.js';
2
- import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, OrderRecord } from '../index';
2
+ import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, OrderRecord, SettlePnlRecord } from '../index';
3
3
  export declare type EventSubscriptionOptions = {
4
4
  eventTypes?: EventType[];
5
5
  maxEventsPerType?: number;
@@ -27,6 +27,7 @@ export declare type EventMap = {
27
27
  LiquidationRecord: Event<LiquidationRecord>;
28
28
  FundingRateRecord: Event<FundingRateRecord>;
29
29
  OrderRecord: Event<OrderRecord>;
30
+ SettlePnlRecord: Event<SettlePnlRecord>;
30
31
  };
31
32
  export declare type EventType = keyof EventMap;
32
33
  export interface EventSubscriberEvents {
@@ -6,6 +6,7 @@ export declare class BigNum {
6
6
  static delim: string;
7
7
  static spacer: string;
8
8
  constructor(val: BN | number | string, precisionVal?: BN | number | string);
9
+ private bigNumFromParam;
9
10
  add(bn: BigNum): BigNum;
10
11
  sub(bn: BigNum): BigNum;
11
12
  mul(bn: BigNum | BN): BigNum;
@@ -10,6 +10,9 @@ class BigNum {
10
10
  this.val = new anchor_1.BN(val);
11
11
  this.precision = new anchor_1.BN(precisionVal);
12
12
  }
13
+ bigNumFromParam(bn) {
14
+ return anchor_1.BN.isBN(bn) ? BigNum.from(bn) : bn;
15
+ }
13
16
  add(bn) {
14
17
  (0, assert_1.assert)(bn.precision.eq(this.precision), 'Adding unequal precisions');
15
18
  return BigNum.from(this.val.add(bn.val), this.precision);
@@ -19,7 +22,7 @@ class BigNum {
19
22
  return BigNum.from(this.val.sub(bn.val), this.precision);
20
23
  }
21
24
  mul(bn) {
22
- const mulVal = bn instanceof BigNum ? bn : BigNum.from(bn);
25
+ const mulVal = this.bigNumFromParam(bn);
23
26
  return BigNum.from(this.val.mul(mulVal.val), this.precision.add(mulVal.precision));
24
27
  }
25
28
  /**
@@ -28,12 +31,12 @@ class BigNum {
28
31
  * @returns
29
32
  */
30
33
  scalarMul(bn) {
31
- if (bn instanceof anchor_1.BN)
34
+ if (anchor_1.BN.isBN(bn))
32
35
  return BigNum.from(this.val.mul(bn), this.precision);
33
36
  return BigNum.from(this.val.mul(bn.val), this.precision.add(bn.precision)).shift(bn.precision.neg());
34
37
  }
35
38
  div(bn) {
36
- if (bn instanceof anchor_1.BN)
39
+ if (anchor_1.BN.isBN(bn))
37
40
  return BigNum.from(this.val.div(bn), this.precision);
38
41
  return BigNum.from(this.val.div(bn.val), this.precision.sub(bn.precision));
39
42
  }
@@ -73,35 +76,35 @@ class BigNum {
73
76
  .toPrecision(precision);
74
77
  }
75
78
  gt(bn, ignorePrecision) {
76
- const comparisonVal = bn instanceof BigNum ? bn : BigNum.from(bn);
79
+ const comparisonVal = this.bigNumFromParam(bn);
77
80
  if (!ignorePrecision && !comparisonVal.eq(numericConstants_1.ZERO)) {
78
81
  (0, assert_1.assert)(comparisonVal.precision.eq(this.precision), 'Trying to compare numbers with different precision. Yo can opt to ignore precision using the ignorePrecision parameter');
79
82
  }
80
83
  return this.val.gt(comparisonVal.val);
81
84
  }
82
85
  lt(bn, ignorePrecision) {
83
- const comparisonVal = bn instanceof BigNum ? bn : BigNum.from(bn);
86
+ const comparisonVal = this.bigNumFromParam(bn);
84
87
  if (!ignorePrecision && !comparisonVal.val.eq(numericConstants_1.ZERO)) {
85
88
  (0, assert_1.assert)(comparisonVal.precision.eq(this.precision), 'Trying to compare numbers with different precision. Yo can opt to ignore precision using the ignorePrecision parameter');
86
89
  }
87
90
  return this.val.lt(comparisonVal.val);
88
91
  }
89
92
  gte(bn, ignorePrecision) {
90
- const comparisonVal = bn instanceof BigNum ? bn : BigNum.from(bn);
93
+ const comparisonVal = this.bigNumFromParam(bn);
91
94
  if (!ignorePrecision && !comparisonVal.val.eq(numericConstants_1.ZERO)) {
92
95
  (0, assert_1.assert)(comparisonVal.precision.eq(this.precision), 'Trying to compare numbers with different precision. Yo can opt to ignore precision using the ignorePrecision parameter');
93
96
  }
94
97
  return this.val.gte(comparisonVal.val);
95
98
  }
96
99
  lte(bn, ignorePrecision) {
97
- const comparisonVal = bn instanceof BigNum ? bn : BigNum.from(bn);
100
+ const comparisonVal = this.bigNumFromParam(bn);
98
101
  if (!ignorePrecision && !comparisonVal.val.eq(numericConstants_1.ZERO)) {
99
102
  (0, assert_1.assert)(comparisonVal.precision.eq(this.precision), 'Trying to compare numbers with different precision. Yo can opt to ignore precision using the ignorePrecision parameter');
100
103
  }
101
104
  return this.val.lte(comparisonVal.val);
102
105
  }
103
106
  eq(bn, ignorePrecision) {
104
- const comparisonVal = bn instanceof BigNum ? bn : BigNum.from(bn);
107
+ const comparisonVal = this.bigNumFromParam(bn);
105
108
  if (!ignorePrecision && !comparisonVal.val.eq(numericConstants_1.ZERO)) {
106
109
  (0, assert_1.assert)(comparisonVal.precision.eq(this.precision), 'Trying to compare numbers with different precision. Yo can opt to ignore precision using the ignorePrecision parameter');
107
110
  }
@@ -149,8 +152,14 @@ class BigNum {
149
152
  // remove leading zeroes
150
153
  printString = printString.replace(/^0+/, '');
151
154
  // add zero if leading delim
152
- if (printString[0] === BigNum.delim)
153
- printString = `0${printString}`;
155
+ if (this.isNeg()) {
156
+ if (printString[1] === BigNum.delim)
157
+ printString = printString.replace('-.', '-0.');
158
+ }
159
+ else {
160
+ if (printString[0] === BigNum.delim)
161
+ printString = `0${printString}`;
162
+ }
154
163
  // remove trailing delim
155
164
  if (printString[printString.length - 1] === BigNum.delim)
156
165
  printString = printString.slice(0, printString.length - 1);
@@ -261,10 +270,27 @@ class BigNum {
261
270
  * @returns
262
271
  */
263
272
  toNotional(useTradePrecision, precisionOverride) {
273
+ var _a;
264
274
  const prefix = `${this.lt(BigNum.zero()) ? `-` : ``}$`;
265
- const val = useTradePrecision || precisionOverride
275
+ const usingCustomPrecision = true && (useTradePrecision || precisionOverride);
276
+ let val = usingCustomPrecision
266
277
  ? this.prettyPrint(useTradePrecision, precisionOverride)
267
278
  : BigNum.fromPrint(this.toFixed(2), new anchor_1.BN(2)).prettyPrint();
279
+ // Append two trailing zeroes if not using custom precision
280
+ if (!usingCustomPrecision) {
281
+ const [_, rightSide] = val.split(BigNum.delim);
282
+ const trailingLength = (_a = rightSide === null || rightSide === void 0 ? void 0 : rightSide.length) !== null && _a !== void 0 ? _a : 0;
283
+ if (trailingLength < 2) {
284
+ const numHasDecimals = this.print().includes(BigNum.delim);
285
+ // Handle case where pretty print won't include the decimal point
286
+ if (trailingLength === 0 && numHasDecimals) {
287
+ val = `${val}.00`;
288
+ }
289
+ else {
290
+ val = `${val}${new Array(2 - trailingLength).fill('0').join('')}`;
291
+ }
292
+ }
293
+ }
268
294
  return `${prefix}${val.replace('-', '')}`;
269
295
  }
270
296
  toMillified(precision = 3) {