@drift-labs/sdk 2.38.1-beta.7 → 2.38.1-beta.9
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 +11 -0
- package/lib/idl/drift.json +36 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/math/spotBalance.d.ts +6 -5
- package/lib/math/spotBalance.js +28 -11
- package/lib/math/spotMarket.d.ts +1 -1
- package/lib/math/spotMarket.js +2 -2
- package/lib/math/spotPosition.d.ts +16 -3
- package/lib/math/spotPosition.js +53 -9
- package/lib/oracles/strictOraclePrice.d.ts +8 -0
- package/lib/oracles/strictOraclePrice.js +17 -0
- package/lib/types.d.ts +4 -0
- package/lib/types.js +3 -0
- package/lib/user.d.ts +5 -4
- package/lib/user.js +71 -105
- package/package.json +1 -1
- package/src/adminClient.ts +23 -0
- package/src/idl/drift.json +36 -1
- package/src/index.ts +2 -0
- package/src/math/spotBalance.ts +37 -11
- package/src/math/spotMarket.ts +7 -1
- package/src/math/spotPosition.ts +133 -18
- package/src/oracles/strictOraclePrice.ts +19 -0
- package/src/types.ts +4 -0
- package/src/user.ts +171 -228
- package/tests/dlob/helpers.ts +10 -7
- package/tests/user/test.ts +77 -4
package/lib/user.js
CHANGED
|
@@ -13,6 +13,7 @@ const webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccoun
|
|
|
13
13
|
const spotPosition_1 = require("./math/spotPosition");
|
|
14
14
|
const oracles_1 = require("./math/oracles");
|
|
15
15
|
const tiers_1 = require("./math/tiers");
|
|
16
|
+
const strictOraclePrice_1 = require("./oracles/strictOraclePrice");
|
|
16
17
|
class User {
|
|
17
18
|
get isSubscribed() {
|
|
18
19
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -543,15 +544,21 @@ class User {
|
|
|
543
544
|
}
|
|
544
545
|
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
545
546
|
const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
|
|
547
|
+
let twap5min;
|
|
548
|
+
if (strict) {
|
|
549
|
+
twap5min = (0, oracles_1.calculateLiveOracleTwap)(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
const strictOraclePrice = new strictOraclePrice_1.StrictOraclePrice(oraclePriceData.price, twap5min);
|
|
546
553
|
if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX &&
|
|
547
554
|
countForQuote) {
|
|
548
555
|
const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), spotPosition.balanceType);
|
|
549
556
|
if ((0, types_1.isVariant)(spotPosition.balanceType, 'borrow')) {
|
|
550
|
-
const weightedTokenValue = this.getSpotLiabilityValue(tokenAmount,
|
|
557
|
+
const weightedTokenValue = this.getSpotLiabilityValue(tokenAmount, strictOraclePrice, spotMarketAccount, marginCategory, liquidationBuffer).abs();
|
|
551
558
|
netQuoteValue = netQuoteValue.sub(weightedTokenValue);
|
|
552
559
|
}
|
|
553
560
|
else {
|
|
554
|
-
const weightedTokenValue = this.getSpotAssetValue(tokenAmount,
|
|
561
|
+
const weightedTokenValue = this.getSpotAssetValue(tokenAmount, strictOraclePrice, spotMarketAccount, marginCategory);
|
|
555
562
|
netQuoteValue = netQuoteValue.add(weightedTokenValue);
|
|
556
563
|
}
|
|
557
564
|
continue;
|
|
@@ -559,24 +566,24 @@ class User {
|
|
|
559
566
|
if (!includeOpenOrders && countForBase) {
|
|
560
567
|
if ((0, types_1.isVariant)(spotPosition.balanceType, 'borrow')) {
|
|
561
568
|
const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), _1.SpotBalanceType.BORROW);
|
|
562
|
-
const liabilityValue = this.getSpotLiabilityValue(tokenAmount,
|
|
569
|
+
const liabilityValue = this.getSpotLiabilityValue(tokenAmount, strictOraclePrice, spotMarketAccount, marginCategory, liquidationBuffer).abs();
|
|
563
570
|
totalLiabilityValue = totalLiabilityValue.add(liabilityValue);
|
|
564
571
|
continue;
|
|
565
572
|
}
|
|
566
573
|
else {
|
|
567
574
|
const tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType);
|
|
568
|
-
const assetValue = this.getSpotAssetValue(tokenAmount,
|
|
575
|
+
const assetValue = this.getSpotAssetValue(tokenAmount, strictOraclePrice, spotMarketAccount, marginCategory);
|
|
569
576
|
totalAssetValue = totalAssetValue.add(assetValue);
|
|
570
577
|
continue;
|
|
571
578
|
}
|
|
572
579
|
}
|
|
573
|
-
const
|
|
580
|
+
const { tokenAmount: worstCaseTokenAmount, ordersValue: worstCaseQuoteTokenAmount, } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory);
|
|
574
581
|
if (worstCaseTokenAmount.gt(numericConstants_1.ZERO) && countForBase) {
|
|
575
|
-
const baseAssetValue = this.getSpotAssetValue(worstCaseTokenAmount,
|
|
582
|
+
const baseAssetValue = this.getSpotAssetValue(worstCaseTokenAmount, strictOraclePrice, spotMarketAccount, marginCategory);
|
|
576
583
|
totalAssetValue = totalAssetValue.add(baseAssetValue);
|
|
577
584
|
}
|
|
578
585
|
if (worstCaseTokenAmount.lt(numericConstants_1.ZERO) && countForBase) {
|
|
579
|
-
const baseLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount,
|
|
586
|
+
const baseLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount, strictOraclePrice, spotMarketAccount, marginCategory, liquidationBuffer).abs();
|
|
580
587
|
totalLiabilityValue = totalLiabilityValue.add(baseLiabilityValue);
|
|
581
588
|
}
|
|
582
589
|
if (worstCaseQuoteTokenAmount.gt(numericConstants_1.ZERO) && countForQuote) {
|
|
@@ -609,16 +616,8 @@ class User {
|
|
|
609
616
|
const { totalLiabilityValue } = this.getSpotMarketAssetAndLiabilityValue(marketIndex, marginCategory, liquidationBuffer, includeOpenOrders, strict, now);
|
|
610
617
|
return totalLiabilityValue;
|
|
611
618
|
}
|
|
612
|
-
getSpotLiabilityValue(tokenAmount,
|
|
613
|
-
let liabilityValue =
|
|
614
|
-
if (strict) {
|
|
615
|
-
const estOracleTwap = (0, oracles_1.calculateLiveOracleTwap)(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
|
|
616
|
-
);
|
|
617
|
-
liabilityValue = (0, _1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, oraclePriceData, estOracleTwap);
|
|
618
|
-
}
|
|
619
|
-
else {
|
|
620
|
-
liabilityValue = (0, _1.getTokenValue)(tokenAmount, spotMarketAccount.decimals, oraclePriceData);
|
|
621
|
-
}
|
|
619
|
+
getSpotLiabilityValue(tokenAmount, strictOraclePrice, spotMarketAccount, marginCategory, liquidationBuffer) {
|
|
620
|
+
let liabilityValue = (0, _1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, strictOraclePrice);
|
|
622
621
|
if (marginCategory !== undefined) {
|
|
623
622
|
let weight = (0, spotBalance_1.calculateLiabilityWeight)(tokenAmount, spotMarketAccount, marginCategory);
|
|
624
623
|
if (marginCategory === 'Initial') {
|
|
@@ -637,18 +636,10 @@ class User {
|
|
|
637
636
|
const { totalAssetValue } = this.getSpotMarketAssetAndLiabilityValue(marketIndex, marginCategory, undefined, includeOpenOrders, strict, now);
|
|
638
637
|
return totalAssetValue;
|
|
639
638
|
}
|
|
640
|
-
getSpotAssetValue(tokenAmount,
|
|
641
|
-
let assetValue =
|
|
642
|
-
if (strict) {
|
|
643
|
-
const estOracleTwap = (0, oracles_1.calculateLiveOracleTwap)(spotMarketAccount.historicalOracleData, oraclePriceData, now, numericConstants_1.FIVE_MINUTE // 5MIN
|
|
644
|
-
);
|
|
645
|
-
assetValue = (0, _1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, oraclePriceData, estOracleTwap);
|
|
646
|
-
}
|
|
647
|
-
else {
|
|
648
|
-
assetValue = (0, _1.getTokenValue)(tokenAmount, spotMarketAccount.decimals, oraclePriceData);
|
|
649
|
-
}
|
|
639
|
+
getSpotAssetValue(tokenAmount, strictOraclePrice, spotMarketAccount, marginCategory) {
|
|
640
|
+
let assetValue = (0, _1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, strictOraclePrice);
|
|
650
641
|
if (marginCategory !== undefined) {
|
|
651
|
-
const weight = (0, spotBalance_1.calculateAssetWeight)(tokenAmount, spotMarketAccount, marginCategory);
|
|
642
|
+
const weight = (0, spotBalance_1.calculateAssetWeight)(tokenAmount, strictOraclePrice.current, spotMarketAccount, marginCategory);
|
|
652
643
|
assetValue = assetValue.mul(weight).div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
|
|
653
644
|
}
|
|
654
645
|
return assetValue;
|
|
@@ -1157,7 +1148,7 @@ class User {
|
|
|
1157
1148
|
calculateFreeCollateralDeltaForSpot(market, signedTokenAmount) {
|
|
1158
1149
|
const tokenPrecision = new _1.BN(Math.pow(10, market.decimals));
|
|
1159
1150
|
if (signedTokenAmount.gt(numericConstants_1.ZERO)) {
|
|
1160
|
-
const assetWeight = (0, spotBalance_1.calculateAssetWeight)(signedTokenAmount, market, 'Maintenance');
|
|
1151
|
+
const assetWeight = (0, spotBalance_1.calculateAssetWeight)(signedTokenAmount, this.driftClient.getOraclePriceDataAndSlot(market.oracle).data.price, market, 'Maintenance');
|
|
1161
1152
|
return numericConstants_1.QUOTE_PRECISION.mul(assetWeight)
|
|
1162
1153
|
.div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
|
|
1163
1154
|
.mul(signedTokenAmount)
|
|
@@ -1279,11 +1270,12 @@ class User {
|
|
|
1279
1270
|
*/
|
|
1280
1271
|
getMaxTradeSizeUSDCForSpot(targetMarketIndex, direction, currentQuoteAssetValue, currentSpotMarketNetValue) {
|
|
1281
1272
|
const market = this.driftClient.getSpotMarketAccount(targetMarketIndex);
|
|
1273
|
+
const oraclePrice = this.driftClient.getOraclePriceDataAndSlot(market.oracle).data.price;
|
|
1282
1274
|
currentQuoteAssetValue = this.getSpotMarketAssetValue(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
|
|
1283
1275
|
currentSpotMarketNetValue =
|
|
1284
1276
|
currentSpotMarketNetValue !== null && currentSpotMarketNetValue !== void 0 ? currentSpotMarketNetValue : this.getSpotPositionValue(targetMarketIndex);
|
|
1285
1277
|
let freeCollateral = this.getFreeCollateral();
|
|
1286
|
-
const marginRatio = (0, _1.calculateSpotMarketMarginRatio)(market, 'Initial', numericConstants_1.ZERO, (0, types_1.isVariant)(direction, 'long')
|
|
1278
|
+
const marginRatio = (0, _1.calculateSpotMarketMarginRatio)(market, oraclePrice, 'Initial', numericConstants_1.ZERO, (0, types_1.isVariant)(direction, 'long')
|
|
1287
1279
|
? _1.SpotBalanceType.DEPOSIT
|
|
1288
1280
|
: _1.SpotBalanceType.BORROW);
|
|
1289
1281
|
let tradeAmount = numericConstants_1.ZERO;
|
|
@@ -1291,13 +1283,13 @@ class User {
|
|
|
1291
1283
|
// if the user is buying/selling and already short/long, need to account for closing out short/long
|
|
1292
1284
|
if ((0, types_1.isVariant)(direction, 'long') && currentSpotMarketNetValue.lt(numericConstants_1.ZERO)) {
|
|
1293
1285
|
tradeAmount = currentSpotMarketNetValue.abs();
|
|
1294
|
-
const marginRatio = (0, _1.calculateSpotMarketMarginRatio)(market, 'Initial', this.getTokenAmount(targetMarketIndex).abs(), _1.SpotBalanceType.BORROW);
|
|
1286
|
+
const marginRatio = (0, _1.calculateSpotMarketMarginRatio)(market, oraclePrice, 'Initial', this.getTokenAmount(targetMarketIndex).abs(), _1.SpotBalanceType.BORROW);
|
|
1295
1287
|
freeCollateral = freeCollateral.add(tradeAmount.mul(new _1.BN(marginRatio)).div(numericConstants_1.MARGIN_PRECISION));
|
|
1296
1288
|
}
|
|
1297
1289
|
else if ((0, types_1.isVariant)(direction, 'short') &&
|
|
1298
1290
|
currentSpotMarketNetValue.gt(numericConstants_1.ZERO)) {
|
|
1299
1291
|
tradeAmount = currentSpotMarketNetValue;
|
|
1300
|
-
const marginRatio = (0, _1.calculateSpotMarketMarginRatio)(market, 'Initial', this.getTokenAmount(targetMarketIndex), _1.SpotBalanceType.DEPOSIT);
|
|
1292
|
+
const marginRatio = (0, _1.calculateSpotMarketMarginRatio)(market, oraclePrice, 'Initial', this.getTokenAmount(targetMarketIndex), _1.SpotBalanceType.DEPOSIT);
|
|
1301
1293
|
freeCollateral = freeCollateral.add(tradeAmount.mul(new _1.BN(marginRatio)).div(numericConstants_1.MARGIN_PRECISION));
|
|
1302
1294
|
}
|
|
1303
1295
|
tradeAmount = tradeAmount.add(freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new _1.BN(marginRatio)));
|
|
@@ -1322,8 +1314,12 @@ class User {
|
|
|
1322
1314
|
getMaxSwapAmount({ inMarketIndex, outMarketIndex, calculateSwap, iterationLimit = 1000, }) {
|
|
1323
1315
|
const inMarket = this.driftClient.getSpotMarketAccount(inMarketIndex);
|
|
1324
1316
|
const outMarket = this.driftClient.getSpotMarketAccount(outMarketIndex);
|
|
1325
|
-
const
|
|
1326
|
-
const
|
|
1317
|
+
const inOraclePriceData = this.getOracleDataForSpotMarket(inMarketIndex);
|
|
1318
|
+
const inOraclePrice = inOraclePriceData.price;
|
|
1319
|
+
const outOraclePriceData = this.getOracleDataForSpotMarket(outMarketIndex);
|
|
1320
|
+
const outOraclePrice = outOraclePriceData.price;
|
|
1321
|
+
const inStrictOraclePrice = new strictOraclePrice_1.StrictOraclePrice(inOraclePrice);
|
|
1322
|
+
const outStrictOraclePrice = new strictOraclePrice_1.StrictOraclePrice(outOraclePrice);
|
|
1327
1323
|
const inPrecision = new _1.BN(10 ** inMarket.decimals);
|
|
1328
1324
|
const outPrecision = new _1.BN(10 ** outMarket.decimals);
|
|
1329
1325
|
const inSpotPosition = this.getSpotPosition(inMarketIndex) ||
|
|
@@ -1331,10 +1327,10 @@ class User {
|
|
|
1331
1327
|
const outSpotPosition = this.getSpotPosition(outMarketIndex) ||
|
|
1332
1328
|
this.getEmptySpotPosition(outMarketIndex);
|
|
1333
1329
|
const freeCollateral = this.getFreeCollateral();
|
|
1334
|
-
const inContributionInitial = this.calculateSpotPositionFreeCollateralContribution(inSpotPosition);
|
|
1335
|
-
const { totalAssetValue: inTotalAssetValueInitial, totalLiabilityValue: inTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(inSpotPosition);
|
|
1336
|
-
const outContributionInitial = this.calculateSpotPositionFreeCollateralContribution(outSpotPosition);
|
|
1337
|
-
const { totalAssetValue: outTotalAssetValueInitial, totalLiabilityValue: outTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(outSpotPosition);
|
|
1330
|
+
const inContributionInitial = this.calculateSpotPositionFreeCollateralContribution(inSpotPosition, inStrictOraclePrice);
|
|
1331
|
+
const { totalAssetValue: inTotalAssetValueInitial, totalLiabilityValue: inTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(inSpotPosition, inStrictOraclePrice);
|
|
1332
|
+
const outContributionInitial = this.calculateSpotPositionFreeCollateralContribution(outSpotPosition, outStrictOraclePrice);
|
|
1333
|
+
const { totalAssetValue: outTotalAssetValueInitial, totalLiabilityValue: outTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(outSpotPosition, outStrictOraclePrice);
|
|
1338
1334
|
const initialContribution = inContributionInitial.add(outContributionInitial);
|
|
1339
1335
|
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents();
|
|
1340
1336
|
if (!calculateSwap) {
|
|
@@ -1374,8 +1370,8 @@ class User {
|
|
|
1374
1370
|
outSwap = calculateSwap(inSwap);
|
|
1375
1371
|
const inPositionAfter = this.cloneAndUpdateSpotPosition(inSpotPosition, inSwap.neg(), inMarket);
|
|
1376
1372
|
const outPositionAfter = this.cloneAndUpdateSpotPosition(outSpotPosition, outSwap, outMarket);
|
|
1377
|
-
const inContributionAfter = this.calculateSpotPositionFreeCollateralContribution(inPositionAfter);
|
|
1378
|
-
const outContributionAfter = this.calculateSpotPositionFreeCollateralContribution(outPositionAfter);
|
|
1373
|
+
const inContributionAfter = this.calculateSpotPositionFreeCollateralContribution(inPositionAfter, inStrictOraclePrice);
|
|
1374
|
+
const outContributionAfter = this.calculateSpotPositionFreeCollateralContribution(outPositionAfter, outStrictOraclePrice);
|
|
1379
1375
|
const contributionAfter = inContributionAfter.add(outContributionAfter);
|
|
1380
1376
|
const contributionDelta = contributionAfter.sub(initialContribution);
|
|
1381
1377
|
freeCollateralAfter = freeCollateral.add(contributionDelta);
|
|
@@ -1395,8 +1391,8 @@ class User {
|
|
|
1395
1391
|
}
|
|
1396
1392
|
const inPositionAfter = this.cloneAndUpdateSpotPosition(inSpotPosition, inSwap.neg(), inMarket);
|
|
1397
1393
|
const outPositionAfter = this.cloneAndUpdateSpotPosition(outSpotPosition, outSwap, outMarket);
|
|
1398
|
-
const { totalAssetValue: inTotalAssetValueAfter, totalLiabilityValue: inTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(inPositionAfter);
|
|
1399
|
-
const { totalAssetValue: outTotalAssetValueAfter, totalLiabilityValue: outTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(outPositionAfter);
|
|
1394
|
+
const { totalAssetValue: inTotalAssetValueAfter, totalLiabilityValue: inTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(inPositionAfter, inStrictOraclePrice);
|
|
1395
|
+
const { totalAssetValue: outTotalAssetValueAfter, totalLiabilityValue: outTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(outPositionAfter, outStrictOraclePrice);
|
|
1400
1396
|
const spotAssetValueDelta = inTotalAssetValueAfter
|
|
1401
1397
|
.add(outTotalAssetValueAfter)
|
|
1402
1398
|
.sub(inTotalAssetValueInitial)
|
|
@@ -1441,45 +1437,28 @@ class User {
|
|
|
1441
1437
|
}
|
|
1442
1438
|
return clonedPosition;
|
|
1443
1439
|
}
|
|
1444
|
-
calculateSpotPositionFreeCollateralContribution(spotPosition) {
|
|
1445
|
-
let freeCollateralContribution = numericConstants_1.ZERO;
|
|
1446
|
-
const now = new _1.BN(new Date().getTime() / 1000);
|
|
1447
|
-
const strict = true;
|
|
1440
|
+
calculateSpotPositionFreeCollateralContribution(spotPosition, strictOraclePrice) {
|
|
1448
1441
|
const marginCategory = 'Initial';
|
|
1449
1442
|
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
1450
|
-
const
|
|
1451
|
-
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, oraclePriceData);
|
|
1452
|
-
if (worstCaseTokenAmount.gt(numericConstants_1.ZERO)) {
|
|
1453
|
-
const baseAssetValue = this.getSpotAssetValue(worstCaseTokenAmount, oraclePriceData, spotMarketAccount, marginCategory, strict, now);
|
|
1454
|
-
freeCollateralContribution =
|
|
1455
|
-
freeCollateralContribution.add(baseAssetValue);
|
|
1456
|
-
}
|
|
1457
|
-
else {
|
|
1458
|
-
const baseLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount, oraclePriceData, spotMarketAccount, marginCategory, undefined, strict, now).abs();
|
|
1459
|
-
freeCollateralContribution =
|
|
1460
|
-
freeCollateralContribution.sub(baseLiabilityValue);
|
|
1461
|
-
}
|
|
1462
|
-
freeCollateralContribution.add(worstCaseQuoteTokenAmount);
|
|
1443
|
+
const { freeCollateralContribution } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory);
|
|
1463
1444
|
return freeCollateralContribution;
|
|
1464
1445
|
}
|
|
1465
|
-
calculateSpotPositionLeverageContribution(spotPosition) {
|
|
1446
|
+
calculateSpotPositionLeverageContribution(spotPosition, strictOraclePrice) {
|
|
1466
1447
|
let totalAssetValue = numericConstants_1.ZERO;
|
|
1467
1448
|
let totalLiabilityValue = numericConstants_1.ZERO;
|
|
1468
|
-
const now = new _1.BN(new Date().getTime() / 1000);
|
|
1469
1449
|
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
1470
|
-
const
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
totalAssetValue = this.getSpotAssetValue(worstCaseTokenAmount, oraclePriceData, spotMarketAccount, undefined, false, now);
|
|
1450
|
+
const { tokenValue, ordersValue } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, strictOraclePrice, 'Initial');
|
|
1451
|
+
if (tokenValue.gte(numericConstants_1.ZERO)) {
|
|
1452
|
+
totalAssetValue = tokenValue;
|
|
1474
1453
|
}
|
|
1475
1454
|
else {
|
|
1476
|
-
totalLiabilityValue =
|
|
1455
|
+
totalLiabilityValue = tokenValue.abs();
|
|
1477
1456
|
}
|
|
1478
|
-
if (
|
|
1479
|
-
totalAssetValue = totalAssetValue.add(
|
|
1457
|
+
if (ordersValue.gt(numericConstants_1.ZERO)) {
|
|
1458
|
+
totalAssetValue = totalAssetValue.add(ordersValue);
|
|
1480
1459
|
}
|
|
1481
1460
|
else {
|
|
1482
|
-
totalLiabilityValue = totalLiabilityValue.add(
|
|
1461
|
+
totalLiabilityValue = totalLiabilityValue.add(ordersValue.abs());
|
|
1483
1462
|
}
|
|
1484
1463
|
return {
|
|
1485
1464
|
totalAssetValue,
|
|
@@ -1496,17 +1475,23 @@ class User {
|
|
|
1496
1475
|
accountLeverageAfterSwap({ inMarketIndex, outMarketIndex, inAmount, outAmount, }) {
|
|
1497
1476
|
const inMarket = this.driftClient.getSpotMarketAccount(inMarketIndex);
|
|
1498
1477
|
const outMarket = this.driftClient.getSpotMarketAccount(outMarketIndex);
|
|
1478
|
+
const inOraclePriceData = this.getOracleDataForSpotMarket(inMarketIndex);
|
|
1479
|
+
const inOraclePrice = inOraclePriceData.price;
|
|
1480
|
+
const outOraclePriceData = this.getOracleDataForSpotMarket(outMarketIndex);
|
|
1481
|
+
const outOraclePrice = outOraclePriceData.price;
|
|
1482
|
+
const inStrictOraclePrice = new strictOraclePrice_1.StrictOraclePrice(inOraclePrice);
|
|
1483
|
+
const outStrictOraclePrice = new strictOraclePrice_1.StrictOraclePrice(outOraclePrice);
|
|
1499
1484
|
const inSpotPosition = this.getSpotPosition(inMarketIndex) ||
|
|
1500
1485
|
this.getEmptySpotPosition(inMarketIndex);
|
|
1501
1486
|
const outSpotPosition = this.getSpotPosition(outMarketIndex) ||
|
|
1502
1487
|
this.getEmptySpotPosition(outMarketIndex);
|
|
1503
|
-
const { totalAssetValue: inTotalAssetValueInitial, totalLiabilityValue: inTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(inSpotPosition);
|
|
1504
|
-
const { totalAssetValue: outTotalAssetValueInitial, totalLiabilityValue: outTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(outSpotPosition);
|
|
1488
|
+
const { totalAssetValue: inTotalAssetValueInitial, totalLiabilityValue: inTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(inSpotPosition, inStrictOraclePrice);
|
|
1489
|
+
const { totalAssetValue: outTotalAssetValueInitial, totalLiabilityValue: outTotalLiabilityValueInitial, } = this.calculateSpotPositionLeverageContribution(outSpotPosition, outStrictOraclePrice);
|
|
1505
1490
|
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } = this.getLeverageComponents();
|
|
1506
1491
|
const inPositionAfter = this.cloneAndUpdateSpotPosition(inSpotPosition, inAmount.abs().neg(), inMarket);
|
|
1507
1492
|
const outPositionAfter = this.cloneAndUpdateSpotPosition(outSpotPosition, outAmount.abs(), outMarket);
|
|
1508
|
-
const { totalAssetValue: inTotalAssetValueAfter, totalLiabilityValue: inTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(inPositionAfter);
|
|
1509
|
-
const { totalAssetValue: outTotalAssetValueAfter, totalLiabilityValue: outTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(outPositionAfter);
|
|
1493
|
+
const { totalAssetValue: inTotalAssetValueAfter, totalLiabilityValue: inTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(inPositionAfter, inStrictOraclePrice);
|
|
1494
|
+
const { totalAssetValue: outTotalAssetValueAfter, totalLiabilityValue: outTotalLiabilityValueAfter, } = this.calculateSpotPositionLeverageContribution(outPositionAfter, outStrictOraclePrice);
|
|
1510
1495
|
const spotAssetValueDelta = inTotalAssetValueAfter
|
|
1511
1496
|
.add(outTotalAssetValueAfter)
|
|
1512
1497
|
.sub(inTotalAssetValueInitial)
|
|
@@ -1634,7 +1619,7 @@ class User {
|
|
|
1634
1619
|
if (canBypass) {
|
|
1635
1620
|
withdrawLimit = _1.BN.max(withdrawLimit, userDepositAmount);
|
|
1636
1621
|
}
|
|
1637
|
-
const assetWeight = (0, spotBalance_1.calculateAssetWeight)(userDepositAmount, spotMarket, 'Initial');
|
|
1622
|
+
const assetWeight = (0, spotBalance_1.calculateAssetWeight)(userDepositAmount, oracleData.price, spotMarket, 'Initial');
|
|
1638
1623
|
const amountWithdrawable = assetWeight.eq(numericConstants_1.ZERO)
|
|
1639
1624
|
? userDepositAmount
|
|
1640
1625
|
: freeCollateral
|
|
@@ -1816,26 +1801,17 @@ class User {
|
|
|
1816
1801
|
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
1817
1802
|
const spotMarketAccount = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
1818
1803
|
const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
|
|
1804
|
+
const strictOraclePrice = new strictOraclePrice_1.StrictOraclePrice(oraclePriceData.price);
|
|
1819
1805
|
if (spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
1820
1806
|
const tokenAmount = (0, _1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), spotPosition.balanceType);
|
|
1821
1807
|
netQuoteValue = netQuoteValue.add(tokenAmount);
|
|
1822
1808
|
continue;
|
|
1823
1809
|
}
|
|
1824
|
-
const
|
|
1825
|
-
netQuoteValue = netQuoteValue.add(
|
|
1826
|
-
const baseAssetValue =
|
|
1827
|
-
const
|
|
1828
|
-
|
|
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) {
|
|
1810
|
+
const { tokenAmount: worstCaseTokenAmount, tokenValue: tokenValue, weight, weightedTokenValue: weightedTokenValue, ordersValue: ordersValue, } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory);
|
|
1811
|
+
netQuoteValue = netQuoteValue.add(ordersValue);
|
|
1812
|
+
const baseAssetValue = tokenValue.abs();
|
|
1813
|
+
const weightedValue = weightedTokenValue.abs();
|
|
1814
|
+
if (weightedTokenValue.lt(numericConstants_1.ZERO)) {
|
|
1839
1815
|
healthComponents.borrows.push({
|
|
1840
1816
|
marketIndex: spotMarketAccount.marketIndex,
|
|
1841
1817
|
size: worstCaseTokenAmount,
|
|
@@ -1857,25 +1833,15 @@ class User {
|
|
|
1857
1833
|
if (!netQuoteValue.eq(numericConstants_1.ZERO)) {
|
|
1858
1834
|
const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
|
|
1859
1835
|
const oraclePriceData = this.getOracleDataForSpotMarket(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
|
|
1860
|
-
const baseAssetValue = (0, _1.getTokenValue)(netQuoteValue
|
|
1861
|
-
const
|
|
1862
|
-
|
|
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) {
|
|
1836
|
+
const baseAssetValue = (0, _1.getTokenValue)(netQuoteValue, spotMarketAccount.decimals, oraclePriceData);
|
|
1837
|
+
const { weight, weightedTokenValue } = (0, spotPosition_1.calculateWeightedTokenValue)(netQuoteValue, baseAssetValue, oraclePriceData, spotMarketAccount, marginCategory);
|
|
1838
|
+
if (netQuoteValue.lt(numericConstants_1.ZERO)) {
|
|
1873
1839
|
healthComponents.borrows.push({
|
|
1874
1840
|
marketIndex: spotMarketAccount.marketIndex,
|
|
1875
1841
|
size: netQuoteValue,
|
|
1876
|
-
value: baseAssetValue,
|
|
1842
|
+
value: baseAssetValue.abs(),
|
|
1877
1843
|
weight: weight,
|
|
1878
|
-
weightedValue:
|
|
1844
|
+
weightedValue: weightedTokenValue.abs(),
|
|
1879
1845
|
});
|
|
1880
1846
|
}
|
|
1881
1847
|
else {
|
|
@@ -1884,7 +1850,7 @@ class User {
|
|
|
1884
1850
|
size: netQuoteValue,
|
|
1885
1851
|
value: baseAssetValue,
|
|
1886
1852
|
weight: weight,
|
|
1887
|
-
weightedValue:
|
|
1853
|
+
weightedValue: weightedTokenValue,
|
|
1888
1854
|
});
|
|
1889
1855
|
}
|
|
1890
1856
|
}
|
package/package.json
CHANGED
package/src/adminClient.ts
CHANGED
|
@@ -909,6 +909,29 @@ export class AdminClient extends DriftClient {
|
|
|
909
909
|
return txSig;
|
|
910
910
|
}
|
|
911
911
|
|
|
912
|
+
public async updateSpotMarketScaleInitialAssetWeightStart(
|
|
913
|
+
spotMarketIndex: number,
|
|
914
|
+
scaleInitialAssetWeightStart: BN
|
|
915
|
+
): Promise<TransactionSignature> {
|
|
916
|
+
const tx =
|
|
917
|
+
this.program.transaction.updateSpotMarketScaleInitialAssetWeightStart(
|
|
918
|
+
scaleInitialAssetWeightStart,
|
|
919
|
+
{
|
|
920
|
+
accounts: {
|
|
921
|
+
admin: this.wallet.publicKey,
|
|
922
|
+
state: await this.getStatePublicKey(),
|
|
923
|
+
spotMarket: await getSpotMarketPublicKey(
|
|
924
|
+
this.program.programId,
|
|
925
|
+
spotMarketIndex
|
|
926
|
+
),
|
|
927
|
+
},
|
|
928
|
+
}
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
932
|
+
return txSig;
|
|
933
|
+
}
|
|
934
|
+
|
|
912
935
|
public async updateInsuranceFundUnstakingPeriod(
|
|
913
936
|
spotMarketIndex: number,
|
|
914
937
|
insuranceWithdrawEscrowPeriod: BN
|
package/src/idl/drift.json
CHANGED
|
@@ -3538,6 +3538,32 @@
|
|
|
3538
3538
|
}
|
|
3539
3539
|
]
|
|
3540
3540
|
},
|
|
3541
|
+
{
|
|
3542
|
+
"name": "updateSpotMarketScaleInitialAssetWeightStart",
|
|
3543
|
+
"accounts": [
|
|
3544
|
+
{
|
|
3545
|
+
"name": "admin",
|
|
3546
|
+
"isMut": false,
|
|
3547
|
+
"isSigner": true
|
|
3548
|
+
},
|
|
3549
|
+
{
|
|
3550
|
+
"name": "state",
|
|
3551
|
+
"isMut": false,
|
|
3552
|
+
"isSigner": false
|
|
3553
|
+
},
|
|
3554
|
+
{
|
|
3555
|
+
"name": "spotMarket",
|
|
3556
|
+
"isMut": true,
|
|
3557
|
+
"isSigner": false
|
|
3558
|
+
}
|
|
3559
|
+
],
|
|
3560
|
+
"args": [
|
|
3561
|
+
{
|
|
3562
|
+
"name": "scaleInitialAssetWeightStart",
|
|
3563
|
+
"type": "u64"
|
|
3564
|
+
}
|
|
3565
|
+
]
|
|
3566
|
+
},
|
|
3541
3567
|
{
|
|
3542
3568
|
"name": "updateSpotMarketOracle",
|
|
3543
3569
|
"accounts": [
|
|
@@ -5357,12 +5383,21 @@
|
|
|
5357
5383
|
],
|
|
5358
5384
|
"type": "u64"
|
|
5359
5385
|
},
|
|
5386
|
+
{
|
|
5387
|
+
"name": "scaleInitialAssetWeightStart",
|
|
5388
|
+
"docs": [
|
|
5389
|
+
"When to begin scaling down the initial asset weight",
|
|
5390
|
+
"disabled when 0",
|
|
5391
|
+
"precision: QUOTE_PRECISION"
|
|
5392
|
+
],
|
|
5393
|
+
"type": "u64"
|
|
5394
|
+
},
|
|
5360
5395
|
{
|
|
5361
5396
|
"name": "padding",
|
|
5362
5397
|
"type": {
|
|
5363
5398
|
"array": [
|
|
5364
5399
|
"u8",
|
|
5365
|
-
|
|
5400
|
+
48
|
|
5366
5401
|
]
|
|
5367
5402
|
}
|
|
5368
5403
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import pyth from '@pythnetwork/client';
|
|
|
5
5
|
export * from './tokenFaucet';
|
|
6
6
|
export * from './oracles/types';
|
|
7
7
|
export * from './oracles/pythClient';
|
|
8
|
+
export * from './oracles/strictOraclePrice';
|
|
8
9
|
export * from './types';
|
|
9
10
|
export * from './constants/perpMarkets';
|
|
10
11
|
export * from './accounts/fetch';
|
|
@@ -49,6 +50,7 @@ export * from './math/repeg';
|
|
|
49
50
|
export * from './math/margin';
|
|
50
51
|
export * from './math/insurance';
|
|
51
52
|
export * from './math/superStake';
|
|
53
|
+
export * from './math/spotPosition';
|
|
52
54
|
export * from './marinade';
|
|
53
55
|
export * from './orderParams';
|
|
54
56
|
export * from './slot/SlotSubscriber';
|
package/src/math/spotBalance.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { OraclePriceData } from '../oracles/types';
|
|
23
23
|
import { PERCENTAGE_PRECISION } from '../constants/numericConstants';
|
|
24
24
|
import { divCeil } from './utils';
|
|
25
|
+
import { StrictOraclePrice } from '../oracles/strictOraclePrice';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Calculates the balance of a given token amount including any accumulated interest. This
|
|
@@ -102,25 +103,23 @@ export function getSignedTokenAmount(
|
|
|
102
103
|
*
|
|
103
104
|
* @param {BN} tokenAmount - The amount of tokens to calculate the value for (from `getTokenAmount`)
|
|
104
105
|
* @param {number} spotDecimals - The number of decimals in the token.
|
|
105
|
-
* @param {
|
|
106
|
-
* @param {BN} oraclePriceTwap - The Time-Weighted Average Price of the oracle.
|
|
106
|
+
* @param {StrictOraclePrice} strictOraclePrice - Contains oracle price and 5min twap.
|
|
107
107
|
* @return {BN} The calculated value of the given token amount, scaled by `PRICE_PRECISION`
|
|
108
108
|
*/
|
|
109
109
|
export function getStrictTokenValue(
|
|
110
110
|
tokenAmount: BN,
|
|
111
111
|
spotDecimals: number,
|
|
112
|
-
|
|
113
|
-
oraclePriceTwap: BN
|
|
112
|
+
strictOraclePrice: StrictOraclePrice
|
|
114
113
|
): BN {
|
|
115
114
|
if (tokenAmount.eq(ZERO)) {
|
|
116
115
|
return ZERO;
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
let price
|
|
120
|
-
if (tokenAmount.
|
|
121
|
-
price =
|
|
118
|
+
let price;
|
|
119
|
+
if (tokenAmount.gte(ZERO)) {
|
|
120
|
+
price = strictOraclePrice.min();
|
|
122
121
|
} else {
|
|
123
|
-
price =
|
|
122
|
+
price = strictOraclePrice.max();
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
const precisionDecrease = TEN.pow(new BN(spotDecimals));
|
|
@@ -139,7 +138,7 @@ export function getStrictTokenValue(
|
|
|
139
138
|
export function getTokenValue(
|
|
140
139
|
tokenAmount: BN,
|
|
141
140
|
spotDecimals: number,
|
|
142
|
-
oraclePriceData: OraclePriceData
|
|
141
|
+
oraclePriceData: Pick<OraclePriceData, 'price'>
|
|
143
142
|
): BN {
|
|
144
143
|
if (tokenAmount.eq(ZERO)) {
|
|
145
144
|
return ZERO;
|
|
@@ -152,6 +151,7 @@ export function getTokenValue(
|
|
|
152
151
|
|
|
153
152
|
export function calculateAssetWeight(
|
|
154
153
|
balanceAmount: BN,
|
|
154
|
+
oraclePrice: BN,
|
|
155
155
|
spotMarket: SpotMarketAccount,
|
|
156
156
|
marginCategory: MarginCategory
|
|
157
157
|
): BN {
|
|
@@ -174,7 +174,7 @@ export function calculateAssetWeight(
|
|
|
174
174
|
assetWeight = calculateSizeDiscountAssetWeight(
|
|
175
175
|
sizeInAmmReservePrecision,
|
|
176
176
|
new BN(spotMarket.imfFactor),
|
|
177
|
-
|
|
177
|
+
calculateScaledInitialAssetWeight(spotMarket, oraclePrice)
|
|
178
178
|
);
|
|
179
179
|
break;
|
|
180
180
|
case 'Maintenance':
|
|
@@ -185,13 +185,39 @@ export function calculateAssetWeight(
|
|
|
185
185
|
);
|
|
186
186
|
break;
|
|
187
187
|
default:
|
|
188
|
-
assetWeight =
|
|
188
|
+
assetWeight = calculateScaledInitialAssetWeight(spotMarket, oraclePrice);
|
|
189
189
|
break;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
return assetWeight;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
export function calculateScaledInitialAssetWeight(
|
|
196
|
+
spotMarket: SpotMarketAccount,
|
|
197
|
+
oraclePrice: BN
|
|
198
|
+
): BN {
|
|
199
|
+
if (spotMarket.scaleInitialAssetWeightStart.eq(ZERO)) {
|
|
200
|
+
return new BN(spotMarket.initialAssetWeight);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const deposits = getTokenAmount(
|
|
204
|
+
spotMarket.depositBalance,
|
|
205
|
+
spotMarket,
|
|
206
|
+
SpotBalanceType.DEPOSIT
|
|
207
|
+
);
|
|
208
|
+
const depositsValue = getTokenValue(deposits, spotMarket.decimals, {
|
|
209
|
+
price: oraclePrice,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (depositsValue.lt(spotMarket.scaleInitialAssetWeightStart)) {
|
|
213
|
+
return new BN(spotMarket.initialAssetWeight);
|
|
214
|
+
} else {
|
|
215
|
+
return new BN(spotMarket.initialAssetWeight)
|
|
216
|
+
.mul(spotMarket.scaleInitialAssetWeightStart)
|
|
217
|
+
.div(depositsValue);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
195
221
|
export function calculateLiabilityWeight(
|
|
196
222
|
size: BN,
|
|
197
223
|
spotMarket: SpotMarketAccount,
|
package/src/math/spotMarket.ts
CHANGED
|
@@ -21,12 +21,18 @@ export function castNumberToSpotPrecision(
|
|
|
21
21
|
|
|
22
22
|
export function calculateSpotMarketMarginRatio(
|
|
23
23
|
market: SpotMarketAccount,
|
|
24
|
+
oraclePrice: BN,
|
|
24
25
|
marginCategory: MarginCategory,
|
|
25
26
|
size: BN,
|
|
26
27
|
balanceType: SpotBalanceType
|
|
27
28
|
): number {
|
|
28
29
|
if (isVariant(balanceType, 'deposit')) {
|
|
29
|
-
const assetWeight = calculateAssetWeight(
|
|
30
|
+
const assetWeight = calculateAssetWeight(
|
|
31
|
+
size,
|
|
32
|
+
oraclePrice,
|
|
33
|
+
market,
|
|
34
|
+
marginCategory
|
|
35
|
+
);
|
|
30
36
|
return MARGIN_PRECISION.sub(assetWeight).toNumber();
|
|
31
37
|
} else {
|
|
32
38
|
const liabilityWeight = calculateLiabilityWeight(
|