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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/types.ts CHANGED
@@ -31,6 +31,7 @@ export class UserStatus {
31
31
  static readonly ACTIVE = { active: {} };
32
32
  static readonly BEING_LIQUIDATED = { beingLiquidated: {} };
33
33
  static readonly BANKRUPT = { bankrupt: {} };
34
+ static readonly REDUCE_ONLY = { reduceOnly: {} };
34
35
  }
35
36
 
36
37
  export class ContractType {
@@ -766,6 +767,8 @@ export type AMM = {
766
767
  bidQuoteAssetReserve: BN;
767
768
  askBaseAssetReserve: BN;
768
769
  askQuoteAssetReserve: BN;
770
+
771
+ perLpBase: number; // i8
769
772
  };
770
773
 
771
774
  // # User Account Types
@@ -784,6 +787,7 @@ export type PerpPosition = {
784
787
  remainderBaseAssetAmount: number;
785
788
  lastBaseAssetAmountPerLp: BN;
786
789
  lastQuoteAssetAmountPerLp: BN;
790
+ perLpBase: number;
787
791
  };
788
792
 
789
793
  export type UserStatsAccount = {
@@ -1099,3 +1103,18 @@ export type PerpMarketExtendedInfo = {
1099
1103
  pnlPoolValue: BN;
1100
1104
  contractTier: ContractTier;
1101
1105
  };
1106
+
1107
+ export type HealthComponents = {
1108
+ deposits: HealthComponent[];
1109
+ borrows: HealthComponent[];
1110
+ perpPositions: HealthComponent[];
1111
+ perpPnl: HealthComponent[];
1112
+ };
1113
+
1114
+ export type HealthComponent = {
1115
+ marketIndex: number;
1116
+ size: BN;
1117
+ value: BN;
1118
+ weight: BN;
1119
+ weightedValue: BN;
1120
+ };
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);
@@ -749,7 +793,7 @@ export class User {
749
793
 
750
794
  positionUnrealizedPnl = positionUnrealizedPnl
751
795
  .mul(quotePrice)
752
- .div(new BN(PRICE_PRECISION));
796
+ .div(PRICE_PRECISION);
753
797
 
754
798
  if (withWeightMarginCategory !== undefined) {
755
799
  if (positionUnrealizedPnl.gt(ZERO)) {
@@ -1196,116 +1240,157 @@ export class User {
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
+ }
1303
+
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
+ }
1282
1320
 
1283
- baseAssetValue = baseAssetValue
1284
- .mul(quotePrice)
1285
- .div(PRICE_PRECISION)
1286
- .mul(marginRatio)
1287
- .div(MARGIN_PRECISION);
1321
+ baseAssetValue = baseAssetValue
1322
+ .mul(quotePrice)
1323
+ .div(PRICE_PRECISION)
1324
+ .mul(marginRatio)
1325
+ .div(MARGIN_PRECISION);
1288
1326
 
1289
- if (includeOpenOrders) {
1290
- baseAssetValue = baseAssetValue.add(
1291
- new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1292
- );
1327
+ if (includeOpenOrders) {
1328
+ baseAssetValue = baseAssetValue.add(
1329
+ new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1330
+ );
1293
1331
 
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
- }
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
+ }
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
+ if (!perpPosition) {
1363
+ return ZERO;
1364
+ } else {
1365
+ return this.calculateWeightedPerpPositionValue(
1366
+ perpPosition,
1367
+ marginCategory,
1368
+ liquidationBuffer,
1369
+ includeOpenOrders,
1370
+ strict
1371
+ );
1372
+ }
1373
+ }
1308
1374
 
1375
+ /**
1376
+ * calculates sum of position value across all positions in margin system
1377
+ * @returns : Precision QUOTE_PRECISION
1378
+ */
1379
+ getTotalPerpPositionValue(
1380
+ marginCategory?: MarginCategory,
1381
+ liquidationBuffer?: BN,
1382
+ includeOpenOrders?: boolean,
1383
+ strict = false
1384
+ ): BN {
1385
+ return this.getActivePerpPositions().reduce(
1386
+ (totalPerpValue, perpPosition) => {
1387
+ const baseAssetValue = this.calculateWeightedPerpPositionValue(
1388
+ perpPosition,
1389
+ marginCategory,
1390
+ liquidationBuffer,
1391
+ includeOpenOrders,
1392
+ strict
1393
+ );
1309
1394
  return totalPerpValue.add(baseAssetValue);
1310
1395
  },
1311
1396
  ZERO
@@ -2896,12 +2981,20 @@ export class User {
2896
2981
  withdrawLimit = BN.max(withdrawLimit, userDepositAmount);
2897
2982
  }
2898
2983
 
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);
2984
+ const assetWeight = calculateAssetWeight(
2985
+ userDepositAmount,
2986
+ spotMarket,
2987
+ 'Initial'
2988
+ );
2989
+
2990
+ const amountWithdrawable = assetWeight.eq(ZERO)
2991
+ ? userDepositAmount
2992
+ : freeCollateral
2993
+ .mul(MARGIN_PRECISION)
2994
+ .div(assetWeight)
2995
+ .mul(PRICE_PRECISION)
2996
+ .div(oracleData.price)
2997
+ .mul(precisionIncrease);
2905
2998
 
2906
2999
  const maxWithdrawValue = BN.min(
2907
3000
  BN.min(amountWithdrawable, userDepositAmount),
@@ -3068,6 +3161,253 @@ export class User {
3068
3161
  };
3069
3162
  }
3070
3163
 
3164
+ public getHealthComponents({
3165
+ marginCategory,
3166
+ }: {
3167
+ marginCategory: MarginCategory;
3168
+ }): HealthComponents {
3169
+ const healthComponents: HealthComponents = {
3170
+ deposits: [],
3171
+ borrows: [],
3172
+ perpPositions: [],
3173
+ perpPnl: [],
3174
+ };
3175
+
3176
+ for (const perpPosition of this.getActivePerpPositions()) {
3177
+ const perpMarket = this.driftClient.getPerpMarketAccount(
3178
+ perpPosition.marketIndex
3179
+ );
3180
+ const oraclePriceData = this.driftClient.getOraclePriceDataAndSlot(
3181
+ perpMarket.amm.oracle
3182
+ ).data;
3183
+ const oraclePrice = oraclePriceData.price;
3184
+ const worstCaseBaseAmount =
3185
+ calculateWorstCaseBaseAssetAmount(perpPosition);
3186
+
3187
+ const marginRatio = new BN(
3188
+ calculateMarketMarginRatio(
3189
+ perpMarket,
3190
+ worstCaseBaseAmount.abs(),
3191
+ marginCategory
3192
+ )
3193
+ );
3194
+
3195
+ const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
3196
+ perpMarket.quoteSpotMarketIndex
3197
+ );
3198
+ const quoteOraclePriceData = this.driftClient.getOraclePriceDataAndSlot(
3199
+ quoteSpotMarket.oracle
3200
+ ).data;
3201
+
3202
+ const baseAssetValue = worstCaseBaseAmount
3203
+ .abs()
3204
+ .mul(oraclePrice)
3205
+ .div(BASE_PRECISION);
3206
+
3207
+ let marginRequirement = baseAssetValue
3208
+ .mul(quoteOraclePriceData.price)
3209
+ .div(PRICE_PRECISION)
3210
+ .mul(marginRatio)
3211
+ .div(MARGIN_PRECISION);
3212
+
3213
+ marginRequirement = marginRequirement.add(
3214
+ new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
3215
+ );
3216
+
3217
+ if (perpPosition.lpShares.gt(ZERO)) {
3218
+ marginRequirement = marginRequirement.add(
3219
+ BN.max(
3220
+ QUOTE_PRECISION,
3221
+ oraclePrice
3222
+ .mul(perpMarket.amm.orderStepSize)
3223
+ .mul(QUOTE_PRECISION)
3224
+ .div(AMM_RESERVE_PRECISION)
3225
+ .div(PRICE_PRECISION)
3226
+ )
3227
+ );
3228
+ }
3229
+
3230
+ healthComponents.perpPositions.push({
3231
+ marketIndex: perpMarket.marketIndex,
3232
+ size: worstCaseBaseAmount,
3233
+ value: baseAssetValue,
3234
+ weight: marginRatio,
3235
+ weightedValue: marginRequirement,
3236
+ });
3237
+
3238
+ const settledPerpPosition = this.getPerpPositionWithLPSettle(
3239
+ perpPosition.marketIndex,
3240
+ perpPosition
3241
+ )[0];
3242
+
3243
+ const positionUnrealizedPnl = calculatePositionPNL(
3244
+ perpMarket,
3245
+ settledPerpPosition,
3246
+ true,
3247
+ oraclePriceData
3248
+ );
3249
+
3250
+ let pnlWeight;
3251
+ if (positionUnrealizedPnl.gt(ZERO)) {
3252
+ pnlWeight = calculateUnrealizedAssetWeight(
3253
+ perpMarket,
3254
+ quoteSpotMarket,
3255
+ positionUnrealizedPnl,
3256
+ marginCategory,
3257
+ oraclePriceData
3258
+ );
3259
+ } else {
3260
+ pnlWeight = SPOT_MARKET_WEIGHT_PRECISION;
3261
+ }
3262
+
3263
+ const pnlValue = positionUnrealizedPnl
3264
+ .mul(quoteOraclePriceData.price)
3265
+ .div(PRICE_PRECISION);
3266
+
3267
+ const wegithedPnlValue = pnlValue
3268
+ .mul(pnlWeight)
3269
+ .div(SPOT_MARKET_WEIGHT_PRECISION);
3270
+
3271
+ healthComponents.perpPnl.push({
3272
+ marketIndex: perpMarket.marketIndex,
3273
+ size: positionUnrealizedPnl,
3274
+ value: pnlValue,
3275
+ weight: pnlWeight,
3276
+ weightedValue: wegithedPnlValue,
3277
+ });
3278
+ }
3279
+
3280
+ let netQuoteValue = ZERO;
3281
+ for (const spotPosition of this.getActiveSpotPositions()) {
3282
+ const spotMarketAccount: SpotMarketAccount =
3283
+ this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
3284
+
3285
+ const oraclePriceData = this.getOracleDataForSpotMarket(
3286
+ spotPosition.marketIndex
3287
+ );
3288
+
3289
+ if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
3290
+ const tokenAmount = getSignedTokenAmount(
3291
+ getTokenAmount(
3292
+ spotPosition.scaledBalance,
3293
+ spotMarketAccount,
3294
+ spotPosition.balanceType
3295
+ ),
3296
+ spotPosition.balanceType
3297
+ );
3298
+
3299
+ netQuoteValue = netQuoteValue.add(tokenAmount);
3300
+ continue;
3301
+ }
3302
+
3303
+ const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
3304
+ getWorstCaseTokenAmounts(
3305
+ spotPosition,
3306
+ spotMarketAccount,
3307
+ oraclePriceData
3308
+ );
3309
+
3310
+ netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
3311
+
3312
+ const baseAssetValue = getTokenValue(
3313
+ worstCaseTokenAmount.abs(),
3314
+ spotMarketAccount.decimals,
3315
+ oraclePriceData
3316
+ );
3317
+ const isLiability = isVariant(spotPosition.balanceType, 'borrow');
3318
+
3319
+ let weight;
3320
+ if (isLiability) {
3321
+ weight = calculateLiabilityWeight(
3322
+ worstCaseTokenAmount.abs(),
3323
+ spotMarketAccount,
3324
+ marginCategory
3325
+ );
3326
+ } else {
3327
+ weight = calculateAssetWeight(
3328
+ worstCaseTokenAmount,
3329
+ spotMarketAccount,
3330
+ marginCategory
3331
+ );
3332
+ }
3333
+
3334
+ const weightedValue = baseAssetValue
3335
+ .mul(weight)
3336
+ .div(SPOT_MARKET_WEIGHT_PRECISION);
3337
+
3338
+ if (isLiability) {
3339
+ healthComponents.borrows.push({
3340
+ marketIndex: spotMarketAccount.marketIndex,
3341
+ size: worstCaseTokenAmount,
3342
+ value: baseAssetValue,
3343
+ weight: weight,
3344
+ weightedValue: weightedValue,
3345
+ });
3346
+ } else {
3347
+ healthComponents.deposits.push({
3348
+ marketIndex: spotMarketAccount.marketIndex,
3349
+ size: worstCaseTokenAmount,
3350
+ value: baseAssetValue,
3351
+ weight: weight,
3352
+ weightedValue: weightedValue,
3353
+ });
3354
+ }
3355
+ }
3356
+
3357
+ if (!netQuoteValue.eq(ZERO)) {
3358
+ const spotMarketAccount = this.driftClient.getQuoteSpotMarketAccount();
3359
+ const oraclePriceData = this.getOracleDataForSpotMarket(
3360
+ QUOTE_SPOT_MARKET_INDEX
3361
+ );
3362
+
3363
+ const baseAssetValue = getTokenValue(
3364
+ netQuoteValue.abs(),
3365
+ spotMarketAccount.decimals,
3366
+ oraclePriceData
3367
+ );
3368
+ const isLiability = netQuoteValue.lt(ZERO);
3369
+
3370
+ let weight;
3371
+ if (isLiability) {
3372
+ weight = calculateLiabilityWeight(
3373
+ netQuoteValue.abs(),
3374
+ spotMarketAccount,
3375
+ marginCategory
3376
+ );
3377
+ } else {
3378
+ weight = calculateAssetWeight(
3379
+ netQuoteValue,
3380
+ spotMarketAccount,
3381
+ marginCategory
3382
+ );
3383
+ }
3384
+
3385
+ const weightedValue = baseAssetValue
3386
+ .mul(weight)
3387
+ .div(SPOT_MARKET_WEIGHT_PRECISION);
3388
+
3389
+ if (isLiability) {
3390
+ healthComponents.borrows.push({
3391
+ marketIndex: spotMarketAccount.marketIndex,
3392
+ size: netQuoteValue,
3393
+ value: baseAssetValue,
3394
+ weight: weight,
3395
+ weightedValue: weightedValue,
3396
+ });
3397
+ } else {
3398
+ healthComponents.deposits.push({
3399
+ marketIndex: spotMarketAccount.marketIndex,
3400
+ size: netQuoteValue,
3401
+ value: baseAssetValue,
3402
+ weight: weight,
3403
+ weightedValue: weightedValue,
3404
+ });
3405
+ }
3406
+ }
3407
+
3408
+ return healthComponents;
3409
+ }
3410
+
3071
3411
  /**
3072
3412
  * Get the total position value, excluding any position coming from the given target market
3073
3413
  * @param marketToIgnore