@drift-labs/sdk 0.2.0-master.27 → 0.2.0-master.28

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 (50) hide show
  1. package/lib/accounts/types.d.ts +1 -0
  2. package/lib/clearingHouse.d.ts +1 -0
  3. package/lib/clearingHouse.js +5 -0
  4. package/lib/clearingHouseUser.js +2 -2
  5. package/lib/idl/clearing_house.json +1 -1
  6. package/lib/math/market.d.ts +2 -1
  7. package/lib/math/market.js +16 -11
  8. package/lib/math/position.d.ts +3 -3
  9. package/lib/math/position.js +23 -16
  10. package/lib/math/repeg.js +8 -0
  11. package/lib/types.d.ts +1 -1
  12. package/package.json +1 -1
  13. package/src/clearingHouse.ts +7 -0
  14. package/src/clearingHouseUser.ts +2 -2
  15. package/src/idl/clearing_house.json +1 -1
  16. package/src/math/market.ts +21 -12
  17. package/src/math/position.ts +36 -22
  18. package/src/math/repeg.ts +9 -0
  19. package/src/types.ts +1 -1
  20. package/tests/dlob/helpers.ts +1 -1
  21. package/src/addresses/marketAddresses.js +0 -26
  22. package/src/assert/assert.js +0 -9
  23. package/src/constants/banks.js +0 -42
  24. package/src/constants/markets.js +0 -42
  25. package/src/events/eventList.js +0 -77
  26. package/src/events/txEventCache.js +0 -71
  27. package/src/examples/makeTradeExample.js +0 -157
  28. package/src/factory/bigNum.js +0 -390
  29. package/src/factory/oracleClient.js +0 -20
  30. package/src/math/auction.js +0 -42
  31. package/src/math/conversion.js +0 -11
  32. package/src/math/funding.js +0 -248
  33. package/src/math/repeg.js +0 -128
  34. package/src/math/trade.js +0 -253
  35. package/src/math/utils.js +0 -26
  36. package/src/math/utils.js.map +0 -1
  37. package/src/oracles/oracleClientCache.js +0 -19
  38. package/src/oracles/pythClient.js +0 -46
  39. package/src/oracles/quoteAssetOracleClient.js +0 -32
  40. package/src/oracles/switchboardClient.js +0 -69
  41. package/src/oracles/types.js +0 -2
  42. package/src/token/index.js +0 -38
  43. package/src/tx/types.js +0 -2
  44. package/src/tx/utils.js +0 -17
  45. package/src/userName.js +0 -20
  46. package/src/util/computeUnits.js +0 -27
  47. package/src/util/getTokenAddress.js +0 -9
  48. package/src/util/promiseTimeout.js +0 -14
  49. package/src/util/tps.js +0 -27
  50. package/src/wallet.js +0 -35
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="bn.js" />
3
+ /// <reference types="node" />
3
4
  import { SpotMarketAccount, PerpMarketAccount, OracleSource, StateAccount, UserAccount, UserStatsAccount } from '../types';
4
5
  import StrictEventEmitter from 'strict-event-emitter-types';
5
6
  import { EventEmitter } from 'events';
@@ -193,6 +193,7 @@ export declare class ClearingHouse {
193
193
  getSettleFundingPaymentIx(userAccount: PublicKey): Promise<TransactionInstruction>;
194
194
  triggerEvent(eventName: keyof ClearingHouseAccountEvents, data?: any): void;
195
195
  getOracleDataForMarket(marketIndex: BN): OraclePriceData;
196
+ getOracleDataForSpotMarket(marketIndex: BN): OraclePriceData;
196
197
  initializeInsuranceFundStake(marketIndex: BN): Promise<TransactionSignature>;
197
198
  getInitializeInsuranceFundStakeIx(marketIndex: BN): Promise<TransactionInstruction>;
198
199
  addInsuranceFundStake(marketIndex: BN, amount: BN, collateralAccountPublicKey: PublicKey): Promise<TransactionSignature>;
@@ -2002,6 +2002,11 @@ class ClearingHouse {
2002
2002
  const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
2003
2003
  return oracleData;
2004
2004
  }
2005
+ getOracleDataForSpotMarket(marketIndex) {
2006
+ const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
2007
+ const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
2008
+ return oracleData;
2009
+ }
2005
2010
  async initializeInsuranceFundStake(marketIndex) {
2006
2011
  const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getInitializeInsuranceFundStakeIx(marketIndex)), [], this.opts);
2007
2012
  return txSig;
@@ -73,7 +73,7 @@ class ClearingHouseUser {
73
73
  openOrders: numericConstants_1.ZERO,
74
74
  openBids: numericConstants_1.ZERO,
75
75
  openAsks: numericConstants_1.ZERO,
76
- realizedPnl: numericConstants_1.ZERO,
76
+ settledPnl: numericConstants_1.ZERO,
77
77
  lpShares: numericConstants_1.ZERO,
78
78
  lastFeePerLp: numericConstants_1.ZERO,
79
79
  lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
@@ -622,7 +622,7 @@ class ClearingHouseUser {
622
622
  openOrders: new _1.BN(0),
623
623
  openBids: new _1.BN(0),
624
624
  openAsks: new _1.BN(0),
625
- realizedPnl: numericConstants_1.ZERO,
625
+ settledPnl: numericConstants_1.ZERO,
626
626
  lpShares: numericConstants_1.ZERO,
627
627
  lastFeePerLp: numericConstants_1.ZERO,
628
628
  lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
@@ -4586,7 +4586,7 @@
4586
4586
  "type": "i128"
4587
4587
  },
4588
4588
  {
4589
- "name": "realizedPnl",
4589
+ "name": "settledPnl",
4590
4590
  "type": "i64"
4591
4591
  },
4592
4592
  {
@@ -29,4 +29,5 @@ export declare function calculateOracleSpread(price: BN, oraclePriceData: Oracle
29
29
  export declare function calculateMarketMarginRatio(market: PerpMarketAccount, size: BN, marginCategory: MarginCategory): number;
30
30
  export declare function calculateUnrealizedAssetWeight(market: PerpMarketAccount, quoteSpotMarket: SpotMarketAccount, unrealizedPnl: BN, marginCategory: MarginCategory, oraclePriceData: OraclePriceData): BN;
31
31
  export declare function calculateMarketAvailablePNL(perpMarket: PerpMarketAccount, spotMarket: SpotMarketAccount): BN;
32
- export declare function calculateNetUserImbalance(market: PerpMarketAccount, bank: SpotMarketAccount, oraclePriceData: OraclePriceData): BN;
32
+ export declare function calculateNetUserPnl(perpMarket: PerpMarketAccount, oraclePriceData: OraclePriceData): BN;
33
+ export declare function calculateNetUserPnlImbalance(perpMarket: PerpMarketAccount, spotMarket: SpotMarketAccount, oraclePriceData: OraclePriceData): BN;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateNetUserImbalance = exports.calculateMarketAvailablePNL = exports.calculateUnrealizedAssetWeight = exports.calculateMarketMarginRatio = exports.calculateOracleSpread = exports.calculateMarkOracleSpread = exports.calculateNewMarketAfterTrade = exports.calculateAskPrice = exports.calculateBidPrice = exports.calculateMarkPrice = void 0;
3
+ exports.calculateNetUserPnlImbalance = exports.calculateNetUserPnl = exports.calculateMarketAvailablePNL = exports.calculateUnrealizedAssetWeight = exports.calculateMarketMarginRatio = exports.calculateOracleSpread = exports.calculateMarkOracleSpread = exports.calculateNewMarketAfterTrade = exports.calculateAskPrice = exports.calculateBidPrice = exports.calculateMarkPrice = void 0;
4
4
  const anchor_1 = require("@project-serum/anchor");
5
5
  const types_1 = require("../types");
6
6
  const amm_1 = require("./amm");
@@ -78,7 +78,7 @@ function calculateUnrealizedAssetWeight(market, quoteSpotMarket, unrealizedPnl,
78
78
  case 'Initial':
79
79
  assetWeight = new anchor_1.BN(market.unrealizedInitialAssetWeight);
80
80
  if (market.unrealizedMaxImbalance.gt(numericConstants_1.ZERO)) {
81
- const netUnsettledPnl = calculateNetUserImbalance(market, quoteSpotMarket, oraclePriceData);
81
+ const netUnsettledPnl = calculateNetUserPnlImbalance(market, quoteSpotMarket, oraclePriceData);
82
82
  if (netUnsettledPnl.gt(market.unrealizedMaxImbalance)) {
83
83
  assetWeight = assetWeight
84
84
  .mul(market.unrealizedMaxImbalance)
@@ -98,17 +98,22 @@ function calculateMarketAvailablePNL(perpMarket, spotMarket) {
98
98
  return (0, spotBalance_1.getTokenAmount)(perpMarket.pnlPool.balance, spotMarket, types_1.SpotBalanceType.DEPOSIT);
99
99
  }
100
100
  exports.calculateMarketAvailablePNL = calculateMarketAvailablePNL;
101
- function calculateNetUserImbalance(market, bank, oraclePriceData) {
102
- const netUserPositionValue = market.amm.netBaseAssetAmount
101
+ function calculateNetUserPnl(perpMarket, oraclePriceData) {
102
+ const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
103
103
  .mul(oraclePriceData.price)
104
104
  .div(numericConstants_1.BASE_PRECISION)
105
105
  .div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
106
- const netUserCostBasis = market.amm.quoteAssetAmountLong
107
- .add(market.amm.quoteAssetAmountShort)
108
- .sub(market.amm.cumulativeSocialLoss);
109
- const userEntitledPnl = netUserPositionValue.add(netUserCostBasis);
110
- const pnlPool = (0, spotBalance_1.getTokenAmount)(market.pnlPool.balance, bank, types_1.SpotBalanceType.DEPOSIT);
111
- const imbalance = userEntitledPnl.sub(pnlPool);
106
+ const netUserCostBasis = perpMarket.amm.quoteAssetAmountLong
107
+ .add(perpMarket.amm.quoteAssetAmountShort)
108
+ .sub(perpMarket.amm.cumulativeSocialLoss);
109
+ const netUserPnl = netUserPositionValue.add(netUserCostBasis);
110
+ return netUserPnl;
111
+ }
112
+ exports.calculateNetUserPnl = calculateNetUserPnl;
113
+ function calculateNetUserPnlImbalance(perpMarket, spotMarket, oraclePriceData) {
114
+ const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
115
+ const pnlPool = (0, spotBalance_1.getTokenAmount)(perpMarket.pnlPool.balance, spotMarket, types_1.SpotBalanceType.DEPOSIT);
116
+ const imbalance = netUserPnl.sub(pnlPool);
112
117
  return imbalance;
113
118
  }
114
- exports.calculateNetUserImbalance = calculateNetUserImbalance;
119
+ exports.calculateNetUserPnlImbalance = calculateNetUserPnlImbalance;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="bn.js" />
2
- import { BN } from '../';
2
+ import { BN, SpotMarketAccount } from '../';
3
3
  import { OraclePriceData } from '../oracles/types';
4
4
  import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
5
5
  /**
@@ -10,7 +10,7 @@ import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
10
10
  * @param oraclePriceData
11
11
  * @returns Base Asset Value. : Precision QUOTE_PRECISION
12
12
  */
13
- export declare function calculateBaseAssetValue(market: PerpMarketAccount, userPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
13
+ export declare function calculateBaseAssetValue(market: PerpMarketAccount, userPosition: PerpPosition, oraclePriceData: OraclePriceData, useSpread?: boolean, skipUpdate?: boolean): BN;
14
14
  /**
15
15
  * calculatePositionPNL
16
16
  * = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
@@ -21,7 +21,7 @@ export declare function calculateBaseAssetValue(market: PerpMarketAccount, userP
21
21
  * @returns BaseAssetAmount : Precision QUOTE_PRECISION
22
22
  */
23
23
  export declare function calculatePositionPNL(market: PerpMarketAccount, perpPosition: PerpPosition, withFunding: boolean, oraclePriceData: OraclePriceData): BN;
24
- export declare function calculateUnsettledPnl(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
24
+ export declare function calculateClaimablePnl(market: PerpMarketAccount, spotMarket: SpotMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
25
25
  /**
26
26
  *
27
27
  * @param market
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateCostBasis = exports.calculateEntryPrice = exports.positionIsAvailable = exports.calculatePositionFundingPNL = exports.calculateUnsettledPnl = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
3
+ exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateCostBasis = exports.calculateEntryPrice = exports.positionIsAvailable = exports.calculatePositionFundingPNL = exports.calculateClaimablePnl = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
4
4
  const __1 = require("../");
5
5
  const numericConstants_1 = require("../constants/numericConstants");
6
6
  const types_1 = require("../types");
7
7
  const amm_1 = require("./amm");
8
8
  const margin_1 = require("./margin");
9
+ const market_1 = require("./market");
9
10
  /**
10
11
  * calculateBaseAssetValue
11
12
  * = market value of closing entire position
@@ -14,23 +15,28 @@ const margin_1 = require("./margin");
14
15
  * @param oraclePriceData
15
16
  * @returns Base Asset Value. : Precision QUOTE_PRECISION
16
17
  */
17
- function calculateBaseAssetValue(market, userPosition, oraclePriceData) {
18
+ function calculateBaseAssetValue(market, userPosition, oraclePriceData, useSpread = true, skipUpdate = false) {
18
19
  if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
19
20
  return numericConstants_1.ZERO;
20
21
  }
21
22
  const directionToClose = findDirectionToClose(userPosition);
22
23
  let prepegAmm;
23
- if (market.amm.baseSpread > 0) {
24
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, directionToClose, oraclePriceData);
25
- prepegAmm = {
26
- baseAssetReserve,
27
- quoteAssetReserve,
28
- sqrtK: sqrtK,
29
- pegMultiplier: newPeg,
30
- };
24
+ if (!skipUpdate) {
25
+ if (market.amm.baseSpread > 0 && useSpread) {
26
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, directionToClose, oraclePriceData);
27
+ prepegAmm = {
28
+ baseAssetReserve,
29
+ quoteAssetReserve,
30
+ sqrtK: sqrtK,
31
+ pegMultiplier: newPeg,
32
+ };
33
+ }
34
+ else {
35
+ prepegAmm = (0, amm_1.calculateUpdatedAMM)(market.amm, oraclePriceData);
36
+ }
31
37
  }
32
38
  else {
33
- prepegAmm = (0, amm_1.calculateUpdatedAMM)(market.amm, oraclePriceData);
39
+ prepegAmm = market.amm;
34
40
  }
35
41
  const [newQuoteAssetReserve, _] = (0, amm_1.calculateAmmReservesAfterSwap)(prepegAmm, 'base', userPosition.baseAssetAmount.abs(), (0, amm_1.getSwapDirection)('base', directionToClose));
36
42
  switch (directionToClose) {
@@ -75,19 +81,20 @@ function calculatePositionPNL(market, perpPosition, withFunding = false, oracleP
75
81
  return pnl;
76
82
  }
77
83
  exports.calculatePositionPNL = calculatePositionPNL;
78
- function calculateUnsettledPnl(market, perpPosition, oraclePriceData) {
84
+ function calculateClaimablePnl(market, spotMarket, perpPosition, oraclePriceData) {
79
85
  const unrealizedPnl = calculatePositionPNL(market, perpPosition, true, oraclePriceData);
80
- let unsettledPnl = unrealizedPnl;
86
+ const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
87
+ let unsettledPnl = unrealizedPnl.add(fundingPnL);
81
88
  if (unrealizedPnl.gt(numericConstants_1.ZERO)) {
82
- const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
89
+ const excessPnlPool = __1.BN.max(numericConstants_1.ZERO, (0, market_1.calculateNetUserPnlImbalance)(market, spotMarket, oraclePriceData).mul(new __1.BN(-1)));
83
90
  const maxPositivePnl = __1.BN.max(perpPosition.quoteAssetAmount
84
91
  .sub(perpPosition.quoteEntryAmount)
85
- .add(fundingPnL), numericConstants_1.ZERO);
92
+ .add(excessPnlPool), numericConstants_1.ZERO);
86
93
  unsettledPnl = __1.BN.min(maxPositivePnl, unrealizedPnl);
87
94
  }
88
95
  return unsettledPnl;
89
96
  }
90
- exports.calculateUnsettledPnl = calculateUnsettledPnl;
97
+ exports.calculateClaimablePnl = calculateClaimablePnl;
91
98
  /**
92
99
  *
93
100
  * @param market
package/lib/math/repeg.js CHANGED
@@ -71,6 +71,14 @@ function calculateBudgetedKBN(x, y, budget, Q, d) {
71
71
  .div(numericConstants_1.AMM_RESERVE_PRECISION)
72
72
  .div(numericConstants_1.QUOTE_PRECISION);
73
73
  const denom2 = pegged_y_d_d;
74
+ // protocol is spending to increase k
75
+ if (C.lt(numericConstants_1.ZERO)) {
76
+ // thus denom1 is negative and solution is unstable
77
+ if (denom1.lt(pegged_y_d_d.abs())) {
78
+ console.log('budget cost exceeds stable K solution');
79
+ return [new anchor_1.BN(10000), new anchor_1.BN(1)];
80
+ }
81
+ }
74
82
  const numerator = numer1.sub(numer2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
75
83
  const denominator = denom1.add(denom2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
76
84
  return [numerator, denominator];
package/lib/types.d.ts CHANGED
@@ -581,7 +581,7 @@ export declare type PerpPosition = {
581
581
  openOrders: BN;
582
582
  openBids: BN;
583
583
  openAsks: BN;
584
- realizedPnl: BN;
584
+ settledPnl: BN;
585
585
  lpShares: BN;
586
586
  lastFeePerLp: BN;
587
587
  lastNetBaseAssetAmountPerLp: BN;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.2.0-master.27",
3
+ "version": "0.2.0-master.28",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -3199,6 +3199,13 @@ export class ClearingHouse {
3199
3199
  return oracleData;
3200
3200
  }
3201
3201
 
3202
+ public getOracleDataForSpotMarket(marketIndex: BN): OraclePriceData {
3203
+ const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
3204
+ const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
3205
+
3206
+ return oracleData;
3207
+ }
3208
+
3202
3209
  public async initializeInsuranceFundStake(
3203
3210
  marketIndex: BN
3204
3211
  ): Promise<TransactionSignature> {
@@ -142,7 +142,7 @@ export class ClearingHouseUser {
142
142
  openOrders: ZERO,
143
143
  openBids: ZERO,
144
144
  openAsks: ZERO,
145
- realizedPnl: ZERO,
145
+ settledPnl: ZERO,
146
146
  lpShares: ZERO,
147
147
  lastFeePerLp: ZERO,
148
148
  lastNetBaseAssetAmountPerLp: ZERO,
@@ -1071,7 +1071,7 @@ export class ClearingHouseUser {
1071
1071
  openOrders: new BN(0),
1072
1072
  openBids: new BN(0),
1073
1073
  openAsks: new BN(0),
1074
- realizedPnl: ZERO,
1074
+ settledPnl: ZERO,
1075
1075
  lpShares: ZERO,
1076
1076
  lastFeePerLp: ZERO,
1077
1077
  lastNetBaseAssetAmountPerLp: ZERO,
@@ -4586,7 +4586,7 @@
4586
4586
  "type": "i128"
4587
4587
  },
4588
4588
  {
4589
- "name": "realizedPnl",
4589
+ "name": "settledPnl",
4590
4590
  "type": "i64"
4591
4591
  },
4592
4592
  {
@@ -157,7 +157,7 @@ export function calculateUnrealizedAssetWeight(
157
157
  assetWeight = new BN(market.unrealizedInitialAssetWeight);
158
158
 
159
159
  if (market.unrealizedMaxImbalance.gt(ZERO)) {
160
- const netUnsettledPnl = calculateNetUserImbalance(
160
+ const netUnsettledPnl = calculateNetUserPnlImbalance(
161
161
  market,
162
162
  quoteSpotMarket,
163
163
  oraclePriceData
@@ -194,29 +194,38 @@ export function calculateMarketAvailablePNL(
194
194
  );
195
195
  }
196
196
 
197
- export function calculateNetUserImbalance(
198
- market: PerpMarketAccount,
199
- bank: SpotMarketAccount,
197
+ export function calculateNetUserPnl(
198
+ perpMarket: PerpMarketAccount,
200
199
  oraclePriceData: OraclePriceData
201
200
  ): BN {
202
- const netUserPositionValue = market.amm.netBaseAssetAmount
201
+ const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
203
202
  .mul(oraclePriceData.price)
204
203
  .div(BASE_PRECISION)
205
204
  .div(PRICE_TO_QUOTE_PRECISION);
206
205
 
207
- const netUserCostBasis = market.amm.quoteAssetAmountLong
208
- .add(market.amm.quoteAssetAmountShort)
209
- .sub(market.amm.cumulativeSocialLoss);
206
+ const netUserCostBasis = perpMarket.amm.quoteAssetAmountLong
207
+ .add(perpMarket.amm.quoteAssetAmountShort)
208
+ .sub(perpMarket.amm.cumulativeSocialLoss);
209
+
210
+ const netUserPnl = netUserPositionValue.add(netUserCostBasis);
211
+
212
+ return netUserPnl;
213
+ }
210
214
 
211
- const userEntitledPnl = netUserPositionValue.add(netUserCostBasis);
215
+ export function calculateNetUserPnlImbalance(
216
+ perpMarket: PerpMarketAccount,
217
+ spotMarket: SpotMarketAccount,
218
+ oraclePriceData: OraclePriceData
219
+ ): BN {
220
+ const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
212
221
 
213
222
  const pnlPool = getTokenAmount(
214
- market.pnlPool.balance,
215
- bank,
223
+ perpMarket.pnlPool.balance,
224
+ spotMarket,
216
225
  SpotBalanceType.DEPOSIT
217
226
  );
218
227
 
219
- const imbalance = userEntitledPnl.sub(pnlPool);
228
+ const imbalance = netUserPnl.sub(pnlPool);
220
229
 
221
230
  return imbalance;
222
231
  }
@@ -1,4 +1,4 @@
1
- import { BN } from '../';
1
+ import { BN, SpotMarketAccount } from '../';
2
2
  import {
3
3
  AMM_RESERVE_PRECISION,
4
4
  AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
@@ -17,8 +17,8 @@ import {
17
17
  calculateAmmReservesAfterSwap,
18
18
  getSwapDirection,
19
19
  } from './amm';
20
-
21
20
  import { calculateBaseAssetValueWithOracle } from './margin';
21
+ import { calculateNetUserPnlImbalance } from './market';
22
22
 
23
23
  /**
24
24
  * calculateBaseAssetValue
@@ -31,7 +31,9 @@ import { calculateBaseAssetValueWithOracle } from './margin';
31
31
  export function calculateBaseAssetValue(
32
32
  market: PerpMarketAccount,
33
33
  userPosition: PerpPosition,
34
- oraclePriceData: OraclePriceData
34
+ oraclePriceData: OraclePriceData,
35
+ useSpread = true,
36
+ skipUpdate = false
35
37
  ): BN {
36
38
  if (userPosition.baseAssetAmount.eq(ZERO)) {
37
39
  return ZERO;
@@ -40,21 +42,25 @@ export function calculateBaseAssetValue(
40
42
  const directionToClose = findDirectionToClose(userPosition);
41
43
  let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
42
44
 
43
- if (market.amm.baseSpread > 0) {
44
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
45
- calculateUpdatedAMMSpreadReserves(
46
- market.amm,
47
- directionToClose,
48
- oraclePriceData
49
- );
50
- prepegAmm = {
51
- baseAssetReserve,
52
- quoteAssetReserve,
53
- sqrtK: sqrtK,
54
- pegMultiplier: newPeg,
55
- };
45
+ if (!skipUpdate) {
46
+ if (market.amm.baseSpread > 0 && useSpread) {
47
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
48
+ calculateUpdatedAMMSpreadReserves(
49
+ market.amm,
50
+ directionToClose,
51
+ oraclePriceData
52
+ );
53
+ prepegAmm = {
54
+ baseAssetReserve,
55
+ quoteAssetReserve,
56
+ sqrtK: sqrtK,
57
+ pegMultiplier: newPeg,
58
+ };
59
+ } else {
60
+ prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
61
+ }
56
62
  } else {
57
- prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
63
+ prepegAmm = market.amm;
58
64
  }
59
65
 
60
66
  const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
@@ -124,8 +130,9 @@ export function calculatePositionPNL(
124
130
  return pnl;
125
131
  }
126
132
 
127
- export function calculateUnsettledPnl(
133
+ export function calculateClaimablePnl(
128
134
  market: PerpMarketAccount,
135
+ spotMarket: SpotMarketAccount,
129
136
  perpPosition: PerpPosition,
130
137
  oraclePriceData: OraclePriceData
131
138
  ): BN {
@@ -136,16 +143,23 @@ export function calculateUnsettledPnl(
136
143
  oraclePriceData
137
144
  );
138
145
 
139
- let unsettledPnl = unrealizedPnl;
146
+ const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
147
+ PRICE_TO_QUOTE_PRECISION
148
+ );
149
+
150
+ let unsettledPnl = unrealizedPnl.add(fundingPnL);
140
151
  if (unrealizedPnl.gt(ZERO)) {
141
- const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
142
- PRICE_TO_QUOTE_PRECISION
152
+ const excessPnlPool = BN.max(
153
+ ZERO,
154
+ calculateNetUserPnlImbalance(market, spotMarket, oraclePriceData).mul(
155
+ new BN(-1)
156
+ )
143
157
  );
144
158
 
145
159
  const maxPositivePnl = BN.max(
146
160
  perpPosition.quoteAssetAmount
147
161
  .sub(perpPosition.quoteEntryAmount)
148
- .add(fundingPnL),
162
+ .add(excessPnlPool),
149
163
  ZERO
150
164
  );
151
165
 
package/src/math/repeg.ts CHANGED
@@ -98,6 +98,15 @@ export function calculateBudgetedKBN(
98
98
  .div(QUOTE_PRECISION);
99
99
  const denom2 = pegged_y_d_d;
100
100
 
101
+ // protocol is spending to increase k
102
+ if (C.lt(ZERO)) {
103
+ // thus denom1 is negative and solution is unstable
104
+ if (denom1.lt(pegged_y_d_d.abs())) {
105
+ console.log('budget cost exceeds stable K solution');
106
+ return [new BN(10000), new BN(1)];
107
+ }
108
+ }
109
+
101
110
  const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
102
111
  const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
103
112
 
package/src/types.ts CHANGED
@@ -559,7 +559,7 @@ export type PerpPosition = {
559
559
  openOrders: BN;
560
560
  openBids: BN;
561
561
  openAsks: BN;
562
- realizedPnl: BN;
562
+ settledPnl: BN;
563
563
  lpShares: BN;
564
564
  lastFeePerLp: BN;
565
565
  lastNetBaseAssetAmountPerLp: BN;
@@ -20,7 +20,7 @@ export const mockPerpPosition = {
20
20
  openOrders: new BN(0),
21
21
  openBids: new BN(0),
22
22
  openAsks: new BN(0),
23
- realizedPnl: new BN(0),
23
+ settledPnl: new BN(0),
24
24
  lpShares: new BN(0),
25
25
  lastFeePerLp: new BN(0),
26
26
  lastNetBaseAssetAmountPerLp: new BN(0),
@@ -1,26 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getMarketAddress = void 0;
13
- const pda_1 = require("./pda");
14
- const CACHE = new Map();
15
- function getMarketAddress(programId, marketIndex) {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- const cacheKey = `${programId.toString()}-${marketIndex.toString()}`;
18
- if (CACHE.has(cacheKey)) {
19
- return CACHE.get(cacheKey);
20
- }
21
- const publicKey = yield pda_1.getMarketPublicKey(programId, marketIndex);
22
- CACHE.set(cacheKey, publicKey);
23
- return publicKey;
24
- });
25
- }
26
- exports.getMarketAddress = getMarketAddress;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assert = void 0;
4
- function assert(condition, error) {
5
- if (!condition) {
6
- throw new Error(error || 'Unspecified AssertionError');
7
- }
8
- }
9
- exports.assert = assert;
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Banks = exports.MainnetBanks = exports.DevnetBanks = exports.WRAPPED_SOL_MINT = void 0;
4
- const web3_js_1 = require("@solana/web3.js");
5
- const __1 = require("../");
6
- exports.WRAPPED_SOL_MINT = new web3_js_1.PublicKey('So11111111111111111111111111111111111111112');
7
- exports.DevnetBanks = [
8
- {
9
- symbol: 'USDC',
10
- bankIndex: new __1.BN(0),
11
- oracle: web3_js_1.PublicKey.default,
12
- oracleSource: __1.OracleSource.QUOTE_ASSET,
13
- mint: new web3_js_1.PublicKey('8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2'),
14
- },
15
- {
16
- symbol: 'SOL',
17
- bankIndex: new __1.BN(1),
18
- oracle: new web3_js_1.PublicKey('J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'),
19
- oracleSource: __1.OracleSource.PYTH,
20
- mint: new web3_js_1.PublicKey(exports.WRAPPED_SOL_MINT),
21
- },
22
- {
23
- symbol: 'BTC',
24
- bankIndex: new __1.BN(2),
25
- oracle: new web3_js_1.PublicKey('HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'),
26
- oracleSource: __1.OracleSource.PYTH,
27
- mint: new web3_js_1.PublicKey('3BZPwbcqB5kKScF3TEXxwNfx5ipV13kbRVDvfVp5c6fv'),
28
- },
29
- ];
30
- exports.MainnetBanks = [
31
- {
32
- symbol: 'USDC',
33
- bankIndex: new __1.BN(0),
34
- oracle: web3_js_1.PublicKey.default,
35
- oracleSource: __1.OracleSource.QUOTE_ASSET,
36
- mint: new web3_js_1.PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
37
- },
38
- ];
39
- exports.Banks = {
40
- devnet: exports.DevnetBanks,
41
- 'mainnet-beta': exports.MainnetBanks,
42
- };
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Markets = exports.MainnetMarkets = exports.DevnetMarkets = void 0;
4
- const __1 = require("../");
5
- const web3_js_1 = require("@solana/web3.js");
6
- exports.DevnetMarkets = [
7
- {
8
- fullName: 'Solana',
9
- category: ['L1', 'Infra'],
10
- symbol: 'SOL-PERP',
11
- baseAssetSymbol: 'SOL',
12
- marketIndex: new __1.BN(0),
13
- oracle: new web3_js_1.PublicKey('J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'),
14
- launchTs: 1655751353000,
15
- oracleSource: __1.OracleSource.PYTH,
16
- },
17
- {
18
- fullName: 'Bitcoin',
19
- category: ['L1', 'Payment'],
20
- symbol: 'BTC-PERP',
21
- baseAssetSymbol: 'BTC',
22
- marketIndex: new __1.BN(1),
23
- oracle: new web3_js_1.PublicKey('HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'),
24
- launchTs: 1655751353000,
25
- oracleSource: __1.OracleSource.PYTH,
26
- },
27
- {
28
- fullName: 'Ethereum',
29
- category: ['L1', 'Infra'],
30
- symbol: 'ETH-PERP',
31
- baseAssetSymbol: 'ETH',
32
- marketIndex: new __1.BN(2),
33
- oracle: new web3_js_1.PublicKey('EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw'),
34
- launchTs: 1637691133472,
35
- oracleSource: __1.OracleSource.PYTH,
36
- },
37
- ];
38
- exports.MainnetMarkets = [];
39
- exports.Markets = {
40
- devnet: exports.DevnetMarkets,
41
- 'mainnet-beta': [],
42
- };