@drift-labs/sdk 2.131.0-beta.9 → 2.131.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.
package/lib/node/user.js CHANGED
@@ -426,7 +426,7 @@ class User {
426
426
  * calculates Buying Power = free collateral / initial margin ratio
427
427
  * @returns : Precision QUOTE_PRECISION
428
428
  */
429
- getPerpBuyingPower(marketIndex, collateralBuffer = numericConstants_1.ZERO, enterHighLeverageMode = false) {
429
+ getPerpBuyingPower(marketIndex, collateralBuffer = numericConstants_1.ZERO, enterHighLeverageMode = undefined) {
430
430
  const perpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0];
431
431
  const perpMarket = this.driftClient.getPerpMarketAccount(marketIndex);
432
432
  const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
@@ -436,7 +436,7 @@ class User {
436
436
  const freeCollateral = this.getFreeCollateral('Initial', enterHighLeverageMode).sub(collateralBuffer);
437
437
  return this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, worstCaseBaseAssetAmount, enterHighLeverageMode);
438
438
  }
439
- getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, baseAssetAmount, enterHighLeverageMode = false) {
439
+ getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, baseAssetAmount, enterHighLeverageMode = undefined) {
440
440
  const marginRatio = (0, market_1.calculateMarketMarginRatio)(this.driftClient.getPerpMarketAccount(marketIndex), baseAssetAmount, 'Initial', this.getUserAccount().maxMarginRatio, enterHighLeverageMode || this.isHighLeverageMode('Initial'));
441
441
  return freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new anchor_1.BN(marginRatio));
442
442
  }
@@ -444,7 +444,7 @@ class User {
444
444
  * calculates Free Collateral = Total collateral - margin requirement
445
445
  * @returns : Precision QUOTE_PRECISION
446
446
  */
447
- getFreeCollateral(marginCategory = 'Initial', enterHighLeverageMode = false) {
447
+ getFreeCollateral(marginCategory = 'Initial', enterHighLeverageMode = undefined) {
448
448
  const totalCollateral = this.getTotalCollateral(marginCategory, true);
449
449
  const marginRequirement = marginCategory === 'Initial'
450
450
  ? this.getInitialMarginRequirement(enterHighLeverageMode)
@@ -455,13 +455,13 @@ class User {
455
455
  /**
456
456
  * @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
457
457
  */
458
- getMarginRequirement(marginCategory, liquidationBuffer, strict = false, includeOpenOrders = true, enteringHighLeverage = false) {
458
+ getMarginRequirement(marginCategory, liquidationBuffer, strict = false, includeOpenOrders = true, enteringHighLeverage = undefined) {
459
459
  return this.getTotalPerpPositionLiability(marginCategory, liquidationBuffer, includeOpenOrders, strict, enteringHighLeverage).add(this.getSpotMarketLiabilityValue(undefined, marginCategory, liquidationBuffer, includeOpenOrders, strict));
460
460
  }
461
461
  /**
462
462
  * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
463
463
  */
464
- getInitialMarginRequirement(enterHighLeverageMode = false) {
464
+ getInitialMarginRequirement(enterHighLeverageMode = undefined) {
465
465
  return this.getMarginRequirement('Initial', undefined, true, undefined, enterHighLeverageMode);
466
466
  }
467
467
  /**
@@ -749,7 +749,7 @@ class User {
749
749
  }
750
750
  return health;
751
751
  }
752
- calculateWeightedPerpPositionLiability(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict = false, enteringHighLeverage = false) {
752
+ calculateWeightedPerpPositionLiability(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict = false, enteringHighLeverage = undefined) {
753
753
  const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
754
754
  if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
755
755
  // is an lp, clone so we dont mutate the position
@@ -771,7 +771,11 @@ class User {
771
771
  liabilityValue = (0, margin_1.calculatePerpLiabilityValue)(baseAssetAmount, valuationPrice, (0, types_1.isVariant)(market.contractType, 'prediction'));
772
772
  }
773
773
  if (marginCategory) {
774
- let marginRatio = new anchor_1.BN((0, market_1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory, this.getUserAccount().maxMarginRatio, this.isHighLeverageMode(marginCategory) || enteringHighLeverage));
774
+ const userCustomMargin = this.getUserAccount().maxMarginRatio;
775
+ let marginRatio = new anchor_1.BN((0, market_1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory, enteringHighLeverage === false
776
+ ? Math.max(market.marginRatioInitial, userCustomMargin)
777
+ : userCustomMargin, this.isHighLeverageMode(marginCategory) ||
778
+ enteringHighLeverage === true));
775
779
  if (liquidationBuffer !== undefined) {
776
780
  marginRatio = marginRatio.add(liquidationBuffer);
777
781
  }
@@ -817,7 +821,7 @@ class User {
817
821
  * calculates sum of position value across all positions in margin system
818
822
  * @returns : Precision QUOTE_PRECISION
819
823
  */
820
- getTotalPerpPositionLiability(marginCategory, liquidationBuffer, includeOpenOrders, strict = false, enteringHighLeverage = false) {
824
+ getTotalPerpPositionLiability(marginCategory, liquidationBuffer, includeOpenOrders, strict = false, enteringHighLeverage = undefined) {
821
825
  return this.getActivePerpPositions().reduce((totalPerpValue, perpPosition) => {
822
826
  const baseAssetValue = this.calculateWeightedPerpPositionLiability(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict, enteringHighLeverage);
823
827
  return totalPerpValue.add(baseAssetValue);
@@ -984,7 +988,7 @@ class User {
984
988
  * @param enterHighLeverageMode can pass this as true to calculate max leverage if the user was to enter high leverage mode
985
989
  * @returns : Precision TEN_THOUSAND
986
990
  */
987
- getMaxLeverageForPerp(perpMarketIndex, _marginCategory = 'Initial', isLp = false, enterHighLeverageMode = false) {
991
+ getMaxLeverageForPerp(perpMarketIndex, _marginCategory = 'Initial', isLp = false, enterHighLeverageMode = undefined) {
988
992
  const market = this.driftClient.getPerpMarketAccount(perpMarketIndex);
989
993
  const marketPrice = this.driftClient.getOracleDataForPerpMarket(perpMarketIndex).price;
990
994
  const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents();
@@ -1166,7 +1170,7 @@ class User {
1166
1170
  * @param offsetCollateral // allows calculating the liquidation price after this offset collateral is added to the user's account (e.g. : what will the liquidation price be for this position AFTER I deposit $x worth of collateral)
1167
1171
  * @returns Precision : PRICE_PRECISION
1168
1172
  */
1169
- liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO, marginCategory = 'Maintenance', includeOpenOrders = false, offsetCollateral = numericConstants_1.ZERO, enteringHighLeverage = false) {
1173
+ liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO, marginCategory = 'Maintenance', includeOpenOrders = false, offsetCollateral = numericConstants_1.ZERO, enteringHighLeverage = undefined) {
1170
1174
  const totalCollateral = this.getTotalCollateral(marginCategory, false, includeOpenOrders);
1171
1175
  const marginRequirement = this.getMarginRequirement(marginCategory, undefined, false, includeOpenOrders, enteringHighLeverage);
1172
1176
  let freeCollateral = anchor_1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(marginRequirement)).add(offsetCollateral);
@@ -1211,7 +1215,7 @@ class User {
1211
1215
  }
1212
1216
  return liqPrice;
1213
1217
  }
1214
- calculateEntriesEffectOnFreeCollateral(market, oraclePrice, perpPosition, positionBaseSizeChange, estimatedEntryPrice, includeOpenOrders, enteringHighLeverage = false, marginCategory = 'Maintenance') {
1218
+ calculateEntriesEffectOnFreeCollateral(market, oraclePrice, perpPosition, positionBaseSizeChange, estimatedEntryPrice, includeOpenOrders, enteringHighLeverage = undefined, marginCategory = 'Maintenance') {
1215
1219
  let freeCollateralChange = numericConstants_1.ZERO;
1216
1220
  // update free collateral to account for change in pnl from new position
1217
1221
  if (!estimatedEntryPrice.eq(numericConstants_1.ZERO) &&
@@ -1248,7 +1252,10 @@ class User {
1248
1252
  baseAssetAmount = perpPosition.baseAssetAmount;
1249
1253
  liabilityValue = (0, margin_1.calculatePerpLiabilityValue)(baseAssetAmount, oraclePrice, (0, types_1.isVariant)(market.contractType, 'prediction'));
1250
1254
  }
1251
- const marginRatio = (0, market_1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory, this.getUserAccount().maxMarginRatio, this.isHighLeverageMode(marginCategory) || enteringHighLeverage);
1255
+ const userCustomMargin = this.getUserAccount().maxMarginRatio;
1256
+ const marginRatio = (0, market_1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory, enteringHighLeverage === false
1257
+ ? Math.max(market.marginRatioInitial, userCustomMargin)
1258
+ : userCustomMargin, this.isHighLeverageMode(marginCategory) || enteringHighLeverage === true);
1252
1259
  return liabilityValue.mul(new anchor_1.BN(marginRatio)).div(numericConstants_1.MARGIN_PRECISION);
1253
1260
  };
1254
1261
  const freeCollateralConsumptionBefore = calculateMarginRequirement(perpPosition);
@@ -1257,14 +1264,17 @@ class User {
1257
1264
  const freeCollateralConsumptionAfter = calculateMarginRequirement(perpPositionAfter);
1258
1265
  return freeCollateralChange.sub(freeCollateralConsumptionAfter.sub(freeCollateralConsumptionBefore));
1259
1266
  }
1260
- calculateFreeCollateralDeltaForPerp(market, perpPosition, positionBaseSizeChange, oraclePrice, marginCategory = 'Maintenance', includeOpenOrders = false, enteringHighLeverage = false) {
1267
+ calculateFreeCollateralDeltaForPerp(market, perpPosition, positionBaseSizeChange, oraclePrice, marginCategory = 'Maintenance', includeOpenOrders = false, enteringHighLeverage = undefined) {
1261
1268
  const baseAssetAmount = includeOpenOrders
1262
1269
  ? (0, margin_2.calculateWorstCaseBaseAssetAmount)(perpPosition, market, oraclePrice)
1263
1270
  : perpPosition.baseAssetAmount;
1264
1271
  // zero if include orders == false
1265
1272
  const orderBaseAssetAmount = baseAssetAmount.sub(perpPosition.baseAssetAmount);
1266
1273
  const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
1267
- const marginRatio = (0, market_1.calculateMarketMarginRatio)(market, proposedBaseAssetAmount.abs(), marginCategory, this.getUserAccount().maxMarginRatio, this.isHighLeverageMode(marginCategory) || enteringHighLeverage);
1274
+ const userCustomMargin = this.getUserAccount().maxMarginRatio;
1275
+ const marginRatio = (0, market_1.calculateMarketMarginRatio)(market, proposedBaseAssetAmount.abs(), marginCategory, enteringHighLeverage === false
1276
+ ? Math.max(market.marginRatioInitial, userCustomMargin)
1277
+ : userCustomMargin, this.isHighLeverageMode(marginCategory) || enteringHighLeverage === true);
1268
1278
  const marginRatioQuotePrecision = new anchor_1.BN(marginRatio)
1269
1279
  .mul(numericConstants_1.QUOTE_PRECISION)
1270
1280
  .div(numericConstants_1.MARGIN_PRECISION);
@@ -1353,7 +1363,7 @@ class User {
1353
1363
  * @param isLp
1354
1364
  * @returns { tradeSize: BN, oppositeSideTradeSize: BN} : Precision QUOTE_PRECISION
1355
1365
  */
1356
- getMaxTradeSizeUSDCForPerp(targetMarketIndex, tradeSide, isLp = false, enterHighLeverageMode = false) {
1366
+ getMaxTradeSizeUSDCForPerp(targetMarketIndex, tradeSide, isLp = false, enterHighLeverageMode = undefined) {
1357
1367
  let tradeSize = numericConstants_1.ZERO;
1358
1368
  let oppositeSideTradeSize = numericConstants_1.ZERO;
1359
1369
  const currentPosition = this.getPerpPositionWithLPSettle(targetMarketIndex, undefined, true)[0] ||
@@ -1772,7 +1782,7 @@ class User {
1772
1782
  }
1773
1783
  getUserFeeTier(marketType, now) {
1774
1784
  const state = this.driftClient.getStateAccount();
1775
- let feeTierIndex = 0;
1785
+ const feeTierIndex = 0;
1776
1786
  if ((0, types_1.isVariant)(marketType, 'perp')) {
1777
1787
  if (this.isHighLeverageMode('Initial')) {
1778
1788
  return state.perpFeeStructure.feeTiers[0];
@@ -1782,28 +1792,43 @@ class User {
1782
1792
  .getAccount();
1783
1793
  const total30dVolume = (0, trade_1.getUser30dRollingVolumeEstimate)(userStatsAccount, now);
1784
1794
  const stakedGovAssetAmount = userStatsAccount.ifStakedGovTokenAmount;
1785
- const volumeTiers = [
1786
- new anchor_1.BN(100000000).mul(numericConstants_1.QUOTE_PRECISION),
1787
- new anchor_1.BN(50000000).mul(numericConstants_1.QUOTE_PRECISION),
1795
+ const volumeThresholds = [
1796
+ new anchor_1.BN(2000000).mul(numericConstants_1.QUOTE_PRECISION),
1788
1797
  new anchor_1.BN(10000000).mul(numericConstants_1.QUOTE_PRECISION),
1789
- new anchor_1.BN(5000000).mul(numericConstants_1.QUOTE_PRECISION),
1790
- new anchor_1.BN(1000000).mul(numericConstants_1.QUOTE_PRECISION),
1798
+ new anchor_1.BN(20000000).mul(numericConstants_1.QUOTE_PRECISION),
1799
+ new anchor_1.BN(100000000).mul(numericConstants_1.QUOTE_PRECISION),
1800
+ new anchor_1.BN(200000000).mul(numericConstants_1.QUOTE_PRECISION),
1791
1801
  ];
1792
- const stakedTiers = [
1793
- new anchor_1.BN(120000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1794
- new anchor_1.BN(100000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1795
- new anchor_1.BN(25000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1796
- new anchor_1.BN(10000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1802
+ const stakeThresholds = [
1797
1803
  new anchor_1.BN(1000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1804
+ new anchor_1.BN(10000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1805
+ new anchor_1.BN(50000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1806
+ new anchor_1.BN(100000 - 1).mul(numericConstants_1.QUOTE_PRECISION),
1807
+ new anchor_1.BN(250000 - 5).mul(numericConstants_1.QUOTE_PRECISION),
1798
1808
  ];
1799
- for (let i = 0; i < volumeTiers.length; i++) {
1800
- if (total30dVolume.gte(volumeTiers[i]) ||
1801
- stakedGovAssetAmount.gte(stakedTiers[i])) {
1802
- feeTierIndex = 5 - i;
1809
+ const stakeBenefitFrac = [0, 5, 10, 20, 30, 40];
1810
+ let feeTierIndex = 5;
1811
+ for (let i = 0; i < volumeThresholds.length; i++) {
1812
+ if (total30dVolume.lt(volumeThresholds[i])) {
1813
+ feeTierIndex = i;
1803
1814
  break;
1804
1815
  }
1805
1816
  }
1806
- return state.perpFeeStructure.feeTiers[feeTierIndex];
1817
+ let stakeBenefitIndex = 5;
1818
+ for (let i = 0; i < stakeThresholds.length; i++) {
1819
+ if (stakedGovAssetAmount.lt(stakeThresholds[i])) {
1820
+ stakeBenefitIndex = i;
1821
+ break;
1822
+ }
1823
+ }
1824
+ const stakeBenefit = stakeBenefitFrac[stakeBenefitIndex];
1825
+ const tier = { ...state.perpFeeStructure.feeTiers[feeTierIndex] };
1826
+ if (stakeBenefit > 0) {
1827
+ tier.feeNumerator = (tier.feeNumerator * (100 - stakeBenefit)) / 100;
1828
+ tier.makerRebateNumerator =
1829
+ (tier.makerRebateNumerator * (100 + stakeBenefit)) / 100;
1830
+ }
1831
+ return tier;
1807
1832
  }
1808
1833
  return state.spotFeeStructure.feeTiers[feeTierIndex];
1809
1834
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.131.0-beta.9",
3
+ "version": "2.131.0",
4
4
  "main": "lib/node/index.js",
5
5
  "types": "lib/node/index.d.ts",
6
6
  "browser": "./lib/browser/index.js",
@@ -4357,14 +4357,24 @@ export class DriftClient {
4357
4357
  });
4358
4358
  }
4359
4359
 
4360
+ /**
4361
+ * Sends a transaction to cancel the provided order ids.
4362
+ *
4363
+ * @param orderIds - The order ids to cancel.
4364
+ * @param txParams - The transaction parameters.
4365
+ * @param subAccountId - The sub account id to cancel the orders for.
4366
+ * @param user - The user to cancel the orders for. If provided, it will be prioritized over the subAccountId.
4367
+ * @returns The transaction signature.
4368
+ */
4360
4369
  public async cancelOrdersByIds(
4361
4370
  orderIds?: number[],
4362
4371
  txParams?: TxParams,
4363
- subAccountId?: number
4372
+ subAccountId?: number,
4373
+ user?: User
4364
4374
  ): Promise<TransactionSignature> {
4365
4375
  const { txSig } = await this.sendTransaction(
4366
4376
  await this.buildTransaction(
4367
- await this.getCancelOrdersByIdsIx(orderIds, subAccountId),
4377
+ await this.getCancelOrdersByIdsIx(orderIds, subAccountId, user),
4368
4378
  txParams
4369
4379
  ),
4370
4380
  [],
@@ -4373,21 +4383,34 @@ export class DriftClient {
4373
4383
  return txSig;
4374
4384
  }
4375
4385
 
4386
+ /**
4387
+ * Returns the transaction instruction to cancel the provided order ids.
4388
+ *
4389
+ * @param orderIds - The order ids to cancel.
4390
+ * @param subAccountId - The sub account id to cancel the orders for.
4391
+ * @param user - The user to cancel the orders for. If provided, it will be prioritized over the subAccountId.
4392
+ * @returns The transaction instruction to cancel the orders.
4393
+ */
4376
4394
  public async getCancelOrdersByIdsIx(
4377
4395
  orderIds?: number[],
4378
- subAccountId?: number
4396
+ subAccountId?: number,
4397
+ user?: User
4379
4398
  ): Promise<TransactionInstruction> {
4380
- const user = await this.getUserAccountPublicKey(subAccountId);
4399
+ const userAccountPubKey =
4400
+ user?.userAccountPublicKey ??
4401
+ (await this.getUserAccountPublicKey(subAccountId));
4402
+ const userAccount =
4403
+ user?.getUserAccount() ?? this.getUserAccount(subAccountId);
4381
4404
 
4382
4405
  const remainingAccounts = this.getRemainingAccounts({
4383
- userAccounts: [this.getUserAccount(subAccountId)],
4406
+ userAccounts: [userAccount],
4384
4407
  useMarketLastSlotCache: true,
4385
4408
  });
4386
4409
 
4387
4410
  return await this.program.instruction.cancelOrdersByIds(orderIds, {
4388
4411
  accounts: {
4389
4412
  state: await this.getStatePublicKey(),
4390
- user,
4413
+ user: userAccountPubKey,
4391
4414
  authority: this.wallet.publicKey,
4392
4415
  },
4393
4416
  remainingAccounts,
@@ -6969,6 +6992,12 @@ export class DriftClient {
6969
6992
  return txSig;
6970
6993
  }
6971
6994
 
6995
+ /**
6996
+ * @param orderParams: The parameters for the order to modify.
6997
+ * @param subAccountId: Optional - The subaccount ID of the user to modify the order for.
6998
+ * @param userPublicKey: Optional - The public key of the user to modify the order for. This takes precedence over subAccountId.
6999
+ * @returns
7000
+ */
6972
7001
  public async getModifyOrderIx(
6973
7002
  {
6974
7003
  orderId,
@@ -7003,9 +7032,11 @@ export class DriftClient {
7003
7032
  maxTs?: BN;
7004
7033
  policy?: number;
7005
7034
  },
7006
- subAccountId?: number
7035
+ subAccountId?: number,
7036
+ userPublicKey?: PublicKey
7007
7037
  ): Promise<TransactionInstruction> {
7008
- const user = await this.getUserAccountPublicKey(subAccountId);
7038
+ const user =
7039
+ userPublicKey ?? (await this.getUserAccountPublicKey(subAccountId));
7009
7040
 
7010
7041
  const remainingAccounts = this.getRemainingAccounts({
7011
7042
  userAccounts: [this.getUserAccount(subAccountId)],
@@ -9854,17 +9885,20 @@ export class DriftClient {
9854
9885
  })
9855
9886
  : undefined;
9856
9887
 
9857
- const ix = await this.program.instruction.disableUserHighLeverageMode({
9858
- accounts: {
9859
- state: await this.getStatePublicKey(),
9860
- user,
9861
- authority: this.wallet.publicKey,
9862
- highLeverageModeConfig: getHighLeverageModeConfigPublicKey(
9863
- this.program.programId
9864
- ),
9865
- },
9866
- remainingAccounts,
9867
- });
9888
+ const ix = await this.program.instruction.disableUserHighLeverageMode(
9889
+ false,
9890
+ {
9891
+ accounts: {
9892
+ state: await this.getStatePublicKey(),
9893
+ user,
9894
+ authority: this.wallet.publicKey,
9895
+ highLeverageModeConfig: getHighLeverageModeConfigPublicKey(
9896
+ this.program.programId
9897
+ ),
9898
+ },
9899
+ remainingAccounts,
9900
+ }
9901
+ );
9868
9902
 
9869
9903
  return ix;
9870
9904
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.130.0",
2
+ "version": "2.131.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -16077,4 +16077,4 @@
16077
16077
  "metadata": {
16078
16078
  "address": "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH"
16079
16079
  }
16080
- }
16080
+ }
@@ -126,7 +126,7 @@ export function calculateOraclePriceForPerpMargin(
126
126
  export function calculateBaseAssetValueWithOracle(
127
127
  market: PerpMarketAccount,
128
128
  perpPosition: PerpPosition,
129
- oraclePriceData: OraclePriceData,
129
+ oraclePriceData: Pick<OraclePriceData, 'price'>,
130
130
  includeOpenOrders = false
131
131
  ): BN {
132
132
  let price = oraclePriceData.price;
@@ -3,7 +3,7 @@ import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
3
3
  import { UserAccount } from '../types';
4
4
  import { Commitment, Context, PublicKey } from '@solana/web3.js';
5
5
  import { ResubOpts } from '../accounts/types';
6
- import { WebSocketProgramAccountSubscriberV2 } from '../accounts/webSocketProgramAccountSubscriberV2';
6
+ import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
7
7
 
8
8
  export class WebsocketSubscription {
9
9
  private orderSubscriber: OrderSubscriber;
@@ -12,7 +12,7 @@ export class WebsocketSubscription {
12
12
  private resubOpts?: ResubOpts;
13
13
  private resyncIntervalMs?: number;
14
14
 
15
- private subscriber?: WebSocketProgramAccountSubscriberV2<UserAccount>;
15
+ private subscriber?: WebSocketProgramAccountSubscriber<UserAccount>;
16
16
  private resyncTimeoutId?: ReturnType<typeof setTimeout>;
17
17
 
18
18
  private decoded?: boolean;
@@ -45,7 +45,7 @@ export class WebsocketSubscription {
45
45
  return;
46
46
  }
47
47
 
48
- this.subscriber = new WebSocketProgramAccountSubscriberV2<UserAccount>(
48
+ this.subscriber = new WebSocketProgramAccountSubscriber<UserAccount>(
49
49
  'OrderSubscriber',
50
50
  'User',
51
51
  this.orderSubscriber.driftClient.program,
package/src/user.ts CHANGED
@@ -662,7 +662,7 @@ export class User {
662
662
  public getPerpBuyingPower(
663
663
  marketIndex: number,
664
664
  collateralBuffer = ZERO,
665
- enterHighLeverageMode = false
665
+ enterHighLeverageMode = undefined
666
666
  ): BN {
667
667
  const perpPosition = this.getPerpPositionWithLPSettle(
668
668
  marketIndex,
@@ -697,7 +697,7 @@ export class User {
697
697
  marketIndex: number,
698
698
  freeCollateral: BN,
699
699
  baseAssetAmount: BN,
700
- enterHighLeverageMode = false
700
+ enterHighLeverageMode = undefined
701
701
  ): BN {
702
702
  const marginRatio = calculateMarketMarginRatio(
703
703
  this.driftClient.getPerpMarketAccount(marketIndex),
@@ -716,7 +716,7 @@ export class User {
716
716
  */
717
717
  public getFreeCollateral(
718
718
  marginCategory: MarginCategory = 'Initial',
719
- enterHighLeverageMode = false
719
+ enterHighLeverageMode = undefined
720
720
  ): BN {
721
721
  const totalCollateral = this.getTotalCollateral(marginCategory, true);
722
722
  const marginRequirement =
@@ -735,7 +735,7 @@ export class User {
735
735
  liquidationBuffer?: BN,
736
736
  strict = false,
737
737
  includeOpenOrders = true,
738
- enteringHighLeverage = false
738
+ enteringHighLeverage = undefined
739
739
  ): BN {
740
740
  return this.getTotalPerpPositionLiability(
741
741
  marginCategory,
@@ -757,7 +757,7 @@ export class User {
757
757
  /**
758
758
  * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
759
759
  */
760
- public getInitialMarginRequirement(enterHighLeverageMode = false): BN {
760
+ public getInitialMarginRequirement(enterHighLeverageMode = undefined): BN {
761
761
  return this.getMarginRequirement(
762
762
  'Initial',
763
763
  undefined,
@@ -1432,7 +1432,7 @@ export class User {
1432
1432
  liquidationBuffer?: BN,
1433
1433
  includeOpenOrders?: boolean,
1434
1434
  strict = false,
1435
- enteringHighLeverage = false
1435
+ enteringHighLeverage = undefined
1436
1436
  ): BN {
1437
1437
  const market = this.driftClient.getPerpMarketAccount(
1438
1438
  perpPosition.marketIndex
@@ -1476,13 +1476,17 @@ export class User {
1476
1476
  }
1477
1477
 
1478
1478
  if (marginCategory) {
1479
+ const userCustomMargin = this.getUserAccount().maxMarginRatio;
1479
1480
  let marginRatio = new BN(
1480
1481
  calculateMarketMarginRatio(
1481
1482
  market,
1482
1483
  baseAssetAmount.abs(),
1483
1484
  marginCategory,
1484
- this.getUserAccount().maxMarginRatio,
1485
- this.isHighLeverageMode(marginCategory) || enteringHighLeverage
1485
+ enteringHighLeverage === false
1486
+ ? Math.max(market.marginRatioInitial, userCustomMargin)
1487
+ : userCustomMargin,
1488
+ this.isHighLeverageMode(marginCategory) ||
1489
+ enteringHighLeverage === true
1486
1490
  )
1487
1491
  );
1488
1492
 
@@ -1570,7 +1574,7 @@ export class User {
1570
1574
  liquidationBuffer?: BN,
1571
1575
  includeOpenOrders?: boolean,
1572
1576
  strict = false,
1573
- enteringHighLeverage = false
1577
+ enteringHighLeverage = undefined
1574
1578
  ): BN {
1575
1579
  return this.getActivePerpPositions().reduce(
1576
1580
  (totalPerpValue, perpPosition) => {
@@ -1594,7 +1598,7 @@ export class User {
1594
1598
  */
1595
1599
  public getPerpPositionValue(
1596
1600
  marketIndex: number,
1597
- oraclePriceData: OraclePriceData,
1601
+ oraclePriceData: Pick<OraclePriceData, 'price'>,
1598
1602
  includeOpenOrders = false
1599
1603
  ): BN {
1600
1604
  const userPosition =
@@ -1894,7 +1898,7 @@ export class User {
1894
1898
  perpMarketIndex: number,
1895
1899
  _marginCategory: MarginCategory = 'Initial',
1896
1900
  isLp = false,
1897
- enterHighLeverageMode = false
1901
+ enterHighLeverageMode = undefined
1898
1902
  ): BN {
1899
1903
  const market = this.driftClient.getPerpMarketAccount(perpMarketIndex);
1900
1904
  const marketPrice =
@@ -2245,7 +2249,7 @@ export class User {
2245
2249
  marginCategory: MarginCategory = 'Maintenance',
2246
2250
  includeOpenOrders = false,
2247
2251
  offsetCollateral = ZERO,
2248
- enteringHighLeverage = false
2252
+ enteringHighLeverage = undefined
2249
2253
  ): BN {
2250
2254
  const totalCollateral = this.getTotalCollateral(
2251
2255
  marginCategory,
@@ -2370,7 +2374,7 @@ export class User {
2370
2374
  positionBaseSizeChange: BN,
2371
2375
  estimatedEntryPrice: BN,
2372
2376
  includeOpenOrders: boolean,
2373
- enteringHighLeverage = false,
2377
+ enteringHighLeverage = undefined,
2374
2378
  marginCategory: MarginCategory = 'Maintenance'
2375
2379
  ): BN {
2376
2380
  let freeCollateralChange = ZERO;
@@ -2423,12 +2427,15 @@ export class User {
2423
2427
  );
2424
2428
  }
2425
2429
 
2430
+ const userCustomMargin = this.getUserAccount().maxMarginRatio;
2426
2431
  const marginRatio = calculateMarketMarginRatio(
2427
2432
  market,
2428
2433
  baseAssetAmount.abs(),
2429
2434
  marginCategory,
2430
- this.getUserAccount().maxMarginRatio,
2431
- this.isHighLeverageMode(marginCategory) || enteringHighLeverage
2435
+ enteringHighLeverage === false
2436
+ ? Math.max(market.marginRatioInitial, userCustomMargin)
2437
+ : userCustomMargin,
2438
+ this.isHighLeverageMode(marginCategory) || enteringHighLeverage === true
2432
2439
  );
2433
2440
 
2434
2441
  return liabilityValue.mul(new BN(marginRatio)).div(MARGIN_PRECISION);
@@ -2457,7 +2464,7 @@ export class User {
2457
2464
  oraclePrice: BN,
2458
2465
  marginCategory: MarginCategory = 'Maintenance',
2459
2466
  includeOpenOrders = false,
2460
- enteringHighLeverage = false
2467
+ enteringHighLeverage = undefined
2461
2468
  ): BN | undefined {
2462
2469
  const baseAssetAmount = includeOpenOrders
2463
2470
  ? calculateWorstCaseBaseAssetAmount(perpPosition, market, oraclePrice)
@@ -2470,12 +2477,16 @@ export class User {
2470
2477
 
2471
2478
  const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
2472
2479
 
2480
+ const userCustomMargin = this.getUserAccount().maxMarginRatio;
2481
+
2473
2482
  const marginRatio = calculateMarketMarginRatio(
2474
2483
  market,
2475
2484
  proposedBaseAssetAmount.abs(),
2476
2485
  marginCategory,
2477
- this.getUserAccount().maxMarginRatio,
2478
- this.isHighLeverageMode(marginCategory) || enteringHighLeverage
2486
+ enteringHighLeverage === false
2487
+ ? Math.max(market.marginRatioInitial, userCustomMargin)
2488
+ : userCustomMargin,
2489
+ this.isHighLeverageMode(marginCategory) || enteringHighLeverage === true
2479
2490
  );
2480
2491
 
2481
2492
  const marginRatioQuotePrecision = new BN(marginRatio)
@@ -2631,7 +2642,7 @@ export class User {
2631
2642
  targetMarketIndex: number,
2632
2643
  tradeSide: PositionDirection,
2633
2644
  isLp = false,
2634
- enterHighLeverageMode = false
2645
+ enterHighLeverageMode = undefined
2635
2646
  ): { tradeSize: BN; oppositeSideTradeSize: BN } {
2636
2647
  let tradeSize = ZERO;
2637
2648
  let oppositeSideTradeSize = ZERO;
@@ -3484,7 +3495,7 @@ export class User {
3484
3495
  public getUserFeeTier(marketType: MarketType, now?: BN) {
3485
3496
  const state = this.driftClient.getStateAccount();
3486
3497
 
3487
- let feeTierIndex = 0;
3498
+ const feeTierIndex = 0;
3488
3499
  if (isVariant(marketType, 'perp')) {
3489
3500
  if (this.isHighLeverageMode('Initial')) {
3490
3501
  return state.perpFeeStructure.feeTiers[0];
@@ -3498,34 +3509,52 @@ export class User {
3498
3509
  userStatsAccount,
3499
3510
  now
3500
3511
  );
3501
-
3502
3512
  const stakedGovAssetAmount = userStatsAccount.ifStakedGovTokenAmount;
3503
- const volumeTiers = [
3504
- new BN(100_000_000).mul(QUOTE_PRECISION),
3505
- new BN(50_000_000).mul(QUOTE_PRECISION),
3513
+
3514
+ const volumeThresholds = [
3515
+ new BN(2_000_000).mul(QUOTE_PRECISION),
3506
3516
  new BN(10_000_000).mul(QUOTE_PRECISION),
3507
- new BN(5_000_000).mul(QUOTE_PRECISION),
3508
- new BN(1_000_000).mul(QUOTE_PRECISION),
3517
+ new BN(20_000_000).mul(QUOTE_PRECISION),
3518
+ new BN(100_000_000).mul(QUOTE_PRECISION),
3519
+ new BN(200_000_000).mul(QUOTE_PRECISION),
3509
3520
  ];
3510
- const stakedTiers = [
3511
- new BN(120000 - 1).mul(QUOTE_PRECISION),
3512
- new BN(100000 - 1).mul(QUOTE_PRECISION),
3513
- new BN(25000 - 1).mul(QUOTE_PRECISION),
3514
- new BN(10000 - 1).mul(QUOTE_PRECISION),
3515
- new BN(1000 - 1).mul(QUOTE_PRECISION),
3521
+ const stakeThresholds = [
3522
+ new BN(1_000 - 1).mul(QUOTE_PRECISION),
3523
+ new BN(10_000 - 1).mul(QUOTE_PRECISION),
3524
+ new BN(50_000 - 1).mul(QUOTE_PRECISION),
3525
+ new BN(100_000 - 1).mul(QUOTE_PRECISION),
3526
+ new BN(250_000 - 5).mul(QUOTE_PRECISION),
3516
3527
  ];
3528
+ const stakeBenefitFrac = [0, 5, 10, 20, 30, 40];
3517
3529
 
3518
- for (let i = 0; i < volumeTiers.length; i++) {
3519
- if (
3520
- total30dVolume.gte(volumeTiers[i]) ||
3521
- stakedGovAssetAmount.gte(stakedTiers[i])
3522
- ) {
3523
- feeTierIndex = 5 - i;
3530
+ let feeTierIndex = 5;
3531
+ for (let i = 0; i < volumeThresholds.length; i++) {
3532
+ if (total30dVolume.lt(volumeThresholds[i])) {
3533
+ feeTierIndex = i;
3524
3534
  break;
3525
3535
  }
3526
3536
  }
3527
3537
 
3528
- return state.perpFeeStructure.feeTiers[feeTierIndex];
3538
+ let stakeBenefitIndex = 5;
3539
+ for (let i = 0; i < stakeThresholds.length; i++) {
3540
+ if (stakedGovAssetAmount.lt(stakeThresholds[i])) {
3541
+ stakeBenefitIndex = i;
3542
+ break;
3543
+ }
3544
+ }
3545
+
3546
+ const stakeBenefit = stakeBenefitFrac[stakeBenefitIndex];
3547
+
3548
+ const tier = { ...state.perpFeeStructure.feeTiers[feeTierIndex] };
3549
+
3550
+ if (stakeBenefit > 0) {
3551
+ tier.feeNumerator = (tier.feeNumerator * (100 - stakeBenefit)) / 100;
3552
+
3553
+ tier.makerRebateNumerator =
3554
+ (tier.makerRebateNumerator * (100 + stakeBenefit)) / 100;
3555
+ }
3556
+
3557
+ return tier;
3529
3558
  }
3530
3559
 
3531
3560
  return state.spotFeeStructure.feeTiers[feeTierIndex];