@drift-labs/sdk 2.37.1-beta.1 → 2.37.1-beta.11

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/user.js CHANGED
@@ -145,6 +145,7 @@ class User {
145
145
  lpShares: numericConstants_1.ZERO,
146
146
  lastBaseAssetAmountPerLp: numericConstants_1.ZERO,
147
147
  lastQuoteAssetAmountPerLp: numericConstants_1.ZERO,
148
+ perLpBase: 0,
148
149
  };
149
150
  }
150
151
  getClonedPosition(position) {
@@ -258,17 +259,54 @@ class User {
258
259
  }
259
260
  const position = this.getClonedPosition(originalPosition);
260
261
  const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
262
+ if (market.amm.perLpBase != position.perLpBase) {
263
+ // perLpBase = 1 => per 10 LP shares, perLpBase = -1 => per 0.1 LP shares
264
+ const expoDiff = market.amm.perLpBase - position.perLpBase;
265
+ const marketPerLpRebaseScalar = new _1.BN(10 ** Math.abs(expoDiff));
266
+ if (expoDiff > 0) {
267
+ position.lastBaseAssetAmountPerLp =
268
+ position.lastBaseAssetAmountPerLp.mul(marketPerLpRebaseScalar);
269
+ position.lastQuoteAssetAmountPerLp =
270
+ position.lastQuoteAssetAmountPerLp.mul(marketPerLpRebaseScalar);
271
+ }
272
+ else {
273
+ position.lastBaseAssetAmountPerLp =
274
+ position.lastBaseAssetAmountPerLp.div(marketPerLpRebaseScalar);
275
+ position.lastQuoteAssetAmountPerLp =
276
+ position.lastQuoteAssetAmountPerLp.div(marketPerLpRebaseScalar);
277
+ }
278
+ position.perLpBase = position.perLpBase + expoDiff;
279
+ }
261
280
  const nShares = position.lpShares;
262
281
  // incorp unsettled funding on pre settled position
263
282
  const quoteFundingPnl = (0, _1.calculatePositionFundingPNL)(market, position);
283
+ let baseUnit = numericConstants_1.AMM_RESERVE_PRECISION;
284
+ if (market.amm.perLpBase == position.perLpBase) {
285
+ if (position.perLpBase >= 0 &&
286
+ position.perLpBase <= numericConstants_1.AMM_RESERVE_PRECISION_EXP.toNumber()) {
287
+ const marketPerLpRebase = new _1.BN(10 ** market.amm.perLpBase);
288
+ baseUnit = baseUnit.mul(marketPerLpRebase);
289
+ }
290
+ else if (position.perLpBase < 0 &&
291
+ position.perLpBase >= -numericConstants_1.AMM_RESERVE_PRECISION_EXP.toNumber()) {
292
+ const marketPerLpRebase = new _1.BN(10 ** Math.abs(market.amm.perLpBase));
293
+ baseUnit = baseUnit.div(marketPerLpRebase);
294
+ }
295
+ else {
296
+ throw 'cannot calc';
297
+ }
298
+ }
299
+ else {
300
+ throw 'market.amm.perLpBase != position.perLpBase';
301
+ }
264
302
  const deltaBaa = market.amm.baseAssetAmountPerLp
265
303
  .sub(position.lastBaseAssetAmountPerLp)
266
304
  .mul(nShares)
267
- .div(numericConstants_1.AMM_RESERVE_PRECISION);
305
+ .div(baseUnit);
268
306
  const deltaQaa = market.amm.quoteAssetAmountPerLp
269
307
  .sub(position.lastQuoteAssetAmountPerLp)
270
308
  .mul(nShares)
271
- .div(numericConstants_1.AMM_RESERVE_PRECISION);
309
+ .div(baseUnit);
272
310
  function sign(v) {
273
311
  return v.isNeg() ? new _1.BN(-1) : new _1.BN(1);
274
312
  }
@@ -376,13 +414,15 @@ class User {
376
414
  return freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new _1.BN(marginRatio));
377
415
  }
378
416
  /**
379
- * calculates Free Collateral = Total collateral - initial margin requirement
417
+ * calculates Free Collateral = Total collateral - margin requirement
380
418
  * @returns : Precision QUOTE_PRECISION
381
419
  */
382
- getFreeCollateral() {
383
- const totalCollateral = this.getTotalCollateral('Initial', true);
384
- const initialMarginRequirement = this.getInitialMarginRequirement();
385
- const freeCollateral = totalCollateral.sub(initialMarginRequirement);
420
+ getFreeCollateral(marginCategory = 'Initial') {
421
+ const totalCollateral = this.getTotalCollateral(marginCategory, true);
422
+ const marginRequirement = marginCategory === 'Initial'
423
+ ? this.getInitialMarginRequirement()
424
+ : this.getMaintenanceMarginRequirement();
425
+ const freeCollateral = totalCollateral.sub(marginRequirement);
386
426
  return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
387
427
  }
388
428
  /**
@@ -464,7 +504,7 @@ class User {
464
504
  }
465
505
  positionUnrealizedPnl = positionUnrealizedPnl
466
506
  .mul(quotePrice)
467
- .div(new _1.BN(numericConstants_1.PRICE_PRECISION));
507
+ .div(numericConstants_1.PRICE_PRECISION);
468
508
  if (withWeightMarginCategory !== undefined) {
469
509
  if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
470
510
  positionUnrealizedPnl = positionUnrealizedPnl
@@ -648,17 +688,73 @@ class User {
648
688
  health = 0;
649
689
  }
650
690
  else {
651
- const healthP1 = Math.max(0, (1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
652
- 100) + 1;
653
- health = Math.min(1, Math.log(healthP1) / Math.log(100)) * 100;
654
- if (health > 1) {
655
- health = Math.round(health);
691
+ health = Math.round(Math.min(100, Math.max(0, (1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
692
+ 100)));
693
+ }
694
+ return health;
695
+ }
696
+ calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
697
+ const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
698
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
699
+ // is an lp, clone so we dont mutate the position
700
+ perpPosition = this.getPerpPositionWithLPSettle(market.marketIndex, this.getClonedPosition(perpPosition), !!marginCategory)[0];
701
+ }
702
+ let valuationPrice = this.getOracleDataForPerpMarket(market.marketIndex).price;
703
+ if ((0, types_1.isVariant)(market.status, 'settlement')) {
704
+ valuationPrice = market.expiryPrice;
705
+ }
706
+ const baseAssetAmount = includeOpenOrders
707
+ ? (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition)
708
+ : perpPosition.baseAssetAmount;
709
+ let baseAssetValue = baseAssetAmount
710
+ .abs()
711
+ .mul(valuationPrice)
712
+ .div(numericConstants_1.BASE_PRECISION);
713
+ if (marginCategory) {
714
+ let marginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory));
715
+ if (marginCategory === 'Initial') {
716
+ marginRatio = _1.BN.max(marginRatio, new _1.BN(this.getUserAccount().maxMarginRatio));
717
+ }
718
+ if (liquidationBuffer !== undefined) {
719
+ marginRatio = marginRatio.add(liquidationBuffer);
720
+ }
721
+ if ((0, types_1.isVariant)(market.status, 'settlement')) {
722
+ marginRatio = numericConstants_1.ZERO;
723
+ }
724
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
725
+ const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
726
+ let quotePrice;
727
+ if (strict) {
728
+ quotePrice = _1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
656
729
  }
657
730
  else {
658
- health = Math.round(health * 100) / 100;
731
+ quotePrice = quoteOraclePriceData.price;
732
+ }
733
+ baseAssetValue = baseAssetValue
734
+ .mul(quotePrice)
735
+ .div(numericConstants_1.PRICE_PRECISION)
736
+ .mul(marginRatio)
737
+ .div(numericConstants_1.MARGIN_PRECISION);
738
+ if (includeOpenOrders) {
739
+ baseAssetValue = baseAssetValue.add(new _1.BN(perpPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
740
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
741
+ baseAssetValue = baseAssetValue.add(_1.BN.max(numericConstants_1.QUOTE_PRECISION, valuationPrice
742
+ .mul(market.amm.orderStepSize)
743
+ .mul(numericConstants_1.QUOTE_PRECISION)
744
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
745
+ .div(numericConstants_1.PRICE_PRECISION)));
746
+ }
659
747
  }
660
748
  }
661
- return health;
749
+ return baseAssetValue;
750
+ }
751
+ /**
752
+ * calculates position value of a single perp market in margin system
753
+ * @returns : Precision QUOTE_PRECISION
754
+ */
755
+ getPerpMarketLiabilityValue(marketIndex, marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
756
+ const perpPosition = this.getPerpPosition(marketIndex);
757
+ return this.calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict);
662
758
  }
663
759
  /**
664
760
  * calculates sum of position value across all positions in margin system
@@ -666,58 +762,7 @@ class User {
666
762
  */
667
763
  getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
668
764
  return this.getActivePerpPositions().reduce((totalPerpValue, perpPosition) => {
669
- const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
670
- if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
671
- // is an lp, clone so we dont mutate the position
672
- perpPosition = this.getPerpPositionWithLPSettle(market.marketIndex, this.getClonedPosition(perpPosition), !!marginCategory)[0];
673
- }
674
- let valuationPrice = this.getOracleDataForPerpMarket(market.marketIndex).price;
675
- if ((0, types_1.isVariant)(market.status, 'settlement')) {
676
- valuationPrice = market.expiryPrice;
677
- }
678
- const baseAssetAmount = includeOpenOrders
679
- ? (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition)
680
- : perpPosition.baseAssetAmount;
681
- let baseAssetValue = baseAssetAmount
682
- .abs()
683
- .mul(valuationPrice)
684
- .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.PRICE_PRECISION));
685
- if (marginCategory) {
686
- let marginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory));
687
- if (marginCategory === 'Initial') {
688
- marginRatio = _1.BN.max(marginRatio, new _1.BN(this.getUserAccount().maxMarginRatio));
689
- }
690
- if (liquidationBuffer !== undefined) {
691
- marginRatio = marginRatio.add(liquidationBuffer);
692
- }
693
- if ((0, types_1.isVariant)(market.status, 'settlement')) {
694
- marginRatio = numericConstants_1.ZERO;
695
- }
696
- const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
697
- const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
698
- let quotePrice;
699
- if (strict) {
700
- quotePrice = _1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
701
- }
702
- else {
703
- quotePrice = quoteOraclePriceData.price;
704
- }
705
- baseAssetValue = baseAssetValue
706
- .mul(quotePrice)
707
- .div(numericConstants_1.PRICE_PRECISION)
708
- .mul(marginRatio)
709
- .div(numericConstants_1.MARGIN_PRECISION);
710
- if (includeOpenOrders) {
711
- baseAssetValue = baseAssetValue.add(new _1.BN(perpPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
712
- if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
713
- baseAssetValue = baseAssetValue.add(_1.BN.max(numericConstants_1.QUOTE_PRECISION, valuationPrice
714
- .mul(market.amm.orderStepSize)
715
- .mul(numericConstants_1.QUOTE_PRECISION)
716
- .div(numericConstants_1.AMM_RESERVE_PRECISION)
717
- .div(numericConstants_1.PRICE_PRECISION)));
718
- }
719
- }
720
- }
765
+ const baseAssetValue = this.calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict);
721
766
  return totalPerpValue.add(baseAssetValue);
722
767
  }, numericConstants_1.ZERO);
723
768
  }
@@ -1589,12 +1634,15 @@ class User {
1589
1634
  if (canBypass) {
1590
1635
  withdrawLimit = _1.BN.max(withdrawLimit, userDepositAmount);
1591
1636
  }
1592
- const amountWithdrawable = freeCollateral
1593
- .mul(numericConstants_1.MARGIN_PRECISION)
1594
- .div(new _1.BN(spotMarket.initialAssetWeight))
1595
- .mul(numericConstants_1.PRICE_PRECISION)
1596
- .div(oracleData.price)
1597
- .mul(precisionIncrease);
1637
+ const assetWeight = (0, spotBalance_1.calculateAssetWeight)(userDepositAmount, spotMarket, 'Initial');
1638
+ const amountWithdrawable = assetWeight.eq(numericConstants_1.ZERO)
1639
+ ? userDepositAmount
1640
+ : freeCollateral
1641
+ .mul(numericConstants_1.MARGIN_PRECISION)
1642
+ .div(assetWeight)
1643
+ .mul(numericConstants_1.PRICE_PRECISION)
1644
+ .div(oracleData.price)
1645
+ .mul(precisionIncrease);
1598
1646
  const maxWithdrawValue = _1.BN.min(_1.BN.min(amountWithdrawable, userDepositAmount), withdrawLimit.abs());
1599
1647
  if (reduceOnly) {
1600
1648
  return _1.BN.max(maxWithdrawValue, numericConstants_1.ZERO);
@@ -1702,6 +1750,146 @@ class User {
1702
1750
  spotTier: safestSpotTier,
1703
1751
  };
1704
1752
  }
1753
+ getHealthComponents({ marginCategory, }) {
1754
+ const healthComponents = {
1755
+ deposits: [],
1756
+ borrows: [],
1757
+ perpPositions: [],
1758
+ perpPnl: [],
1759
+ };
1760
+ for (const perpPosition of this.getActivePerpPositions()) {
1761
+ const perpMarket = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
1762
+ const oraclePriceData = this.driftClient.getOraclePriceDataAndSlot(perpMarket.amm.oracle).data;
1763
+ const oraclePrice = oraclePriceData.price;
1764
+ const worstCaseBaseAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition);
1765
+ const marginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(perpMarket, worstCaseBaseAmount.abs(), marginCategory));
1766
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(perpMarket.quoteSpotMarketIndex);
1767
+ const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
1768
+ const baseAssetValue = worstCaseBaseAmount
1769
+ .abs()
1770
+ .mul(oraclePrice)
1771
+ .div(numericConstants_1.BASE_PRECISION);
1772
+ let marginRequirement = baseAssetValue
1773
+ .mul(quoteOraclePriceData.price)
1774
+ .div(numericConstants_1.PRICE_PRECISION)
1775
+ .mul(marginRatio)
1776
+ .div(numericConstants_1.MARGIN_PRECISION);
1777
+ marginRequirement = marginRequirement.add(new _1.BN(perpPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
1778
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
1779
+ marginRequirement = marginRequirement.add(_1.BN.max(numericConstants_1.QUOTE_PRECISION, oraclePrice
1780
+ .mul(perpMarket.amm.orderStepSize)
1781
+ .mul(numericConstants_1.QUOTE_PRECISION)
1782
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
1783
+ .div(numericConstants_1.PRICE_PRECISION)));
1784
+ }
1785
+ healthComponents.perpPositions.push({
1786
+ marketIndex: perpMarket.marketIndex,
1787
+ size: worstCaseBaseAmount,
1788
+ value: baseAssetValue,
1789
+ weight: marginRatio,
1790
+ weightedValue: marginRequirement,
1791
+ });
1792
+ const settledPerpPosition = this.getPerpPositionWithLPSettle(perpPosition.marketIndex, perpPosition)[0];
1793
+ const positionUnrealizedPnl = (0, _1.calculatePositionPNL)(perpMarket, settledPerpPosition, true, oraclePriceData);
1794
+ let pnlWeight;
1795
+ if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
1796
+ pnlWeight = (0, _1.calculateUnrealizedAssetWeight)(perpMarket, quoteSpotMarket, positionUnrealizedPnl, marginCategory, oraclePriceData);
1797
+ }
1798
+ else {
1799
+ pnlWeight = numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION;
1800
+ }
1801
+ const pnlValue = positionUnrealizedPnl
1802
+ .mul(quoteOraclePriceData.price)
1803
+ .div(numericConstants_1.PRICE_PRECISION);
1804
+ const wegithedPnlValue = pnlValue
1805
+ .mul(pnlWeight)
1806
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
1807
+ healthComponents.perpPnl.push({
1808
+ marketIndex: perpMarket.marketIndex,
1809
+ size: positionUnrealizedPnl,
1810
+ value: pnlValue,
1811
+ weight: pnlWeight,
1812
+ weightedValue: wegithedPnlValue,
1813
+ });
1814
+ }
1815
+ let netQuoteValue = numericConstants_1.ZERO;
1816
+ for (const spotPosition of this.getActiveSpotPositions()) {
1817
+ const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
1818
+ const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
1819
+ if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
1820
+ const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), spotPosition.balanceType);
1821
+ netQuoteValue = netQuoteValue.add(tokenAmount);
1822
+ continue;
1823
+ }
1824
+ const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, oraclePriceData);
1825
+ netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
1826
+ const baseAssetValue = (0, _1.getTokenValue)(worstCaseTokenAmount.abs(), spotMarketAccount.decimals, oraclePriceData);
1827
+ const isLiability = (0, types_1.isVariant)(spotPosition.balanceType, 'borrow');
1828
+ let weight;
1829
+ if (isLiability) {
1830
+ weight = (0, spotBalance_1.calculateLiabilityWeight)(worstCaseTokenAmount.abs(), spotMarketAccount, marginCategory);
1831
+ }
1832
+ else {
1833
+ weight = (0, spotBalance_1.calculateAssetWeight)(worstCaseTokenAmount, spotMarketAccount, marginCategory);
1834
+ }
1835
+ const weightedValue = baseAssetValue
1836
+ .mul(weight)
1837
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
1838
+ if (isLiability) {
1839
+ healthComponents.borrows.push({
1840
+ marketIndex: spotMarketAccount.marketIndex,
1841
+ size: worstCaseTokenAmount,
1842
+ value: baseAssetValue,
1843
+ weight: weight,
1844
+ weightedValue: weightedValue,
1845
+ });
1846
+ }
1847
+ else {
1848
+ healthComponents.deposits.push({
1849
+ marketIndex: spotMarketAccount.marketIndex,
1850
+ size: worstCaseTokenAmount,
1851
+ value: baseAssetValue,
1852
+ weight: weight,
1853
+ weightedValue: weightedValue,
1854
+ });
1855
+ }
1856
+ }
1857
+ if (!netQuoteValue.eq(numericConstants_1.ZERO)) {
1858
+ const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
1859
+ const oraclePriceData = this.getOracleDataForSpotMarket(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
1860
+ const baseAssetValue = (0, _1.getTokenValue)(netQuoteValue.abs(), spotMarketAccount.decimals, oraclePriceData);
1861
+ const isLiability = netQuoteValue.lt(numericConstants_1.ZERO);
1862
+ let weight;
1863
+ if (isLiability) {
1864
+ weight = (0, spotBalance_1.calculateLiabilityWeight)(netQuoteValue.abs(), spotMarketAccount, marginCategory);
1865
+ }
1866
+ else {
1867
+ weight = (0, spotBalance_1.calculateAssetWeight)(netQuoteValue, spotMarketAccount, marginCategory);
1868
+ }
1869
+ const weightedValue = baseAssetValue
1870
+ .mul(weight)
1871
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
1872
+ if (isLiability) {
1873
+ healthComponents.borrows.push({
1874
+ marketIndex: spotMarketAccount.marketIndex,
1875
+ size: netQuoteValue,
1876
+ value: baseAssetValue,
1877
+ weight: weight,
1878
+ weightedValue: weightedValue,
1879
+ });
1880
+ }
1881
+ else {
1882
+ healthComponents.deposits.push({
1883
+ marketIndex: spotMarketAccount.marketIndex,
1884
+ size: netQuoteValue,
1885
+ value: baseAssetValue,
1886
+ weight: weight,
1887
+ weightedValue: weightedValue,
1888
+ });
1889
+ }
1890
+ }
1891
+ return healthComponents;
1892
+ }
1705
1893
  /**
1706
1894
  * Get the total position value, excluding any position coming from the given target market
1707
1895
  * @param marketToIgnore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.37.1-beta.1",
3
+ "version": "2.37.1-beta.11",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -55,7 +55,7 @@
55
55
  "eslint-plugin-prettier": "^3.4.0",
56
56
  "lodash": "^4.17.21",
57
57
  "mocha": "^10.0.0",
58
- "prettier": "^2.4.1",
58
+ "prettier": "^3.0.1",
59
59
  "ts-node": "^10.8.0",
60
60
  "typescript": "^4.9.5"
61
61
  },
@@ -691,6 +691,24 @@ export class AdminClient extends DriftClient {
691
691
  });
692
692
  }
693
693
 
694
+ public async updatePerpMarketPerLpBase(
695
+ perpMarketIndex: number,
696
+ perLpBase: number
697
+ ): Promise<TransactionSignature> {
698
+ const perpMarketPublicKey = await getPerpMarketPublicKey(
699
+ this.program.programId,
700
+ perpMarketIndex
701
+ );
702
+
703
+ return await this.program.rpc.updatePerpMarketPerLpBase(perLpBase, {
704
+ accounts: {
705
+ admin: this.wallet.publicKey,
706
+ state: await this.getStatePublicKey(),
707
+ perpMarket: perpMarketPublicKey,
708
+ },
709
+ });
710
+ }
711
+
694
712
  public async updatePerpMarketMaxSpread(
695
713
  perpMarketIndex: number,
696
714
  maxSpread: number
@@ -154,6 +154,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
154
154
  launchTs: 1689270550000,
155
155
  oracleSource: OracleSource.PYTH,
156
156
  },
157
+ {
158
+ fullName: 'HNT',
159
+ category: ['IoT'],
160
+ symbol: 'HNT-PERP',
161
+ baseAssetSymbol: 'HNT',
162
+ marketIndex: 14,
163
+ oracle: new PublicKey('6Eg8YdfFJQF2HHonzPUBSCCmyUEhrStg9VBLK957sBe6'),
164
+ launchTs: 16922949550000,
165
+ oracleSource: OracleSource.PYTH,
166
+ },
157
167
  ];
158
168
 
159
169
  export const MainnetPerpMarkets: PerpMarketConfig[] = [
@@ -297,6 +307,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
297
307
  launchTs: 1689270550000,
298
308
  oracleSource: OracleSource.PYTH,
299
309
  },
310
+ {
311
+ fullName: 'HNT',
312
+ category: ['IoT'],
313
+ symbol: 'HNT-PERP',
314
+ baseAssetSymbol: 'HNT',
315
+ marketIndex: 14,
316
+ oracle: new PublicKey('7moA1i5vQUpfDwSpK6Pw9s56ahB7WFGidtbL2ujWrVvm'),
317
+ launchTs: 16922949550000,
318
+ oracleSource: OracleSource.PYTH,
319
+ },
300
320
  ];
301
321
 
302
322
  export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
@@ -1122,6 +1122,31 @@
1122
1122
  }
1123
1123
  ]
1124
1124
  },
1125
+ {
1126
+ "name": "updateUserReduceOnly",
1127
+ "accounts": [
1128
+ {
1129
+ "name": "user",
1130
+ "isMut": true,
1131
+ "isSigner": false
1132
+ },
1133
+ {
1134
+ "name": "authority",
1135
+ "isMut": false,
1136
+ "isSigner": true
1137
+ }
1138
+ ],
1139
+ "args": [
1140
+ {
1141
+ "name": "subAccountId",
1142
+ "type": "u16"
1143
+ },
1144
+ {
1145
+ "name": "reduceOnly",
1146
+ "type": "bool"
1147
+ }
1148
+ ]
1149
+ },
1125
1150
  {
1126
1151
  "name": "deleteUser",
1127
1152
  "accounts": [
@@ -3857,6 +3882,32 @@
3857
3882
  }
3858
3883
  ]
3859
3884
  },
3885
+ {
3886
+ "name": "updatePerpMarketPerLpBase",
3887
+ "accounts": [
3888
+ {
3889
+ "name": "admin",
3890
+ "isMut": false,
3891
+ "isSigner": true
3892
+ },
3893
+ {
3894
+ "name": "state",
3895
+ "isMut": false,
3896
+ "isSigner": false
3897
+ },
3898
+ {
3899
+ "name": "perpMarket",
3900
+ "isMut": true,
3901
+ "isSigner": false
3902
+ }
3903
+ ],
3904
+ "args": [
3905
+ {
3906
+ "name": "perLpBase",
3907
+ "type": "i8"
3908
+ }
3909
+ ]
3910
+ },
3860
3911
  {
3861
3912
  "name": "updateLpCooldownTime",
3862
3913
  "accounts": [
@@ -6953,9 +7004,20 @@
6953
7004
  ],
6954
7005
  "type": "i32"
6955
7006
  },
7007
+ {
7008
+ "name": "perLpBase",
7009
+ "docs": [
7010
+ "expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)"
7011
+ ],
7012
+ "type": "i8"
7013
+ },
6956
7014
  {
6957
7015
  "name": "padding1",
6958
- "type": "u32"
7016
+ "type": "u8"
7017
+ },
7018
+ {
7019
+ "name": "padding2",
7020
+ "type": "u16"
6959
7021
  },
6960
7022
  {
6961
7023
  "name": "totalFeeEarnedPerLp",
@@ -7422,13 +7484,8 @@
7422
7484
  "type": "u8"
7423
7485
  },
7424
7486
  {
7425
- "name": "padding",
7426
- "type": {
7427
- "array": [
7428
- "u8",
7429
- 1
7430
- ]
7431
- }
7487
+ "name": "perLpBase",
7488
+ "type": "i8"
7432
7489
  }
7433
7490
  ]
7434
7491
  }
@@ -8314,6 +8371,9 @@
8314
8371
  },
8315
8372
  {
8316
8373
  "name": "Bankrupt"
8374
+ },
8375
+ {
8376
+ "name": "ReduceOnly"
8317
8377
  }
8318
8378
  ]
8319
8379
  }
@@ -10681,6 +10741,11 @@
10681
10741
  "code": 6253,
10682
10742
  "name": "CantUpdatePerpBidAskTwap",
10683
10743
  "msg": "CantUpdatePerpBidAskTwap"
10744
+ },
10745
+ {
10746
+ "code": 6254,
10747
+ "name": "UserReduceOnly",
10748
+ "msg": "UserReduceOnly"
10684
10749
  }
10685
10750
  ]
10686
10751
  }
package/src/index.ts CHANGED
@@ -61,6 +61,7 @@ export * from './serum/serumSubscriber';
61
61
  export * from './serum/serumFulfillmentConfigMap';
62
62
  export * from './phoenix/phoenixSubscriber';
63
63
  export * from './phoenix/phoenixFulfillmentConfigMap';
64
+ export * from './tx/fastSingleTxSender';
64
65
  export * from './tx/retryTxSender';
65
66
  export * from './tx/types';
66
67
  export * from './util/computeUnits';