@drift-labs/sdk 2.35.1-beta.0 → 2.35.1-beta.1

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 CHANGED
@@ -1 +1 @@
1
- 2.35.1-beta.0
1
+ 2.35.1-beta.1
@@ -25,7 +25,7 @@ export declare function calculateClaimablePnl(market: PerpMarketAccount, spotMar
25
25
  *
26
26
  * @param market
27
27
  * @param PerpPosition
28
- * @returns // TODO-PRECISION
28
+ * @returns // QUOTE_PRECISION
29
29
  */
30
30
  export declare function calculatePositionFundingPNL(market: PerpMarketAccount, perpPosition: PerpPosition): BN;
31
31
  export declare function positionIsAvailable(position: PerpPosition): boolean;
@@ -96,7 +96,7 @@ exports.calculateClaimablePnl = calculateClaimablePnl;
96
96
  *
97
97
  * @param market
98
98
  * @param PerpPosition
99
- * @returns // TODO-PRECISION
99
+ * @returns // QUOTE_PRECISION
100
100
  */
101
101
  function calculatePositionFundingPNL(market, perpPosition) {
102
102
  if (perpPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
package/lib/user.d.ts CHANGED
@@ -93,7 +93,7 @@ export declare class User {
93
93
  * @returns : the dust base asset amount (ie, < stepsize)
94
94
  * @returns : pnl from settle
95
95
  */
96
- getPerpPositionWithLPSettle(marketIndex: number, originalPosition?: PerpPosition): [PerpPosition, BN, BN];
96
+ getPerpPositionWithLPSettle(marketIndex: number, originalPosition?: PerpPosition, burnLpShares?: boolean): [PerpPosition, BN, BN];
97
97
  /**
98
98
  * calculates Buying Power = free collateral / initial margin ratio
99
99
  * @returns : Precision QUOTE_PRECISION
package/lib/user.js CHANGED
@@ -249,7 +249,7 @@ class User {
249
249
  * @returns : the dust base asset amount (ie, < stepsize)
250
250
  * @returns : pnl from settle
251
251
  */
252
- getPerpPositionWithLPSettle(marketIndex, originalPosition) {
252
+ getPerpPositionWithLPSettle(marketIndex, originalPosition, burnLpShares = false) {
253
253
  var _a;
254
254
  originalPosition =
255
255
  (_a = originalPosition !== null && originalPosition !== void 0 ? originalPosition : this.getPerpPosition(marketIndex)) !== null && _a !== void 0 ? _a : this.getEmptyPosition(marketIndex);
@@ -259,6 +259,8 @@ class User {
259
259
  const position = this.getClonedPosition(originalPosition);
260
260
  const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
261
261
  const nShares = position.lpShares;
262
+ // incorp unsettled funding on pre settled position
263
+ const quoteFundingPnl = (0, _1.calculatePositionFundingPNL)(market, position);
262
264
  const deltaBaa = market.amm.baseAssetAmountPerLp
263
265
  .sub(position.lastBaseAssetAmountPerLp)
264
266
  .mul(nShares)
@@ -284,6 +286,14 @@ class User {
284
286
  position.baseAssetAmount.add(newStandardizedBaa);
285
287
  position.remainderBaseAssetAmount = newRemainderBaa.toNumber();
286
288
  }
289
+ let dustBaseAssetValue = numericConstants_1.ZERO;
290
+ if (burnLpShares && position.remainderBaseAssetAmount != 0) {
291
+ const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(position.marketIndex);
292
+ dustBaseAssetValue = _1.BN.abs(position.remainderBaseAssetAmount)
293
+ .mul(oraclePriceData.price)
294
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
295
+ .add(numericConstants_1.ONE);
296
+ }
287
297
  let updateType;
288
298
  if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
289
299
  updateType = 'open';
@@ -318,7 +328,25 @@ class User {
318
328
  }
319
329
  position.quoteEntryAmount = newQuoteEntry;
320
330
  position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
321
- position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
331
+ position.quoteAssetAmount = position.quoteAssetAmount
332
+ .add(deltaQaa)
333
+ .add(quoteFundingPnl)
334
+ .sub(dustBaseAssetValue);
335
+ position.quoteBreakEvenAmount = position.quoteBreakEvenAmount
336
+ .add(deltaQaa)
337
+ .add(quoteFundingPnl)
338
+ .sub(dustBaseAssetValue);
339
+ // update open bids/asks
340
+ const [marketOpenBids, marketOpenAsks] = (0, amm_1.calculateMarketOpenBidAsk)(market.amm.baseAssetReserve, market.amm.minBaseAssetReserve, market.amm.maxBaseAssetReserve, market.amm.orderStepSize);
341
+ const lpOpenBids = marketOpenBids
342
+ .mul(position.lpShares)
343
+ .div(market.amm.sqrtK);
344
+ const lpOpenAsks = marketOpenAsks
345
+ .mul(position.lpShares)
346
+ .div(market.amm.sqrtK);
347
+ position.openBids = lpOpenBids.add(position.openBids);
348
+ position.openAsks = lpOpenAsks.add(position.openAsks);
349
+ // eliminate counting funding on settled position
322
350
  if (position.baseAssetAmount.gt(numericConstants_1.ZERO)) {
323
351
  position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
324
352
  }
@@ -336,7 +364,7 @@ class User {
336
364
  * @returns : Precision QUOTE_PRECISION
337
365
  */
338
366
  getPerpBuyingPower(marketIndex) {
339
- const perpPosition = this.getPerpPosition(marketIndex);
367
+ const perpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0];
340
368
  const worstCaseBaseAssetAmount = perpPosition
341
369
  ? (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition)
342
370
  : numericConstants_1.ZERO;
@@ -421,7 +449,7 @@ class User {
421
449
  const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
422
450
  const quoteOraclePriceData = this.getOracleDataForSpotMarket(market.quoteSpotMarketIndex);
423
451
  if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
424
- perpPosition = this.getPerpPositionWithLPSettle(perpPosition.marketIndex)[0];
452
+ perpPosition = this.getPerpPositionWithLPSettle(perpPosition.marketIndex, undefined, !!withWeightMarginCategory)[0];
425
453
  }
426
454
  let positionUnrealizedPnl = (0, _1.calculatePositionPNL)(market, perpPosition, withFunding, oraclePriceData);
427
455
  let quotePrice;
@@ -640,17 +668,8 @@ class User {
640
668
  return this.getActivePerpPositions().reduce((totalPerpValue, perpPosition) => {
641
669
  const market = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
642
670
  if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
643
- // is an lp
644
- // clone so we dont mutate the position
645
- perpPosition = this.getClonedPosition(perpPosition);
646
- // settle position
647
- const [settledPosition, dustBaa, _] = this.getPerpPositionWithLPSettle(market.marketIndex);
648
- perpPosition.baseAssetAmount =
649
- settledPosition.baseAssetAmount.add(dustBaa);
650
- perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
651
- const [totalOpenBids, totalOpenAsks] = this.getPerpBidAsks(market.marketIndex);
652
- perpPosition.openAsks = totalOpenAsks;
653
- perpPosition.openBids = totalOpenBids;
671
+ // is an lp, clone so we dont mutate the position
672
+ perpPosition = this.getPerpPositionWithLPSettle(market.marketIndex, this.getClonedPosition(perpPosition), !!marginCategory)[0];
654
673
  }
655
674
  let valuationPrice = this.getOracleDataForPerpMarket(market.marketIndex).price;
656
675
  if ((0, types_1.isVariant)(market.status, 'settlement')) {
@@ -972,7 +991,7 @@ class User {
972
991
  .getPerpMarketAccounts()
973
992
  .find((market) => market.amm.oracle.equals(oracle));
974
993
  if (perpMarketWithSameOracle) {
975
- const perpPosition = this.getPerpPosition(perpMarketWithSameOracle.marketIndex);
994
+ const perpPosition = this.getPerpPositionWithLPSettle(perpMarketWithSameOracle.marketIndex, undefined, true)[0];
976
995
  if (perpPosition) {
977
996
  const freeCollateralDeltaForPerp = this.calculateFreeCollateralDeltaForPerp(perpMarketWithSameOracle, perpPosition, numericConstants_1.ZERO);
978
997
  freeCollateralDelta = freeCollateralDelta.add(freeCollateralDeltaForPerp || numericConstants_1.ZERO);
@@ -1002,7 +1021,8 @@ class User {
1002
1021
  const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
1003
1022
  const freeCollateral = _1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(maintenanceMarginRequirement));
1004
1023
  const market = this.driftClient.getPerpMarketAccount(marketIndex);
1005
- const currentPerpPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
1024
+ const currentPerpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
1025
+ this.getEmptyPosition(marketIndex);
1006
1026
  let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(market, currentPerpPosition, positionBaseSizeChange);
1007
1027
  if (!freeCollateralDelta) {
1008
1028
  return new _1.BN(-1);
@@ -1087,8 +1107,7 @@ class User {
1087
1107
  * @returns : Precision PRICE_PRECISION
1088
1108
  */
1089
1109
  liquidationPriceAfterClose(positionMarketIndex, closeQuoteAmount) {
1090
- const currentPosition = this.getPerpPosition(positionMarketIndex) ||
1091
- this.getEmptyPosition(positionMarketIndex);
1110
+ const currentPosition = this.getPerpPositionWithLPSettle(positionMarketIndex, undefined, true)[0] || this.getEmptyPosition(positionMarketIndex);
1092
1111
  const closeBaseAmount = currentPosition.baseAssetAmount
1093
1112
  .mul(closeQuoteAmount)
1094
1113
  .div(currentPosition.quoteAssetAmount.abs())
@@ -1120,7 +1139,7 @@ class User {
1120
1139
  * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
1121
1140
  */
1122
1141
  getMaxTradeSizeUSDCForPerp(targetMarketIndex, tradeSide) {
1123
- const currentPosition = this.getPerpPosition(targetMarketIndex) ||
1142
+ const currentPosition = this.getPerpPositionWithLPSettle(targetMarketIndex, undefined, true)[0] ||
1124
1143
  this.getEmptyPosition(targetMarketIndex);
1125
1144
  const targetSide = (0, types_1.isVariant)(tradeSide, 'short') ? 'short' : 'long';
1126
1145
  const currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
@@ -1478,7 +1497,7 @@ class User {
1478
1497
  .div(netAssetValueAfterTrade);
1479
1498
  return newLeverage;
1480
1499
  }
1481
- const currentPosition = this.getPerpPosition(targetMarketIndex) ||
1500
+ const currentPosition = this.getPerpPositionWithLPSettle(targetMarketIndex)[0] ||
1482
1501
  this.getEmptyPosition(targetMarketIndex);
1483
1502
  const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
1484
1503
  let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData, includeOpenOrders);
@@ -1656,8 +1675,7 @@ class User {
1656
1675
  * @returns positionValue : Precision QUOTE_PRECISION
1657
1676
  */
1658
1677
  getTotalPerpPositionValueExcludingMarket(marketToIgnore, marginCategory, liquidationBuffer, includeOpenOrders) {
1659
- const currentPerpPosition = this.getPerpPosition(marketToIgnore) ||
1660
- this.getEmptyPosition(marketToIgnore);
1678
+ const currentPerpPosition = this.getPerpPositionWithLPSettle(marketToIgnore, undefined, !!marginCategory)[0] || this.getEmptyPosition(marketToIgnore);
1661
1679
  const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
1662
1680
  let currentPerpPositionValueUSDC = numericConstants_1.ZERO;
1663
1681
  if (currentPerpPosition) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.35.1-beta.0",
3
+ "version": "2.35.1-beta.1",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -162,7 +162,7 @@ export function calculateClaimablePnl(
162
162
  *
163
163
  * @param market
164
164
  * @param PerpPosition
165
- * @returns // TODO-PRECISION
165
+ * @returns // QUOTE_PRECISION
166
166
  */
167
167
  export function calculatePositionFundingPNL(
168
168
  market: PerpMarketAccount,
package/src/user.ts CHANGED
@@ -413,7 +413,8 @@ export class User {
413
413
  */
414
414
  public getPerpPositionWithLPSettle(
415
415
  marketIndex: number,
416
- originalPosition?: PerpPosition
416
+ originalPosition?: PerpPosition,
417
+ burnLpShares = false
417
418
  ): [PerpPosition, BN, BN] {
418
419
  originalPosition =
419
420
  originalPosition ??
@@ -429,6 +430,9 @@ export class User {
429
430
  const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
430
431
  const nShares = position.lpShares;
431
432
 
433
+ // incorp unsettled funding on pre settled position
434
+ const quoteFundingPnl = calculatePositionFundingPNL(market, position);
435
+
432
436
  const deltaBaa = market.amm.baseAssetAmountPerLp
433
437
  .sub(position.lastBaseAssetAmountPerLp)
434
438
  .mul(nShares)
@@ -468,6 +472,17 @@ export class User {
468
472
  position.remainderBaseAssetAmount = newRemainderBaa.toNumber();
469
473
  }
470
474
 
475
+ let dustBaseAssetValue = ZERO;
476
+ if (burnLpShares && position.remainderBaseAssetAmount != 0) {
477
+ const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(
478
+ position.marketIndex
479
+ );
480
+ dustBaseAssetValue = BN.abs(position.remainderBaseAssetAmount)
481
+ .mul(oraclePriceData.price)
482
+ .div(AMM_RESERVE_PRECISION)
483
+ .add(ONE);
484
+ }
485
+
471
486
  let updateType;
472
487
  if (position.baseAssetAmount.eq(ZERO)) {
473
488
  updateType = 'open';
@@ -501,8 +516,32 @@ export class User {
501
516
  }
502
517
  position.quoteEntryAmount = newQuoteEntry;
503
518
  position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
504
- position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
519
+ position.quoteAssetAmount = position.quoteAssetAmount
520
+ .add(deltaQaa)
521
+ .add(quoteFundingPnl)
522
+ .sub(dustBaseAssetValue);
523
+ position.quoteBreakEvenAmount = position.quoteBreakEvenAmount
524
+ .add(deltaQaa)
525
+ .add(quoteFundingPnl)
526
+ .sub(dustBaseAssetValue);
527
+
528
+ // update open bids/asks
529
+ const [marketOpenBids, marketOpenAsks] = calculateMarketOpenBidAsk(
530
+ market.amm.baseAssetReserve,
531
+ market.amm.minBaseAssetReserve,
532
+ market.amm.maxBaseAssetReserve,
533
+ market.amm.orderStepSize
534
+ );
535
+ const lpOpenBids = marketOpenBids
536
+ .mul(position.lpShares)
537
+ .div(market.amm.sqrtK);
538
+ const lpOpenAsks = marketOpenAsks
539
+ .mul(position.lpShares)
540
+ .div(market.amm.sqrtK);
541
+ position.openBids = lpOpenBids.add(position.openBids);
542
+ position.openAsks = lpOpenAsks.add(position.openAsks);
505
543
 
544
+ // eliminate counting funding on settled position
506
545
  if (position.baseAssetAmount.gt(ZERO)) {
507
546
  position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
508
547
  } else if (position.baseAssetAmount.lt(ZERO)) {
@@ -520,7 +559,11 @@ export class User {
520
559
  * @returns : Precision QUOTE_PRECISION
521
560
  */
522
561
  public getPerpBuyingPower(marketIndex: number): BN {
523
- const perpPosition = this.getPerpPosition(marketIndex);
562
+ const perpPosition = this.getPerpPositionWithLPSettle(
563
+ marketIndex,
564
+ undefined,
565
+ true
566
+ )[0];
524
567
  const worstCaseBaseAssetAmount = perpPosition
525
568
  ? calculateWorstCaseBaseAssetAmount(perpPosition)
526
569
  : ZERO;
@@ -676,7 +719,9 @@ export class User {
676
719
 
677
720
  if (perpPosition.lpShares.gt(ZERO)) {
678
721
  perpPosition = this.getPerpPositionWithLPSettle(
679
- perpPosition.marketIndex
722
+ perpPosition.marketIndex,
723
+ undefined,
724
+ !!withWeightMarginCategory
680
725
  )[0];
681
726
  }
682
727
 
@@ -1168,23 +1213,12 @@ export class User {
1168
1213
  );
1169
1214
 
1170
1215
  if (perpPosition.lpShares.gt(ZERO)) {
1171
- // is an lp
1172
- // clone so we dont mutate the position
1173
- perpPosition = this.getClonedPosition(perpPosition);
1174
-
1175
- // settle position
1176
- const [settledPosition, dustBaa, _] =
1177
- this.getPerpPositionWithLPSettle(market.marketIndex);
1178
- perpPosition.baseAssetAmount =
1179
- settledPosition.baseAssetAmount.add(dustBaa);
1180
- perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
1181
-
1182
- const [totalOpenBids, totalOpenAsks] = this.getPerpBidAsks(
1183
- market.marketIndex
1184
- );
1185
-
1186
- perpPosition.openAsks = totalOpenAsks;
1187
- perpPosition.openBids = totalOpenBids;
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];
1188
1222
  }
1189
1223
 
1190
1224
  let valuationPrice = this.getOracleDataForPerpMarket(
@@ -1757,9 +1791,11 @@ export class User {
1757
1791
  .getPerpMarketAccounts()
1758
1792
  .find((market) => market.amm.oracle.equals(oracle));
1759
1793
  if (perpMarketWithSameOracle) {
1760
- const perpPosition = this.getPerpPosition(
1761
- perpMarketWithSameOracle.marketIndex
1762
- );
1794
+ const perpPosition = this.getPerpPositionWithLPSettle(
1795
+ perpMarketWithSameOracle.marketIndex,
1796
+ undefined,
1797
+ true
1798
+ )[0];
1763
1799
  if (perpPosition) {
1764
1800
  const freeCollateralDeltaForPerp =
1765
1801
  this.calculateFreeCollateralDeltaForPerp(
@@ -1812,7 +1848,8 @@ export class User {
1812
1848
 
1813
1849
  const market = this.driftClient.getPerpMarketAccount(marketIndex);
1814
1850
  const currentPerpPosition =
1815
- this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
1851
+ this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
1852
+ this.getEmptyPosition(marketIndex);
1816
1853
 
1817
1854
  let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
1818
1855
  market,
@@ -1967,8 +2004,11 @@ export class User {
1967
2004
  closeQuoteAmount: BN
1968
2005
  ): BN {
1969
2006
  const currentPosition =
1970
- this.getPerpPosition(positionMarketIndex) ||
1971
- this.getEmptyPosition(positionMarketIndex);
2007
+ this.getPerpPositionWithLPSettle(
2008
+ positionMarketIndex,
2009
+ undefined,
2010
+ true
2011
+ )[0] || this.getEmptyPosition(positionMarketIndex);
1972
2012
 
1973
2013
  const closeBaseAmount = currentPosition.baseAssetAmount
1974
2014
  .mul(closeQuoteAmount)
@@ -2009,7 +2049,7 @@ export class User {
2009
2049
  tradeSide: PositionDirection
2010
2050
  ): BN {
2011
2051
  const currentPosition =
2012
- this.getPerpPosition(targetMarketIndex) ||
2052
+ this.getPerpPositionWithLPSettle(targetMarketIndex, undefined, true)[0] ||
2013
2053
  this.getEmptyPosition(targetMarketIndex);
2014
2054
 
2015
2055
  const targetSide = isVariant(tradeSide, 'short') ? 'short' : 'long';
@@ -2703,7 +2743,7 @@ export class User {
2703
2743
  }
2704
2744
 
2705
2745
  const currentPosition =
2706
- this.getPerpPosition(targetMarketIndex) ||
2746
+ this.getPerpPositionWithLPSettle(targetMarketIndex)[0] ||
2707
2747
  this.getEmptyPosition(targetMarketIndex);
2708
2748
 
2709
2749
  const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
@@ -2989,8 +3029,11 @@ export class User {
2989
3029
  includeOpenOrders?: boolean
2990
3030
  ): BN {
2991
3031
  const currentPerpPosition =
2992
- this.getPerpPosition(marketToIgnore) ||
2993
- this.getEmptyPosition(marketToIgnore);
3032
+ this.getPerpPositionWithLPSettle(
3033
+ marketToIgnore,
3034
+ undefined,
3035
+ !!marginCategory
3036
+ )[0] || this.getEmptyPosition(marketToIgnore);
2994
3037
 
2995
3038
  const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
2996
3039