@drift-labs/sdk 2.137.0-beta.0 → 2.137.0-beta.1

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.
package/src/user.ts CHANGED
@@ -22,14 +22,12 @@ import {
22
22
  } from './math/position';
23
23
  import {
24
24
  AMM_RESERVE_PRECISION,
25
- AMM_RESERVE_PRECISION_EXP,
26
25
  AMM_TO_QUOTE_PRECISION_RATIO,
27
26
  BASE_PRECISION,
28
27
  BN_MAX,
29
28
  DUST_POSITION_SIZE,
30
29
  FIVE_MINUTE,
31
30
  MARGIN_PRECISION,
32
- ONE,
33
31
  OPEN_ORDER_MARGIN_REQUIREMENT,
34
32
  PRICE_PRECISION,
35
33
  QUOTE_PRECISION,
@@ -84,7 +82,6 @@ import {
84
82
  getSpotLiabilityValue,
85
83
  getTokenAmount,
86
84
  } from './math/spotBalance';
87
- import { calculateMarketOpenBidAsk } from './math/amm';
88
85
  import {
89
86
  calculateBaseAssetValueWithOracle,
90
87
  calculateCollateralDepositRequiredForTrade,
@@ -227,6 +224,14 @@ export class User {
227
224
  return this.getPerpPositionForUserAccount(userAccount, marketIndex);
228
225
  }
229
226
 
227
+ public getPerpPositionOrEmpty(marketIndex: number): PerpPosition {
228
+ const userAccount = this.getUserAccount();
229
+ return (
230
+ this.getPerpPositionForUserAccount(userAccount, marketIndex) ??
231
+ this.getEmptyPosition(marketIndex)
232
+ );
233
+ }
234
+
230
235
  public getPerpPositionAndSlot(
231
236
  marketIndex: number
232
237
  ): DataAndSlot<PerpPosition | undefined> {
@@ -430,243 +435,12 @@ export class User {
430
435
  public getPerpBidAsks(marketIndex: number): [BN, BN] {
431
436
  const position = this.getPerpPosition(marketIndex);
432
437
 
433
- const [lpOpenBids, lpOpenAsks] = this.getLPBidAsks(marketIndex);
434
-
435
- const totalOpenBids = lpOpenBids.add(position.openBids);
436
- const totalOpenAsks = lpOpenAsks.add(position.openAsks);
438
+ const totalOpenBids = position.openBids;
439
+ const totalOpenAsks = position.openAsks;
437
440
 
438
441
  return [totalOpenBids, totalOpenAsks];
439
442
  }
440
443
 
441
- /**
442
- * calculates the open bids and asks for an lp
443
- * optionally pass in lpShares to see what bid/asks a user *would* take on
444
- * @returns : lp open bids
445
- * @returns : lp open asks
446
- */
447
- public getLPBidAsks(marketIndex: number, lpShares?: BN): [BN, BN] {
448
- const position = this.getPerpPosition(marketIndex);
449
-
450
- const lpSharesToCalc = lpShares ?? position?.lpShares;
451
-
452
- if (!lpSharesToCalc || lpSharesToCalc.eq(ZERO)) {
453
- return [ZERO, ZERO];
454
- }
455
-
456
- const market = this.driftClient.getPerpMarketAccount(marketIndex);
457
- const [marketOpenBids, marketOpenAsks] = calculateMarketOpenBidAsk(
458
- market.amm.baseAssetReserve,
459
- market.amm.minBaseAssetReserve,
460
- market.amm.maxBaseAssetReserve,
461
- market.amm.orderStepSize
462
- );
463
-
464
- const lpOpenBids = marketOpenBids.mul(lpSharesToCalc).div(market.amm.sqrtK);
465
- const lpOpenAsks = marketOpenAsks.mul(lpSharesToCalc).div(market.amm.sqrtK);
466
-
467
- return [lpOpenBids, lpOpenAsks];
468
- }
469
-
470
- /**
471
- * calculates the market position if the lp position was settled
472
- * @returns : the settled userPosition
473
- * @returns : the dust base asset amount (ie, < stepsize)
474
- * @returns : pnl from settle
475
- */
476
- public getPerpPositionWithLPSettle(
477
- marketIndex: number,
478
- originalPosition?: PerpPosition,
479
- burnLpShares = false,
480
- includeRemainderInBaseAmount = false
481
- ): [PerpPosition, BN, BN] {
482
- originalPosition =
483
- originalPosition ??
484
- this.getPerpPosition(marketIndex) ??
485
- this.getEmptyPosition(marketIndex);
486
-
487
- if (originalPosition.lpShares.eq(ZERO)) {
488
- return [originalPosition, ZERO, ZERO];
489
- }
490
-
491
- const position = this.getClonedPosition(originalPosition);
492
- const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
493
-
494
- if (market.amm.perLpBase != position.perLpBase) {
495
- // perLpBase = 1 => per 10 LP shares, perLpBase = -1 => per 0.1 LP shares
496
- const expoDiff = market.amm.perLpBase - position.perLpBase;
497
- const marketPerLpRebaseScalar = new BN(10 ** Math.abs(expoDiff));
498
-
499
- if (expoDiff > 0) {
500
- position.lastBaseAssetAmountPerLp =
501
- position.lastBaseAssetAmountPerLp.mul(marketPerLpRebaseScalar);
502
- position.lastQuoteAssetAmountPerLp =
503
- position.lastQuoteAssetAmountPerLp.mul(marketPerLpRebaseScalar);
504
- } else {
505
- position.lastBaseAssetAmountPerLp =
506
- position.lastBaseAssetAmountPerLp.div(marketPerLpRebaseScalar);
507
- position.lastQuoteAssetAmountPerLp =
508
- position.lastQuoteAssetAmountPerLp.div(marketPerLpRebaseScalar);
509
- }
510
-
511
- position.perLpBase = position.perLpBase + expoDiff;
512
- }
513
-
514
- const nShares = position.lpShares;
515
-
516
- // incorp unsettled funding on pre settled position
517
- const quoteFundingPnl = calculateUnsettledFundingPnl(market, position);
518
-
519
- let baseUnit = AMM_RESERVE_PRECISION;
520
- if (market.amm.perLpBase == position.perLpBase) {
521
- if (
522
- position.perLpBase >= 0 &&
523
- position.perLpBase <= AMM_RESERVE_PRECISION_EXP.toNumber()
524
- ) {
525
- const marketPerLpRebase = new BN(10 ** market.amm.perLpBase);
526
- baseUnit = baseUnit.mul(marketPerLpRebase);
527
- } else if (
528
- position.perLpBase < 0 &&
529
- position.perLpBase >= -AMM_RESERVE_PRECISION_EXP.toNumber()
530
- ) {
531
- const marketPerLpRebase = new BN(10 ** Math.abs(market.amm.perLpBase));
532
- baseUnit = baseUnit.div(marketPerLpRebase);
533
- } else {
534
- throw 'cannot calc';
535
- }
536
- } else {
537
- throw 'market.amm.perLpBase != position.perLpBase';
538
- }
539
-
540
- const deltaBaa = market.amm.baseAssetAmountPerLp
541
- .sub(position.lastBaseAssetAmountPerLp)
542
- .mul(nShares)
543
- .div(baseUnit);
544
- const deltaQaa = market.amm.quoteAssetAmountPerLp
545
- .sub(position.lastQuoteAssetAmountPerLp)
546
- .mul(nShares)
547
- .div(baseUnit);
548
-
549
- function sign(v: BN) {
550
- return v.isNeg() ? new BN(-1) : new BN(1);
551
- }
552
-
553
- function standardize(amount: BN, stepSize: BN) {
554
- const remainder = amount.abs().mod(stepSize).mul(sign(amount));
555
- const standardizedAmount = amount.sub(remainder);
556
- return [standardizedAmount, remainder];
557
- }
558
-
559
- const [standardizedBaa, remainderBaa] = standardize(
560
- deltaBaa,
561
- market.amm.orderStepSize
562
- );
563
-
564
- position.remainderBaseAssetAmount += remainderBaa.toNumber();
565
-
566
- if (
567
- Math.abs(position.remainderBaseAssetAmount) >
568
- market.amm.orderStepSize.toNumber()
569
- ) {
570
- const [newStandardizedBaa, newRemainderBaa] = standardize(
571
- new BN(position.remainderBaseAssetAmount),
572
- market.amm.orderStepSize
573
- );
574
- position.baseAssetAmount =
575
- position.baseAssetAmount.add(newStandardizedBaa);
576
- position.remainderBaseAssetAmount = newRemainderBaa.toNumber();
577
- }
578
-
579
- let dustBaseAssetValue = ZERO;
580
- if (burnLpShares && position.remainderBaseAssetAmount != 0) {
581
- const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(
582
- position.marketIndex
583
- );
584
- dustBaseAssetValue = new BN(Math.abs(position.remainderBaseAssetAmount))
585
- .mul(oraclePriceData.price)
586
- .div(AMM_RESERVE_PRECISION)
587
- .add(ONE);
588
- }
589
-
590
- let updateType;
591
- if (position.baseAssetAmount.eq(ZERO)) {
592
- updateType = 'open';
593
- } else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
594
- updateType = 'increase';
595
- } else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
596
- updateType = 'reduce';
597
- } else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
598
- updateType = 'close';
599
- } else {
600
- updateType = 'flip';
601
- }
602
-
603
- let newQuoteEntry;
604
- let pnl;
605
- if (updateType == 'open' || updateType == 'increase') {
606
- newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
607
- pnl = ZERO;
608
- } else if (updateType == 'reduce' || updateType == 'close') {
609
- newQuoteEntry = position.quoteEntryAmount.sub(
610
- position.quoteEntryAmount
611
- .mul(deltaBaa.abs())
612
- .div(position.baseAssetAmount.abs())
613
- );
614
- pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
615
- } else {
616
- newQuoteEntry = deltaQaa.sub(
617
- deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
618
- );
619
- pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
620
- }
621
- position.quoteEntryAmount = newQuoteEntry;
622
- position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
623
- position.quoteAssetAmount = position.quoteAssetAmount
624
- .add(deltaQaa)
625
- .add(quoteFundingPnl)
626
- .sub(dustBaseAssetValue);
627
- position.quoteBreakEvenAmount = position.quoteBreakEvenAmount
628
- .add(deltaQaa)
629
- .add(quoteFundingPnl)
630
- .sub(dustBaseAssetValue);
631
-
632
- // update open bids/asks
633
- const [marketOpenBids, marketOpenAsks] = calculateMarketOpenBidAsk(
634
- market.amm.baseAssetReserve,
635
- market.amm.minBaseAssetReserve,
636
- market.amm.maxBaseAssetReserve,
637
- market.amm.orderStepSize
638
- );
639
- const lpOpenBids = marketOpenBids
640
- .mul(position.lpShares)
641
- .div(market.amm.sqrtK);
642
- const lpOpenAsks = marketOpenAsks
643
- .mul(position.lpShares)
644
- .div(market.amm.sqrtK);
645
- position.openBids = lpOpenBids.add(position.openBids);
646
- position.openAsks = lpOpenAsks.add(position.openAsks);
647
-
648
- // eliminate counting funding on settled position
649
- if (position.baseAssetAmount.gt(ZERO)) {
650
- position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
651
- } else if (position.baseAssetAmount.lt(ZERO)) {
652
- position.lastCumulativeFundingRate =
653
- market.amm.cumulativeFundingRateShort;
654
- } else {
655
- position.lastCumulativeFundingRate = ZERO;
656
- }
657
-
658
- const remainderBeforeRemoval = new BN(position.remainderBaseAssetAmount);
659
-
660
- if (includeRemainderInBaseAmount) {
661
- position.baseAssetAmount = position.baseAssetAmount.add(
662
- remainderBeforeRemoval
663
- );
664
- position.remainderBaseAssetAmount = 0;
665
- }
666
-
667
- return [position, remainderBeforeRemoval, pnl];
668
- }
669
-
670
444
  /**
671
445
  * calculates Buying Power = free collateral / initial margin ratio
672
446
  * @returns : Precision QUOTE_PRECISION
@@ -676,11 +450,7 @@ export class User {
676
450
  collateralBuffer = ZERO,
677
451
  enterHighLeverageMode = undefined
678
452
  ): BN {
679
- const perpPosition = this.getPerpPositionWithLPSettle(
680
- marketIndex,
681
- undefined,
682
- true
683
- )[0];
453
+ const perpPosition = this.getPerpPositionOrEmpty(marketIndex);
684
454
 
685
455
  const perpMarket = this.driftClient.getPerpMarketAccount(marketIndex);
686
456
  const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
@@ -793,8 +563,7 @@ export class User {
793
563
  (pos) =>
794
564
  !pos.baseAssetAmount.eq(ZERO) ||
795
565
  !pos.quoteAssetAmount.eq(ZERO) ||
796
- !(pos.openOrders == 0) ||
797
- !pos.lpShares.eq(ZERO)
566
+ !(pos.openOrders == 0)
798
567
  );
799
568
  }
800
569
 
@@ -866,14 +635,6 @@ export class User {
866
635
  market.quoteSpotMarketIndex
867
636
  );
868
637
 
869
- if (perpPosition.lpShares.gt(ZERO)) {
870
- perpPosition = this.getPerpPositionWithLPSettle(
871
- perpPosition.marketIndex,
872
- undefined,
873
- !!withWeightMarginCategory
874
- )[0];
875
- }
876
-
877
638
  let positionUnrealizedPnl = calculatePositionPNL(
878
639
  market,
879
640
  perpPosition,
@@ -1450,15 +1211,6 @@ export class User {
1450
1211
  perpPosition.marketIndex
1451
1212
  );
1452
1213
 
1453
- if (perpPosition.lpShares.gt(ZERO)) {
1454
- // is an lp, clone so we dont mutate the position
1455
- perpPosition = this.getPerpPositionWithLPSettle(
1456
- market.marketIndex,
1457
- this.getClonedPosition(perpPosition),
1458
- !!marginCategory
1459
- )[0];
1460
- }
1461
-
1462
1214
  let valuationPrice = this.getOracleDataForPerpMarket(
1463
1215
  market.marketIndex
1464
1216
  ).price;
@@ -1537,19 +1289,6 @@ export class User {
1537
1289
  liabilityValue = liabilityValue.add(
1538
1290
  new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1539
1291
  );
1540
-
1541
- if (perpPosition.lpShares.gt(ZERO)) {
1542
- liabilityValue = liabilityValue.add(
1543
- BN.max(
1544
- QUOTE_PRECISION,
1545
- valuationPrice
1546
- .mul(market.amm.orderStepSize)
1547
- .mul(QUOTE_PRECISION)
1548
- .div(AMM_RESERVE_PRECISION)
1549
- .div(PRICE_PRECISION)
1550
- )
1551
- );
1552
- }
1553
1292
  }
1554
1293
  }
1555
1294
 
@@ -1613,13 +1352,7 @@ export class User {
1613
1352
  oraclePriceData: Pick<OraclePriceData, 'price'>,
1614
1353
  includeOpenOrders = false
1615
1354
  ): BN {
1616
- const userPosition =
1617
- this.getPerpPositionWithLPSettle(
1618
- marketIndex,
1619
- undefined,
1620
- false,
1621
- true
1622
- )[0] || this.getEmptyPosition(marketIndex);
1355
+ const userPosition = this.getPerpPositionOrEmpty(marketIndex);
1623
1356
  const market = this.driftClient.getPerpMarketAccount(
1624
1357
  userPosition.marketIndex
1625
1358
  );
@@ -1640,13 +1373,7 @@ export class User {
1640
1373
  oraclePriceData: OraclePriceData,
1641
1374
  includeOpenOrders = false
1642
1375
  ): BN {
1643
- const userPosition =
1644
- this.getPerpPositionWithLPSettle(
1645
- marketIndex,
1646
- undefined,
1647
- false,
1648
- true
1649
- )[0] || this.getEmptyPosition(marketIndex);
1376
+ const userPosition = this.getPerpPositionOrEmpty(marketIndex);
1650
1377
  const market = this.driftClient.getPerpMarketAccount(
1651
1378
  userPosition.marketIndex
1652
1379
  );
@@ -2197,11 +1924,9 @@ export class User {
2197
1924
  const oraclePrice =
2198
1925
  this.driftClient.getOracleDataForSpotMarket(marketIndex).price;
2199
1926
  if (perpMarketWithSameOracle) {
2200
- const perpPosition = this.getPerpPositionWithLPSettle(
2201
- perpMarketWithSameOracle.marketIndex,
2202
- undefined,
2203
- true
2204
- )[0];
1927
+ const perpPosition = this.getPerpPositionOrEmpty(
1928
+ perpMarketWithSameOracle.marketIndex
1929
+ );
2205
1930
  if (perpPosition) {
2206
1931
  let freeCollateralDeltaForPerp =
2207
1932
  this.calculateFreeCollateralDeltaForPerp(
@@ -2287,9 +2012,7 @@ export class User {
2287
2012
  this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
2288
2013
 
2289
2014
  const market = this.driftClient.getPerpMarketAccount(marketIndex);
2290
- const currentPerpPosition =
2291
- this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
2292
- this.getEmptyPosition(marketIndex);
2015
+ const currentPerpPosition = this.getPerpPositionOrEmpty(marketIndex);
2293
2016
 
2294
2017
  positionBaseSizeChange = standardizeBaseAssetAmount(
2295
2018
  positionBaseSizeChange,
@@ -2587,12 +2310,7 @@ export class User {
2587
2310
  closeQuoteAmount: BN,
2588
2311
  estimatedEntryPrice: BN = ZERO
2589
2312
  ): BN {
2590
- const currentPosition =
2591
- this.getPerpPositionWithLPSettle(
2592
- positionMarketIndex,
2593
- undefined,
2594
- true
2595
- )[0] || this.getEmptyPosition(positionMarketIndex);
2313
+ const currentPosition = this.getPerpPositionOrEmpty(positionMarketIndex);
2596
2314
 
2597
2315
  const closeBaseAmount = currentPosition.baseAssetAmount
2598
2316
  .mul(closeQuoteAmount)
@@ -2658,9 +2376,7 @@ export class User {
2658
2376
  ): { tradeSize: BN; oppositeSideTradeSize: BN } {
2659
2377
  let tradeSize = ZERO;
2660
2378
  let oppositeSideTradeSize = ZERO;
2661
- const currentPosition =
2662
- this.getPerpPositionWithLPSettle(targetMarketIndex, undefined, true)[0] ||
2663
- this.getEmptyPosition(targetMarketIndex);
2379
+ const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
2664
2380
 
2665
2381
  const targetSide = isVariant(tradeSide, 'short') ? 'short' : 'long';
2666
2382
 
@@ -3433,9 +3149,7 @@ export class User {
3433
3149
  return newLeverage;
3434
3150
  }
3435
3151
 
3436
- const currentPosition =
3437
- this.getPerpPositionWithLPSettle(targetMarketIndex)[0] ||
3438
- this.getEmptyPosition(targetMarketIndex);
3152
+ const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
3439
3153
 
3440
3154
  const perpMarket = this.driftClient.getPerpMarketAccount(targetMarketIndex);
3441
3155
  const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
@@ -3848,10 +3562,6 @@ export class User {
3848
3562
  oraclePriceData?: OraclePriceData;
3849
3563
  quoteOraclePriceData?: OraclePriceData;
3850
3564
  }): HealthComponent {
3851
- const settledLpPosition = this.getPerpPositionWithLPSettle(
3852
- perpPosition.marketIndex,
3853
- perpPosition
3854
- )[0];
3855
3565
  const perpMarket = this.driftClient.getPerpMarketAccount(
3856
3566
  perpPosition.marketIndex
3857
3567
  );
@@ -3863,7 +3573,7 @@ export class User {
3863
3573
  worstCaseBaseAssetAmount: worstCaseBaseAmount,
3864
3574
  worstCaseLiabilityValue,
3865
3575
  } = calculateWorstCasePerpLiabilityValue(
3866
- settledLpPosition,
3576
+ perpPosition,
3867
3577
  perpMarket,
3868
3578
  oraclePrice
3869
3579
  );
@@ -3892,19 +3602,6 @@ export class User {
3892
3602
  new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
3893
3603
  );
3894
3604
 
3895
- if (perpPosition.lpShares.gt(ZERO)) {
3896
- marginRequirement = marginRequirement.add(
3897
- BN.max(
3898
- QUOTE_PRECISION,
3899
- oraclePrice
3900
- .mul(perpMarket.amm.orderStepSize)
3901
- .mul(QUOTE_PRECISION)
3902
- .div(AMM_RESERVE_PRECISION)
3903
- .div(PRICE_PRECISION)
3904
- )
3905
- );
3906
- }
3907
-
3908
3605
  return {
3909
3606
  marketIndex: perpMarket.marketIndex,
3910
3607
  size: worstCaseBaseAmount,
@@ -3952,14 +3649,9 @@ export class User {
3952
3649
  perpMarket.quoteSpotMarketIndex
3953
3650
  );
3954
3651
 
3955
- const settledPerpPosition = this.getPerpPositionWithLPSettle(
3956
- perpPosition.marketIndex,
3957
- perpPosition
3958
- )[0];
3959
-
3960
3652
  const positionUnrealizedPnl = calculatePositionPNL(
3961
3653
  perpMarket,
3962
- settledPerpPosition,
3654
+ perpPosition,
3963
3655
  true,
3964
3656
  oraclePriceData
3965
3657
  );
@@ -4111,12 +3803,7 @@ export class User {
4111
3803
  liquidationBuffer?: BN,
4112
3804
  includeOpenOrders?: boolean
4113
3805
  ): BN {
4114
- const currentPerpPosition =
4115
- this.getPerpPositionWithLPSettle(
4116
- marketToIgnore,
4117
- undefined,
4118
- !!marginCategory
4119
- )[0] || this.getEmptyPosition(marketToIgnore);
3806
+ const currentPerpPosition = this.getPerpPositionOrEmpty(marketToIgnore);
4120
3807
 
4121
3808
  const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
4122
3809