@drift-labs/sdk 2.22.0 → 2.23.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
@@ -424,7 +424,8 @@ export class User {
424
424
  return this.getTotalPerpPositionValue(
425
425
  marginCategory,
426
426
  liquidationBuffer,
427
- true
427
+ true,
428
+ strict
428
429
  ).add(
429
430
  this.getSpotMarketLiabilityValue(
430
431
  undefined,
@@ -467,9 +468,9 @@ export class User {
467
468
  public getUnrealizedPNL(
468
469
  withFunding?: boolean,
469
470
  marketIndex?: number,
470
- withWeightMarginCategory?: MarginCategory
471
+ withWeightMarginCategory?: MarginCategory,
472
+ strict = false
471
473
  ): BN {
472
- const quoteSpotMarket = this.driftClient.getQuoteSpotMarketAccount();
473
474
  return this.getActivePerpPositions()
474
475
  .filter((pos) => (marketIndex ? pos.marketIndex === marketIndex : true))
475
476
  .reduce((unrealizedPnl, perpPosition) => {
@@ -480,6 +481,13 @@ export class User {
480
481
  market.marketIndex
481
482
  );
482
483
 
484
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
485
+ market.quoteSpotMarketIndex
486
+ );
487
+ const quoteOraclePriceData = this.getOracleDataForSpotMarket(
488
+ market.quoteSpotMarketIndex
489
+ );
490
+
483
491
  if (perpPosition.lpShares.gt(ZERO)) {
484
492
  perpPosition = this.getSettledLPPosition(perpPosition.marketIndex)[0];
485
493
  }
@@ -491,6 +499,25 @@ export class User {
491
499
  oraclePriceData
492
500
  );
493
501
 
502
+ let quotePrice;
503
+ if (strict && positionUnrealizedPnl.gt(ZERO)) {
504
+ quotePrice = BN.min(
505
+ quoteOraclePriceData.price,
506
+ quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
507
+ );
508
+ } else if (strict && positionUnrealizedPnl.lt(ZERO)) {
509
+ quotePrice = BN.max(
510
+ quoteOraclePriceData.price,
511
+ quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
512
+ );
513
+ } else {
514
+ quotePrice = quoteOraclePriceData.price;
515
+ }
516
+
517
+ positionUnrealizedPnl = positionUnrealizedPnl
518
+ .mul(quotePrice)
519
+ .div(new BN(PRICE_PRECISION));
520
+
494
521
  if (withWeightMarginCategory !== undefined) {
495
522
  if (positionUnrealizedPnl.gt(ZERO)) {
496
523
  positionUnrealizedPnl = positionUnrealizedPnl
@@ -558,55 +585,60 @@ export class User {
558
585
  const spotMarketAccount: SpotMarketAccount =
559
586
  this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
560
587
 
588
+ const oraclePriceData = this.getOracleDataForSpotMarket(
589
+ spotPosition.marketIndex
590
+ );
591
+
561
592
  if (
562
593
  spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX &&
563
594
  countForQuote
564
595
  ) {
565
- if (isVariant(spotPosition.balanceType, 'borrow')) {
566
- const tokenAmount = getTokenAmount(
596
+ const tokenAmount = getSignedTokenAmount(
597
+ getTokenAmount(
567
598
  spotPosition.scaledBalance,
568
599
  spotMarketAccount,
569
600
  spotPosition.balanceType
570
- );
571
-
572
- let weight = SPOT_MARKET_WEIGHT_PRECISION;
573
- if (marginCategory === 'Initial') {
574
- weight = BN.max(
575
- weight,
576
- new BN(this.getUserAccount().maxMarginRatio)
577
- );
578
- }
601
+ ),
602
+ spotPosition.balanceType
603
+ );
579
604
 
580
- const weightedTokenValue = tokenAmount
581
- .mul(weight)
582
- .div(SPOT_MARKET_WEIGHT_PRECISION);
605
+ if (isVariant(spotPosition.balanceType, 'borrow')) {
606
+ const weightedTokenValue = this.getSpotLiabilityValue(
607
+ tokenAmount,
608
+ oraclePriceData,
609
+ spotMarketAccount,
610
+ marginCategory,
611
+ liquidationBuffer,
612
+ strict,
613
+ now
614
+ ).abs();
583
615
 
584
616
  netQuoteValue = netQuoteValue.sub(weightedTokenValue);
585
-
586
- continue;
587
617
  } else {
588
- const tokenAmount = getTokenAmount(
589
- spotPosition.scaledBalance,
618
+ const weightedTokenValue = this.getSpotAssetValue(
619
+ tokenAmount,
620
+ oraclePriceData,
590
621
  spotMarketAccount,
591
- spotPosition.balanceType
622
+ marginCategory,
623
+ strict,
624
+ now
592
625
  );
593
626
 
594
- netQuoteValue = netQuoteValue.add(tokenAmount);
595
-
596
- continue;
627
+ netQuoteValue = netQuoteValue.add(weightedTokenValue);
597
628
  }
598
- }
599
629
 
600
- const oraclePriceData = this.getOracleDataForSpotMarket(
601
- spotPosition.marketIndex
602
- );
630
+ continue;
631
+ }
603
632
 
604
633
  if (!includeOpenOrders && countForBase) {
605
634
  if (isVariant(spotPosition.balanceType, 'borrow')) {
606
- const tokenAmount = getTokenAmount(
607
- spotPosition.scaledBalance,
608
- spotMarketAccount,
609
- spotPosition.balanceType
635
+ const tokenAmount = getSignedTokenAmount(
636
+ getTokenAmount(
637
+ spotPosition.scaledBalance,
638
+ spotMarketAccount,
639
+ spotPosition.balanceType
640
+ ),
641
+ SpotBalanceType.BORROW
610
642
  );
611
643
  const liabilityValue = this.getSpotLiabilityValue(
612
644
  tokenAmount,
@@ -616,7 +648,7 @@ export class User {
616
648
  liquidationBuffer,
617
649
  strict,
618
650
  now
619
- );
651
+ ).abs();
620
652
  totalLiabilityValue = totalLiabilityValue.add(liabilityValue);
621
653
 
622
654
  continue;
@@ -662,14 +694,14 @@ export class User {
662
694
 
663
695
  if (worstCaseTokenAmount.lt(ZERO) && countForBase) {
664
696
  const baseLiabilityValue = this.getSpotLiabilityValue(
665
- worstCaseTokenAmount.abs(),
697
+ worstCaseTokenAmount,
666
698
  oraclePriceData,
667
699
  spotMarketAccount,
668
700
  marginCategory,
669
701
  liquidationBuffer,
670
702
  strict,
671
703
  now
672
- );
704
+ ).abs();
673
705
 
674
706
  totalLiabilityValue = totalLiabilityValue.add(baseLiabilityValue);
675
707
  }
@@ -738,7 +770,7 @@ export class User {
738
770
  ): BN {
739
771
  let liabilityValue = null;
740
772
 
741
- if (strict && spotMarketAccount.marketIndex != QUOTE_SPOT_MARKET_INDEX) {
773
+ if (strict) {
742
774
  const estOracleTwap = calculateLiveOracleTwap(
743
775
  spotMarketAccount.historicalOracleData,
744
776
  oraclePriceData,
@@ -809,7 +841,7 @@ export class User {
809
841
  now?: BN
810
842
  ): BN {
811
843
  let assetValue = null;
812
- if (strict && spotMarketAccount.marketIndex != QUOTE_SPOT_MARKET_INDEX) {
844
+ if (strict) {
813
845
  const estOracleTwap = calculateLiveOracleTwap(
814
846
  spotMarketAccount.historicalOracleData,
815
847
  oraclePriceData,
@@ -886,10 +918,16 @@ export class User {
886
918
  * calculates TotalCollateral: collateral + unrealized pnl
887
919
  * @returns : Precision QUOTE_PRECISION
888
920
  */
889
- public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
890
- return this.getSpotMarketAssetValue(undefined, marginCategory, true).add(
891
- this.getUnrealizedPNL(true, undefined, marginCategory)
892
- );
921
+ public getTotalCollateral(
922
+ marginCategory: MarginCategory = 'Initial',
923
+ strict = false
924
+ ): BN {
925
+ return this.getSpotMarketAssetValue(
926
+ undefined,
927
+ marginCategory,
928
+ true,
929
+ strict
930
+ ).add(this.getUnrealizedPNL(true, undefined, marginCategory, strict));
893
931
  }
894
932
 
895
933
  /**
@@ -941,7 +979,8 @@ export class User {
941
979
  getTotalPerpPositionValue(
942
980
  marginCategory?: MarginCategory,
943
981
  liquidationBuffer?: BN,
944
- includeOpenOrders?: boolean
982
+ includeOpenOrders?: boolean,
983
+ strict = false
945
984
  ): BN {
946
985
  return this.getActivePerpPositions().reduce(
947
986
  (totalPerpValue, perpPosition) => {
@@ -1011,7 +1050,27 @@ export class User {
1011
1050
  marginRatio = ZERO;
1012
1051
  }
1013
1052
 
1053
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
1054
+ market.quoteSpotMarketIndex
1055
+ );
1056
+ const quoteOraclePriceData =
1057
+ this.driftClient.getOraclePriceDataAndSlot(
1058
+ quoteSpotMarket.oracle
1059
+ ).data;
1060
+
1061
+ let quotePrice;
1062
+ if (strict) {
1063
+ quotePrice = BN.max(
1064
+ quoteOraclePriceData.price,
1065
+ quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
1066
+ );
1067
+ } else {
1068
+ quotePrice = quoteOraclePriceData.price;
1069
+ }
1070
+
1014
1071
  baseAssetValue = baseAssetValue
1072
+ .mul(quotePrice)
1073
+ .div(PRICE_PRECISION)
1015
1074
  .mul(marginRatio)
1016
1075
  .div(MARGIN_PRECISION);
1017
1076
 
@@ -2178,7 +2237,8 @@ export class User {
2178
2237
  }
2179
2238
 
2180
2239
  const userLastActiveSlot = userAccount.lastActiveSlot;
2181
- if (userLastActiveSlot.lt(slotsBeforeIdle)) {
2240
+ const slotsSinceLastActive = slot.sub(userLastActiveSlot);
2241
+ if (slotsSinceLastActive.lt(slotsBeforeIdle)) {
2182
2242
  return false;
2183
2243
  }
2184
2244
 
@@ -172,6 +172,7 @@ export const mockPerpMarkets: Array<PerpMarketAccount> = [
172
172
  quoteSettledInsurance: new BN(0),
173
173
  quoteMaxInsurance: new BN(0),
174
174
  },
175
+ quoteSpotMarketIndex: 0,
175
176
  },
176
177
  {
177
178
  status: MarketStatus.INITIALIZED,
@@ -208,6 +209,7 @@ export const mockPerpMarkets: Array<PerpMarketAccount> = [
208
209
  quoteSettledInsurance: new BN(0),
209
210
  quoteMaxInsurance: new BN(0),
210
211
  },
212
+ quoteSpotMarketIndex: 0,
211
213
  },
212
214
  {
213
215
  status: MarketStatus.INITIALIZED,
@@ -244,6 +246,7 @@ export const mockPerpMarkets: Array<PerpMarketAccount> = [
244
246
  quoteSettledInsurance: new BN(0),
245
247
  quoteMaxInsurance: new BN(0),
246
248
  },
249
+ quoteSpotMarketIndex: 0,
247
250
  },
248
251
  ];
249
252