@drift-labs/sdk 0.1.23-master.2 → 0.1.24

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 (45) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +1 -0
  2. package/lib/accounts/bulkAccountLoader.js +14 -13
  3. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +3 -3
  4. package/lib/accounts/pollingTokenAccountSubscriber.js +2 -2
  5. package/lib/accounts/pollingUserAccountSubscriber.js +4 -4
  6. package/lib/accounts/webSocketAccountSubscriber.js +2 -2
  7. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +1 -1
  8. package/lib/accounts/webSocketUserAccountSubscriber.js +2 -2
  9. package/lib/admin.d.ts +2 -2
  10. package/lib/admin.js +12 -11
  11. package/lib/clearingHouse.js +19 -19
  12. package/lib/clearingHouseUser.d.ts +12 -17
  13. package/lib/clearingHouseUser.js +125 -228
  14. package/lib/constants/numericConstants.d.ts +1 -2
  15. package/lib/constants/numericConstants.js +2 -3
  16. package/lib/examples/makeTradeExample.js +6 -6
  17. package/lib/idl/clearing_house.json +42 -4
  18. package/lib/math/amm.js +12 -12
  19. package/lib/math/conversion.js +1 -1
  20. package/lib/math/funding.js +1 -1
  21. package/lib/math/market.js +2 -2
  22. package/lib/math/orders.d.ts +2 -0
  23. package/lib/math/orders.js +44 -4
  24. package/lib/math/position.js +1 -1
  25. package/lib/math/trade.js +18 -18
  26. package/lib/orders.d.ts +3 -1
  27. package/lib/orders.js +47 -19
  28. package/lib/pythClient.js +1 -1
  29. package/lib/tx/retryTxSender.js +1 -1
  30. package/lib/types.d.ts +4 -1
  31. package/package.json +1 -1
  32. package/src/accounts/bulkAccountLoader.ts +18 -13
  33. package/src/accounts/types.js +10 -0
  34. package/src/accounts/utils.js +7 -0
  35. package/src/accounts/webSocketAccountSubscriber.js +76 -0
  36. package/src/addresses.js +83 -0
  37. package/src/admin.ts +13 -4
  38. package/src/clearingHouseUser.ts +161 -330
  39. package/src/constants/numericConstants.ts +1 -2
  40. package/src/idl/clearing_house.json +42 -4
  41. package/src/math/orders.ts +61 -0
  42. package/src/mockUSDCFaucet.js +171 -0
  43. package/src/orders.ts +56 -3
  44. package/src/types.js +60 -0
  45. package/src/types.ts +5 -1
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ClearingHouseUser = void 0;
13
+ const types_1 = require("./types");
13
14
  const position_1 = require("./math/position");
14
15
  const numericConstants_1 = require("./constants/numericConstants");
15
16
  const _1 = require(".");
@@ -38,8 +39,8 @@ class ClearingHouseUser {
38
39
  static from(clearingHouse, authority) {
39
40
  if (clearingHouse.accountSubscriber.type !== 'websocket')
40
41
  throw 'This method only works for clearing houses with a websocket account listener. Try using the getClearingHouseUser factory method to initialize a ClearingHouseUser instead';
41
- const config = (0, clearingHouseUser_1.getWebSocketClearingHouseUserConfig)(clearingHouse, authority);
42
- return (0, clearingHouseUser_1.getClearingHouseUser)(config);
42
+ const config = clearingHouseUser_1.getWebSocketClearingHouseUserConfig(clearingHouse, authority);
43
+ return clearingHouseUser_1.getClearingHouseUser(config);
43
44
  }
44
45
  /**
45
46
  * Subscribe to ClearingHouseUser state accounts
@@ -112,7 +113,7 @@ class ClearingHouseUser {
112
113
  if (this.userAccountPublicKey) {
113
114
  return this.userAccountPublicKey;
114
115
  }
115
- this.userAccountPublicKey = yield (0, addresses_1.getUserAccountPublicKey)(this.clearingHouse.program.programId, this.authority);
116
+ this.userAccountPublicKey = yield addresses_1.getUserAccountPublicKey(this.clearingHouse.program.programId, this.authority);
116
117
  return this.userAccountPublicKey;
117
118
  });
118
119
  }
@@ -121,7 +122,7 @@ class ClearingHouseUser {
121
122
  if (this.userOrdersAccountPublicKey) {
122
123
  return this.userOrdersAccountPublicKey;
123
124
  }
124
- this.userOrdersAccountPublicKey = yield (0, _1.getUserOrdersAccountPublicKey)(this.clearingHouse.program.programId, yield this.getUserAccountPublicKey());
125
+ this.userOrdersAccountPublicKey = yield _1.getUserOrdersAccountPublicKey(this.clearingHouse.program.programId, yield this.getUserAccountPublicKey());
125
126
  return this.userOrdersAccountPublicKey;
126
127
  });
127
128
  }
@@ -136,19 +137,39 @@ class ClearingHouseUser {
136
137
  * calculates Buying Power = FC * MAX_LEVERAGE
137
138
  * @returns : Precision QUOTE_PRECISION
138
139
  */
139
- getBuyingPower() {
140
+ getBuyingPower(marketIndex) {
140
141
  return this.getFreeCollateral()
141
- .mul(this.getMaxLeverage('Initial'))
142
+ .mul(this.getMaxLeverage(marketIndex, 'Initial'))
142
143
  .div(numericConstants_1.TEN_THOUSAND);
143
144
  }
144
145
  /**
145
- * calculates Free Collateral = (TC - TPV) * MAX_LEVERAGE
146
+ * calculates Free Collateral = Total collateral - initial margin requirement
146
147
  * @returns : Precision QUOTE_PRECISION
147
148
  */
148
149
  getFreeCollateral() {
149
- return this.getTotalCollateral().sub(this.getTotalPositionValue()
150
- .mul(numericConstants_1.TEN_THOUSAND)
151
- .div(this.getMaxLeverage('Initial')));
150
+ const totalCollateral = this.getTotalCollateral();
151
+ const initialMarginRequirement = this.getInitialMarginRequirement();
152
+ const freeCollateral = totalCollateral.sub(initialMarginRequirement);
153
+ return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
154
+ }
155
+ getInitialMarginRequirement() {
156
+ return this.getUserPositionsAccount().positions.reduce((marginRequirement, marketPosition) => {
157
+ const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
158
+ return marginRequirement.add(_1.calculateBaseAssetValue(market, marketPosition)
159
+ .mul(new _1.BN(market.marginRatioInitial))
160
+ .div(numericConstants_1.MARGIN_PRECISION));
161
+ }, numericConstants_1.ZERO);
162
+ }
163
+ /**
164
+ * @returns The partial margin requirement in USDC. : QUOTE_PRECISION
165
+ */
166
+ getPartialMarginRequirement() {
167
+ return this.getUserPositionsAccount().positions.reduce((marginRequirement, marketPosition) => {
168
+ const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
169
+ return marginRequirement.add(_1.calculateBaseAssetValue(market, marketPosition)
170
+ .mul(new _1.BN(market.marginRatioPartial))
171
+ .div(numericConstants_1.MARGIN_PRECISION));
172
+ }, numericConstants_1.ZERO);
152
173
  }
153
174
  /**
154
175
  * calculates unrealized position price pnl
@@ -159,7 +180,7 @@ class ClearingHouseUser {
159
180
  .positions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
160
181
  .reduce((pnl, marketPosition) => {
161
182
  const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
162
- return pnl.add((0, _1.calculatePositionPNL)(market, marketPosition, withFunding));
183
+ return pnl.add(_1.calculatePositionPNL(market, marketPosition, withFunding));
163
184
  }, numericConstants_1.ZERO);
164
185
  }
165
186
  /**
@@ -171,7 +192,7 @@ class ClearingHouseUser {
171
192
  .positions.filter((pos) => marketIndex ? pos.marketIndex === marketIndex : true)
172
193
  .reduce((pnl, marketPosition) => {
173
194
  const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
174
- return pnl.add((0, _1.calculatePositionFundingPNL)(market, marketPosition));
195
+ return pnl.add(_1.calculatePositionFundingPNL(market, marketPosition));
175
196
  }, numericConstants_1.ZERO);
176
197
  }
177
198
  /**
@@ -189,7 +210,7 @@ class ClearingHouseUser {
189
210
  getTotalPositionValue() {
190
211
  return this.getUserPositionsAccount().positions.reduce((positionValue, marketPosition) => {
191
212
  const market = this.clearingHouse.getMarket(marketPosition.marketIndex);
192
- return positionValue.add((0, _1.calculateBaseAssetValue)(market, marketPosition));
213
+ return positionValue.add(_1.calculateBaseAssetValue(market, marketPosition));
193
214
  }, numericConstants_1.ZERO);
194
215
  }
195
216
  /**
@@ -199,7 +220,7 @@ class ClearingHouseUser {
199
220
  getPositionValue(marketIndex) {
200
221
  const userPosition = this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
201
222
  const market = this.clearingHouse.getMarket(userPosition.marketIndex);
202
- return (0, _1.calculateBaseAssetValue)(market, userPosition);
223
+ return _1.calculateBaseAssetValue(market, userPosition);
203
224
  }
204
225
  getPositionSide(currentPosition) {
205
226
  if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
@@ -218,10 +239,10 @@ class ClearingHouseUser {
218
239
  */
219
240
  getPositionEstimatedExitPriceAndPnl(position, amountToClose) {
220
241
  const market = this.clearingHouse.getMarket(position.marketIndex);
221
- const entryPrice = (0, position_1.calculateEntryPrice)(position);
242
+ const entryPrice = position_1.calculateEntryPrice(position);
222
243
  if (amountToClose) {
223
244
  if (amountToClose.eq(numericConstants_1.ZERO)) {
224
- return [(0, _1.calculateMarkPrice)(market), numericConstants_1.ZERO];
245
+ return [_1.calculateMarkPrice(market), numericConstants_1.ZERO];
225
246
  }
226
247
  position = {
227
248
  baseAssetAmount: amountToClose,
@@ -230,7 +251,7 @@ class ClearingHouseUser {
230
251
  quoteAssetAmount: position.quoteAssetAmount,
231
252
  };
232
253
  }
233
- const baseAssetValue = (0, _1.calculateBaseAssetValue)(market, position);
254
+ const baseAssetValue = _1.calculateBaseAssetValue(market, position);
234
255
  if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
235
256
  return [numericConstants_1.ZERO, numericConstants_1.ZERO];
236
257
  }
@@ -262,24 +283,24 @@ class ClearingHouseUser {
262
283
  * @params category {Initial, Partial, Maintenance}
263
284
  * @returns : Precision TEN_THOUSAND
264
285
  */
265
- getMaxLeverage(category) {
266
- const chState = this.clearingHouse.getStateAccount();
286
+ getMaxLeverage(marketIndex, category = 'Initial') {
287
+ const market = this.clearingHouse.getMarket(marketIndex);
267
288
  let marginRatioCategory;
268
289
  switch (category) {
269
290
  case 'Initial':
270
- marginRatioCategory = chState.marginRatioInitial;
291
+ marginRatioCategory = market.marginRatioInitial;
271
292
  break;
272
293
  case 'Maintenance':
273
- marginRatioCategory = chState.marginRatioMaintenance;
294
+ marginRatioCategory = market.marginRatioMaintenance;
274
295
  break;
275
296
  case 'Partial':
276
- marginRatioCategory = chState.marginRatioPartial;
297
+ marginRatioCategory = market.marginRatioPartial;
277
298
  break;
278
299
  default:
279
- marginRatioCategory = chState.marginRatioInitial;
300
+ marginRatioCategory = market.marginRatioInitial;
280
301
  break;
281
302
  }
282
- const maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(marginRatioCategory);
303
+ const maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(new _1.BN(marginRatioCategory));
283
304
  return maxLeverage;
284
305
  }
285
306
  /**
@@ -294,8 +315,10 @@ class ClearingHouseUser {
294
315
  return this.getTotalCollateral().mul(numericConstants_1.TEN_THOUSAND).div(totalPositionValue);
295
316
  }
296
317
  canBeLiquidated() {
318
+ const totalCollateral = this.getTotalCollateral();
319
+ const partialMaintenanceRequirement = this.getPartialMarginRequirement();
297
320
  const marginRatio = this.getMarginRatio();
298
- const canLiquidate = marginRatio.lte(numericConstants_1.PARTIAL_LIQUIDATION_RATIO);
321
+ const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
299
322
  return [canLiquidate, marginRatio];
300
323
  }
301
324
  /**
@@ -319,97 +342,13 @@ class ClearingHouseUser {
319
342
  }
320
343
  /**
321
344
  * Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
322
- * @param targetMarket
323
- * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
324
- * @param partial
325
- * @returns Precision : MARK_PRICE_PRECISION
326
- */
327
- liquidationPriceOld(targetMarket, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
328
- // +/-(margin_ratio-liq_ratio) * price_now = price_liq
329
- // todo: margin_ratio is not symmetric on price action (both numer and denom change)
330
- // margin_ratio = collateral / base_asset_value
331
- /* example: assume BTC price is $40k (examine 10% up/down)
332
-
333
- if 10k deposit and levered 10x short BTC => BTC up $400 means:
334
- 1. higher base_asset_value (+$4k)
335
- 2. lower collateral (-$4k)
336
- 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
337
-
338
- for 10x long, BTC down $400:
339
- 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
340
- const currentPrice = (0, _1.calculateMarkPrice)(this.clearingHouse.getMarket(targetMarket.marketIndex));
341
- const totalCollateralUSDC = this.getTotalCollateral();
342
- // calculate the total position value ignoring any value from the target market of the trade
343
- const totalCurrentPositionValueIgnoringTargetUSDC = this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
344
- const currentMarketPosition = this.getUserPosition(targetMarket.marketIndex) ||
345
- this.getEmptyPosition(targetMarket.marketIndex);
346
- const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
347
- // calculate position for current market after trade
348
- const proposedMarketPosition = {
349
- marketIndex: targetMarket.marketIndex,
350
- baseAssetAmount: currentMarketPositionBaseSize.add(positionBaseSizeChange),
351
- lastCumulativeFundingRate: new _1.BN(0),
352
- quoteAssetAmount: new _1.BN(0),
353
- openOrders: new _1.BN(0),
354
- };
355
- const market = this.clearingHouse.getMarket(proposedMarketPosition.marketIndex);
356
- const proposedMarketPositionValueUSDC = (0, _1.calculateBaseAssetValue)(market, proposedMarketPosition);
357
- // total position value after trade
358
- const targetTotalPositionValueUSDC = totalCurrentPositionValueIgnoringTargetUSDC.add(proposedMarketPositionValueUSDC);
359
- let totalFreeCollateralUSDC = this.getTotalCollateral().sub(this.getTotalPositionValue()
360
- .mul(numericConstants_1.TEN_THOUSAND)
361
- .div(this.getMaxLeverage('Maintenance')));
362
- if (partial) {
363
- totalFreeCollateralUSDC = this.getTotalCollateral().sub(this.getTotalPositionValue()
364
- .mul(numericConstants_1.TEN_THOUSAND)
365
- .div(this.getMaxLeverage('Partial')));
366
- }
367
- // if the position value after the trade is less than total collateral, there is no liq price
368
- if (targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
369
- proposedMarketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
370
- return new _1.BN(-1);
371
- }
372
- // get current margin ratio based on current collateral and proposed total position value
373
- let marginRatio;
374
- if (proposedMarketPositionValueUSDC.eq(numericConstants_1.ZERO)) {
375
- marginRatio = numericConstants_1.BN_MAX;
376
- }
377
- else {
378
- marginRatio = totalCollateralUSDC
379
- .mul(numericConstants_1.TEN_THOUSAND)
380
- .div(proposedMarketPositionValueUSDC);
381
- }
382
- let liqRatio = numericConstants_1.FULL_LIQUIDATION_RATIO;
383
- if (partial) {
384
- liqRatio = numericConstants_1.PARTIAL_LIQUIDATION_RATIO;
385
- }
386
- // sign of position in current market after the trade
387
- const baseAssetSignIsNeg = proposedMarketPosition.baseAssetAmount.isNeg();
388
- let pctChange = marginRatio.abs().sub(liqRatio);
389
- // if user is short, higher price is liq
390
- if (baseAssetSignIsNeg) {
391
- pctChange = pctChange.add(numericConstants_1.TEN_THOUSAND);
392
- }
393
- else {
394
- if (numericConstants_1.TEN_THOUSAND.lte(pctChange)) {
395
- // no liquidation price, position is a fully/over collateralized long
396
- // handle as NaN on UI
397
- return new _1.BN(-1);
398
- }
399
- pctChange = numericConstants_1.TEN_THOUSAND.sub(pctChange);
400
- }
401
- const liqPrice = currentPrice.mul(pctChange).div(numericConstants_1.TEN_THOUSAND);
402
- return liqPrice;
403
- }
404
- /**
405
- * Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
406
- * @param targetMarket
345
+ * @param marketPosition
407
346
  * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
408
347
  * @param partial
409
348
  * @returns Precision : MARK_PRICE_PRECISION
410
349
  */
411
- liquidationPrice(targetMarket, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
412
- // solves formula for example calc below
350
+ liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
351
+ // solves formula for example canBeLiquidated below
413
352
  /* example: assume BTC price is $40k (examine 10% up/down)
414
353
 
415
354
  if 10k deposit and levered 10x short BTC => BTC up $400 means:
@@ -419,77 +358,86 @@ class ClearingHouseUser {
419
358
 
420
359
  for 10x long, BTC down $400:
421
360
  3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
422
- const tc = this.getTotalCollateral();
423
- const tpv = this.getTotalPositionValue();
424
- const partialLev = 16;
425
- const maintLev = 20;
426
- const thisLev = partial ? new _1.BN(partialLev) : new _1.BN(maintLev);
361
+ const totalCollateral = this.getTotalCollateral();
427
362
  // calculate the total position value ignoring any value from the target market of the trade
428
- const totalCurrentPositionValueIgnoringTargetUSDC = this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
429
- const currentMarketPosition = this.getUserPosition(targetMarket.marketIndex) ||
430
- this.getEmptyPosition(targetMarket.marketIndex);
363
+ const totalPositionValueExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(marketPosition.marketIndex);
364
+ const currentMarketPosition = this.getUserPosition(marketPosition.marketIndex) ||
365
+ this.getEmptyPosition(marketPosition.marketIndex);
431
366
  const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
432
367
  const proposedBaseAssetAmount = currentMarketPositionBaseSize.add(positionBaseSizeChange);
433
368
  // calculate position for current market after trade
434
369
  const proposedMarketPosition = {
435
- marketIndex: targetMarket.marketIndex,
370
+ marketIndex: marketPosition.marketIndex,
436
371
  baseAssetAmount: proposedBaseAssetAmount,
437
372
  lastCumulativeFundingRate: currentMarketPosition.lastCumulativeFundingRate,
438
373
  quoteAssetAmount: new _1.BN(0),
439
374
  openOrders: new _1.BN(0),
440
375
  };
376
+ if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
377
+ return new _1.BN(-1);
441
378
  const market = this.clearingHouse.getMarket(proposedMarketPosition.marketIndex);
442
- const proposedMarketPositionValueUSDC = (0, _1.calculateBaseAssetValue)(market, proposedMarketPosition);
379
+ const proposedMarketPositionValue = _1.calculateBaseAssetValue(market, proposedMarketPosition);
443
380
  // total position value after trade
444
- const targetTotalPositionValueUSDC = totalCurrentPositionValueIgnoringTargetUSDC.add(proposedMarketPositionValueUSDC);
445
- let totalFreeCollateralUSDC = tc.sub(totalCurrentPositionValueIgnoringTargetUSDC
446
- .mul(numericConstants_1.TEN_THOUSAND)
447
- .div(this.getMaxLeverage('Maintenance')));
448
- if (partial) {
449
- totalFreeCollateralUSDC = tc.sub(totalCurrentPositionValueIgnoringTargetUSDC
450
- .mul(numericConstants_1.TEN_THOUSAND)
451
- .div(this.getMaxLeverage('Partial')));
381
+ const totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
382
+ const marginRequirementExcludingTargetMarket = this.getUserPositionsAccount().positions.reduce((totalMarginRequirement, position) => {
383
+ if (!position.marketIndex.eq(marketPosition.marketIndex)) {
384
+ const market = this.clearingHouse.getMarket(position.marketIndex);
385
+ const positionValue = _1.calculateBaseAssetValue(market, position);
386
+ const marketMarginRequirement = positionValue
387
+ .mul(partial
388
+ ? new _1.BN(market.marginRatioPartial)
389
+ : new _1.BN(market.marginRatioMaintenance))
390
+ .div(numericConstants_1.MARGIN_PRECISION);
391
+ totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
392
+ }
393
+ return totalMarginRequirement;
394
+ }, numericConstants_1.ZERO);
395
+ const freeCollateralExcludingTargetMarket = totalCollateral.sub(marginRequirementExcludingTargetMarket);
396
+ // if the position value after the trade is less than free collateral, there is no liq price
397
+ if (totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
398
+ proposedMarketPosition.baseAssetAmount.abs().gt(numericConstants_1.ZERO)) {
399
+ return new _1.BN(-1);
452
400
  }
453
- let priceDelt;
401
+ const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedMarketPositionValue
402
+ .mul(partial
403
+ ? new _1.BN(market.marginRatioPartial)
404
+ : new _1.BN(market.marginRatioMaintenance))
405
+ .div(numericConstants_1.MARGIN_PRECISION));
406
+ const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
407
+ const marketMaxLeverage = partial
408
+ ? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
409
+ : this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
410
+ let priceDelta;
454
411
  if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
455
- priceDelt = tc
456
- .mul(thisLev)
457
- .sub(tpv)
412
+ priceDelta = freeCollateralAfterTrade
413
+ .mul(marketMaxLeverage) // precision is TEN_THOUSAND
414
+ .div(marketMaxLeverage.add(numericConstants_1.TEN_THOUSAND))
458
415
  .mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
459
- .div(thisLev.add(new _1.BN(1)));
416
+ .mul(numericConstants_1.AMM_RESERVE_PRECISION)
417
+ .div(proposedBaseAssetAmount);
460
418
  }
461
419
  else {
462
- priceDelt = tc
463
- .mul(thisLev)
464
- .sub(tpv)
420
+ priceDelta = freeCollateralAfterTrade
421
+ .mul(marketMaxLeverage) // precision is TEN_THOUSAND
422
+ .div(marketMaxLeverage.sub(numericConstants_1.TEN_THOUSAND))
465
423
  .mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
466
- .div(thisLev.sub(new _1.BN(1)));
424
+ .mul(numericConstants_1.AMM_RESERVE_PRECISION)
425
+ .div(proposedBaseAssetAmount);
467
426
  }
468
- let currentPrice;
427
+ let markPriceAfterTrade;
469
428
  if (positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
470
- currentPrice = (0, _1.calculateMarkPrice)(this.clearingHouse.getMarket(targetMarket.marketIndex));
429
+ markPriceAfterTrade = _1.calculateMarkPrice(this.clearingHouse.getMarket(marketPosition.marketIndex));
471
430
  }
472
431
  else {
473
432
  const direction = positionBaseSizeChange.gt(numericConstants_1.ZERO)
474
433
  ? _1.PositionDirection.LONG
475
434
  : _1.PositionDirection.SHORT;
476
- currentPrice = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.clearingHouse.getMarket(targetMarket.marketIndex), 'base')[3]; // newPrice after swap
477
- }
478
- // if the position value after the trade is less than total collateral, there is no liq price
479
- if (targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
480
- proposedMarketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
481
- return new _1.BN(-1);
435
+ markPriceAfterTrade = _1.calculateTradeSlippage(direction, positionBaseSizeChange.abs(), this.clearingHouse.getMarket(marketPosition.marketIndex), 'base')[3]; // newPrice after swap
482
436
  }
483
- if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
484
- return new _1.BN(-1);
485
- const eatMargin2 = priceDelt
486
- .mul(numericConstants_1.AMM_RESERVE_PRECISION)
487
- .div(proposedBaseAssetAmount);
488
- if (eatMargin2.gt(currentPrice)) {
437
+ if (priceDelta.gt(markPriceAfterTrade)) {
489
438
  return new _1.BN(-1);
490
439
  }
491
- const liqPrice = currentPrice.sub(eatMargin2);
492
- return liqPrice;
440
+ return markPriceAfterTrade.sub(priceDelta);
493
441
  }
494
442
  /**
495
443
  * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
@@ -530,33 +478,24 @@ class ClearingHouseUser {
530
478
  *
531
479
  * @param targetMarketIndex
532
480
  * @param tradeSide
533
- * @param userMaxLeverageSetting - leverage : Precision TEN_THOUSAND
534
481
  * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
535
482
  */
536
- getMaxTradeSizeUSDC(targetMarketIndex, tradeSide, userMaxLeverageSetting) {
483
+ getMaxTradeSizeUSDC(targetMarketIndex, tradeSide) {
537
484
  const currentPosition = this.getUserPosition(targetMarketIndex) ||
538
485
  this.getEmptyPosition(targetMarketIndex);
539
- const targetSide = tradeSide === _1.PositionDirection.SHORT ? 'short' : 'long';
486
+ const targetSide = types_1.isVariant(tradeSide, 'short') ? 'short' : 'long';
540
487
  const currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
541
488
  ? 'short'
542
489
  : 'long';
543
- const targettingSameSide = !currentPosition
490
+ const targetingSameSide = !currentPosition
544
491
  ? true
545
492
  : targetSide === currentPositionSide;
546
493
  // 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.
547
- const oppositeSizeValueUSDC = targettingSameSide
494
+ const oppositeSizeValueUSDC = targetingSameSide
548
495
  ? numericConstants_1.ZERO
549
496
  : this.getPositionValue(targetMarketIndex);
550
- // get current leverage
551
- const currentLeverage = this.getLeverage();
552
- const remainingLeverage = _1.BN.max(userMaxLeverageSetting.sub(currentLeverage), numericConstants_1.ZERO);
553
- // get total collateral
554
- const totalCollateral = this.getTotalCollateral();
555
- // position side allowed based purely on current leverage
556
- let maxPositionSize = remainingLeverage
557
- .mul(totalCollateral)
558
- .div(numericConstants_1.TEN_THOUSAND);
559
- if (userMaxLeverageSetting.sub(currentLeverage).gte(numericConstants_1.ZERO)) {
497
+ let maxPositionSize = this.getBuyingPower(targetMarketIndex);
498
+ if (maxPositionSize.gte(numericConstants_1.ZERO)) {
560
499
  if (oppositeSizeValueUSDC.eq(numericConstants_1.ZERO)) {
561
500
  // case 1 : Regular trade where current total position less than max, and no opposite position to account for
562
501
  // do nothing
@@ -568,25 +507,24 @@ class ClearingHouseUser {
568
507
  }
569
508
  else {
570
509
  // current leverage is greater than max leverage - can only reduce position size
571
- if (!targettingSameSide) {
572
- const currentPositionQuoteSize = this.getPositionValue(targetMarketIndex);
573
- const currentTotalQuoteSize = currentLeverage
574
- .mul(totalCollateral)
575
- .div(numericConstants_1.TEN_THOUSAND);
576
- const otherPositionsTotalQuoteSize = currentTotalQuoteSize.sub(currentPositionQuoteSize);
577
- const quoteValueOfMaxLeverage = userMaxLeverageSetting
578
- .mul(totalCollateral)
579
- .div(numericConstants_1.TEN_THOUSAND);
580
- if (otherPositionsTotalQuoteSize
581
- .sub(currentPositionQuoteSize)
582
- .gte(quoteValueOfMaxLeverage)) {
583
- // case 3: Can only reduce the current position because it will still be greater than max leverage
584
- maxPositionSize = currentPositionQuoteSize;
510
+ if (!targetingSameSide) {
511
+ const market = this.clearingHouse.getMarket(targetMarketIndex);
512
+ const marketPositionValue = this.getPositionValue(targetMarketIndex);
513
+ const totalCollateral = this.getTotalCollateral();
514
+ const marginRequirement = this.getInitialMarginRequirement();
515
+ const marginFreedByClosing = marketPositionValue
516
+ .mul(new _1.BN(market.marginRatioInitial))
517
+ .div(numericConstants_1.MARGIN_PRECISION);
518
+ const marginRequirementAfterClosing = marginRequirement.sub(marginFreedByClosing);
519
+ if (marginRequirementAfterClosing.gt(totalCollateral)) {
520
+ maxPositionSize = marketPositionValue;
585
521
  }
586
522
  else {
587
- // case 4: Can reduce the position, and then take extra remaining quote to get to max leverage
588
- const allowedQuoteSizeAfterClosingCurrentPosition = quoteValueOfMaxLeverage.sub(otherPositionsTotalQuoteSize);
589
- maxPositionSize = currentPositionQuoteSize.add(allowedQuoteSizeAfterClosingCurrentPosition);
523
+ const freeCollateralAfterClose = totalCollateral.sub(marginRequirementAfterClosing);
524
+ const buyingPowerAfterClose = freeCollateralAfterClose
525
+ .mul(this.getMaxLeverage(targetMarketIndex))
526
+ .div(numericConstants_1.TEN_THOUSAND);
527
+ maxPositionSize = marketPositionValue.add(buyingPowerAfterClose);
590
528
  }
591
529
  }
592
530
  else {
@@ -659,46 +597,5 @@ class ClearingHouseUser {
659
597
  }
660
598
  return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
661
599
  }
662
- canFillOrder(order) {
663
- const userAccount = this.getUserAccount();
664
- const userPositionsAccount = this.getUserPositionsAccount();
665
- const userPosition = this.getUserPosition(order.marketIndex);
666
- const market = this.clearingHouse.getMarket(order.marketIndex);
667
- if ((0, position_1.isEmptyPosition)(userPosition)) {
668
- return false;
669
- }
670
- const newState = (0, _1.calculateNewStateAfterOrder)(userAccount, userPosition, market, order);
671
- if (newState === null) {
672
- return false;
673
- }
674
- const [userAccountAfter, userPositionAfter, marketAfter] = newState;
675
- const totalPositionValue = userPositionsAccount.positions.reduce((positionValue, marketPosition) => {
676
- let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
677
- if (marketPosition.marketIndex.eq(order.marketIndex)) {
678
- market = marketAfter;
679
- marketPosition = userPositionAfter;
680
- }
681
- return positionValue.add((0, _1.calculateBaseAssetValue)(market, marketPosition));
682
- }, numericConstants_1.ZERO);
683
- if (totalPositionValue.eq(numericConstants_1.ZERO)) {
684
- return true;
685
- }
686
- const unrealizedPnL = userPositionsAccount.positions.reduce((pnl, marketPosition) => {
687
- let market = this.clearingHouse.getMarket(marketPosition.marketIndex);
688
- pnl = pnl.add((0, _1.calculatePositionFundingPNL)(market, marketPosition).div(numericConstants_1.PRICE_TO_QUOTE_PRECISION));
689
- if (marketPosition.marketIndex.eq(order.marketIndex)) {
690
- market = marketAfter;
691
- marketPosition = userPositionAfter;
692
- }
693
- // update
694
- return pnl.add((0, _1.calculatePositionPNL)(market, marketPosition, false));
695
- }, numericConstants_1.ZERO);
696
- const totalCollateral = userAccountAfter.collateral.add(unrealizedPnL);
697
- const marginRatioAfter = totalCollateral
698
- .mul(numericConstants_1.TEN_THOUSAND)
699
- .div(totalPositionValue);
700
- const marginRatioInitial = this.clearingHouse.getStateAccount().marginRatioInitial;
701
- return marginRatioAfter.gte(marginRatioInitial);
702
- }
703
600
  }
704
601
  exports.ClearingHouseUser = ClearingHouseUser;
@@ -6,8 +6,6 @@ export declare const TWO: BN;
6
6
  export declare const TEN_THOUSAND: BN;
7
7
  export declare const BN_MAX: BN;
8
8
  export declare const MAX_LEVERAGE: BN;
9
- export declare const FULL_LIQUIDATION_RATIO: BN;
10
- export declare const PARTIAL_LIQUIDATION_RATIO: BN;
11
9
  export declare const QUOTE_PRECISION: BN;
12
10
  export declare const MARK_PRICE_PRECISION: BN;
13
11
  export declare const FUNDING_PAYMENT_PRECISION: BN;
@@ -17,3 +15,4 @@ export declare const BASE_PRECISION: BN;
17
15
  export declare const AMM_TO_QUOTE_PRECISION_RATIO: BN;
18
16
  export declare const PRICE_TO_QUOTE_PRECISION: BN;
19
17
  export declare const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO: BN;
18
+ export declare const MARGIN_PRECISION: BN;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_PAYMENT_PRECISION = exports.MARK_PRICE_PRECISION = exports.QUOTE_PRECISION = exports.PARTIAL_LIQUIDATION_RATIO = exports.FULL_LIQUIDATION_RATIO = exports.MAX_LEVERAGE = exports.BN_MAX = exports.TEN_THOUSAND = exports.TWO = exports.ONE = exports.ZERO = void 0;
3
+ exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_PAYMENT_PRECISION = exports.MARK_PRICE_PRECISION = exports.QUOTE_PRECISION = exports.MAX_LEVERAGE = exports.BN_MAX = exports.TEN_THOUSAND = 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);
@@ -8,8 +8,6 @@ exports.TWO = new __1.BN(2);
8
8
  exports.TEN_THOUSAND = new __1.BN(10000);
9
9
  exports.BN_MAX = new __1.BN(Number.MAX_SAFE_INTEGER);
10
10
  exports.MAX_LEVERAGE = new __1.BN(5);
11
- exports.FULL_LIQUIDATION_RATIO = new __1.BN(500);
12
- exports.PARTIAL_LIQUIDATION_RATIO = new __1.BN(625);
13
11
  exports.QUOTE_PRECISION = new __1.BN(Math.pow(10, 6));
14
12
  exports.MARK_PRICE_PRECISION = new __1.BN(Math.pow(10, 10));
15
13
  exports.FUNDING_PAYMENT_PRECISION = new __1.BN(10000);
@@ -19,3 +17,4 @@ exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION;
19
17
  exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.AMM_RESERVE_PRECISION.div(exports.QUOTE_PRECISION); // 10^7
20
18
  exports.PRICE_TO_QUOTE_PRECISION = exports.MARK_PRICE_PRECISION.div(exports.QUOTE_PRECISION);
21
19
  exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.AMM_RESERVE_PRECISION.mul(exports.PEG_PRECISION).div(exports.QUOTE_PRECISION); // 10^10
20
+ exports.MARGIN_PRECISION = exports.TEN_THOUSAND;
@@ -21,7 +21,7 @@ const getTokenAddress = (mintAddress, userPubKey) => {
21
21
  exports.getTokenAddress = getTokenAddress;
22
22
  const main = () => __awaiter(void 0, void 0, void 0, function* () {
23
23
  // Initialize Drift SDK
24
- const sdkConfig = (0, __2.initialize)({ env: 'devnet' });
24
+ const sdkConfig = __2.initialize({ env: 'devnet' });
25
25
  // Set up the Wallet and Provider
26
26
  const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
27
27
  const keypair = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(privateKey)));
@@ -35,7 +35,7 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
35
35
  const lamportsBalance = yield connection.getBalance(wallet.publicKey);
36
36
  console.log('SOL balance:', lamportsBalance / Math.pow(10, 9));
37
37
  // Misc. other things to set up
38
- const usdcTokenAddress = yield (0, exports.getTokenAddress)(sdkConfig.USDC_MINT_ADDRESS, wallet.publicKey.toString());
38
+ const usdcTokenAddress = yield exports.getTokenAddress(sdkConfig.USDC_MINT_ADDRESS, wallet.publicKey.toString());
39
39
  // Set up the Drift Clearing House
40
40
  const clearingHousePublicKey = new web3_js_1.PublicKey(sdkConfig.CLEARING_HOUSE_PROGRAM_ID);
41
41
  const clearingHouse = __2.ClearingHouse.from(connection, provider.wallet, clearingHousePublicKey);
@@ -47,18 +47,18 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
47
47
  if (!userAccountExists) {
48
48
  //// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
49
49
  const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
50
- yield clearingHouse.initializeUserAccountAndDepositCollateral(depositAmount, yield (0, exports.getTokenAddress)(usdcTokenAddress.toString(), wallet.publicKey.toString()));
50
+ yield clearingHouse.initializeUserAccountAndDepositCollateral(depositAmount, yield exports.getTokenAddress(usdcTokenAddress.toString(), wallet.publicKey.toString()));
51
51
  }
52
52
  yield user.subscribe();
53
53
  // Get current price
54
54
  const solMarketInfo = __2.Markets.find((market) => market.baseAssetSymbol === 'SOL');
55
- const currentMarketPrice = (0, __2.calculateMarkPrice)(clearingHouse.getMarket(solMarketInfo.marketIndex));
56
- const formattedPrice = (0, __2.convertToNumber)(currentMarketPrice, __2.MARK_PRICE_PRECISION);
55
+ const currentMarketPrice = __2.calculateMarkPrice(clearingHouse.getMarket(solMarketInfo.marketIndex));
56
+ const formattedPrice = __2.convertToNumber(currentMarketPrice, __2.MARK_PRICE_PRECISION);
57
57
  console.log(`Current Market Price is $${formattedPrice}`);
58
58
  // Estimate the slippage for a $5000 LONG trade
59
59
  const solMarketAccount = clearingHouse.getMarket(solMarketInfo.marketIndex);
60
60
  const longAmount = new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION);
61
- const slippage = (0, __2.convertToNumber)((0, __2.calculateTradeSlippage)(__2.PositionDirection.LONG, longAmount, solMarketAccount)[0], __2.MARK_PRICE_PRECISION);
61
+ const slippage = __2.convertToNumber(__2.calculateTradeSlippage(__2.PositionDirection.LONG, longAmount, solMarketAccount)[0], __2.MARK_PRICE_PRECISION);
62
62
  console.log(`Slippage for a $5000 LONG on the SOL market would be $${slippage}`);
63
63
  // Make a $5000 LONG trade
64
64
  yield clearingHouse.openPosition(__2.PositionDirection.LONG, longAmount, solMarketInfo.marketIndex);