@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/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(AMM_RESERVE_PRECISION);
483
+ .div(baseUnit);
440
484
  const deltaQaa = market.amm.quoteAssetAmountPerLp
441
485
  .sub(position.lastQuoteAssetAmountPerLp)
442
486
  .mul(nShares)
443
- .div(AMM_RESERVE_PRECISION);
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 - initial margin requirement
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('Initial', true);
600
- const initialMarginRequirement = this.getInitialMarginRequirement();
601
- const freeCollateral = totalCollateral.sub(initialMarginRequirement);
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(new BN(PRICE_PRECISION));
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
- const healthP1 =
1182
- Math.max(
1183
- 0,
1184
- (1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
1185
- 100
1186
- ) + 1;
1187
-
1188
- health = Math.min(1, Math.log(healthP1) / Math.log(100)) * 100;
1189
- if (health > 1) {
1190
- health = Math.round(health);
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
- * calculates sum of position value across all positions in margin system
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
- return this.getActivePerpPositions().reduce(
1210
- (totalPerpValue, perpPosition) => {
1211
- const market = this.driftClient.getPerpMarketAccount(
1212
- perpPosition.marketIndex
1213
- );
1250
+ const market = this.driftClient.getPerpMarketAccount(
1251
+ perpPosition.marketIndex
1252
+ );
1214
1253
 
1215
- if (perpPosition.lpShares.gt(ZERO)) {
1216
- // is an lp, clone so we dont mutate the position
1217
- perpPosition = this.getPerpPositionWithLPSettle(
1218
- market.marketIndex,
1219
- this.getClonedPosition(perpPosition),
1220
- !!marginCategory
1221
- )[0];
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
- let valuationPrice = this.getOracleDataForPerpMarket(
1225
- market.marketIndex
1226
- ).price;
1263
+ let valuationPrice = this.getOracleDataForPerpMarket(
1264
+ market.marketIndex
1265
+ ).price;
1227
1266
 
1228
- if (isVariant(market.status, 'settlement')) {
1229
- valuationPrice = market.expiryPrice;
1230
- }
1267
+ if (isVariant(market.status, 'settlement')) {
1268
+ valuationPrice = market.expiryPrice;
1269
+ }
1231
1270
 
1232
- const baseAssetAmount = includeOpenOrders
1233
- ? calculateWorstCaseBaseAssetAmount(perpPosition)
1234
- : perpPosition.baseAssetAmount;
1271
+ const baseAssetAmount = includeOpenOrders
1272
+ ? calculateWorstCaseBaseAssetAmount(perpPosition)
1273
+ : perpPosition.baseAssetAmount;
1235
1274
 
1236
- let baseAssetValue = baseAssetAmount
1237
- .abs()
1238
- .mul(valuationPrice)
1239
- .div(AMM_TO_QUOTE_PRECISION_RATIO.mul(PRICE_PRECISION));
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
- if (marginCategory === 'Initial') {
1251
- marginRatio = BN.max(
1252
- marginRatio,
1253
- new BN(this.getUserAccount().maxMarginRatio)
1254
- );
1255
- }
1280
+ if (marginCategory) {
1281
+ let marginRatio = new BN(
1282
+ calculateMarketMarginRatio(
1283
+ market,
1284
+ baseAssetAmount.abs(),
1285
+ marginCategory
1286
+ )
1287
+ );
1256
1288
 
1257
- if (liquidationBuffer !== undefined) {
1258
- marginRatio = marginRatio.add(liquidationBuffer);
1259
- }
1289
+ if (marginCategory === 'Initial') {
1290
+ marginRatio = BN.max(
1291
+ marginRatio,
1292
+ new BN(this.getUserAccount().maxMarginRatio)
1293
+ );
1294
+ }
1260
1295
 
1261
- if (isVariant(market.status, 'settlement')) {
1262
- marginRatio = ZERO;
1263
- }
1296
+ if (liquidationBuffer !== undefined) {
1297
+ marginRatio = marginRatio.add(liquidationBuffer);
1298
+ }
1264
1299
 
1265
- const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
1266
- market.quoteSpotMarketIndex
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
- baseAssetValue = baseAssetValue
1284
- .mul(quotePrice)
1285
- .div(PRICE_PRECISION)
1286
- .mul(marginRatio)
1287
- .div(MARGIN_PRECISION);
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
- if (includeOpenOrders) {
1290
- baseAssetValue = baseAssetValue.add(
1291
- new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1292
- );
1321
+ baseAssetValue = baseAssetValue
1322
+ .mul(quotePrice)
1323
+ .div(PRICE_PRECISION)
1324
+ .mul(marginRatio)
1325
+ .div(MARGIN_PRECISION);
1293
1326
 
1294
- if (perpPosition.lpShares.gt(ZERO)) {
1295
- baseAssetValue = baseAssetValue.add(
1296
- BN.max(
1297
- QUOTE_PRECISION,
1298
- valuationPrice
1299
- .mul(market.amm.orderStepSize)
1300
- .mul(QUOTE_PRECISION)
1301
- .div(AMM_RESERVE_PRECISION)
1302
- .div(PRICE_PRECISION)
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 amountWithdrawable = freeCollateral
2900
- .mul(MARGIN_PRECISION)
2901
- .div(new BN(spotMarket.initialAssetWeight))
2902
- .mul(PRICE_PRECISION)
2903
- .div(oracleData.price)
2904
- .mul(precisionIncrease);
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