@drift-labs/sdk 2.37.1-beta.0 → 2.37.1-beta.10

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.
Files changed (44) hide show
  1. package/VERSION +1 -1
  2. package/lib/adminClient.d.ts +1 -0
  3. package/lib/adminClient.js +10 -0
  4. package/lib/constants/perpMarkets.js +20 -0
  5. package/lib/events/eventSubscriber.js +3 -0
  6. package/lib/events/fetchLogs.js +3 -0
  7. package/lib/events/types.d.ts +1 -0
  8. package/lib/idl/drift.json +73 -8
  9. package/lib/index.d.ts +1 -0
  10. package/lib/index.js +1 -0
  11. package/lib/math/auction.js +1 -1
  12. package/lib/orderSubscriber/OrderSubscriber.d.ts +5 -1
  13. package/lib/orderSubscriber/OrderSubscriber.js +10 -0
  14. package/lib/orderSubscriber/types.d.ts +5 -0
  15. package/lib/tx/baseTxSender.d.ts +30 -0
  16. package/lib/tx/baseTxSender.js +176 -0
  17. package/lib/tx/fastSingleTxSender.d.ts +27 -0
  18. package/lib/tx/fastSingleTxSender.js +83 -0
  19. package/lib/tx/retryTxSender.d.ts +5 -14
  20. package/lib/tx/retryTxSender.js +7 -158
  21. package/lib/types.d.ts +18 -0
  22. package/lib/types.js +1 -0
  23. package/lib/user.d.ts +10 -1
  24. package/lib/user.js +259 -61
  25. package/package.json +2 -2
  26. package/src/adminClient.ts +18 -0
  27. package/src/constants/perpMarkets.ts +20 -0
  28. package/src/events/eventSubscriber.ts +3 -0
  29. package/src/events/fetchLogs.ts +3 -0
  30. package/src/events/types.ts +1 -0
  31. package/src/idl/drift.json +73 -8
  32. package/src/index.ts +1 -0
  33. package/src/marinade/types.ts +70 -70
  34. package/src/math/auction.ts +1 -1
  35. package/src/orderSubscriber/OrderSubscriber.ts +19 -2
  36. package/src/orderSubscriber/types.ts +11 -0
  37. package/src/tx/baseTxSender.ts +276 -0
  38. package/src/tx/fastSingleTxSender.ts +142 -0
  39. package/src/tx/retryTxSender.ts +9 -235
  40. package/src/types.ts +19 -0
  41. package/src/user.ts +441 -101
  42. package/tests/amm/test.ts +83 -39
  43. package/tests/dlob/helpers.ts +2 -0
  44. package/tests/dlob/test.ts +19 -17
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
  }
@@ -464,7 +502,7 @@ class User {
464
502
  }
465
503
  positionUnrealizedPnl = positionUnrealizedPnl
466
504
  .mul(quotePrice)
467
- .div(new _1.BN(numericConstants_1.PRICE_PRECISION));
505
+ .div(numericConstants_1.PRICE_PRECISION);
468
506
  if (withWeightMarginCategory !== undefined) {
469
507
  if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
470
508
  positionUnrealizedPnl = positionUnrealizedPnl
@@ -660,64 +698,81 @@ class User {
660
698
  }
661
699
  return health;
662
700
  }
701
+ calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
702
+ const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
703
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
704
+ // is an lp, clone so we dont mutate the position
705
+ perpPosition = this.getPerpPositionWithLPSettle(market.marketIndex, this.getClonedPosition(perpPosition), !!marginCategory)[0];
706
+ }
707
+ let valuationPrice = this.getOracleDataForPerpMarket(market.marketIndex).price;
708
+ if ((0, types_1.isVariant)(market.status, 'settlement')) {
709
+ valuationPrice = market.expiryPrice;
710
+ }
711
+ const baseAssetAmount = includeOpenOrders
712
+ ? (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition)
713
+ : perpPosition.baseAssetAmount;
714
+ let baseAssetValue = baseAssetAmount
715
+ .abs()
716
+ .mul(valuationPrice)
717
+ .div(numericConstants_1.BASE_PRECISION);
718
+ if (marginCategory) {
719
+ let marginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(market, baseAssetAmount.abs(), marginCategory));
720
+ if (marginCategory === 'Initial') {
721
+ marginRatio = _1.BN.max(marginRatio, new _1.BN(this.getUserAccount().maxMarginRatio));
722
+ }
723
+ if (liquidationBuffer !== undefined) {
724
+ marginRatio = marginRatio.add(liquidationBuffer);
725
+ }
726
+ if ((0, types_1.isVariant)(market.status, 'settlement')) {
727
+ marginRatio = numericConstants_1.ZERO;
728
+ }
729
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
730
+ const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
731
+ let quotePrice;
732
+ if (strict) {
733
+ quotePrice = _1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
734
+ }
735
+ else {
736
+ quotePrice = quoteOraclePriceData.price;
737
+ }
738
+ baseAssetValue = baseAssetValue
739
+ .mul(quotePrice)
740
+ .div(numericConstants_1.PRICE_PRECISION)
741
+ .mul(marginRatio)
742
+ .div(numericConstants_1.MARGIN_PRECISION);
743
+ if (includeOpenOrders) {
744
+ baseAssetValue = baseAssetValue.add(new _1.BN(perpPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
745
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
746
+ baseAssetValue = baseAssetValue.add(_1.BN.max(numericConstants_1.QUOTE_PRECISION, valuationPrice
747
+ .mul(market.amm.orderStepSize)
748
+ .mul(numericConstants_1.QUOTE_PRECISION)
749
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
750
+ .div(numericConstants_1.PRICE_PRECISION)));
751
+ }
752
+ }
753
+ }
754
+ return baseAssetValue;
755
+ }
756
+ /**
757
+ * calculates position value of a single perp market in margin system
758
+ * @returns : Precision QUOTE_PRECISION
759
+ */
760
+ getPerpMarketLiabilityValue(marketIndex, marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
761
+ const perpPosition = this.getPerpPosition(marketIndex);
762
+ if (!perpPosition) {
763
+ return numericConstants_1.ZERO;
764
+ }
765
+ else {
766
+ return this.calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict);
767
+ }
768
+ }
663
769
  /**
664
770
  * calculates sum of position value across all positions in margin system
665
771
  * @returns : Precision QUOTE_PRECISION
666
772
  */
667
773
  getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders, strict = false) {
668
774
  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
- }
775
+ const baseAssetValue = this.calculateWeightedPerpPositionValue(perpPosition, marginCategory, liquidationBuffer, includeOpenOrders, strict);
721
776
  return totalPerpValue.add(baseAssetValue);
722
777
  }, numericConstants_1.ZERO);
723
778
  }
@@ -1589,12 +1644,15 @@ class User {
1589
1644
  if (canBypass) {
1590
1645
  withdrawLimit = _1.BN.max(withdrawLimit, userDepositAmount);
1591
1646
  }
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);
1647
+ const assetWeight = (0, spotBalance_1.calculateAssetWeight)(userDepositAmount, spotMarket, 'Initial');
1648
+ const amountWithdrawable = assetWeight.eq(numericConstants_1.ZERO)
1649
+ ? userDepositAmount
1650
+ : freeCollateral
1651
+ .mul(numericConstants_1.MARGIN_PRECISION)
1652
+ .div(assetWeight)
1653
+ .mul(numericConstants_1.PRICE_PRECISION)
1654
+ .div(oracleData.price)
1655
+ .mul(precisionIncrease);
1598
1656
  const maxWithdrawValue = _1.BN.min(_1.BN.min(amountWithdrawable, userDepositAmount), withdrawLimit.abs());
1599
1657
  if (reduceOnly) {
1600
1658
  return _1.BN.max(maxWithdrawValue, numericConstants_1.ZERO);
@@ -1702,6 +1760,146 @@ class User {
1702
1760
  spotTier: safestSpotTier,
1703
1761
  };
1704
1762
  }
1763
+ getHealthComponents({ marginCategory, }) {
1764
+ const healthComponents = {
1765
+ deposits: [],
1766
+ borrows: [],
1767
+ perpPositions: [],
1768
+ perpPnl: [],
1769
+ };
1770
+ for (const perpPosition of this.getActivePerpPositions()) {
1771
+ const perpMarket = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
1772
+ const oraclePriceData = this.driftClient.getOraclePriceDataAndSlot(perpMarket.amm.oracle).data;
1773
+ const oraclePrice = oraclePriceData.price;
1774
+ const worstCaseBaseAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition);
1775
+ const marginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(perpMarket, worstCaseBaseAmount.abs(), marginCategory));
1776
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(perpMarket.quoteSpotMarketIndex);
1777
+ const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
1778
+ const baseAssetValue = worstCaseBaseAmount
1779
+ .abs()
1780
+ .mul(oraclePrice)
1781
+ .div(numericConstants_1.BASE_PRECISION);
1782
+ let marginRequirement = baseAssetValue
1783
+ .mul(quoteOraclePriceData.price)
1784
+ .div(numericConstants_1.PRICE_PRECISION)
1785
+ .mul(marginRatio)
1786
+ .div(numericConstants_1.MARGIN_PRECISION);
1787
+ marginRequirement = marginRequirement.add(new _1.BN(perpPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
1788
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
1789
+ marginRequirement = marginRequirement.add(_1.BN.max(numericConstants_1.QUOTE_PRECISION, oraclePrice
1790
+ .mul(perpMarket.amm.orderStepSize)
1791
+ .mul(numericConstants_1.QUOTE_PRECISION)
1792
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
1793
+ .div(numericConstants_1.PRICE_PRECISION)));
1794
+ }
1795
+ healthComponents.perpPositions.push({
1796
+ marketIndex: perpMarket.marketIndex,
1797
+ size: worstCaseBaseAmount,
1798
+ value: baseAssetValue,
1799
+ weight: marginRatio,
1800
+ weightedValue: marginRequirement,
1801
+ });
1802
+ const settledPerpPosition = this.getPerpPositionWithLPSettle(perpPosition.marketIndex, perpPosition)[0];
1803
+ const positionUnrealizedPnl = (0, _1.calculatePositionPNL)(perpMarket, settledPerpPosition, true, oraclePriceData);
1804
+ let pnlWeight;
1805
+ if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
1806
+ pnlWeight = (0, _1.calculateUnrealizedAssetWeight)(perpMarket, quoteSpotMarket, positionUnrealizedPnl, marginCategory, oraclePriceData);
1807
+ }
1808
+ else {
1809
+ pnlWeight = numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION;
1810
+ }
1811
+ const pnlValue = positionUnrealizedPnl
1812
+ .mul(quoteOraclePriceData.price)
1813
+ .div(numericConstants_1.PRICE_PRECISION);
1814
+ const wegithedPnlValue = pnlValue
1815
+ .mul(pnlWeight)
1816
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
1817
+ healthComponents.perpPnl.push({
1818
+ marketIndex: perpMarket.marketIndex,
1819
+ size: positionUnrealizedPnl,
1820
+ value: pnlValue,
1821
+ weight: pnlWeight,
1822
+ weightedValue: wegithedPnlValue,
1823
+ });
1824
+ }
1825
+ let netQuoteValue = numericConstants_1.ZERO;
1826
+ for (const spotPosition of this.getActiveSpotPositions()) {
1827
+ const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
1828
+ const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
1829
+ if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
1830
+ const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), spotPosition.balanceType);
1831
+ netQuoteValue = netQuoteValue.add(tokenAmount);
1832
+ continue;
1833
+ }
1834
+ const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, oraclePriceData);
1835
+ netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
1836
+ const baseAssetValue = (0, _1.getTokenValue)(worstCaseTokenAmount.abs(), spotMarketAccount.decimals, oraclePriceData);
1837
+ const isLiability = (0, types_1.isVariant)(spotPosition.balanceType, 'borrow');
1838
+ let weight;
1839
+ if (isLiability) {
1840
+ weight = (0, spotBalance_1.calculateLiabilityWeight)(worstCaseTokenAmount.abs(), spotMarketAccount, marginCategory);
1841
+ }
1842
+ else {
1843
+ weight = (0, spotBalance_1.calculateAssetWeight)(worstCaseTokenAmount, spotMarketAccount, marginCategory);
1844
+ }
1845
+ const weightedValue = baseAssetValue
1846
+ .mul(weight)
1847
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
1848
+ if (isLiability) {
1849
+ healthComponents.borrows.push({
1850
+ marketIndex: spotMarketAccount.marketIndex,
1851
+ size: worstCaseTokenAmount,
1852
+ value: baseAssetValue,
1853
+ weight: weight,
1854
+ weightedValue: weightedValue,
1855
+ });
1856
+ }
1857
+ else {
1858
+ healthComponents.deposits.push({
1859
+ marketIndex: spotMarketAccount.marketIndex,
1860
+ size: worstCaseTokenAmount,
1861
+ value: baseAssetValue,
1862
+ weight: weight,
1863
+ weightedValue: weightedValue,
1864
+ });
1865
+ }
1866
+ }
1867
+ if (!netQuoteValue.eq(numericConstants_1.ZERO)) {
1868
+ const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
1869
+ const oraclePriceData = this.getOracleDataForSpotMarket(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
1870
+ const baseAssetValue = (0, _1.getTokenValue)(netQuoteValue.abs(), spotMarketAccount.decimals, oraclePriceData);
1871
+ const isLiability = netQuoteValue.lt(numericConstants_1.ZERO);
1872
+ let weight;
1873
+ if (isLiability) {
1874
+ weight = (0, spotBalance_1.calculateLiabilityWeight)(netQuoteValue.abs(), spotMarketAccount, marginCategory);
1875
+ }
1876
+ else {
1877
+ weight = (0, spotBalance_1.calculateAssetWeight)(netQuoteValue, spotMarketAccount, marginCategory);
1878
+ }
1879
+ const weightedValue = baseAssetValue
1880
+ .mul(weight)
1881
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
1882
+ if (isLiability) {
1883
+ healthComponents.borrows.push({
1884
+ marketIndex: spotMarketAccount.marketIndex,
1885
+ size: netQuoteValue,
1886
+ value: baseAssetValue,
1887
+ weight: weight,
1888
+ weightedValue: weightedValue,
1889
+ });
1890
+ }
1891
+ else {
1892
+ healthComponents.deposits.push({
1893
+ marketIndex: spotMarketAccount.marketIndex,
1894
+ size: netQuoteValue,
1895
+ value: baseAssetValue,
1896
+ weight: weight,
1897
+ weightedValue: weightedValue,
1898
+ });
1899
+ }
1900
+ }
1901
+ return healthComponents;
1902
+ }
1705
1903
  /**
1706
1904
  * Get the total position value, excluding any position coming from the given target market
1707
1905
  * @param marketToIgnore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.37.1-beta.0",
3
+ "version": "2.37.1-beta.10",
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[] } = {
@@ -168,6 +168,7 @@ export class EventSubscriber {
168
168
  const records = [];
169
169
  // @ts-ignore
170
170
  const events = parseLogs(this.program, slot, logs);
171
+ let runningEventIndex = 0;
171
172
  for (const event of events) {
172
173
  // @ts-ignore
173
174
  const expectRecordType = this.eventListMap.has(event.name);
@@ -175,8 +176,10 @@ export class EventSubscriber {
175
176
  event.data.txSig = txSig;
176
177
  event.data.slot = slot;
177
178
  event.data.eventType = event.name;
179
+ event.data.txSigIndex = runningEventIndex;
178
180
  records.push(event.data);
179
181
  }
182
+ runningEventIndex++;
180
183
  }
181
184
  return records;
182
185
  }
@@ -155,11 +155,14 @@ export class LogParser {
155
155
  event.logs,
156
156
  false
157
157
  );
158
+ let runningEventIndex = 0;
158
159
  for (const eventLog of eventGenerator) {
159
160
  eventLog.data.txSig = event.txSig;
160
161
  eventLog.data.slot = event.slot;
161
162
  eventLog.data.eventType = eventLog.name;
163
+ eventLog.data.txSigIndex = runningEventIndex;
162
164
  records.push(eventLog.data);
165
+ runningEventIndex++;
163
166
  }
164
167
  return records;
165
168
  }
@@ -64,6 +64,7 @@ export type EventSubscriptionOrderDirection = 'asc' | 'desc';
64
64
  export type Event<T> = T & {
65
65
  txSig: TransactionSignature;
66
66
  slot: number;
67
+ txSigIndex: number; // Unique index for each event inside a tx
67
68
  };
68
69
 
69
70
  export type WrappedEvent<Type extends EventType> = EventMap[Type] & {
@@ -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';