@drift-labs/sdk 2.22.0-beta.3 → 2.23.0-beta.0

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.
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="bn.js" />
3
3
  import { AnchorProvider, BN, Program, ProgramAccount } from '@project-serum/anchor';
4
- import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, OrderType, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo } from './types';
4
+ import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, OrderType, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount } from './types';
5
5
  import * as anchor from '@project-serum/anchor';
6
6
  import { Connection, PublicKey, TransactionSignature, ConfirmOptions, Transaction, TransactionInstruction, AccountMeta, Signer, AddressLookupTableAccount } from '@solana/web3.js';
7
7
  import { TokenFaucet } from './tokenFaucet';
@@ -104,6 +104,7 @@ export declare class DriftClient {
104
104
  fetchAllUserAccounts(includeIdle?: boolean): Promise<ProgramAccount<UserAccount>[]>;
105
105
  getUserAccountsForDelegate(delegate: PublicKey): Promise<UserAccount[]>;
106
106
  getUserAccountsForAuthority(authority: PublicKey): Promise<UserAccount[]>;
107
+ getReferredUserStatsAccountsByReferrer(referrer: PublicKey): Promise<UserStatsAccount[]>;
107
108
  getReferrerNameAccountsForAuthority(authority: PublicKey): Promise<ReferrerNameAccount[]>;
108
109
  deleteUser(subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
109
110
  getUser(subAccountId?: number): User;
@@ -464,6 +464,18 @@ class DriftClient {
464
464
  ]);
465
465
  return programAccounts.map((programAccount) => programAccount.account);
466
466
  }
467
+ async getReferredUserStatsAccountsByReferrer(referrer) {
468
+ const programAccounts = await this.program.account.userStats.all([
469
+ {
470
+ memcmp: {
471
+ offset: 40,
472
+ /** data to match, as base-58 encoded string and limited to less than 129 bytes */
473
+ bytes: bs58_1.default.encode(referrer.toBuffer()),
474
+ },
475
+ },
476
+ ]);
477
+ return programAccounts.map((programAccount) => programAccount.account);
478
+ }
467
479
  async getReferrerNameAccountsForAuthority(authority) {
468
480
  const programAccounts = await this.program.account.referrerName.all([
469
481
  {
@@ -559,17 +571,30 @@ class DriftClient {
559
571
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
560
572
  // otherwise remove from slot
561
573
  if (slot > lastUserSlot) {
562
- const marketAccount = this.getPerpMarketAccount(marketIndex);
574
+ const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
563
575
  perpMarketAccountMap.set(marketIndex, {
564
- pubkey: marketAccount.pubkey,
576
+ pubkey: perpMarketAccount.pubkey,
565
577
  isSigner: false,
566
578
  isWritable: false,
567
579
  });
568
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
569
- pubkey: marketAccount.amm.oracle,
580
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
581
+ pubkey: perpMarketAccount.amm.oracle,
570
582
  isSigner: false,
571
583
  isWritable: false,
572
584
  });
585
+ const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
586
+ spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
587
+ pubkey: spotMarketAccount.pubkey,
588
+ isSigner: false,
589
+ isWritable: false,
590
+ });
591
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
592
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
593
+ pubkey: spotMarketAccount.oracle,
594
+ isSigner: false,
595
+ isWritable: false,
596
+ });
597
+ }
573
598
  }
574
599
  else {
575
600
  this.perpMarketLastSlotCache.delete(marketIndex);
@@ -579,15 +604,15 @@ class DriftClient {
579
604
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
580
605
  // otherwise remove from slot
581
606
  if (slot > lastUserSlot) {
582
- const marketAccount = this.getSpotMarketAccount(marketIndex);
607
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
583
608
  spotMarketAccountMap.set(marketIndex, {
584
- pubkey: marketAccount.pubkey,
609
+ pubkey: spotMarketAccount.pubkey,
585
610
  isSigner: false,
586
611
  isWritable: false,
587
612
  });
588
- if (!marketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
589
- oracleAccountMap.set(marketAccount.oracle.toString(), {
590
- pubkey: marketAccount.oracle,
613
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
614
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
615
+ pubkey: spotMarketAccount.oracle,
591
616
  isSigner: false,
592
617
  isWritable: false,
593
618
  });
@@ -599,42 +624,68 @@ class DriftClient {
599
624
  }
600
625
  }
601
626
  if (params.readablePerpMarketIndex !== undefined) {
602
- const marketAccount = this.getPerpMarketAccount(params.readablePerpMarketIndex);
627
+ const perpMarketAccount = this.getPerpMarketAccount(params.readablePerpMarketIndex);
603
628
  perpMarketAccountMap.set(params.readablePerpMarketIndex, {
604
- pubkey: marketAccount.pubkey,
629
+ pubkey: perpMarketAccount.pubkey,
605
630
  isSigner: false,
606
631
  isWritable: false,
607
632
  });
608
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
609
- pubkey: marketAccount.amm.oracle,
633
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
634
+ pubkey: perpMarketAccount.amm.oracle,
610
635
  isSigner: false,
611
636
  isWritable: false,
612
637
  });
638
+ const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
639
+ spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
640
+ pubkey: spotMarketAccount.pubkey,
641
+ isSigner: false,
642
+ isWritable: false,
643
+ });
644
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
645
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
646
+ pubkey: spotMarketAccount.oracle,
647
+ isSigner: false,
648
+ isWritable: false,
649
+ });
650
+ }
651
+ }
652
+ if (params.readableSpotMarketIndexes !== undefined) {
653
+ for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
654
+ const spotMarketAccount = this.getSpotMarketAccount(readableSpotMarketIndex);
655
+ spotMarketAccountMap.set(readableSpotMarketIndex, {
656
+ pubkey: spotMarketAccount.pubkey,
657
+ isSigner: false,
658
+ isWritable: false,
659
+ });
660
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
661
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
662
+ pubkey: spotMarketAccount.oracle,
663
+ isSigner: false,
664
+ isWritable: false,
665
+ });
666
+ }
667
+ }
613
668
  }
614
669
  if (params.writablePerpMarketIndexes !== undefined) {
615
670
  for (const writablePerpMarketIndex of params.writablePerpMarketIndexes) {
616
- const marketAccount = this.getPerpMarketAccount(writablePerpMarketIndex);
671
+ const perpMarketAccount = this.getPerpMarketAccount(writablePerpMarketIndex);
617
672
  perpMarketAccountMap.set(writablePerpMarketIndex, {
618
- pubkey: marketAccount.pubkey,
673
+ pubkey: perpMarketAccount.pubkey,
619
674
  isSigner: false,
620
675
  isWritable: true,
621
676
  });
622
- oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
623
- pubkey: marketAccount.amm.oracle,
677
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
678
+ pubkey: perpMarketAccount.amm.oracle,
624
679
  isSigner: false,
625
680
  isWritable: false,
626
681
  });
627
- }
628
- }
629
- if (params.readableSpotMarketIndexes !== undefined) {
630
- for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
631
- const spotMarketAccount = this.getSpotMarketAccount(readableSpotMarketIndex);
632
- spotMarketAccountMap.set(readableSpotMarketIndex, {
682
+ const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
683
+ spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
633
684
  pubkey: spotMarketAccount.pubkey,
634
685
  isSigner: false,
635
686
  isWritable: false,
636
687
  });
637
- if (spotMarketAccount.marketIndex !== 0) {
688
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
638
689
  oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
639
690
  pubkey: spotMarketAccount.oracle,
640
691
  isSigner: false,
@@ -688,27 +739,48 @@ class DriftClient {
688
739
  }
689
740
  if (!spotPosition.openAsks.eq(numericConstants_1.ZERO) ||
690
741
  !spotPosition.openBids.eq(numericConstants_1.ZERO)) {
742
+ const quoteSpotMarket = this.getQuoteSpotMarketAccount();
691
743
  spotMarketAccountMap.set(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, {
692
- pubkey: this.getQuoteSpotMarketAccount().pubkey,
744
+ pubkey: quoteSpotMarket.pubkey,
693
745
  isSigner: false,
694
746
  isWritable: false,
695
747
  });
748
+ if (!quoteSpotMarket.oracle.equals(web3_js_1.PublicKey.default)) {
749
+ oracleAccountMap.set(quoteSpotMarket.oracle.toString(), {
750
+ pubkey: quoteSpotMarket.oracle,
751
+ isSigner: false,
752
+ isWritable: false,
753
+ });
754
+ }
696
755
  }
697
756
  }
698
757
  }
699
758
  for (const position of userAccount.perpPositions) {
700
759
  if (!(0, position_1.positionIsAvailable)(position)) {
701
- const market = this.getPerpMarketAccount(position.marketIndex);
760
+ const perpMarketAccount = this.getPerpMarketAccount(position.marketIndex);
702
761
  perpMarketAccountMap.set(position.marketIndex, {
703
- pubkey: market.pubkey,
762
+ pubkey: perpMarketAccount.pubkey,
704
763
  isWritable: false,
705
764
  isSigner: false,
706
765
  });
707
- oracleAccountMap.set(market.amm.oracle.toString(), {
708
- pubkey: market.amm.oracle,
766
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
767
+ pubkey: perpMarketAccount.amm.oracle,
709
768
  isWritable: false,
710
769
  isSigner: false,
711
770
  });
771
+ const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
772
+ spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
773
+ pubkey: spotMarketAccount.pubkey,
774
+ isSigner: false,
775
+ isWritable: false,
776
+ });
777
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
778
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
779
+ pubkey: spotMarketAccount.oracle,
780
+ isSigner: false,
781
+ isWritable: false,
782
+ });
783
+ }
712
784
  }
713
785
  }
714
786
  }
@@ -16,6 +16,9 @@ function getOracleClient(oracleSource, connection) {
16
16
  if ((0, types_1.isVariant)(oracleSource, 'pyth1M')) {
17
17
  return new pythClient_1.PythClient(connection, new anchor_1.BN(1000000));
18
18
  }
19
+ if ((0, types_1.isVariant)(oracleSource, 'pythStableCoin')) {
20
+ return new pythClient_1.PythClient(connection, undefined, true);
21
+ }
19
22
  // if (isVariant(oracleSource, 'switchboard')) {
20
23
  // return new SwitchboardClient(connection);
21
24
  // }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.22.0-beta.3",
2
+ "version": "2.23.0-beta.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -4081,12 +4081,20 @@
4081
4081
  "defined": "ContractTier"
4082
4082
  }
4083
4083
  },
4084
+ {
4085
+ "name": "padding1",
4086
+ "type": "bool"
4087
+ },
4088
+ {
4089
+ "name": "quoteSpotMarketIndex",
4090
+ "type": "u16"
4091
+ },
4084
4092
  {
4085
4093
  "name": "padding",
4086
4094
  "type": {
4087
4095
  "array": [
4088
4096
  "u8",
4089
- 51
4097
+ 48
4090
4098
  ]
4091
4099
  }
4092
4100
  }
@@ -5119,7 +5127,7 @@
5119
5127
  "fields": [
5120
5128
  {
5121
5129
  "name": "revenueWithdrawSinceLastSettle",
5122
- "type": "i64"
5130
+ "type": "u64"
5123
5131
  },
5124
5132
  {
5125
5133
  "name": "maxRevenueWithdrawPerPeriod",
@@ -6383,6 +6391,9 @@
6383
6391
  },
6384
6392
  {
6385
6393
  "name": "Pyth1M"
6394
+ },
6395
+ {
6396
+ "name": "PythStableCoin"
6386
6397
  }
6387
6398
  ]
6388
6399
  }
@@ -6,7 +6,8 @@ import { BN } from '@project-serum/anchor';
6
6
  export declare class PythClient implements OracleClient {
7
7
  private connection;
8
8
  private multiple;
9
- constructor(connection: Connection, multiple?: BN);
9
+ private stableCoin;
10
+ constructor(connection: Connection, multiple?: BN, stableCoin?: boolean);
10
11
  getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
11
12
  getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
12
13
  }
@@ -5,9 +5,10 @@ const client_1 = require("@pythnetwork/client");
5
5
  const anchor_1 = require("@project-serum/anchor");
6
6
  const numericConstants_1 = require("../constants/numericConstants");
7
7
  class PythClient {
8
- constructor(connection, multiple = numericConstants_1.ONE) {
8
+ constructor(connection, multiple = numericConstants_1.ONE, stableCoin = false) {
9
9
  this.connection = connection;
10
10
  this.multiple = multiple;
11
+ this.stableCoin = stableCoin;
11
12
  }
12
13
  async getOraclePriceData(pricePublicKey) {
13
14
  const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
@@ -15,10 +16,15 @@ class PythClient {
15
16
  }
16
17
  getOraclePriceDataFromBuffer(buffer) {
17
18
  const priceData = (0, client_1.parsePriceData)(buffer);
19
+ const confidence = convertPythPrice(priceData.confidence, priceData.exponent, this.multiple);
20
+ let price = convertPythPrice(priceData.aggregate.price, priceData.exponent, this.multiple);
21
+ if (this.stableCoin) {
22
+ price = getStableCoinPrice(price, confidence);
23
+ }
18
24
  return {
19
- price: convertPythPrice(priceData.aggregate.price, priceData.exponent, this.multiple),
25
+ price,
20
26
  slot: new anchor_1.BN(priceData.lastSlot.toString()),
21
- confidence: convertPythPrice(priceData.confidence, priceData.exponent, this.multiple),
27
+ confidence,
22
28
  twap: convertPythPrice(priceData.twap.value, priceData.exponent, this.multiple),
23
29
  twapConfidence: convertPythPrice(priceData.twac.value, priceData.exponent, this.multiple),
24
30
  hasSufficientNumberOfDataPoints: true,
@@ -34,3 +40,12 @@ function convertPythPrice(price, exponent, multiple) {
34
40
  .div(pythPrecision);
35
41
  }
36
42
  exports.convertPythPrice = convertPythPrice;
43
+ const fiveBPS = new anchor_1.BN(500);
44
+ function getStableCoinPrice(price, confidence) {
45
+ if (price.sub(numericConstants_1.QUOTE_PRECISION).abs().lt(anchor_1.BN.min(confidence, fiveBPS))) {
46
+ return numericConstants_1.QUOTE_PRECISION;
47
+ }
48
+ else {
49
+ return price;
50
+ }
51
+ }
package/lib/types.d.ts CHANGED
@@ -139,6 +139,9 @@ export declare class OracleSource {
139
139
  static readonly QUOTE_ASSET: {
140
140
  quoteAsset: {};
141
141
  };
142
+ static readonly PYTH_STABLE_COIN: {
143
+ pythStableCoin: {};
144
+ };
142
145
  }
143
146
  export declare class OrderType {
144
147
  static readonly LIMIT: {
@@ -635,6 +638,7 @@ export type PerpMarketAccount = {
635
638
  quoteSettledInsurance: BN;
636
639
  quoteMaxInsurance: BN;
637
640
  };
641
+ quoteSpotMarketIndex: number;
638
642
  };
639
643
  export type HistoricalOracleData = {
640
644
  lastOraclePrice: BN;
package/lib/types.js CHANGED
@@ -82,6 +82,7 @@ OracleSource.PYTH_1K = { pyth1K: {} };
82
82
  OracleSource.PYTH_1M = { pyth1M: {} };
83
83
  // static readonly SWITCHBOARD = { switchboard: {} };
84
84
  OracleSource.QUOTE_ASSET = { quoteAsset: {} };
85
+ OracleSource.PYTH_STABLE_COIN = { pythStableCoin: {} };
85
86
  class OrderType {
86
87
  }
87
88
  exports.OrderType = OrderType;
package/lib/user.d.ts CHANGED
@@ -104,7 +104,7 @@ export declare class User {
104
104
  * calculates unrealized position price pnl
105
105
  * @returns : Precision QUOTE_PRECISION
106
106
  */
107
- getUnrealizedPNL(withFunding?: boolean, marketIndex?: number, withWeightMarginCategory?: MarginCategory): BN;
107
+ getUnrealizedPNL(withFunding?: boolean, marketIndex?: number, withWeightMarginCategory?: MarginCategory, strict?: boolean): BN;
108
108
  /**
109
109
  * calculates unrealized funding payment pnl
110
110
  * @returns : Precision QUOTE_PRECISION
@@ -125,7 +125,7 @@ export declare class User {
125
125
  * calculates TotalCollateral: collateral + unrealized pnl
126
126
  * @returns : Precision QUOTE_PRECISION
127
127
  */
128
- getTotalCollateral(marginCategory?: MarginCategory): BN;
128
+ getTotalCollateral(marginCategory?: MarginCategory, strict?: boolean): BN;
129
129
  /**
130
130
  * calculates User Health by comparing total collateral and maint. margin requirement
131
131
  * @returns : number (value from [0, 100])
@@ -135,7 +135,7 @@ export declare class User {
135
135
  * calculates sum of position value across all positions in margin system
136
136
  * @returns : Precision QUOTE_PRECISION
137
137
  */
138
- getTotalPerpPositionValue(marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean): BN;
138
+ getTotalPerpPositionValue(marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean): BN;
139
139
  /**
140
140
  * calculates position value in margin system
141
141
  * @returns : Precision QUOTE_PRECISION
package/lib/user.js CHANGED
@@ -268,7 +268,7 @@ class User {
268
268
  * @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
269
269
  */
270
270
  getMarginRequirement(marginCategory, liquidationBuffer, strict = false) {
271
- return this.getTotalPerpPositionValue(marginCategory, liquidationBuffer, true).add(this.getSpotMarketLiabilityValue(undefined, marginCategory, liquidationBuffer, true, strict));
271
+ return this.getTotalPerpPositionValue(marginCategory, liquidationBuffer, true, strict).add(this.getSpotMarketLiabilityValue(undefined, marginCategory, liquidationBuffer, true, strict));
272
272
  }
273
273
  /**
274
274
  * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
@@ -292,17 +292,31 @@ class User {
292
292
  * calculates unrealized position price pnl
293
293
  * @returns : Precision QUOTE_PRECISION
294
294
  */
295
- getUnrealizedPNL(withFunding, marketIndex, withWeightMarginCategory) {
296
- const quoteSpotMarket = this.driftClient.getQuoteSpotMarketAccount();
295
+ getUnrealizedPNL(withFunding, marketIndex, withWeightMarginCategory, strict = false) {
297
296
  return this.getActivePerpPositions()
298
297
  .filter((pos) => (marketIndex ? pos.marketIndex === marketIndex : true))
299
298
  .reduce((unrealizedPnl, perpPosition) => {
300
299
  const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
301
300
  const oraclePriceData = this.getOracleDataForPerpMarket(market.marketIndex);
301
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
302
+ const quoteOraclePriceData = this.getOracleDataForSpotMarket(market.quoteSpotMarketIndex);
302
303
  if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
303
304
  perpPosition = this.getSettledLPPosition(perpPosition.marketIndex)[0];
304
305
  }
305
306
  let positionUnrealizedPnl = (0, _1.calculatePositionPNL)(market, perpPosition, withFunding, oraclePriceData);
307
+ let quotePrice;
308
+ if (strict && positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
309
+ quotePrice = _1.BN.min(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
310
+ }
311
+ else if (strict && positionUnrealizedPnl.lt(numericConstants_1.ZERO)) {
312
+ quotePrice = _1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
313
+ }
314
+ else {
315
+ quotePrice = quoteOraclePriceData.price;
316
+ }
317
+ positionUnrealizedPnl = positionUnrealizedPnl
318
+ .mul(quotePrice)
319
+ .div(new _1.BN(numericConstants_1.PRICE_PRECISION));
306
320
  if (withWeightMarginCategory !== undefined) {
307
321
  if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
308
322
  positionUnrealizedPnl = positionUnrealizedPnl
@@ -340,31 +354,24 @@ class User {
340
354
  continue;
341
355
  }
342
356
  const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
357
+ const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
343
358
  if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX &&
344
359
  countForQuote) {
360
+ const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), spotPosition.balanceType);
345
361
  if ((0, types_1.isVariant)(spotPosition.balanceType, 'borrow')) {
346
- const tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
347
- let weight = numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION;
348
- if (marginCategory === 'Initial') {
349
- weight = _1.BN.max(weight, new _1.BN(this.getUserAccount().maxMarginRatio));
350
- }
351
- const weightedTokenValue = tokenAmount
352
- .mul(weight)
353
- .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
362
+ const weightedTokenValue = this.getSpotLiabilityValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now).abs();
354
363
  netQuoteValue = netQuoteValue.sub(weightedTokenValue);
355
- continue;
356
364
  }
357
365
  else {
358
- const tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
359
- netQuoteValue = netQuoteValue.add(tokenAmount);
360
- continue;
366
+ const weightedTokenValue = this.getSpotAssetValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, strict, now);
367
+ netQuoteValue = netQuoteValue.add(weightedTokenValue);
361
368
  }
369
+ continue;
362
370
  }
363
- const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
364
371
  if (!includeOpenOrders && countForBase) {
365
372
  if ((0, types_1.isVariant)(spotPosition.balanceType, 'borrow')) {
366
- const tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
367
- const liabilityValue = this.getSpotLiabilityValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now);
373
+ const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), _1.SpotBalanceType.BORROW);
374
+ const liabilityValue = this.getSpotLiabilityValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now).abs();
368
375
  totalLiabilityValue = totalLiabilityValue.add(liabilityValue);
369
376
  continue;
370
377
  }
@@ -381,7 +388,7 @@ class User {
381
388
  totalAssetValue = totalAssetValue.add(baseAssetValue);
382
389
  }
383
390
  if (worstCaseTokenAmount.lt(numericConstants_1.ZERO) && countForBase) {
384
- const baseLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount.abs(), oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now);
391
+ const baseLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict, now).abs();
385
392
  totalLiabilityValue = totalLiabilityValue.add(baseLiabilityValue);
386
393
  }
387
394
  if (worstCaseQuoteTokenAmount.gt(numericConstants_1.ZERO) && countForQuote) {
@@ -416,7 +423,7 @@ class User {
416
423
  }
417
424
  getSpotLiabilityValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, liquidationBuffer, strict = false, now) {
418
425
  let liabilityValue = null;
419
- if (strict && spotMarketAccount.marketIndex != numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
426
+ if (strict) {
420
427
  const estOracleTwap = (0, oracles_1.calculateLiveOracleTwap)(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
421
428
  );
422
429
  liabilityValue = (0, _1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, oraclePriceData, estOracleTwap);
@@ -444,7 +451,7 @@ class User {
444
451
  }
445
452
  getSpotAssetValue(tokenAmount, oraclePriceData, spotMarketAccount, marginCategory, strict = false, now) {
446
453
  let assetValue = null;
447
- if (strict && spotMarketAccount.marketIndex != numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
454
+ if (strict) {
448
455
  const estOracleTwap = (0, oracles_1.calculateLiveOracleTwap)(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
449
456
  );
450
457
  assetValue = (0, _1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, oraclePriceData, estOracleTwap);
@@ -474,8 +481,8 @@ class User {
474
481
  * calculates TotalCollateral: collateral + unrealized pnl
475
482
  * @returns : Precision QUOTE_PRECISION
476
483
  */
477
- getTotalCollateral(marginCategory = 'Initial') {
478
- return this.getSpotMarketAssetValue(undefined, marginCategory, true).add(this.getUnrealizedPNL(true, undefined, marginCategory));
484
+ getTotalCollateral(marginCategory = 'Initial', strict = false) {
485
+ return this.getSpotMarketAssetValue(undefined, marginCategory, true, strict).add(this.getUnrealizedPNL(true, undefined, marginCategory, strict));
479
486
  }
480
487
  /**
481
488
  * calculates User Health by comparing total collateral and maint. margin requirement
@@ -513,7 +520,7 @@ class User {
513
520
  * calculates sum of position value across all positions in margin system
514
521
  * @returns : Precision QUOTE_PRECISION
515
522
  */
516
- getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders) {
523
+ getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
517
524
  return this.getActivePerpPositions().reduce((totalPerpValue, perpPosition) => {
518
525
  const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
519
526
  if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
@@ -551,7 +558,18 @@ class User {
551
558
  if ((0, types_1.isVariant)(market.status, 'settlement')) {
552
559
  marginRatio = numericConstants_1.ZERO;
553
560
  }
561
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
562
+ const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
563
+ let quotePrice;
564
+ if (strict) {
565
+ quotePrice = _1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
566
+ }
567
+ else {
568
+ quotePrice = quoteOraclePriceData.price;
569
+ }
554
570
  baseAssetValue = baseAssetValue
571
+ .mul(quotePrice)
572
+ .div(numericConstants_1.PRICE_PRECISION)
555
573
  .mul(marginRatio)
556
574
  .div(numericConstants_1.MARGIN_PRECISION);
557
575
  if (includeOpenOrders) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.22.0-beta.3",
3
+ "version": "2.23.0-beta.0",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assert = void 0;
4
+ function assert(condition, error) {
5
+ if (!condition) {
6
+ throw new Error(error || 'Unspecified AssertionError');
7
+ }
8
+ }
9
+ exports.assert = assert;