@drift-labs/sdk 0.1.23-master.4 → 0.1.26

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 (61) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +2 -0
  2. package/lib/accounts/bulkAccountLoader.js +24 -0
  3. package/lib/addresses.js +5 -1
  4. package/lib/admin.d.ts +2 -2
  5. package/lib/admin.js +11 -5
  6. package/lib/clearingHouse.js +7 -1
  7. package/lib/clearingHouseUser.d.ts +12 -17
  8. package/lib/clearingHouseUser.js +114 -217
  9. package/lib/constants/markets.d.ts +6 -4
  10. package/lib/constants/markets.js +48 -0
  11. package/lib/constants/numericConstants.d.ts +2 -2
  12. package/lib/constants/numericConstants.js +3 -3
  13. package/lib/factory/oracleClient.d.ts +5 -0
  14. package/lib/factory/oracleClient.js +16 -0
  15. package/lib/idl/clearing_house.json +58 -5
  16. package/lib/idl/switchboard_v2.json +4663 -0
  17. package/lib/index.d.ts +4 -1
  18. package/lib/index.js +9 -2
  19. package/lib/math/funding.d.ts +6 -6
  20. package/lib/math/funding.js +4 -16
  21. package/lib/math/orders.d.ts +1 -0
  22. package/lib/math/orders.js +19 -1
  23. package/lib/mockUSDCFaucet.js +5 -1
  24. package/lib/oracles/pythClient.d.ts +14 -0
  25. package/lib/oracles/pythClient.js +53 -0
  26. package/lib/oracles/switchboardClient.d.ts +13 -0
  27. package/lib/oracles/switchboardClient.js +76 -0
  28. package/lib/oracles/types.d.ts +15 -0
  29. package/lib/oracles/types.js +2 -0
  30. package/lib/orderParams.d.ts +1 -1
  31. package/lib/orderParams.js +2 -2
  32. package/lib/orders.js +1 -1
  33. package/lib/types.d.ts +5 -1
  34. package/package.json +2 -1
  35. package/src/accounts/bulkAccountLoader.ts +32 -0
  36. package/src/accounts/types.js +10 -0
  37. package/src/accounts/utils.js +7 -0
  38. package/src/accounts/webSocketAccountSubscriber.js +76 -0
  39. package/src/addresses.js +83 -0
  40. package/src/admin.ts +15 -4
  41. package/src/clearingHouse.ts +2 -0
  42. package/src/clearingHouseUser.ts +161 -330
  43. package/src/constants/markets.ts +54 -3
  44. package/src/constants/numericConstants.ts +2 -2
  45. package/src/factory/oracleClient.ts +22 -0
  46. package/src/idl/clearing_house.json +58 -5
  47. package/src/idl/switchboard_v2.json +4663 -0
  48. package/src/index.ts +4 -1
  49. package/src/math/funding.ts +9 -25
  50. package/src/math/orders.ts +28 -0
  51. package/src/mockUSDCFaucet.js +171 -0
  52. package/src/oracles/pythClient.ts +49 -0
  53. package/src/oracles/switchboardClient.ts +87 -0
  54. package/src/oracles/types.ts +15 -0
  55. package/src/orderParams.ts +3 -2
  56. package/src/orders.ts +1 -1
  57. package/src/types.js +60 -0
  58. package/src/types.ts +6 -1
  59. package/lib/pythClient.d.ts +0 -7
  60. package/lib/pythClient.js +0 -25
  61. package/src/pythClient.ts +0 -15
@@ -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(".");
@@ -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((0, _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((0, _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
@@ -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
345
+ * @param marketPosition
323
346
  * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
324
347
  * @param partial
325
348
  * @returns Precision : MARK_PRICE_PRECISION
326
349
  */
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
407
- * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
408
- * @param partial
409
- * @returns Precision : MARK_PRICE_PRECISION
410
- */
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 = (0, _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 = (0, _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 = (0, _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
435
+ markPriceAfterTrade = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.clearingHouse.getMarket(marketPosition.marketIndex), 'base')[3]; // newPrice after swap
477
436
  }
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)) {
437
+ if (priceDelta.gt(markPriceAfterTrade)) {
481
438
  return new _1.BN(-1);
482
439
  }
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)) {
489
- return new _1.BN(-1);
490
- }
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 = (0, 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;
@@ -1,12 +1,14 @@
1
1
  /// <reference types="bn.js" />
2
- import { BN } from '../';
3
- declare type Market = {
2
+ import { BN, OracleSource } from '../';
3
+ export declare type MarketConfig = {
4
+ fullName?: string;
5
+ category?: string[];
4
6
  symbol: string;
5
7
  baseAssetSymbol: string;
6
8
  marketIndex: BN;
7
9
  devnetPythOracle: string;
8
10
  mainnetPythOracle: string;
9
11
  launchTs: number;
12
+ oracleSource: OracleSource;
10
13
  };
11
- export declare const Markets: Market[];
12
- export {};
14
+ export declare const Markets: MarketConfig[];
@@ -4,108 +4,156 @@ exports.Markets = void 0;
4
4
  const __1 = require("../");
5
5
  exports.Markets = [
6
6
  {
7
+ fullName: 'Solana',
8
+ category: ['L1', 'Infra'],
7
9
  symbol: 'SOL-PERP',
8
10
  baseAssetSymbol: 'SOL',
9
11
  marketIndex: new __1.BN(0),
10
12
  devnetPythOracle: 'J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix',
11
13
  mainnetPythOracle: 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG',
12
14
  launchTs: 1635209696886,
15
+ oracleSource: __1.OracleSource.PYTH,
13
16
  },
14
17
  {
18
+ fullName: 'Bitcoin',
19
+ category: ['L1', 'Payment'],
15
20
  symbol: 'BTC-PERP',
16
21
  baseAssetSymbol: 'BTC',
17
22
  marketIndex: new __1.BN(1),
18
23
  devnetPythOracle: 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J',
19
24
  mainnetPythOracle: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
20
25
  launchTs: 1637691088868,
26
+ oracleSource: __1.OracleSource.PYTH,
21
27
  },
22
28
  {
29
+ fullName: 'Ethereum',
30
+ category: ['L1', 'Infra'],
23
31
  symbol: 'ETH-PERP',
24
32
  baseAssetSymbol: 'ETH',
25
33
  marketIndex: new __1.BN(2),
26
34
  devnetPythOracle: 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw',
27
35
  mainnetPythOracle: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
28
36
  launchTs: 1637691133472,
37
+ oracleSource: __1.OracleSource.PYTH,
29
38
  },
30
39
  {
40
+ fullName: 'Terra',
41
+ category: ['L1', 'Infra'],
31
42
  symbol: 'LUNA-PERP',
32
43
  baseAssetSymbol: 'LUNA',
33
44
  marketIndex: new __1.BN(3),
34
45
  devnetPythOracle: '8PugCXTAHLM9kfLSQWe2njE5pzAgUdpPk3Nx5zSm7BD3',
35
46
  mainnetPythOracle: '5bmWuR1dgP4avtGYMNKLuxumZTVKGgoN2BCMXWDNL9nY',
36
47
  launchTs: 1638821738525,
48
+ oracleSource: __1.OracleSource.PYTH,
37
49
  },
38
50
  {
39
51
  symbol: 'AVAX-PERP',
52
+ category: ['L1', 'Infra'],
40
53
  baseAssetSymbol: 'AVAX',
41
54
  marketIndex: new __1.BN(4),
42
55
  devnetPythOracle: 'FVb5h1VmHPfVb1RfqZckchq18GxRv4iKt8T4eVTQAqdz',
43
56
  mainnetPythOracle: 'Ax9ujW5B9oqcv59N8m6f1BpTBq2rGeGaBcpKjC5UYsXU',
44
57
  launchTs: 1639092501080,
58
+ oracleSource: __1.OracleSource.PYTH,
45
59
  },
46
60
  {
61
+ fullName: 'Binance Coin',
47
62
  symbol: 'BNB-PERP',
63
+ category: ['L1', 'Exchange'],
48
64
  baseAssetSymbol: 'BNB',
49
65
  marketIndex: new __1.BN(5),
50
66
  devnetPythOracle: 'GwzBgrXb4PG59zjce24SF2b9JXbLEjJJTBkmytuEZj1b',
51
67
  mainnetPythOracle: '4CkQJBxhU8EZ2UjhigbtdaPbpTe6mqf811fipYBFbSYN',
52
68
  launchTs: 1639523193012,
69
+ oracleSource: __1.OracleSource.PYTH,
53
70
  },
54
71
  {
72
+ fullName: 'Polygon',
73
+ category: ['L1', 'Infra'],
55
74
  symbol: 'MATIC-PERP',
56
75
  baseAssetSymbol: 'MATIC',
57
76
  marketIndex: new __1.BN(6),
58
77
  devnetPythOracle: 'FBirwuDFuRAu4iSGc7RGxN5koHB7EJM1wbCmyPuQoGur',
59
78
  mainnetPythOracle: '7KVswB9vkCgeM3SHP7aGDijvdRAHK8P5wi9JXViCrtYh',
60
79
  launchTs: 1641488603564,
80
+ oracleSource: __1.OracleSource.PYTH,
61
81
  },
62
82
  {
83
+ fullName: 'Cosmos',
84
+ category: ['L1', 'Infra'],
63
85
  symbol: 'ATOM-PERP',
64
86
  baseAssetSymbol: 'ATOM',
65
87
  marketIndex: new __1.BN(7),
66
88
  devnetPythOracle: '7YAze8qFUMkBnyLVdKT4TFUUFui99EwS5gfRArMcrvFk',
67
89
  mainnetPythOracle: 'CrCpTerNqtZvqLcKqz1k13oVeXV9WkMD2zA9hBKXrsbN',
68
90
  launchTs: 1641920238195,
91
+ oracleSource: __1.OracleSource.PYTH,
69
92
  },
70
93
  {
94
+ fullName: 'Polkadot',
71
95
  symbol: 'DOT-PERP',
72
96
  baseAssetSymbol: 'DOT',
73
97
  marketIndex: new __1.BN(8),
74
98
  devnetPythOracle: '4dqq5VBpN4EwYb7wyywjjfknvMKu7m78j9mKZRXTj462',
75
99
  mainnetPythOracle: 'EcV1X1gY2yb4KXxjVQtTHTbioum2gvmPnFk4zYAt7zne',
76
100
  launchTs: 1642629253786,
101
+ oracleSource: __1.OracleSource.PYTH,
77
102
  },
78
103
  {
104
+ fullName: 'Cardano',
105
+ category: ['L1', 'Infra'],
79
106
  symbol: 'ADA-PERP',
80
107
  baseAssetSymbol: 'ADA',
81
108
  marketIndex: new __1.BN(9),
82
109
  devnetPythOracle: '8oGTURNmSQkrBS1AQ5NjB2p8qY34UVmMA9ojrw8vnHus',
83
110
  mainnetPythOracle: '3pyn4svBbxJ9Wnn3RVeafyLWfzie6yC5eTig2S62v9SC',
84
111
  launchTs: 1643084413000,
112
+ oracleSource: __1.OracleSource.PYTH,
85
113
  },
86
114
  {
115
+ fullName: 'Algorand',
116
+ category: ['L1', 'Infra'],
87
117
  symbol: 'ALGO-PERP',
88
118
  baseAssetSymbol: 'ALGO',
89
119
  marketIndex: new __1.BN(10),
90
120
  devnetPythOracle: 'c1A946dY5NHuVda77C8XXtXytyR3wK1SCP3eA9VRfC3',
91
121
  mainnetPythOracle: 'HqFyq1wh1xKvL7KDqqT7NJeSPdAqsDqnmBisUC2XdXAX',
92
122
  launchTs: 1643686767000,
123
+ oracleSource: __1.OracleSource.PYTH,
93
124
  },
94
125
  {
126
+ fullName: 'FTX Coin',
127
+ category: ['L1', 'Exchange'],
95
128
  symbol: 'FTT-PERP',
96
129
  baseAssetSymbol: 'FTT',
97
130
  marketIndex: new __1.BN(11),
98
131
  devnetPythOracle: '6vivTRs5ZPeeXbjo7dfburfaYDWoXjBtdtuYgQRuGfu',
99
132
  mainnetPythOracle: '8JPJJkmDScpcNmBRKGZuPuG2GYAveQgP3t5gFuMymwvF',
100
133
  launchTs: 1644382122000,
134
+ oracleSource: __1.OracleSource.PYTH,
101
135
  },
102
136
  {
137
+ fullName: 'Litecoin',
138
+ category: ['L1', 'Payments'],
103
139
  symbol: 'LTC-PERP',
104
140
  baseAssetSymbol: 'LTC',
105
141
  marketIndex: new __1.BN(12),
106
142
  devnetPythOracle: 'BLArYBCUYhdWiY8PCUTpvFE21iaJq85dvxLk9bYMobcU',
107
143
  mainnetPythOracle: '8RMnV1eD55iqUFJLMguPkYBkq8DCtx81XcmAja93LvRR',
108
144
  launchTs: 1645027429000,
145
+ oracleSource: __1.OracleSource.PYTH,
146
+ },
147
+ {
148
+ fullName: 'Ripple',
149
+ category: ['L1', 'Payments'],
150
+ symbol: 'XRP-PERP',
151
+ baseAssetSymbol: 'XRP',
152
+ marketIndex: new __1.BN(13),
153
+ devnetPythOracle: 'WMW5xc3HypXwTnPesyUT49uLsyHwNURsWAEk39onKuk',
154
+ mainnetPythOracle: 'WMW5xc3HypXwTnPesyUT49uLsyHwNURsWAEk39onKuk',
155
+ launchTs: 1647543166000,
156
+ oracleSource: __1.OracleSource.SWITCHBOARD,
109
157
  },
110
158
  // {
111
159
  // symbol: 'mSOL-PERP',
@@ -3,11 +3,10 @@ import { BN } from '../';
3
3
  export declare const ZERO: BN;
4
4
  export declare const ONE: BN;
5
5
  export declare const TWO: BN;
6
+ export declare const TEN: BN;
6
7
  export declare const TEN_THOUSAND: BN;
7
8
  export declare const BN_MAX: BN;
8
9
  export declare const MAX_LEVERAGE: BN;
9
- export declare const FULL_LIQUIDATION_RATIO: BN;
10
- export declare const PARTIAL_LIQUIDATION_RATIO: BN;
11
10
  export declare const QUOTE_PRECISION: BN;
12
11
  export declare const MARK_PRICE_PRECISION: BN;
13
12
  export declare const FUNDING_PAYMENT_PRECISION: BN;
@@ -17,3 +16,4 @@ export declare const BASE_PRECISION: BN;
17
16
  export declare const AMM_TO_QUOTE_PRECISION_RATIO: BN;
18
17
  export declare const PRICE_TO_QUOTE_PRECISION: BN;
19
18
  export declare const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO: BN;
19
+ export declare const MARGIN_PRECISION: BN;