@drift-labs/sdk-browser 2.137.0-beta.0 → 2.137.0-beta.2

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.
Files changed (37) hide show
  1. package/VERSION +1 -1
  2. package/lib/browser/accounts/webSocketAccountSubscriberV2.d.ts +1 -1
  3. package/lib/browser/accounts/webSocketProgramAccountsSubscriberV2.d.ts +1 -1
  4. package/lib/browser/decode/user.js +3 -2
  5. package/lib/browser/driftClient.d.ts +2 -0
  6. package/lib/browser/driftClient.js +17 -0
  7. package/lib/browser/idl/drift.json +28 -175
  8. package/lib/browser/math/bankruptcy.js +1 -2
  9. package/lib/browser/types.d.ts +2 -0
  10. package/lib/browser/user.d.ts +2 -15
  11. package/lib/browser/user.js +29 -225
  12. package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts +1 -1
  13. package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts.map +1 -1
  14. package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.d.ts +1 -1
  15. package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.d.ts.map +1 -1
  16. package/lib/node/decode/user.d.ts.map +1 -1
  17. package/lib/node/decode/user.js +3 -2
  18. package/lib/node/driftClient.d.ts +2 -0
  19. package/lib/node/driftClient.d.ts.map +1 -1
  20. package/lib/node/driftClient.js +17 -0
  21. package/lib/node/idl/drift.json +28 -175
  22. package/lib/node/math/bankruptcy.d.ts.map +1 -1
  23. package/lib/node/math/bankruptcy.js +1 -2
  24. package/lib/node/types.d.ts +2 -0
  25. package/lib/node/types.d.ts.map +1 -1
  26. package/lib/node/user.d.ts +2 -15
  27. package/lib/node/user.d.ts.map +1 -1
  28. package/lib/node/user.js +29 -225
  29. package/package.json +1 -1
  30. package/src/accounts/webSocketAccountSubscriberV2.ts +2 -2
  31. package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +2 -2
  32. package/src/decode/user.ts +3 -2
  33. package/src/driftClient.ts +44 -0
  34. package/src/idl/drift.json +29 -176
  35. package/src/math/bankruptcy.ts +1 -2
  36. package/src/types.ts +2 -0
  37. package/src/user.ts +47 -343
package/src/user.ts CHANGED
@@ -22,14 +22,12 @@ import {
22
22
  } from './math/position';
23
23
  import {
24
24
  AMM_RESERVE_PRECISION,
25
- AMM_RESERVE_PRECISION_EXP,
26
25
  AMM_TO_QUOTE_PRECISION_RATIO,
27
26
  BASE_PRECISION,
28
27
  BN_MAX,
29
28
  DUST_POSITION_SIZE,
30
29
  FIVE_MINUTE,
31
30
  MARGIN_PRECISION,
32
- ONE,
33
31
  OPEN_ORDER_MARGIN_REQUIREMENT,
34
32
  PRICE_PRECISION,
35
33
  QUOTE_PRECISION,
@@ -84,7 +82,6 @@ import {
84
82
  getSpotLiabilityValue,
85
83
  getTokenAmount,
86
84
  } from './math/spotBalance';
87
- import { calculateMarketOpenBidAsk } from './math/amm';
88
85
  import {
89
86
  calculateBaseAssetValueWithOracle,
90
87
  calculateCollateralDepositRequiredForTrade,
@@ -227,6 +224,14 @@ export class User {
227
224
  return this.getPerpPositionForUserAccount(userAccount, marketIndex);
228
225
  }
229
226
 
227
+ public getPerpPositionOrEmpty(marketIndex: number): PerpPosition {
228
+ const userAccount = this.getUserAccount();
229
+ return (
230
+ this.getPerpPositionForUserAccount(userAccount, marketIndex) ??
231
+ this.getEmptyPosition(marketIndex)
232
+ );
233
+ }
234
+
230
235
  public getPerpPositionAndSlot(
231
236
  marketIndex: number
232
237
  ): DataAndSlot<PerpPosition | undefined> {
@@ -325,6 +330,7 @@ export class User {
325
330
  lastBaseAssetAmountPerLp: ZERO,
326
331
  lastQuoteAssetAmountPerLp: ZERO,
327
332
  perLpBase: 0,
333
+ maxMarginRatio: 0,
328
334
  };
329
335
  }
330
336
 
@@ -430,243 +436,12 @@ export class User {
430
436
  public getPerpBidAsks(marketIndex: number): [BN, BN] {
431
437
  const position = this.getPerpPosition(marketIndex);
432
438
 
433
- const [lpOpenBids, lpOpenAsks] = this.getLPBidAsks(marketIndex);
434
-
435
- const totalOpenBids = lpOpenBids.add(position.openBids);
436
- const totalOpenAsks = lpOpenAsks.add(position.openAsks);
439
+ const totalOpenBids = position.openBids;
440
+ const totalOpenAsks = position.openAsks;
437
441
 
438
442
  return [totalOpenBids, totalOpenAsks];
439
443
  }
440
444
 
441
- /**
442
- * calculates the open bids and asks for an lp
443
- * optionally pass in lpShares to see what bid/asks a user *would* take on
444
- * @returns : lp open bids
445
- * @returns : lp open asks
446
- */
447
- public getLPBidAsks(marketIndex: number, lpShares?: BN): [BN, BN] {
448
- const position = this.getPerpPosition(marketIndex);
449
-
450
- const lpSharesToCalc = lpShares ?? position?.lpShares;
451
-
452
- if (!lpSharesToCalc || lpSharesToCalc.eq(ZERO)) {
453
- return [ZERO, ZERO];
454
- }
455
-
456
- const market = this.driftClient.getPerpMarketAccount(marketIndex);
457
- const [marketOpenBids, marketOpenAsks] = calculateMarketOpenBidAsk(
458
- market.amm.baseAssetReserve,
459
- market.amm.minBaseAssetReserve,
460
- market.amm.maxBaseAssetReserve,
461
- market.amm.orderStepSize
462
- );
463
-
464
- const lpOpenBids = marketOpenBids.mul(lpSharesToCalc).div(market.amm.sqrtK);
465
- const lpOpenAsks = marketOpenAsks.mul(lpSharesToCalc).div(market.amm.sqrtK);
466
-
467
- return [lpOpenBids, lpOpenAsks];
468
- }
469
-
470
- /**
471
- * calculates the market position if the lp position was settled
472
- * @returns : the settled userPosition
473
- * @returns : the dust base asset amount (ie, < stepsize)
474
- * @returns : pnl from settle
475
- */
476
- public getPerpPositionWithLPSettle(
477
- marketIndex: number,
478
- originalPosition?: PerpPosition,
479
- burnLpShares = false,
480
- includeRemainderInBaseAmount = false
481
- ): [PerpPosition, BN, BN] {
482
- originalPosition =
483
- originalPosition ??
484
- this.getPerpPosition(marketIndex) ??
485
- this.getEmptyPosition(marketIndex);
486
-
487
- if (originalPosition.lpShares.eq(ZERO)) {
488
- return [originalPosition, ZERO, ZERO];
489
- }
490
-
491
- const position = this.getClonedPosition(originalPosition);
492
- const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
493
-
494
- if (market.amm.perLpBase != position.perLpBase) {
495
- // perLpBase = 1 => per 10 LP shares, perLpBase = -1 => per 0.1 LP shares
496
- const expoDiff = market.amm.perLpBase - position.perLpBase;
497
- const marketPerLpRebaseScalar = new BN(10 ** Math.abs(expoDiff));
498
-
499
- if (expoDiff > 0) {
500
- position.lastBaseAssetAmountPerLp =
501
- position.lastBaseAssetAmountPerLp.mul(marketPerLpRebaseScalar);
502
- position.lastQuoteAssetAmountPerLp =
503
- position.lastQuoteAssetAmountPerLp.mul(marketPerLpRebaseScalar);
504
- } else {
505
- position.lastBaseAssetAmountPerLp =
506
- position.lastBaseAssetAmountPerLp.div(marketPerLpRebaseScalar);
507
- position.lastQuoteAssetAmountPerLp =
508
- position.lastQuoteAssetAmountPerLp.div(marketPerLpRebaseScalar);
509
- }
510
-
511
- position.perLpBase = position.perLpBase + expoDiff;
512
- }
513
-
514
- const nShares = position.lpShares;
515
-
516
- // incorp unsettled funding on pre settled position
517
- const quoteFundingPnl = calculateUnsettledFundingPnl(market, position);
518
-
519
- let baseUnit = AMM_RESERVE_PRECISION;
520
- if (market.amm.perLpBase == position.perLpBase) {
521
- if (
522
- position.perLpBase >= 0 &&
523
- position.perLpBase <= AMM_RESERVE_PRECISION_EXP.toNumber()
524
- ) {
525
- const marketPerLpRebase = new BN(10 ** market.amm.perLpBase);
526
- baseUnit = baseUnit.mul(marketPerLpRebase);
527
- } else if (
528
- position.perLpBase < 0 &&
529
- position.perLpBase >= -AMM_RESERVE_PRECISION_EXP.toNumber()
530
- ) {
531
- const marketPerLpRebase = new BN(10 ** Math.abs(market.amm.perLpBase));
532
- baseUnit = baseUnit.div(marketPerLpRebase);
533
- } else {
534
- throw 'cannot calc';
535
- }
536
- } else {
537
- throw 'market.amm.perLpBase != position.perLpBase';
538
- }
539
-
540
- const deltaBaa = market.amm.baseAssetAmountPerLp
541
- .sub(position.lastBaseAssetAmountPerLp)
542
- .mul(nShares)
543
- .div(baseUnit);
544
- const deltaQaa = market.amm.quoteAssetAmountPerLp
545
- .sub(position.lastQuoteAssetAmountPerLp)
546
- .mul(nShares)
547
- .div(baseUnit);
548
-
549
- function sign(v: BN) {
550
- return v.isNeg() ? new BN(-1) : new BN(1);
551
- }
552
-
553
- function standardize(amount: BN, stepSize: BN) {
554
- const remainder = amount.abs().mod(stepSize).mul(sign(amount));
555
- const standardizedAmount = amount.sub(remainder);
556
- return [standardizedAmount, remainder];
557
- }
558
-
559
- const [standardizedBaa, remainderBaa] = standardize(
560
- deltaBaa,
561
- market.amm.orderStepSize
562
- );
563
-
564
- position.remainderBaseAssetAmount += remainderBaa.toNumber();
565
-
566
- if (
567
- Math.abs(position.remainderBaseAssetAmount) >
568
- market.amm.orderStepSize.toNumber()
569
- ) {
570
- const [newStandardizedBaa, newRemainderBaa] = standardize(
571
- new BN(position.remainderBaseAssetAmount),
572
- market.amm.orderStepSize
573
- );
574
- position.baseAssetAmount =
575
- position.baseAssetAmount.add(newStandardizedBaa);
576
- position.remainderBaseAssetAmount = newRemainderBaa.toNumber();
577
- }
578
-
579
- let dustBaseAssetValue = ZERO;
580
- if (burnLpShares && position.remainderBaseAssetAmount != 0) {
581
- const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(
582
- position.marketIndex
583
- );
584
- dustBaseAssetValue = new BN(Math.abs(position.remainderBaseAssetAmount))
585
- .mul(oraclePriceData.price)
586
- .div(AMM_RESERVE_PRECISION)
587
- .add(ONE);
588
- }
589
-
590
- let updateType;
591
- if (position.baseAssetAmount.eq(ZERO)) {
592
- updateType = 'open';
593
- } else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
594
- updateType = 'increase';
595
- } else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
596
- updateType = 'reduce';
597
- } else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
598
- updateType = 'close';
599
- } else {
600
- updateType = 'flip';
601
- }
602
-
603
- let newQuoteEntry;
604
- let pnl;
605
- if (updateType == 'open' || updateType == 'increase') {
606
- newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
607
- pnl = ZERO;
608
- } else if (updateType == 'reduce' || updateType == 'close') {
609
- newQuoteEntry = position.quoteEntryAmount.sub(
610
- position.quoteEntryAmount
611
- .mul(deltaBaa.abs())
612
- .div(position.baseAssetAmount.abs())
613
- );
614
- pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
615
- } else {
616
- newQuoteEntry = deltaQaa.sub(
617
- deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
618
- );
619
- pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
620
- }
621
- position.quoteEntryAmount = newQuoteEntry;
622
- position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
623
- position.quoteAssetAmount = position.quoteAssetAmount
624
- .add(deltaQaa)
625
- .add(quoteFundingPnl)
626
- .sub(dustBaseAssetValue);
627
- position.quoteBreakEvenAmount = position.quoteBreakEvenAmount
628
- .add(deltaQaa)
629
- .add(quoteFundingPnl)
630
- .sub(dustBaseAssetValue);
631
-
632
- // update open bids/asks
633
- const [marketOpenBids, marketOpenAsks] = calculateMarketOpenBidAsk(
634
- market.amm.baseAssetReserve,
635
- market.amm.minBaseAssetReserve,
636
- market.amm.maxBaseAssetReserve,
637
- market.amm.orderStepSize
638
- );
639
- const lpOpenBids = marketOpenBids
640
- .mul(position.lpShares)
641
- .div(market.amm.sqrtK);
642
- const lpOpenAsks = marketOpenAsks
643
- .mul(position.lpShares)
644
- .div(market.amm.sqrtK);
645
- position.openBids = lpOpenBids.add(position.openBids);
646
- position.openAsks = lpOpenAsks.add(position.openAsks);
647
-
648
- // eliminate counting funding on settled position
649
- if (position.baseAssetAmount.gt(ZERO)) {
650
- position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
651
- } else if (position.baseAssetAmount.lt(ZERO)) {
652
- position.lastCumulativeFundingRate =
653
- market.amm.cumulativeFundingRateShort;
654
- } else {
655
- position.lastCumulativeFundingRate = ZERO;
656
- }
657
-
658
- const remainderBeforeRemoval = new BN(position.remainderBaseAssetAmount);
659
-
660
- if (includeRemainderInBaseAmount) {
661
- position.baseAssetAmount = position.baseAssetAmount.add(
662
- remainderBeforeRemoval
663
- );
664
- position.remainderBaseAssetAmount = 0;
665
- }
666
-
667
- return [position, remainderBeforeRemoval, pnl];
668
- }
669
-
670
445
  /**
671
446
  * calculates Buying Power = free collateral / initial margin ratio
672
447
  * @returns : Precision QUOTE_PRECISION
@@ -676,11 +451,7 @@ export class User {
676
451
  collateralBuffer = ZERO,
677
452
  enterHighLeverageMode = undefined
678
453
  ): BN {
679
- const perpPosition = this.getPerpPositionWithLPSettle(
680
- marketIndex,
681
- undefined,
682
- true
683
- )[0];
454
+ const perpPosition = this.getPerpPositionOrEmpty(marketIndex);
684
455
 
685
456
  const perpMarket = this.driftClient.getPerpMarketAccount(marketIndex);
686
457
  const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
@@ -701,7 +472,8 @@ export class User {
701
472
  marketIndex,
702
473
  freeCollateral,
703
474
  worstCaseBaseAssetAmount,
704
- enterHighLeverageMode
475
+ enterHighLeverageMode,
476
+ perpPosition
705
477
  );
706
478
  }
707
479
 
@@ -709,13 +481,18 @@ export class User {
709
481
  marketIndex: number,
710
482
  freeCollateral: BN,
711
483
  baseAssetAmount: BN,
712
- enterHighLeverageMode = undefined
484
+ enterHighLeverageMode = undefined,
485
+ perpPosition?: PerpPosition
713
486
  ): BN {
487
+ const userCustomMargin = Math.max(
488
+ perpPosition?.maxMarginRatio ?? 0,
489
+ this.getUserAccount().maxMarginRatio
490
+ );
714
491
  const marginRatio = calculateMarketMarginRatio(
715
492
  this.driftClient.getPerpMarketAccount(marketIndex),
716
493
  baseAssetAmount,
717
494
  'Initial',
718
- this.getUserAccount().maxMarginRatio,
495
+ userCustomMargin,
719
496
  enterHighLeverageMode || this.isHighLeverageMode('Initial')
720
497
  );
721
498
 
@@ -793,8 +570,7 @@ export class User {
793
570
  (pos) =>
794
571
  !pos.baseAssetAmount.eq(ZERO) ||
795
572
  !pos.quoteAssetAmount.eq(ZERO) ||
796
- !(pos.openOrders == 0) ||
797
- !pos.lpShares.eq(ZERO)
573
+ !(pos.openOrders == 0)
798
574
  );
799
575
  }
800
576
 
@@ -866,14 +642,6 @@ export class User {
866
642
  market.quoteSpotMarketIndex
867
643
  );
868
644
 
869
- if (perpPosition.lpShares.gt(ZERO)) {
870
- perpPosition = this.getPerpPositionWithLPSettle(
871
- perpPosition.marketIndex,
872
- undefined,
873
- !!withWeightMarginCategory
874
- )[0];
875
- }
876
-
877
645
  let positionUnrealizedPnl = calculatePositionPNL(
878
646
  market,
879
647
  perpPosition,
@@ -1450,15 +1218,6 @@ export class User {
1450
1218
  perpPosition.marketIndex
1451
1219
  );
1452
1220
 
1453
- if (perpPosition.lpShares.gt(ZERO)) {
1454
- // is an lp, clone so we dont mutate the position
1455
- perpPosition = this.getPerpPositionWithLPSettle(
1456
- market.marketIndex,
1457
- this.getClonedPosition(perpPosition),
1458
- !!marginCategory
1459
- )[0];
1460
- }
1461
-
1462
1221
  let valuationPrice = this.getOracleDataForPerpMarket(
1463
1222
  market.marketIndex
1464
1223
  ).price;
@@ -1537,19 +1296,6 @@ export class User {
1537
1296
  liabilityValue = liabilityValue.add(
1538
1297
  new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1539
1298
  );
1540
-
1541
- if (perpPosition.lpShares.gt(ZERO)) {
1542
- liabilityValue = liabilityValue.add(
1543
- BN.max(
1544
- QUOTE_PRECISION,
1545
- valuationPrice
1546
- .mul(market.amm.orderStepSize)
1547
- .mul(QUOTE_PRECISION)
1548
- .div(AMM_RESERVE_PRECISION)
1549
- .div(PRICE_PRECISION)
1550
- )
1551
- );
1552
- }
1553
1299
  }
1554
1300
  }
1555
1301
 
@@ -1613,13 +1359,7 @@ export class User {
1613
1359
  oraclePriceData: Pick<OraclePriceData, 'price'>,
1614
1360
  includeOpenOrders = false
1615
1361
  ): BN {
1616
- const userPosition =
1617
- this.getPerpPositionWithLPSettle(
1618
- marketIndex,
1619
- undefined,
1620
- false,
1621
- true
1622
- )[0] || this.getEmptyPosition(marketIndex);
1362
+ const userPosition = this.getPerpPositionOrEmpty(marketIndex);
1623
1363
  const market = this.driftClient.getPerpMarketAccount(
1624
1364
  userPosition.marketIndex
1625
1365
  );
@@ -1640,13 +1380,7 @@ export class User {
1640
1380
  oraclePriceData: OraclePriceData,
1641
1381
  includeOpenOrders = false
1642
1382
  ): BN {
1643
- const userPosition =
1644
- this.getPerpPositionWithLPSettle(
1645
- marketIndex,
1646
- undefined,
1647
- false,
1648
- true
1649
- )[0] || this.getEmptyPosition(marketIndex);
1383
+ const userPosition = this.getPerpPositionOrEmpty(marketIndex);
1650
1384
  const market = this.driftClient.getPerpMarketAccount(
1651
1385
  userPosition.marketIndex
1652
1386
  );
@@ -2197,11 +1931,9 @@ export class User {
2197
1931
  const oraclePrice =
2198
1932
  this.driftClient.getOracleDataForSpotMarket(marketIndex).price;
2199
1933
  if (perpMarketWithSameOracle) {
2200
- const perpPosition = this.getPerpPositionWithLPSettle(
2201
- perpMarketWithSameOracle.marketIndex,
2202
- undefined,
2203
- true
2204
- )[0];
1934
+ const perpPosition = this.getPerpPositionOrEmpty(
1935
+ perpMarketWithSameOracle.marketIndex
1936
+ );
2205
1937
  if (perpPosition) {
2206
1938
  let freeCollateralDeltaForPerp =
2207
1939
  this.calculateFreeCollateralDeltaForPerp(
@@ -2287,9 +2019,7 @@ export class User {
2287
2019
  this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
2288
2020
 
2289
2021
  const market = this.driftClient.getPerpMarketAccount(marketIndex);
2290
- const currentPerpPosition =
2291
- this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
2292
- this.getEmptyPosition(marketIndex);
2022
+ const currentPerpPosition = this.getPerpPositionOrEmpty(marketIndex);
2293
2023
 
2294
2024
  positionBaseSizeChange = standardizeBaseAssetAmount(
2295
2025
  positionBaseSizeChange,
@@ -2439,7 +2169,10 @@ export class User {
2439
2169
  );
2440
2170
  }
2441
2171
 
2442
- const userCustomMargin = this.getUserAccount().maxMarginRatio;
2172
+ const userCustomMargin = Math.max(
2173
+ perpPosition.maxMarginRatio,
2174
+ this.getUserAccount().maxMarginRatio
2175
+ );
2443
2176
  const marginRatio = calculateMarketMarginRatio(
2444
2177
  market,
2445
2178
  baseAssetAmount.abs(),
@@ -2489,7 +2222,10 @@ export class User {
2489
2222
 
2490
2223
  const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
2491
2224
 
2492
- const userCustomMargin = this.getUserAccount().maxMarginRatio;
2225
+ const userCustomMargin = Math.max(
2226
+ perpPosition.maxMarginRatio,
2227
+ this.getUserAccount().maxMarginRatio
2228
+ );
2493
2229
 
2494
2230
  const marginRatio = calculateMarketMarginRatio(
2495
2231
  market,
@@ -2587,12 +2323,7 @@ export class User {
2587
2323
  closeQuoteAmount: BN,
2588
2324
  estimatedEntryPrice: BN = ZERO
2589
2325
  ): BN {
2590
- const currentPosition =
2591
- this.getPerpPositionWithLPSettle(
2592
- positionMarketIndex,
2593
- undefined,
2594
- true
2595
- )[0] || this.getEmptyPosition(positionMarketIndex);
2326
+ const currentPosition = this.getPerpPositionOrEmpty(positionMarketIndex);
2596
2327
 
2597
2328
  const closeBaseAmount = currentPosition.baseAssetAmount
2598
2329
  .mul(closeQuoteAmount)
@@ -2658,9 +2389,7 @@ export class User {
2658
2389
  ): { tradeSize: BN; oppositeSideTradeSize: BN } {
2659
2390
  let tradeSize = ZERO;
2660
2391
  let oppositeSideTradeSize = ZERO;
2661
- const currentPosition =
2662
- this.getPerpPositionWithLPSettle(targetMarketIndex, undefined, true)[0] ||
2663
- this.getEmptyPosition(targetMarketIndex);
2392
+ const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
2664
2393
 
2665
2394
  const targetSide = isVariant(tradeSide, 'short') ? 'short' : 'long';
2666
2395
 
@@ -3433,9 +3162,7 @@ export class User {
3433
3162
  return newLeverage;
3434
3163
  }
3435
3164
 
3436
- const currentPosition =
3437
- this.getPerpPositionWithLPSettle(targetMarketIndex)[0] ||
3438
- this.getEmptyPosition(targetMarketIndex);
3165
+ const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
3439
3166
 
3440
3167
  const perpMarket = this.driftClient.getPerpMarketAccount(targetMarketIndex);
3441
3168
  const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
@@ -3848,10 +3575,6 @@ export class User {
3848
3575
  oraclePriceData?: OraclePriceData;
3849
3576
  quoteOraclePriceData?: OraclePriceData;
3850
3577
  }): HealthComponent {
3851
- const settledLpPosition = this.getPerpPositionWithLPSettle(
3852
- perpPosition.marketIndex,
3853
- perpPosition
3854
- )[0];
3855
3578
  const perpMarket = this.driftClient.getPerpMarketAccount(
3856
3579
  perpPosition.marketIndex
3857
3580
  );
@@ -3863,17 +3586,21 @@ export class User {
3863
3586
  worstCaseBaseAssetAmount: worstCaseBaseAmount,
3864
3587
  worstCaseLiabilityValue,
3865
3588
  } = calculateWorstCasePerpLiabilityValue(
3866
- settledLpPosition,
3589
+ perpPosition,
3867
3590
  perpMarket,
3868
3591
  oraclePrice
3869
3592
  );
3870
3593
 
3594
+ const userCustomMargin = Math.max(
3595
+ perpPosition.maxMarginRatio,
3596
+ this.getUserAccount().maxMarginRatio
3597
+ );
3871
3598
  const marginRatio = new BN(
3872
3599
  calculateMarketMarginRatio(
3873
3600
  perpMarket,
3874
3601
  worstCaseBaseAmount.abs(),
3875
3602
  marginCategory,
3876
- this.getUserAccount().maxMarginRatio,
3603
+ userCustomMargin,
3877
3604
  this.isHighLeverageMode(marginCategory)
3878
3605
  )
3879
3606
  );
@@ -3892,19 +3619,6 @@ export class User {
3892
3619
  new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
3893
3620
  );
3894
3621
 
3895
- if (perpPosition.lpShares.gt(ZERO)) {
3896
- marginRequirement = marginRequirement.add(
3897
- BN.max(
3898
- QUOTE_PRECISION,
3899
- oraclePrice
3900
- .mul(perpMarket.amm.orderStepSize)
3901
- .mul(QUOTE_PRECISION)
3902
- .div(AMM_RESERVE_PRECISION)
3903
- .div(PRICE_PRECISION)
3904
- )
3905
- );
3906
- }
3907
-
3908
3622
  return {
3909
3623
  marketIndex: perpMarket.marketIndex,
3910
3624
  size: worstCaseBaseAmount,
@@ -3952,14 +3666,9 @@ export class User {
3952
3666
  perpMarket.quoteSpotMarketIndex
3953
3667
  );
3954
3668
 
3955
- const settledPerpPosition = this.getPerpPositionWithLPSettle(
3956
- perpPosition.marketIndex,
3957
- perpPosition
3958
- )[0];
3959
-
3960
3669
  const positionUnrealizedPnl = calculatePositionPNL(
3961
3670
  perpMarket,
3962
- settledPerpPosition,
3671
+ perpPosition,
3963
3672
  true,
3964
3673
  oraclePriceData
3965
3674
  );
@@ -4111,12 +3820,7 @@ export class User {
4111
3820
  liquidationBuffer?: BN,
4112
3821
  includeOpenOrders?: boolean
4113
3822
  ): BN {
4114
- const currentPerpPosition =
4115
- this.getPerpPositionWithLPSettle(
4116
- marketToIgnore,
4117
- undefined,
4118
- !!marginCategory
4119
- )[0] || this.getEmptyPosition(marketToIgnore);
3823
+ const currentPerpPosition = this.getPerpPositionOrEmpty(marketToIgnore);
4120
3824
 
4121
3825
  const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
4122
3826