@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/src/user.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
SpotPosition,
|
|
12
12
|
isOneOfVariant,
|
|
13
13
|
PerpMarketAccount,
|
|
14
|
+
HealthComponents,
|
|
14
15
|
} from './types';
|
|
15
16
|
import { calculateEntryPrice, positionIsAvailable } from './math/position';
|
|
16
17
|
import {
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
BASE_PRECISION,
|
|
31
32
|
ONE,
|
|
32
33
|
TWO,
|
|
34
|
+
AMM_RESERVE_PRECISION_EXP,
|
|
33
35
|
} from './constants/numericConstants';
|
|
34
36
|
import {
|
|
35
37
|
UserAccountSubscriber,
|
|
@@ -263,6 +265,7 @@ export class User {
|
|
|
263
265
|
lpShares: ZERO,
|
|
264
266
|
lastBaseAssetAmountPerLp: ZERO,
|
|
265
267
|
lastQuoteAssetAmountPerLp: ZERO,
|
|
268
|
+
perLpBase: 0,
|
|
266
269
|
};
|
|
267
270
|
}
|
|
268
271
|
|
|
@@ -426,21 +429,62 @@ export class User {
|
|
|
426
429
|
}
|
|
427
430
|
|
|
428
431
|
const position = this.getClonedPosition(originalPosition);
|
|
429
|
-
|
|
430
432
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
433
|
+
|
|
434
|
+
if (market.amm.perLpBase != position.perLpBase) {
|
|
435
|
+
// perLpBase = 1 => per 10 LP shares, perLpBase = -1 => per 0.1 LP shares
|
|
436
|
+
const expoDiff = market.amm.perLpBase - position.perLpBase;
|
|
437
|
+
const marketPerLpRebaseScalar = new BN(10 ** Math.abs(expoDiff));
|
|
438
|
+
|
|
439
|
+
if (expoDiff > 0) {
|
|
440
|
+
position.lastBaseAssetAmountPerLp =
|
|
441
|
+
position.lastBaseAssetAmountPerLp.mul(marketPerLpRebaseScalar);
|
|
442
|
+
position.lastQuoteAssetAmountPerLp =
|
|
443
|
+
position.lastQuoteAssetAmountPerLp.mul(marketPerLpRebaseScalar);
|
|
444
|
+
} else {
|
|
445
|
+
position.lastBaseAssetAmountPerLp =
|
|
446
|
+
position.lastBaseAssetAmountPerLp.div(marketPerLpRebaseScalar);
|
|
447
|
+
position.lastQuoteAssetAmountPerLp =
|
|
448
|
+
position.lastQuoteAssetAmountPerLp.div(marketPerLpRebaseScalar);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
position.perLpBase = position.perLpBase + expoDiff;
|
|
452
|
+
}
|
|
453
|
+
|
|
431
454
|
const nShares = position.lpShares;
|
|
432
455
|
|
|
433
456
|
// incorp unsettled funding on pre settled position
|
|
434
457
|
const quoteFundingPnl = calculatePositionFundingPNL(market, position);
|
|
435
458
|
|
|
459
|
+
let baseUnit = AMM_RESERVE_PRECISION;
|
|
460
|
+
if (market.amm.perLpBase == position.perLpBase) {
|
|
461
|
+
if (
|
|
462
|
+
position.perLpBase >= 0 &&
|
|
463
|
+
position.perLpBase <= AMM_RESERVE_PRECISION_EXP.toNumber()
|
|
464
|
+
) {
|
|
465
|
+
const marketPerLpRebase = new BN(10 ** market.amm.perLpBase);
|
|
466
|
+
baseUnit = baseUnit.mul(marketPerLpRebase);
|
|
467
|
+
} else if (
|
|
468
|
+
position.perLpBase < 0 &&
|
|
469
|
+
position.perLpBase >= -AMM_RESERVE_PRECISION_EXP.toNumber()
|
|
470
|
+
) {
|
|
471
|
+
const marketPerLpRebase = new BN(10 ** Math.abs(market.amm.perLpBase));
|
|
472
|
+
baseUnit = baseUnit.div(marketPerLpRebase);
|
|
473
|
+
} else {
|
|
474
|
+
throw 'cannot calc';
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
throw 'market.amm.perLpBase != position.perLpBase';
|
|
478
|
+
}
|
|
479
|
+
|
|
436
480
|
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
437
481
|
.sub(position.lastBaseAssetAmountPerLp)
|
|
438
482
|
.mul(nShares)
|
|
439
|
-
.div(
|
|
483
|
+
.div(baseUnit);
|
|
440
484
|
const deltaQaa = market.amm.quoteAssetAmountPerLp
|
|
441
485
|
.sub(position.lastQuoteAssetAmountPerLp)
|
|
442
486
|
.mul(nShares)
|
|
443
|
-
.div(
|
|
487
|
+
.div(baseUnit);
|
|
444
488
|
|
|
445
489
|
function sign(v: BN) {
|
|
446
490
|
return v.isNeg() ? new BN(-1) : new BN(1);
|
|
@@ -592,13 +636,16 @@ export class User {
|
|
|
592
636
|
}
|
|
593
637
|
|
|
594
638
|
/**
|
|
595
|
-
* calculates Free Collateral = Total collateral -
|
|
639
|
+
* calculates Free Collateral = Total collateral - margin requirement
|
|
596
640
|
* @returns : Precision QUOTE_PRECISION
|
|
597
641
|
*/
|
|
598
|
-
public getFreeCollateral(): BN {
|
|
599
|
-
const totalCollateral = this.getTotalCollateral(
|
|
600
|
-
const
|
|
601
|
-
|
|
642
|
+
public getFreeCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
643
|
+
const totalCollateral = this.getTotalCollateral(marginCategory, true);
|
|
644
|
+
const marginRequirement =
|
|
645
|
+
marginCategory === 'Initial'
|
|
646
|
+
? this.getInitialMarginRequirement()
|
|
647
|
+
: this.getMaintenanceMarginRequirement();
|
|
648
|
+
const freeCollateral = totalCollateral.sub(marginRequirement);
|
|
602
649
|
return freeCollateral.gte(ZERO) ? freeCollateral : ZERO;
|
|
603
650
|
}
|
|
604
651
|
|
|
@@ -749,7 +796,7 @@ export class User {
|
|
|
749
796
|
|
|
750
797
|
positionUnrealizedPnl = positionUnrealizedPnl
|
|
751
798
|
.mul(quotePrice)
|
|
752
|
-
.div(
|
|
799
|
+
.div(PRICE_PRECISION);
|
|
753
800
|
|
|
754
801
|
if (withWeightMarginCategory !== undefined) {
|
|
755
802
|
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
@@ -1178,134 +1225,168 @@ export class User {
|
|
|
1178
1225
|
} else if (totalCollateral.lte(ZERO)) {
|
|
1179
1226
|
health = 0;
|
|
1180
1227
|
} else {
|
|
1181
|
-
|
|
1182
|
-
Math.
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
} else {
|
|
1192
|
-
health = Math.round(health * 100) / 100;
|
|
1193
|
-
}
|
|
1228
|
+
health = Math.round(
|
|
1229
|
+
Math.min(
|
|
1230
|
+
100,
|
|
1231
|
+
Math.max(
|
|
1232
|
+
0,
|
|
1233
|
+
(1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
|
|
1234
|
+
100
|
|
1235
|
+
)
|
|
1236
|
+
)
|
|
1237
|
+
);
|
|
1194
1238
|
}
|
|
1195
1239
|
|
|
1196
1240
|
return health;
|
|
1197
1241
|
}
|
|
1198
1242
|
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
* @returns : Precision QUOTE_PRECISION
|
|
1202
|
-
*/
|
|
1203
|
-
getTotalPerpPositionValue(
|
|
1243
|
+
calculateWeightedPerpPositionValue(
|
|
1244
|
+
perpPosition: PerpPosition,
|
|
1204
1245
|
marginCategory?: MarginCategory,
|
|
1205
1246
|
liquidationBuffer?: BN,
|
|
1206
1247
|
includeOpenOrders?: boolean,
|
|
1207
1248
|
strict = false
|
|
1208
1249
|
): BN {
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
perpPosition.marketIndex
|
|
1213
|
-
);
|
|
1250
|
+
const market = this.driftClient.getPerpMarketAccount(
|
|
1251
|
+
perpPosition.marketIndex
|
|
1252
|
+
);
|
|
1214
1253
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1254
|
+
if (perpPosition.lpShares.gt(ZERO)) {
|
|
1255
|
+
// is an lp, clone so we dont mutate the position
|
|
1256
|
+
perpPosition = this.getPerpPositionWithLPSettle(
|
|
1257
|
+
market.marketIndex,
|
|
1258
|
+
this.getClonedPosition(perpPosition),
|
|
1259
|
+
!!marginCategory
|
|
1260
|
+
)[0];
|
|
1261
|
+
}
|
|
1223
1262
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1263
|
+
let valuationPrice = this.getOracleDataForPerpMarket(
|
|
1264
|
+
market.marketIndex
|
|
1265
|
+
).price;
|
|
1227
1266
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1267
|
+
if (isVariant(market.status, 'settlement')) {
|
|
1268
|
+
valuationPrice = market.expiryPrice;
|
|
1269
|
+
}
|
|
1231
1270
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1271
|
+
const baseAssetAmount = includeOpenOrders
|
|
1272
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
1273
|
+
: perpPosition.baseAssetAmount;
|
|
1235
1274
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
if (marginCategory) {
|
|
1242
|
-
let marginRatio = new BN(
|
|
1243
|
-
calculateMarketMarginRatio(
|
|
1244
|
-
market,
|
|
1245
|
-
baseAssetAmount.abs(),
|
|
1246
|
-
marginCategory
|
|
1247
|
-
)
|
|
1248
|
-
);
|
|
1275
|
+
let baseAssetValue = baseAssetAmount
|
|
1276
|
+
.abs()
|
|
1277
|
+
.mul(valuationPrice)
|
|
1278
|
+
.div(BASE_PRECISION);
|
|
1249
1279
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1280
|
+
if (marginCategory) {
|
|
1281
|
+
let marginRatio = new BN(
|
|
1282
|
+
calculateMarketMarginRatio(
|
|
1283
|
+
market,
|
|
1284
|
+
baseAssetAmount.abs(),
|
|
1285
|
+
marginCategory
|
|
1286
|
+
)
|
|
1287
|
+
);
|
|
1256
1288
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1289
|
+
if (marginCategory === 'Initial') {
|
|
1290
|
+
marginRatio = BN.max(
|
|
1291
|
+
marginRatio,
|
|
1292
|
+
new BN(this.getUserAccount().maxMarginRatio)
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1260
1295
|
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1296
|
+
if (liquidationBuffer !== undefined) {
|
|
1297
|
+
marginRatio = marginRatio.add(liquidationBuffer);
|
|
1298
|
+
}
|
|
1264
1299
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
const quoteOraclePriceData =
|
|
1269
|
-
this.driftClient.getOraclePriceDataAndSlot(
|
|
1270
|
-
quoteSpotMarket.oracle
|
|
1271
|
-
).data;
|
|
1272
|
-
|
|
1273
|
-
let quotePrice;
|
|
1274
|
-
if (strict) {
|
|
1275
|
-
quotePrice = BN.max(
|
|
1276
|
-
quoteOraclePriceData.price,
|
|
1277
|
-
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
1278
|
-
);
|
|
1279
|
-
} else {
|
|
1280
|
-
quotePrice = quoteOraclePriceData.price;
|
|
1281
|
-
}
|
|
1300
|
+
if (isVariant(market.status, 'settlement')) {
|
|
1301
|
+
marginRatio = ZERO;
|
|
1302
|
+
}
|
|
1282
1303
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1304
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
1305
|
+
market.quoteSpotMarketIndex
|
|
1306
|
+
);
|
|
1307
|
+
const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(
|
|
1308
|
+
quoteSpotMarket.oracle
|
|
1309
|
+
).data;
|
|
1310
|
+
|
|
1311
|
+
let quotePrice;
|
|
1312
|
+
if (strict) {
|
|
1313
|
+
quotePrice = BN.max(
|
|
1314
|
+
quoteOraclePriceData.price,
|
|
1315
|
+
quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
1316
|
+
);
|
|
1317
|
+
} else {
|
|
1318
|
+
quotePrice = quoteOraclePriceData.price;
|
|
1319
|
+
}
|
|
1288
1320
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1321
|
+
baseAssetValue = baseAssetValue
|
|
1322
|
+
.mul(quotePrice)
|
|
1323
|
+
.div(PRICE_PRECISION)
|
|
1324
|
+
.mul(marginRatio)
|
|
1325
|
+
.div(MARGIN_PRECISION);
|
|
1293
1326
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1327
|
+
if (includeOpenOrders) {
|
|
1328
|
+
baseAssetValue = baseAssetValue.add(
|
|
1329
|
+
new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
1330
|
+
);
|
|
1331
|
+
|
|
1332
|
+
if (perpPosition.lpShares.gt(ZERO)) {
|
|
1333
|
+
baseAssetValue = baseAssetValue.add(
|
|
1334
|
+
BN.max(
|
|
1335
|
+
QUOTE_PRECISION,
|
|
1336
|
+
valuationPrice
|
|
1337
|
+
.mul(market.amm.orderStepSize)
|
|
1338
|
+
.mul(QUOTE_PRECISION)
|
|
1339
|
+
.div(AMM_RESERVE_PRECISION)
|
|
1340
|
+
.div(PRICE_PRECISION)
|
|
1341
|
+
)
|
|
1342
|
+
);
|
|
1307
1343
|
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1308
1346
|
|
|
1347
|
+
return baseAssetValue;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
/**
|
|
1351
|
+
* calculates position value of a single perp market in margin system
|
|
1352
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1353
|
+
*/
|
|
1354
|
+
public getPerpMarketLiabilityValue(
|
|
1355
|
+
marketIndex: number,
|
|
1356
|
+
marginCategory?: MarginCategory,
|
|
1357
|
+
liquidationBuffer?: BN,
|
|
1358
|
+
includeOpenOrders?: boolean,
|
|
1359
|
+
strict = false
|
|
1360
|
+
): BN {
|
|
1361
|
+
const perpPosition = this.getPerpPosition(marketIndex);
|
|
1362
|
+
return this.calculateWeightedPerpPositionValue(
|
|
1363
|
+
perpPosition,
|
|
1364
|
+
marginCategory,
|
|
1365
|
+
liquidationBuffer,
|
|
1366
|
+
includeOpenOrders,
|
|
1367
|
+
strict
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/**
|
|
1372
|
+
* calculates sum of position value across all positions in margin system
|
|
1373
|
+
* @returns : Precision QUOTE_PRECISION
|
|
1374
|
+
*/
|
|
1375
|
+
getTotalPerpPositionValue(
|
|
1376
|
+
marginCategory?: MarginCategory,
|
|
1377
|
+
liquidationBuffer?: BN,
|
|
1378
|
+
includeOpenOrders?: boolean,
|
|
1379
|
+
strict = false
|
|
1380
|
+
): BN {
|
|
1381
|
+
return this.getActivePerpPositions().reduce(
|
|
1382
|
+
(totalPerpValue, perpPosition) => {
|
|
1383
|
+
const baseAssetValue = this.calculateWeightedPerpPositionValue(
|
|
1384
|
+
perpPosition,
|
|
1385
|
+
marginCategory,
|
|
1386
|
+
liquidationBuffer,
|
|
1387
|
+
includeOpenOrders,
|
|
1388
|
+
strict
|
|
1389
|
+
);
|
|
1309
1390
|
return totalPerpValue.add(baseAssetValue);
|
|
1310
1391
|
},
|
|
1311
1392
|
ZERO
|
|
@@ -2896,12 +2977,20 @@ export class User {
|
|
|
2896
2977
|
withdrawLimit = BN.max(withdrawLimit, userDepositAmount);
|
|
2897
2978
|
}
|
|
2898
2979
|
|
|
2899
|
-
const
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2980
|
+
const assetWeight = calculateAssetWeight(
|
|
2981
|
+
userDepositAmount,
|
|
2982
|
+
spotMarket,
|
|
2983
|
+
'Initial'
|
|
2984
|
+
);
|
|
2985
|
+
|
|
2986
|
+
const amountWithdrawable = assetWeight.eq(ZERO)
|
|
2987
|
+
? userDepositAmount
|
|
2988
|
+
: freeCollateral
|
|
2989
|
+
.mul(MARGIN_PRECISION)
|
|
2990
|
+
.div(assetWeight)
|
|
2991
|
+
.mul(PRICE_PRECISION)
|
|
2992
|
+
.div(oracleData.price)
|
|
2993
|
+
.mul(precisionIncrease);
|
|
2905
2994
|
|
|
2906
2995
|
const maxWithdrawValue = BN.min(
|
|
2907
2996
|
BN.min(amountWithdrawable, userDepositAmount),
|
|
@@ -3068,6 +3157,253 @@ export class User {
|
|
|
3068
3157
|
};
|
|
3069
3158
|
}
|
|
3070
3159
|
|
|
3160
|
+
public getHealthComponents({
|
|
3161
|
+
marginCategory,
|
|
3162
|
+
}: {
|
|
3163
|
+
marginCategory: MarginCategory;
|
|
3164
|
+
}): HealthComponents {
|
|
3165
|
+
const healthComponents: HealthComponents = {
|
|
3166
|
+
deposits: [],
|
|
3167
|
+
borrows: [],
|
|
3168
|
+
perpPositions: [],
|
|
3169
|
+
perpPnl: [],
|
|
3170
|
+
};
|
|
3171
|
+
|
|
3172
|
+
for (const perpPosition of this.getActivePerpPositions()) {
|
|
3173
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(
|
|
3174
|
+
perpPosition.marketIndex
|
|
3175
|
+
);
|
|
3176
|
+
const oraclePriceData = this.driftClient.getOraclePriceDataAndSlot(
|
|
3177
|
+
perpMarket.amm.oracle
|
|
3178
|
+
).data;
|
|
3179
|
+
const oraclePrice = oraclePriceData.price;
|
|
3180
|
+
const worstCaseBaseAmount =
|
|
3181
|
+
calculateWorstCaseBaseAssetAmount(perpPosition);
|
|
3182
|
+
|
|
3183
|
+
const marginRatio = new BN(
|
|
3184
|
+
calculateMarketMarginRatio(
|
|
3185
|
+
perpMarket,
|
|
3186
|
+
worstCaseBaseAmount.abs(),
|
|
3187
|
+
marginCategory
|
|
3188
|
+
)
|
|
3189
|
+
);
|
|
3190
|
+
|
|
3191
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
3192
|
+
perpMarket.quoteSpotMarketIndex
|
|
3193
|
+
);
|
|
3194
|
+
const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(
|
|
3195
|
+
quoteSpotMarket.oracle
|
|
3196
|
+
).data;
|
|
3197
|
+
|
|
3198
|
+
const baseAssetValue = worstCaseBaseAmount
|
|
3199
|
+
.abs()
|
|
3200
|
+
.mul(oraclePrice)
|
|
3201
|
+
.div(BASE_PRECISION);
|
|
3202
|
+
|
|
3203
|
+
let marginRequirement = baseAssetValue
|
|
3204
|
+
.mul(quoteOraclePriceData.price)
|
|
3205
|
+
.div(PRICE_PRECISION)
|
|
3206
|
+
.mul(marginRatio)
|
|
3207
|
+
.div(MARGIN_PRECISION);
|
|
3208
|
+
|
|
3209
|
+
marginRequirement = marginRequirement.add(
|
|
3210
|
+
new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
3211
|
+
);
|
|
3212
|
+
|
|
3213
|
+
if (perpPosition.lpShares.gt(ZERO)) {
|
|
3214
|
+
marginRequirement = marginRequirement.add(
|
|
3215
|
+
BN.max(
|
|
3216
|
+
QUOTE_PRECISION,
|
|
3217
|
+
oraclePrice
|
|
3218
|
+
.mul(perpMarket.amm.orderStepSize)
|
|
3219
|
+
.mul(QUOTE_PRECISION)
|
|
3220
|
+
.div(AMM_RESERVE_PRECISION)
|
|
3221
|
+
.div(PRICE_PRECISION)
|
|
3222
|
+
)
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
healthComponents.perpPositions.push({
|
|
3227
|
+
marketIndex: perpMarket.marketIndex,
|
|
3228
|
+
size: worstCaseBaseAmount,
|
|
3229
|
+
value: baseAssetValue,
|
|
3230
|
+
weight: marginRatio,
|
|
3231
|
+
weightedValue: marginRequirement,
|
|
3232
|
+
});
|
|
3233
|
+
|
|
3234
|
+
const settledPerpPosition = this.getPerpPositionWithLPSettle(
|
|
3235
|
+
perpPosition.marketIndex,
|
|
3236
|
+
perpPosition
|
|
3237
|
+
)[0];
|
|
3238
|
+
|
|
3239
|
+
const positionUnrealizedPnl = calculatePositionPNL(
|
|
3240
|
+
perpMarket,
|
|
3241
|
+
settledPerpPosition,
|
|
3242
|
+
true,
|
|
3243
|
+
oraclePriceData
|
|
3244
|
+
);
|
|
3245
|
+
|
|
3246
|
+
let pnlWeight;
|
|
3247
|
+
if (positionUnrealizedPnl.gt(ZERO)) {
|
|
3248
|
+
pnlWeight = calculateUnrealizedAssetWeight(
|
|
3249
|
+
perpMarket,
|
|
3250
|
+
quoteSpotMarket,
|
|
3251
|
+
positionUnrealizedPnl,
|
|
3252
|
+
marginCategory,
|
|
3253
|
+
oraclePriceData
|
|
3254
|
+
);
|
|
3255
|
+
} else {
|
|
3256
|
+
pnlWeight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
const pnlValue = positionUnrealizedPnl
|
|
3260
|
+
.mul(quoteOraclePriceData.price)
|
|
3261
|
+
.div(PRICE_PRECISION);
|
|
3262
|
+
|
|
3263
|
+
const wegithedPnlValue = pnlValue
|
|
3264
|
+
.mul(pnlWeight)
|
|
3265
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
3266
|
+
|
|
3267
|
+
healthComponents.perpPnl.push({
|
|
3268
|
+
marketIndex: perpMarket.marketIndex,
|
|
3269
|
+
size: positionUnrealizedPnl,
|
|
3270
|
+
value: pnlValue,
|
|
3271
|
+
weight: pnlWeight,
|
|
3272
|
+
weightedValue: wegithedPnlValue,
|
|
3273
|
+
});
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
let netQuoteValue = ZERO;
|
|
3277
|
+
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
3278
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
3279
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
3280
|
+
|
|
3281
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
3282
|
+
spotPosition.marketIndex
|
|
3283
|
+
);
|
|
3284
|
+
|
|
3285
|
+
if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
3286
|
+
const tokenAmount = getSignedTokenAmount(
|
|
3287
|
+
getTokenAmount(
|
|
3288
|
+
spotPosition.scaledBalance,
|
|
3289
|
+
spotMarketAccount,
|
|
3290
|
+
spotPosition.balanceType
|
|
3291
|
+
),
|
|
3292
|
+
spotPosition.balanceType
|
|
3293
|
+
);
|
|
3294
|
+
|
|
3295
|
+
netQuoteValue = netQuoteValue.add(tokenAmount);
|
|
3296
|
+
continue;
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
3300
|
+
getWorstCaseTokenAmounts(
|
|
3301
|
+
spotPosition,
|
|
3302
|
+
spotMarketAccount,
|
|
3303
|
+
oraclePriceData
|
|
3304
|
+
);
|
|
3305
|
+
|
|
3306
|
+
netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
|
|
3307
|
+
|
|
3308
|
+
const baseAssetValue = getTokenValue(
|
|
3309
|
+
worstCaseTokenAmount.abs(),
|
|
3310
|
+
spotMarketAccount.decimals,
|
|
3311
|
+
oraclePriceData
|
|
3312
|
+
);
|
|
3313
|
+
const isLiability = isVariant(spotPosition.balanceType, 'borrow');
|
|
3314
|
+
|
|
3315
|
+
let weight;
|
|
3316
|
+
if (isLiability) {
|
|
3317
|
+
weight = calculateLiabilityWeight(
|
|
3318
|
+
worstCaseTokenAmount.abs(),
|
|
3319
|
+
spotMarketAccount,
|
|
3320
|
+
marginCategory
|
|
3321
|
+
);
|
|
3322
|
+
} else {
|
|
3323
|
+
weight = calculateAssetWeight(
|
|
3324
|
+
worstCaseTokenAmount,
|
|
3325
|
+
spotMarketAccount,
|
|
3326
|
+
marginCategory
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
|
|
3330
|
+
const weightedValue = baseAssetValue
|
|
3331
|
+
.mul(weight)
|
|
3332
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
3333
|
+
|
|
3334
|
+
if (isLiability) {
|
|
3335
|
+
healthComponents.borrows.push({
|
|
3336
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
3337
|
+
size: worstCaseTokenAmount,
|
|
3338
|
+
value: baseAssetValue,
|
|
3339
|
+
weight: weight,
|
|
3340
|
+
weightedValue: weightedValue,
|
|
3341
|
+
});
|
|
3342
|
+
} else {
|
|
3343
|
+
healthComponents.deposits.push({
|
|
3344
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
3345
|
+
size: worstCaseTokenAmount,
|
|
3346
|
+
value: baseAssetValue,
|
|
3347
|
+
weight: weight,
|
|
3348
|
+
weightedValue: weightedValue,
|
|
3349
|
+
});
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
if (!netQuoteValue.eq(ZERO)) {
|
|
3354
|
+
const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
|
|
3355
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
3356
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
3357
|
+
);
|
|
3358
|
+
|
|
3359
|
+
const baseAssetValue = getTokenValue(
|
|
3360
|
+
netQuoteValue.abs(),
|
|
3361
|
+
spotMarketAccount.decimals,
|
|
3362
|
+
oraclePriceData
|
|
3363
|
+
);
|
|
3364
|
+
const isLiability = netQuoteValue.lt(ZERO);
|
|
3365
|
+
|
|
3366
|
+
let weight;
|
|
3367
|
+
if (isLiability) {
|
|
3368
|
+
weight = calculateLiabilityWeight(
|
|
3369
|
+
netQuoteValue.abs(),
|
|
3370
|
+
spotMarketAccount,
|
|
3371
|
+
marginCategory
|
|
3372
|
+
);
|
|
3373
|
+
} else {
|
|
3374
|
+
weight = calculateAssetWeight(
|
|
3375
|
+
netQuoteValue,
|
|
3376
|
+
spotMarketAccount,
|
|
3377
|
+
marginCategory
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
3380
|
+
|
|
3381
|
+
const weightedValue = baseAssetValue
|
|
3382
|
+
.mul(weight)
|
|
3383
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
3384
|
+
|
|
3385
|
+
if (isLiability) {
|
|
3386
|
+
healthComponents.borrows.push({
|
|
3387
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
3388
|
+
size: netQuoteValue,
|
|
3389
|
+
value: baseAssetValue,
|
|
3390
|
+
weight: weight,
|
|
3391
|
+
weightedValue: weightedValue,
|
|
3392
|
+
});
|
|
3393
|
+
} else {
|
|
3394
|
+
healthComponents.deposits.push({
|
|
3395
|
+
marketIndex: spotMarketAccount.marketIndex,
|
|
3396
|
+
size: netQuoteValue,
|
|
3397
|
+
value: baseAssetValue,
|
|
3398
|
+
weight: weight,
|
|
3399
|
+
weightedValue: weightedValue,
|
|
3400
|
+
});
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
return healthComponents;
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3071
3407
|
/**
|
|
3072
3408
|
* Get the total position value, excluding any position coming from the given target market
|
|
3073
3409
|
* @param marketToIgnore
|