@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/VERSION +1 -1
- package/lib/adminClient.d.ts +1 -0
- package/lib/adminClient.js +10 -0
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/idl/drift.json +73 -8
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/auction.js +1 -1
- package/lib/orderSubscriber/OrderSubscriber.d.ts +5 -1
- package/lib/orderSubscriber/OrderSubscriber.js +10 -0
- package/lib/orderSubscriber/types.d.ts +5 -0
- package/lib/tx/baseTxSender.d.ts +30 -0
- package/lib/tx/baseTxSender.js +176 -0
- package/lib/tx/fastSingleTxSender.d.ts +27 -0
- package/lib/tx/fastSingleTxSender.js +83 -0
- package/lib/tx/retryTxSender.d.ts +5 -14
- package/lib/tx/retryTxSender.js +7 -158
- package/lib/types.d.ts +18 -0
- package/lib/types.js +1 -0
- package/lib/user.d.ts +12 -3
- package/lib/user.js +261 -73
- package/package.json +2 -2
- package/src/adminClient.ts +18 -0
- package/src/constants/perpMarkets.ts +20 -0
- package/src/idl/drift.json +73 -8
- package/src/index.ts +1 -0
- package/src/marinade/types.ts +70 -70
- package/src/math/auction.ts +1 -1
- package/src/orderSubscriber/OrderSubscriber.ts +19 -2
- package/src/orderSubscriber/types.ts +11 -0
- package/src/tx/baseTxSender.ts +276 -0
- package/src/tx/fastSingleTxSender.ts +142 -0
- package/src/tx/retryTxSender.ts +9 -235
- package/src/types.ts +19 -0
- package/src/user.ts +455 -119
- package/tests/amm/test.ts +83 -39
- package/tests/dlob/helpers.ts +2 -0
- 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(
|
|
305
|
+
.div(baseUnit);
|
|
268
306
|
const deltaQaa = market.amm.quoteAssetAmountPerLp
|
|
269
307
|
.sub(position.lastQuoteAssetAmountPerLp)
|
|
270
308
|
.mul(nShares)
|
|
271
|
-
.div(
|
|
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 -
|
|
417
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
380
418
|
* @returns : Precision QUOTE_PRECISION
|
|
381
419
|
*/
|
|
382
|
-
getFreeCollateral() {
|
|
383
|
-
const totalCollateral = this.getTotalCollateral(
|
|
384
|
-
const
|
|
385
|
-
|
|
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(
|
|
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
|
-
|
|
652
|
-
100)
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
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.
|
|
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": "^
|
|
58
|
+
"prettier": "^3.0.1",
|
|
59
59
|
"ts-node": "^10.8.0",
|
|
60
60
|
"typescript": "^4.9.5"
|
|
61
61
|
},
|
package/src/adminClient.ts
CHANGED
|
@@ -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[] } = {
|
package/src/idl/drift.json
CHANGED
|
@@ -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": "
|
|
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": "
|
|
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';
|