@drift-labs/sdk 0.1.12 → 0.1.16

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 (83) hide show
  1. package/README.md +2 -2
  2. package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts +1 -0
  3. package/lib/accounts/defaultClearingHouseAccountSubscriber.d.ts.map +1 -1
  4. package/lib/accounts/defaultClearingHouseAccountSubscriber.js +17 -0
  5. package/lib/accounts/defaultUserAccountSubscriber.d.ts +2 -0
  6. package/lib/accounts/defaultUserAccountSubscriber.d.ts.map +1 -1
  7. package/lib/accounts/defaultUserAccountSubscriber.js +16 -0
  8. package/lib/accounts/types.d.ts +3 -21
  9. package/lib/accounts/types.d.ts.map +1 -1
  10. package/lib/accounts/webSocketAccountSubscriber.d.ts +2 -0
  11. package/lib/accounts/webSocketAccountSubscriber.d.ts.map +1 -1
  12. package/lib/accounts/webSocketAccountSubscriber.js +13 -3
  13. package/lib/clearingHouse.d.ts +4 -0
  14. package/lib/clearingHouse.d.ts.map +1 -1
  15. package/lib/clearingHouse.js +8 -0
  16. package/lib/clearingHouseUser.d.ts +31 -3
  17. package/lib/clearingHouseUser.d.ts.map +1 -1
  18. package/lib/clearingHouseUser.js +213 -47
  19. package/lib/constants/markets.d.ts.map +1 -1
  20. package/lib/constants/markets.js +21 -0
  21. package/lib/constants/numericConstants.d.ts +1 -0
  22. package/lib/constants/numericConstants.d.ts.map +1 -1
  23. package/lib/constants/numericConstants.js +2 -1
  24. package/lib/examples/makeTradeExample.d.ts.map +1 -1
  25. package/lib/examples/makeTradeExample.js +14 -13
  26. package/lib/idl/clearing_house.json +94 -42
  27. package/lib/index.d.ts +4 -1
  28. package/lib/index.d.ts.map +1 -1
  29. package/lib/index.js +4 -1
  30. package/lib/math/amm.d.ts +26 -1
  31. package/lib/math/amm.d.ts.map +1 -1
  32. package/lib/math/amm.js +85 -10
  33. package/lib/math/funding.d.ts +6 -6
  34. package/lib/math/funding.d.ts.map +1 -1
  35. package/lib/math/funding.js +41 -22
  36. package/lib/math/insuranceFund.d.ts +15 -0
  37. package/lib/math/insuranceFund.d.ts.map +1 -0
  38. package/lib/math/insuranceFund.js +36 -0
  39. package/lib/math/position.d.ts +1 -1
  40. package/lib/math/position.d.ts.map +1 -1
  41. package/lib/math/position.js +15 -23
  42. package/lib/math/trade.d.ts +1 -1
  43. package/lib/math/trade.d.ts.map +1 -1
  44. package/lib/math/trade.js +9 -4
  45. package/lib/types.d.ts +0 -13
  46. package/lib/types.d.ts.map +1 -1
  47. package/lib/util/computeUnits.d.ts +3 -0
  48. package/lib/util/computeUnits.d.ts.map +1 -0
  49. package/lib/util/computeUnits.js +27 -0
  50. package/lib/util/tps.d.ts +3 -0
  51. package/lib/util/tps.d.ts.map +1 -0
  52. package/lib/util/tps.js +27 -0
  53. package/lib/wallet.d.ts +10 -0
  54. package/lib/wallet.d.ts.map +1 -0
  55. package/lib/wallet.js +35 -0
  56. package/package.json +3 -13
  57. package/src/accounts/defaultClearingHouseAccountSubscriber.ts +18 -0
  58. package/src/accounts/defaultUserAccountSubscriber.ts +18 -0
  59. package/src/accounts/types.ts +3 -28
  60. package/src/accounts/webSocketAccountSubscriber.ts +16 -6
  61. package/src/clearingHouse.ts +9 -3
  62. package/src/clearingHouseUser.ts +306 -65
  63. package/src/constants/markets.ts +21 -0
  64. package/src/constants/numericConstants.ts +2 -0
  65. package/src/examples/makeTradeExample.ts +2 -1
  66. package/src/idl/clearing_house.json +94 -42
  67. package/src/index.ts +4 -1
  68. package/src/math/amm.ts +120 -13
  69. package/src/math/funding.ts +47 -25
  70. package/src/math/insuranceFund.ts +29 -0
  71. package/src/math/position.ts +16 -28
  72. package/src/math/trade.ts +9 -5
  73. package/src/types.ts +0 -14
  74. package/src/util/computeUnits.ts +21 -0
  75. package/src/util/tps.ts +27 -0
  76. package/src/wallet.ts +22 -0
  77. package/.eslintrc.json +0 -36
  78. package/.prettierignore +0 -1
  79. package/.prettierrc.js +0 -9
  80. package/lib/accounts/defaultHistoryAccountSubscriber.d.ts +0 -29
  81. package/lib/accounts/defaultHistoryAccountSubscriber.d.ts.map +0 -1
  82. package/lib/accounts/defaultHistoryAccountSubscriber.js +0 -110
  83. package/src/accounts/defaultHistoryAccountSubscriber.ts +0 -179
@@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.ClearingHouseUser = void 0;
16
16
  const bn_js_1 = __importDefault(require("bn.js"));
17
+ const position_1 = require("./math/position");
17
18
  const numericConstants_1 = require("./constants/numericConstants");
18
19
  const defaultUserAccountSubscriber_1 = require("./accounts/defaultUserAccountSubscriber");
19
20
  const _1 = require(".");
@@ -42,6 +43,14 @@ class ClearingHouseUser {
42
43
  return this.isSubscribed;
43
44
  });
44
45
  }
46
+ /**
47
+ * Forces the accountSubscriber to fetch account updates from rpc
48
+ */
49
+ fetchAccounts() {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ yield this.accountSubscriber.fetch();
52
+ });
53
+ }
45
54
  unsubscribe() {
46
55
  return __awaiter(this, void 0, void 0, function* () {
47
56
  yield this.accountSubscriber.unsubscribe();
@@ -55,18 +64,20 @@ class ClearingHouseUser {
55
64
  return this.accountSubscriber.getUserPositionsAccount();
56
65
  }
57
66
  /**
58
- * Gets the user's current position for a given market
67
+ * Gets the user's current position for a given market. If the user has no position returns undefined
59
68
  * @param marketIndex
60
69
  * @returns userPosition
61
70
  */
62
71
  getUserPosition(marketIndex) {
63
- var _a;
64
- return ((_a = this.getUserPositionsAccount().positions.find((position) => position.marketIndex.eq(marketIndex))) !== null && _a !== void 0 ? _a : {
72
+ return this.getUserPositionsAccount().positions.find((position) => position.marketIndex.eq(marketIndex));
73
+ }
74
+ getEmptyPosition(marketIndex) {
75
+ return {
65
76
  baseAssetAmount: numericConstants_1.ZERO,
66
77
  lastCumulativeFundingRate: numericConstants_1.ZERO,
67
78
  marketIndex,
68
79
  quoteAssetAmount: numericConstants_1.ZERO,
69
- });
80
+ };
70
81
  }
71
82
  getUserAccountPublicKey() {
72
83
  return __awaiter(this, void 0, void 0, function* () {
@@ -149,7 +160,7 @@ class ClearingHouseUser {
149
160
  * @returns : Precision QUOTE_PRECISION
150
161
  */
151
162
  getPositionValue(marketIndex) {
152
- const userPosition = this.getUserPosition(marketIndex);
163
+ const userPosition = this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
153
164
  const market = this.clearingHouse.getMarket(userPosition.marketIndex);
154
165
  return _1.calculateBaseAssetValue(market, userPosition);
155
166
  }
@@ -168,11 +179,12 @@ class ClearingHouseUser {
168
179
  * calculates average exit price for closing 100% of position
169
180
  * @returns : Precision MARK_PRICE_PRECISION
170
181
  */
171
- getPositionEstimatedExitPrice(position, amountToClose) {
182
+ getPositionEstimatedExitPriceAndPnl(position, amountToClose) {
172
183
  const market = this.clearingHouse.getMarket(position.marketIndex);
184
+ const entryPrice = position_1.calculateEntryPrice(position);
173
185
  if (amountToClose) {
174
186
  if (amountToClose.eq(numericConstants_1.ZERO)) {
175
- return _1.calculateMarkPrice(market);
187
+ return [_1.calculateMarkPrice(market), numericConstants_1.ZERO];
176
188
  }
177
189
  position = {
178
190
  baseAssetAmount: amountToClose,
@@ -183,12 +195,18 @@ class ClearingHouseUser {
183
195
  }
184
196
  const baseAssetValue = _1.calculateBaseAssetValue(market, position);
185
197
  if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
186
- return numericConstants_1.ZERO;
198
+ return [numericConstants_1.ZERO, numericConstants_1.ZERO];
187
199
  }
188
- return baseAssetValue
200
+ const exitPrice = baseAssetValue
189
201
  .mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
190
202
  .mul(numericConstants_1.MARK_PRICE_PRECISION)
191
203
  .div(position.baseAssetAmount.abs());
204
+ const pnlPerBase = exitPrice.sub(entryPrice);
205
+ const pnl = pnlPerBase
206
+ .mul(position.baseAssetAmount)
207
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
208
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
209
+ return [exitPrice, pnl];
192
210
  }
193
211
  /**
194
212
  * calculates current user leverage across all positions
@@ -269,7 +287,7 @@ class ClearingHouseUser {
269
287
  * @param partial
270
288
  * @returns Precision : MARK_PRICE_PRECISION
271
289
  */
272
- liquidationPrice(targetMarket, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
290
+ liquidationPriceOld(targetMarket, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
273
291
  // +/-(margin_ratio-liq_ratio) * price_now = price_liq
274
292
  // todo: margin_ratio is not symmetric on price action (both numer and denom change)
275
293
  // margin_ratio = collateral / base_asset_value
@@ -286,10 +304,9 @@ class ClearingHouseUser {
286
304
  const totalCollateralUSDC = this.getTotalCollateral();
287
305
  // calculate the total position value ignoring any value from the target market of the trade
288
306
  const totalCurrentPositionValueIgnoringTargetUSDC = this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
289
- const currentMarketPosition = this.getUserPosition(targetMarket.marketIndex);
290
- const currentMarketPositionBaseSize = currentMarketPosition
291
- ? currentMarketPosition.baseAssetAmount
292
- : numericConstants_1.ZERO;
307
+ const currentMarketPosition = this.getUserPosition(targetMarket.marketIndex) ||
308
+ this.getEmptyPosition(targetMarket.marketIndex);
309
+ const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
293
310
  // calculate position for current market after trade
294
311
  const proposedMarketPosition = {
295
312
  marketIndex: targetMarket.marketIndex,
@@ -301,8 +318,16 @@ class ClearingHouseUser {
301
318
  const proposedMarketPositionValueUSDC = _1.calculateBaseAssetValue(market, proposedMarketPosition);
302
319
  // total position value after trade
303
320
  const targetTotalPositionValueUSDC = totalCurrentPositionValueIgnoringTargetUSDC.add(proposedMarketPositionValueUSDC);
321
+ let totalFreeCollateralUSDC = this.getTotalCollateral().sub(this.getTotalPositionValue()
322
+ .mul(numericConstants_1.TEN_THOUSAND)
323
+ .div(this.getMaxLeverage('Maintenance')));
324
+ if (partial) {
325
+ totalFreeCollateralUSDC = this.getTotalCollateral().sub(this.getTotalPositionValue()
326
+ .mul(numericConstants_1.TEN_THOUSAND)
327
+ .div(this.getMaxLeverage('Partial')));
328
+ }
304
329
  // if the position value after the trade is less than total collateral, there is no liq price
305
- if (targetTotalPositionValueUSDC.lte(totalCollateralUSDC) &&
330
+ if (targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
306
331
  proposedMarketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
307
332
  return new bn_js_1.default(-1);
308
333
  }
@@ -338,6 +363,93 @@ class ClearingHouseUser {
338
363
  const liqPrice = currentPrice.mul(pctChange).div(numericConstants_1.TEN_THOUSAND);
339
364
  return liqPrice;
340
365
  }
366
+ /**
367
+ * Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
368
+ * @param targetMarket
369
+ * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
370
+ * @param partial
371
+ * @returns Precision : MARK_PRICE_PRECISION
372
+ */
373
+ liquidationPrice(targetMarket, positionBaseSizeChange = numericConstants_1.ZERO, partial = false) {
374
+ // solves formula for example calc below
375
+ /* example: assume BTC price is $40k (examine 10% up/down)
376
+
377
+ if 10k deposit and levered 10x short BTC => BTC up $400 means:
378
+ 1. higher base_asset_value (+$4k)
379
+ 2. lower collateral (-$4k)
380
+ 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
381
+
382
+ for 10x long, BTC down $400:
383
+ 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
384
+ const tc = this.getTotalCollateral();
385
+ const tpv = this.getTotalPositionValue();
386
+ const partialLev = 16;
387
+ const maintLev = 20;
388
+ const thisLev = partial ? new bn_js_1.default(partialLev) : new bn_js_1.default(maintLev);
389
+ // calculate the total position value ignoring any value from the target market of the trade
390
+ const totalCurrentPositionValueIgnoringTargetUSDC = this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
391
+ const currentMarketPosition = this.getUserPosition(targetMarket.marketIndex) ||
392
+ this.getEmptyPosition(targetMarket.marketIndex);
393
+ const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
394
+ const proposedBaseAssetAmount = currentMarketPositionBaseSize.add(positionBaseSizeChange);
395
+ // calculate position for current market after trade
396
+ const proposedMarketPosition = {
397
+ marketIndex: targetMarket.marketIndex,
398
+ baseAssetAmount: proposedBaseAssetAmount,
399
+ lastCumulativeFundingRate: currentMarketPosition.lastCumulativeFundingRate,
400
+ quoteAssetAmount: new bn_js_1.default(0),
401
+ };
402
+ const market = this.clearingHouse.getMarket(proposedMarketPosition.marketIndex);
403
+ const proposedMarketPositionValueUSDC = _1.calculateBaseAssetValue(market, proposedMarketPosition);
404
+ // total position value after trade
405
+ const targetTotalPositionValueUSDC = totalCurrentPositionValueIgnoringTargetUSDC.add(proposedMarketPositionValueUSDC);
406
+ let totalFreeCollateralUSDC = tc.sub(totalCurrentPositionValueIgnoringTargetUSDC
407
+ .mul(numericConstants_1.TEN_THOUSAND)
408
+ .div(this.getMaxLeverage('Maintenance')));
409
+ if (partial) {
410
+ totalFreeCollateralUSDC = tc.sub(totalCurrentPositionValueIgnoringTargetUSDC
411
+ .mul(numericConstants_1.TEN_THOUSAND)
412
+ .div(this.getMaxLeverage('Partial')));
413
+ }
414
+ let priceDelt;
415
+ if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
416
+ priceDelt = (tc
417
+ .mul(thisLev)
418
+ .sub(tpv))
419
+ .mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
420
+ .div(thisLev.add(new bn_js_1.default(1)));
421
+ }
422
+ else {
423
+ priceDelt = (tc
424
+ .mul(thisLev)
425
+ .sub(tpv))
426
+ .mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
427
+ .div(thisLev.sub(new bn_js_1.default(1)));
428
+ }
429
+ let currentPrice;
430
+ if (positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
431
+ currentPrice = _1.calculateMarkPrice(this.clearingHouse.getMarket(targetMarket.marketIndex));
432
+ }
433
+ else {
434
+ const direction = positionBaseSizeChange.gt(numericConstants_1.ZERO) ? _1.PositionDirection.LONG : _1.PositionDirection.SHORT;
435
+ currentPrice = _1.calculateTradeSlippage(direction, positionBaseSizeChange.abs(), this.clearingHouse.getMarket(targetMarket.marketIndex), 'base')[3]; // newPrice after swap
436
+ }
437
+ // if the position value after the trade is less than total collateral, there is no liq price
438
+ if (targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
439
+ proposedMarketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
440
+ return new bn_js_1.default(-1);
441
+ }
442
+ if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
443
+ return new bn_js_1.default(-1);
444
+ const eatMargin2 = priceDelt
445
+ .mul(numericConstants_1.AMM_RESERVE_PRECISION)
446
+ .div(proposedBaseAssetAmount);
447
+ if (eatMargin2.gt(currentPrice)) {
448
+ return new bn_js_1.default(-1);
449
+ }
450
+ const liqPrice = currentPrice.sub(eatMargin2);
451
+ return liqPrice;
452
+ }
341
453
  /**
342
454
  * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
343
455
  * @param positionMarketIndex
@@ -345,7 +457,8 @@ class ClearingHouseUser {
345
457
  * @returns : Precision MARK_PRICE_PRECISION
346
458
  */
347
459
  liquidationPriceAfterClose(positionMarketIndex, closeQuoteAmount) {
348
- const currentPosition = this.getUserPosition(positionMarketIndex);
460
+ const currentPosition = this.getUserPosition(positionMarketIndex) ||
461
+ this.getEmptyPosition(positionMarketIndex);
349
462
  const closeBaseAmount = currentPosition.baseAssetAmount
350
463
  .mul(closeQuoteAmount)
351
464
  .div(currentPosition.quoteAssetAmount)
@@ -359,31 +472,42 @@ class ClearingHouseUser {
359
472
  }
360
473
  /**
361
474
  * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
475
+ *
476
+ * To Calculate Max Quote Available:
477
+ *
478
+ * Case 1: SameSide
479
+ * => Remaining quote to get to maxLeverage
480
+ *
481
+ * Case 2: NOT SameSide && currentLeverage <= maxLeverage
482
+ * => Current opposite position x2 + remaining to get to maxLeverage
483
+ *
484
+ * Case 3: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition > maxLeverage
485
+ * => strictly reduce current position size
486
+ *
487
+ * Case 4: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition < maxLeverage
488
+ * => current position + remaining to get to maxLeverage
489
+ *
362
490
  * @param marketIndex
363
491
  * @param tradeSide
364
492
  * @param userMaxLeverageSetting - leverage : Precision TEN_THOUSAND
365
493
  * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
366
494
  */
367
495
  getMaxTradeSizeUSDC(targetMarketIndex, tradeSide, userMaxLeverageSetting) {
368
- // inline function which get's the current position size on the opposite side of the target trade
369
- const getOppositePositionValueUSDC = () => {
370
- if (!currentPosition)
371
- return numericConstants_1.ZERO;
372
- const side = tradeSide === _1.PositionDirection.SHORT ? 'short' : 'long';
373
- if (side === 'long' && (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())) {
374
- return this.getPositionValue(targetMarketIndex);
375
- }
376
- else if (side === 'short' &&
377
- !(currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())) {
378
- return this.getPositionValue(targetMarketIndex);
379
- }
380
- return numericConstants_1.ZERO;
381
- };
382
- const currentPosition = this.getUserPosition(targetMarketIndex);
496
+ const currentPosition = this.getUserPosition(targetMarketIndex) ||
497
+ this.getEmptyPosition(targetMarketIndex);
498
+ const targetSide = tradeSide === _1.PositionDirection.SHORT ? 'short' : 'long';
499
+ const currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
500
+ ? 'short'
501
+ : 'long';
502
+ const targettingSameSide = !currentPosition
503
+ ? true
504
+ : targetSide === currentPositionSide;
505
+ // 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.
506
+ const oppositeSizeValueUSDC = targettingSameSide
507
+ ? numericConstants_1.ZERO
508
+ : this.getPositionValue(targetMarketIndex);
383
509
  // get current leverage
384
510
  const currentLeverage = this.getLeverage();
385
- // remaining leverage
386
- // let remainingLeverage = userMaxLeverageSetting;
387
511
  const remainingLeverage = bn_js_1.default.max(userMaxLeverageSetting.sub(currentLeverage), numericConstants_1.ZERO);
388
512
  // get total collateral
389
513
  const totalCollateral = this.getTotalCollateral();
@@ -391,9 +515,43 @@ class ClearingHouseUser {
391
515
  let maxPositionSize = remainingLeverage
392
516
  .mul(totalCollateral)
393
517
  .div(numericConstants_1.TEN_THOUSAND);
394
- // 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.
395
- const oppositeSizeValueUSDC = getOppositePositionValueUSDC();
396
- maxPositionSize = maxPositionSize.add(oppositeSizeValueUSDC);
518
+ if (userMaxLeverageSetting.sub(currentLeverage).gte(numericConstants_1.ZERO)) {
519
+ if (oppositeSizeValueUSDC.eq(numericConstants_1.ZERO)) {
520
+ // case 1 : Regular trade where current total position less than max, and no opposite position to account for
521
+ // do nothing
522
+ }
523
+ else {
524
+ // case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
525
+ maxPositionSize = maxPositionSize.add(oppositeSizeValueUSDC.mul(new bn_js_1.default(2)));
526
+ }
527
+ }
528
+ else {
529
+ // current leverage is greater than max leverage - can only reduce position size
530
+ if (!targettingSameSide) {
531
+ const currentPositionQuoteSize = this.getPositionValue(targetMarketIndex);
532
+ const currentTotalQuoteSize = currentLeverage
533
+ .mul(totalCollateral)
534
+ .div(numericConstants_1.TEN_THOUSAND);
535
+ const otherPositionsTotalQuoteSize = currentTotalQuoteSize.sub(currentPositionQuoteSize);
536
+ const quoteValueOfMaxLeverage = userMaxLeverageSetting
537
+ .mul(totalCollateral)
538
+ .div(numericConstants_1.TEN_THOUSAND);
539
+ if (otherPositionsTotalQuoteSize
540
+ .sub(currentPositionQuoteSize)
541
+ .gte(quoteValueOfMaxLeverage)) {
542
+ // case 3: Can only reduce the current position because it will still be greater than max leverage
543
+ maxPositionSize = currentPositionQuoteSize;
544
+ }
545
+ else {
546
+ // case 4: Can reduce the position, and then take extra remaining quote to get to max leverage
547
+ const allowedQuoteSizeAfterClosingCurrentPosition = quoteValueOfMaxLeverage.sub(otherPositionsTotalQuoteSize);
548
+ maxPositionSize = currentPositionQuoteSize.add(allowedQuoteSizeAfterClosingCurrentPosition);
549
+ }
550
+ }
551
+ else {
552
+ // do nothing if targetting same side
553
+ }
554
+ }
397
555
  // subtract oneMillionth of maxPositionSize
398
556
  // => to avoid rounding errors when taking max leverage
399
557
  const oneMilli = maxPositionSize.div(numericConstants_1.QUOTE_PRECISION);
@@ -408,9 +566,10 @@ class ClearingHouseUser {
408
566
  * @returns leverageRatio : Precision TEN_THOUSAND
409
567
  */
410
568
  accountLeverageRatioAfterTrade(targetMarketIndex, tradeQuoteAmount, tradeSide) {
411
- const currentPosition = this.getUserPosition(targetMarketIndex);
412
- let currentPositionQuoteAmount = currentPosition.quoteAssetAmount;
413
- const currentSide = currentPosition.baseAssetAmount.isNeg()
569
+ const currentPosition = this.getUserPosition(targetMarketIndex) ||
570
+ this.getEmptyPosition(targetMarketIndex);
571
+ let currentPositionQuoteAmount = this.getPositionValue(targetMarketIndex);
572
+ const currentSide = currentPosition && currentPosition.baseAssetAmount.isNeg()
414
573
  ? _1.PositionDirection.SHORT
415
574
  : _1.PositionDirection.LONG;
416
575
  if (currentSide === _1.PositionDirection.SHORT)
@@ -421,11 +580,18 @@ class ClearingHouseUser {
421
580
  .add(tradeQuoteAmount)
422
581
  .abs();
423
582
  const totalPositionAfterTradeExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(targetMarketIndex);
424
- return currentMarketPositionAfterTrade
425
- .add(totalPositionAfterTradeExcludingTargetMarket)
426
- .abs()
427
- .mul(numericConstants_1.TEN_THOUSAND)
428
- .div(this.getTotalCollateral());
583
+ const totalCollateral = this.getTotalCollateral();
584
+ if (totalCollateral.gt(numericConstants_1.ZERO)) {
585
+ const newLeverage = currentMarketPositionAfterTrade
586
+ .add(totalPositionAfterTradeExcludingTargetMarket)
587
+ .abs()
588
+ .mul(numericConstants_1.TEN_THOUSAND)
589
+ .div(totalCollateral);
590
+ return newLeverage;
591
+ }
592
+ else {
593
+ return new bn_js_1.default(0);
594
+ }
429
595
  }
430
596
  /**
431
597
  * Calculates how much fee will be taken for a given sized trade
@@ -444,11 +610,11 @@ class ClearingHouseUser {
444
610
  * @returns positionValue : Precision QUOTE_PRECISION
445
611
  */
446
612
  getTotalPositionValueExcludingMarket(marketToIgnore) {
447
- const currentMarketPosition = this.getUserPosition(marketToIgnore);
613
+ const currentMarketPosition = this.getUserPosition(marketToIgnore) ||
614
+ this.getEmptyPosition(marketToIgnore);
448
615
  let currentMarketPositionValueUSDC = numericConstants_1.ZERO;
449
616
  if (currentMarketPosition) {
450
- const market = this.clearingHouse.getMarket(currentMarketPosition.marketIndex);
451
- currentMarketPositionValueUSDC = _1.calculateBaseAssetValue(market, currentMarketPosition);
617
+ currentMarketPositionValueUSDC = this.getPositionValue(marketToIgnore);
452
618
  }
453
619
  return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
454
620
  }
@@ -1 +1 @@
1
- {"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../src/constants/markets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvB,aAAK,MAAM,GAAG;IACb,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,EAAE,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,MAAM,EA2C3B,CAAC"}
1
+ {"version":3,"file":"markets.d.ts","sourceRoot":"","sources":["../../src/constants/markets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvB,aAAK,MAAM,GAAG;IACb,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,EAAE,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,MAAM,EAgE3B,CAAC"}
@@ -48,4 +48,25 @@ exports.Markets = [
48
48
  devnetPythOracle: 'GwzBgrXb4PG59zjce24SF2b9JXbLEjJJTBkmytuEZj1b',
49
49
  mainnetPythOracle: '4CkQJBxhU8EZ2UjhigbtdaPbpTe6mqf811fipYBFbSYN',
50
50
  },
51
+ {
52
+ symbol: 'MATIC-PERP',
53
+ baseAssetSymbol: 'MATIC',
54
+ marketIndex: new bn_js_1.default(6),
55
+ devnetPythOracle: 'FBirwuDFuRAu4iSGc7RGxN5koHB7EJM1wbCmyPuQoGur',
56
+ mainnetPythOracle: '7KVswB9vkCgeM3SHP7aGDijvdRAHK8P5wi9JXViCrtYh',
57
+ },
58
+ {
59
+ symbol: 'ATOM-PERP',
60
+ baseAssetSymbol: 'ATOM',
61
+ marketIndex: new bn_js_1.default(7),
62
+ devnetPythOracle: '7YAze8qFUMkBnyLVdKT4TFUUFui99EwS5gfRArMcrvFk',
63
+ mainnetPythOracle: 'CrCpTerNqtZvqLcKqz1k13oVeXV9WkMD2zA9hBKXrsbN',
64
+ },
65
+ {
66
+ symbol: 'DOT-PERP',
67
+ baseAssetSymbol: 'DOT',
68
+ marketIndex: new bn_js_1.default(8),
69
+ devnetPythOracle: '4dqq5VBpN4EwYb7wyywjjfknvMKu7m78j9mKZRXTj462',
70
+ mainnetPythOracle: 'EcV1X1gY2yb4KXxjVQtTHTbioum2gvmPnFk4zYAt7zne',
71
+ },
51
72
  ];
@@ -13,4 +13,5 @@ export declare const PEG_PRECISION: BN;
13
13
  export declare const AMM_RESERVE_PRECISION: BN;
14
14
  export declare const AMM_TO_QUOTE_PRECISION_RATIO: BN;
15
15
  export declare const PRICE_TO_QUOTE_PRECISION: BN;
16
+ export declare const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO: BN;
16
17
  //# sourceMappingURL=numericConstants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"numericConstants.d.ts","sourceRoot":"","sources":["../../src/constants/numericConstants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvB,eAAO,MAAM,IAAI,IAAY,CAAC;AAC9B,eAAO,MAAM,GAAG,IAAY,CAAC;AAC7B,eAAO,MAAM,YAAY,IAAgB,CAAC;AAC1C,eAAO,MAAM,MAAM,IAAkC,CAAC;AAEtD,eAAO,MAAM,YAAY,IAAY,CAAC;AACtC,eAAO,MAAM,sBAAsB,IAAc,CAAC;AAClD,eAAO,MAAM,yBAAyB,IAAc,CAAC;AAErD,eAAO,MAAM,eAAe,IAAkB,CAAC;AAC/C,eAAO,MAAM,oBAAoB,IAAmB,CAAC;AACrD,eAAO,MAAM,yBAAyB,IAAgB,CAAC;AACvD,eAAO,MAAM,aAAa,IAAe,CAAC;AAE1C,eAAO,MAAM,qBAAqB,IAAmB,CAAC;AACtD,eAAO,MAAM,4BAA4B,IACE,CAAC;AAC5C,eAAO,MAAM,wBAAwB,IACK,CAAC"}
1
+ {"version":3,"file":"numericConstants.d.ts","sourceRoot":"","sources":["../../src/constants/numericConstants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvB,eAAO,MAAM,IAAI,IAAY,CAAC;AAC9B,eAAO,MAAM,GAAG,IAAY,CAAC;AAC7B,eAAO,MAAM,YAAY,IAAgB,CAAC;AAC1C,eAAO,MAAM,MAAM,IAAkC,CAAC;AAEtD,eAAO,MAAM,YAAY,IAAY,CAAC;AACtC,eAAO,MAAM,sBAAsB,IAAc,CAAC;AAClD,eAAO,MAAM,yBAAyB,IAAc,CAAC;AAErD,eAAO,MAAM,eAAe,IAAkB,CAAC;AAC/C,eAAO,MAAM,oBAAoB,IAAmB,CAAC;AACrD,eAAO,MAAM,yBAAyB,IAAgB,CAAC;AACvD,eAAO,MAAM,aAAa,IAAe,CAAC;AAE1C,eAAO,MAAM,qBAAqB,IAAmB,CAAC;AACtD,eAAO,MAAM,4BAA4B,IACE,CAAC;AAC5C,eAAO,MAAM,wBAAwB,IACK,CAAC;AAC3C,eAAO,MAAM,sCAAsC,IACW,CAAC"}
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PRICE_TO_QUOTE_PRECISION = exports.AMM_TO_QUOTE_PRECISION_RATIO = 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.ONE = exports.ZERO = void 0;
6
+ exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.AMM_TO_QUOTE_PRECISION_RATIO = 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.ONE = exports.ZERO = void 0;
7
7
  const bn_js_1 = __importDefault(require("bn.js"));
8
8
  exports.ZERO = new bn_js_1.default(0);
9
9
  exports.ONE = new bn_js_1.default(1);
@@ -19,3 +19,4 @@ exports.PEG_PRECISION = new bn_js_1.default(1000);
19
19
  exports.AMM_RESERVE_PRECISION = new bn_js_1.default(Math.pow(10, 13));
20
20
  exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.AMM_RESERVE_PRECISION.div(exports.QUOTE_PRECISION); // 10^7
21
21
  exports.PRICE_TO_QUOTE_PRECISION = exports.MARK_PRICE_PRECISION.div(exports.QUOTE_PRECISION);
22
+ exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.AMM_RESERVE_PRECISION.mul(exports.PEG_PRECISION).div(exports.QUOTE_PRECISION); // 10^10
@@ -1 +1 @@
1
- {"version":3,"file":"makeTradeExample.d.ts","sourceRoot":"","sources":["../../src/examples/makeTradeExample.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAcjE,eAAO,MAAM,eAAe,gBACd,MAAM,cACP,MAAM,KAChB,QAAQ,SAAS,CAOnB,CAAC"}
1
+ {"version":3,"file":"makeTradeExample.d.ts","sourceRoot":"","sources":["../../src/examples/makeTradeExample.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAcjE,eAAO,MAAM,eAAe,gBACd,MAAM,cACP,MAAM,KAChB,QAAQ,SAAS,CAOnB,CAAC"}
@@ -11,20 +11,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getTokenAddress = void 0;
13
13
  const anchor_1 = require("@project-serum/anchor");
14
+ const __1 = require("..");
14
15
  const spl_token_1 = require("@solana/spl-token");
15
16
  const web3_js_1 = require("@solana/web3.js");
16
- const __1 = require("..");
17
+ const __2 = require("..");
17
18
  const getTokenAddress = (mintAddress, userPubKey) => {
18
19
  return spl_token_1.Token.getAssociatedTokenAddress(new web3_js_1.PublicKey(`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`), spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
19
20
  };
20
21
  exports.getTokenAddress = getTokenAddress;
21
22
  const main = () => __awaiter(void 0, void 0, void 0, function* () {
22
23
  // Initialize Drift SDK
23
- const sdkConfig = __1.initialize({ env: 'devnet' });
24
+ const sdkConfig = __2.initialize({ env: 'devnet' });
24
25
  // Set up the Wallet and Provider
25
26
  const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
26
27
  const keypair = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(privateKey)));
27
- const wallet = new anchor_1.Wallet(keypair);
28
+ const wallet = new __1.Wallet(keypair);
28
29
  // Set up the Connection
29
30
  const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
30
31
  const connection = new web3_js_1.Connection(rpcAddress);
@@ -37,35 +38,35 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
37
38
  const usdcTokenAddress = yield exports.getTokenAddress(sdkConfig.USDC_MINT_ADDRESS, wallet.publicKey.toString());
38
39
  // Set up the Drift Clearing House
39
40
  const clearingHousePublicKey = new web3_js_1.PublicKey(sdkConfig.CLEARING_HOUSE_PROGRAM_ID);
40
- const clearingHouse = __1.ClearingHouse.from(connection, provider.wallet, clearingHousePublicKey);
41
+ const clearingHouse = __2.ClearingHouse.from(connection, provider.wallet, clearingHousePublicKey);
41
42
  yield clearingHouse.subscribe();
42
43
  // Set up Clearing House user client
43
- const user = __1.ClearingHouseUser.from(clearingHouse, wallet.publicKey);
44
+ const user = __2.ClearingHouseUser.from(clearingHouse, wallet.publicKey);
44
45
  //// Check if clearing house account exists for the current wallet
45
46
  const userAccountExists = yield user.exists();
46
47
  if (!userAccountExists) {
47
48
  //// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
48
- const depositAmount = new anchor_1.BN(10000).mul(__1.QUOTE_PRECISION);
49
+ const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
49
50
  yield clearingHouse.initializeUserAccountAndDepositCollateral(depositAmount, yield exports.getTokenAddress(usdcTokenAddress.toString(), wallet.publicKey.toString()));
50
51
  }
51
52
  yield user.subscribe();
52
53
  // Get current price
53
- const solMarketInfo = __1.Markets.find((market) => market.baseAssetSymbol === 'SOL');
54
- const currentMarketPrice = __1.calculateMarkPrice(clearingHouse.getMarket(solMarketInfo.marketIndex));
55
- const formattedPrice = __1.convertToNumber(currentMarketPrice, __1.QUOTE_PRECISION);
54
+ const solMarketInfo = __2.Markets.find((market) => market.baseAssetSymbol === 'SOL');
55
+ const currentMarketPrice = __2.calculateMarkPrice(clearingHouse.getMarket(solMarketInfo.marketIndex));
56
+ const formattedPrice = __2.convertToNumber(currentMarketPrice, __2.QUOTE_PRECISION);
56
57
  console.log(`Current Market Price is $${formattedPrice}`);
57
58
  // Estimate the slippage for a $5000 LONG trade
58
59
  const solMarketAccount = clearingHouse.getMarket(solMarketInfo.marketIndex);
59
- const slippage = __1.convertToNumber(__1.calculateTradeSlippage(__1.PositionDirection.LONG, new anchor_1.BN(5000).mul(__1.QUOTE_PRECISION), solMarketAccount)[0], __1.MARK_PRICE_PRECISION);
60
+ const slippage = __2.convertToNumber(__2.calculateTradeSlippage(__2.PositionDirection.LONG, new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION), solMarketAccount)[0], __2.MARK_PRICE_PRECISION);
60
61
  console.log(`Slippage for a $5000 LONG on the SOL market would be $${slippage}`);
61
62
  // Make a $5000 LONG trade
62
- yield clearingHouse.openPosition(__1.PositionDirection.LONG, new anchor_1.BN(5000).mul(__1.QUOTE_PRECISION), solMarketInfo.marketIndex);
63
+ yield clearingHouse.openPosition(__2.PositionDirection.LONG, new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION), solMarketInfo.marketIndex);
63
64
  console.log(`LONGED $5000 SOL`);
64
65
  // Make a $5000 LONG trade
65
- yield clearingHouse.openPosition(__1.PositionDirection.LONG, new anchor_1.BN(5000).mul(__1.QUOTE_PRECISION), solMarketInfo.marketIndex);
66
+ yield clearingHouse.openPosition(__2.PositionDirection.LONG, new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION), solMarketInfo.marketIndex);
66
67
  console.log(`LONGED $5000 worth of SOL`);
67
68
  // Reduce the position by $2000
68
- yield clearingHouse.openPosition(__1.PositionDirection.SHORT, new anchor_1.BN(2000).mul(__1.QUOTE_PRECISION), solMarketInfo.marketIndex);
69
+ yield clearingHouse.openPosition(__2.PositionDirection.SHORT, new anchor_1.BN(2000).mul(__2.QUOTE_PRECISION), solMarketInfo.marketIndex);
69
70
  // Close the rest of the position
70
71
  yield clearingHouse.closePosition(solMarketInfo.marketIndex);
71
72
  });