@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31

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 (208) hide show
  1. package/README.md +13 -13
  2. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  3. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  4. package/lib/accounts/bulkUserSubscription.js +0 -1
  5. package/lib/accounts/fetch.d.ts +2 -1
  6. package/lib/accounts/fetch.js +9 -1
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
  8. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
  9. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  10. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  11. package/lib/accounts/types.d.ts +22 -11
  12. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
  13. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  16. package/lib/addresses/marketAddresses.d.ts +1 -3
  17. package/lib/addresses/pda.d.ts +10 -4
  18. package/lib/addresses/pda.js +51 -14
  19. package/lib/admin.d.ts +42 -26
  20. package/lib/admin.js +228 -81
  21. package/lib/clearingHouse.d.ts +130 -49
  22. package/lib/clearingHouse.js +1256 -367
  23. package/lib/clearingHouseConfig.d.ts +4 -4
  24. package/lib/clearingHouseUser.d.ts +51 -39
  25. package/lib/clearingHouseUser.js +408 -191
  26. package/lib/clearingHouseUserStats.d.ts +18 -0
  27. package/lib/clearingHouseUserStats.js +49 -0
  28. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  29. package/lib/clearingHouseUserStatsConfig.js +2 -0
  30. package/lib/config.d.ts +7 -9
  31. package/lib/config.js +21 -21
  32. package/lib/constants/numericConstants.d.ts +25 -12
  33. package/lib/constants/numericConstants.js +35 -21
  34. package/lib/constants/perpMarkets.d.ts +18 -0
  35. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  36. package/lib/constants/spotMarkets.d.ts +19 -0
  37. package/lib/constants/spotMarkets.js +53 -0
  38. package/lib/dlob/DLOB.d.ts +74 -0
  39. package/lib/dlob/DLOB.js +595 -0
  40. package/lib/dlob/DLOBNode.d.ts +54 -0
  41. package/lib/dlob/DLOBNode.js +85 -0
  42. package/lib/dlob/NodeList.d.ts +26 -0
  43. package/lib/dlob/NodeList.js +139 -0
  44. package/lib/events/eventList.js +3 -0
  45. package/lib/events/eventSubscriber.d.ts +4 -2
  46. package/lib/events/eventSubscriber.js +16 -9
  47. package/lib/events/fetchLogs.d.ts +10 -1
  48. package/lib/events/fetchLogs.js +27 -7
  49. package/lib/events/pollingLogProvider.d.ts +2 -1
  50. package/lib/events/pollingLogProvider.js +6 -2
  51. package/lib/events/sort.js +8 -11
  52. package/lib/events/types.d.ts +8 -2
  53. package/lib/events/types.js +6 -0
  54. package/lib/examples/makeTradeExample.js +20 -8
  55. package/lib/factory/bigNum.d.ts +2 -0
  56. package/lib/factory/bigNum.js +48 -10
  57. package/lib/idl/clearing_house.json +4889 -1529
  58. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  59. package/lib/index.d.ts +21 -6
  60. package/lib/index.js +25 -6
  61. package/lib/math/amm.d.ts +9 -6
  62. package/lib/math/amm.js +91 -66
  63. package/lib/math/auction.js +4 -1
  64. package/lib/math/conversion.js +1 -1
  65. package/lib/math/funding.d.ts +6 -6
  66. package/lib/math/funding.js +11 -10
  67. package/lib/math/insurance.d.ts +4 -0
  68. package/lib/math/insurance.js +27 -0
  69. package/lib/math/margin.d.ts +11 -0
  70. package/lib/math/margin.js +77 -0
  71. package/lib/math/market.d.ts +14 -9
  72. package/lib/math/market.js +72 -10
  73. package/lib/math/oracles.d.ts +4 -0
  74. package/lib/math/oracles.js +36 -8
  75. package/lib/math/orders.d.ts +6 -2
  76. package/lib/math/orders.js +78 -3
  77. package/lib/math/position.d.ts +21 -13
  78. package/lib/math/position.js +76 -36
  79. package/lib/math/repeg.js +14 -5
  80. package/lib/math/spotBalance.d.ts +22 -0
  81. package/lib/math/spotBalance.js +192 -0
  82. package/lib/math/spotMarket.d.ts +4 -0
  83. package/lib/math/spotMarket.js +8 -0
  84. package/lib/math/spotPosition.d.ts +6 -0
  85. package/lib/math/spotPosition.js +23 -0
  86. package/lib/math/trade.d.ts +10 -10
  87. package/lib/math/trade.js +32 -39
  88. package/lib/oracles/pythClient.js +1 -1
  89. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  90. package/lib/oracles/switchboardClient.js +1 -1
  91. package/lib/orderParams.d.ts +14 -5
  92. package/lib/orderParams.js +12 -92
  93. package/lib/serum/serumSubscriber.d.ts +23 -0
  94. package/lib/serum/serumSubscriber.js +41 -0
  95. package/lib/serum/types.d.ts +11 -0
  96. package/lib/serum/types.js +2 -0
  97. package/lib/slot/SlotSubscriber.d.ts +7 -0
  98. package/lib/slot/SlotSubscriber.js +3 -0
  99. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  100. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  101. package/lib/tx/retryTxSender.d.ts +1 -1
  102. package/lib/tx/retryTxSender.js +13 -4
  103. package/lib/tx/types.d.ts +1 -1
  104. package/lib/tx/utils.js +1 -1
  105. package/lib/types.d.ts +566 -138
  106. package/lib/types.js +129 -5
  107. package/lib/userMap/userMap.d.ts +25 -0
  108. package/lib/userMap/userMap.js +73 -0
  109. package/lib/userMap/userStatsMap.d.ts +19 -0
  110. package/lib/userMap/userStatsMap.js +68 -0
  111. package/lib/util/computeUnits.js +1 -1
  112. package/lib/util/getTokenAddress.d.ts +2 -0
  113. package/lib/util/getTokenAddress.js +9 -0
  114. package/package.json +12 -6
  115. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  116. package/src/accounts/bulkUserSubscription.ts +0 -1
  117. package/src/accounts/fetch.ts +27 -2
  118. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
  119. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  120. package/src/accounts/types.ts +31 -11
  121. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
  122. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  123. package/src/addresses/marketAddresses.ts +1 -2
  124. package/src/addresses/pda.ts +88 -14
  125. package/src/admin.ts +452 -147
  126. package/src/assert/assert.js +9 -0
  127. package/src/clearingHouse.ts +2066 -467
  128. package/src/clearingHouseConfig.ts +4 -3
  129. package/src/clearingHouseUser.ts +747 -294
  130. package/src/clearingHouseUserStats.ts +75 -0
  131. package/src/clearingHouseUserStatsConfig.ts +18 -0
  132. package/src/config.ts +30 -31
  133. package/src/constants/numericConstants.ts +48 -25
  134. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  135. package/src/constants/spotMarkets.ts +73 -0
  136. package/src/dlob/DLOB.ts +953 -0
  137. package/src/dlob/DLOBNode.ts +167 -0
  138. package/src/dlob/NodeList.ts +189 -0
  139. package/src/events/eventList.js +77 -0
  140. package/src/events/eventList.ts +3 -0
  141. package/src/events/eventSubscriber.ts +20 -12
  142. package/src/events/fetchLogs.ts +35 -8
  143. package/src/events/pollingLogProvider.ts +10 -2
  144. package/src/events/sort.ts +11 -15
  145. package/src/events/types.ts +19 -1
  146. package/src/examples/makeTradeExample.js +157 -0
  147. package/src/examples/makeTradeExample.ts +32 -14
  148. package/src/factory/bigNum.ts +65 -13
  149. package/src/idl/clearing_house.json +4889 -1529
  150. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  151. package/src/index.ts +21 -6
  152. package/src/math/amm.ts +171 -88
  153. package/src/math/auction.ts +5 -1
  154. package/src/math/conversion.ts +2 -2
  155. package/src/math/funding.ts +20 -18
  156. package/src/math/insurance.ts +35 -0
  157. package/src/math/margin.ts +127 -0
  158. package/src/math/market.ts +145 -14
  159. package/src/math/oracles.ts +63 -9
  160. package/src/math/orders.ts +138 -4
  161. package/src/math/position.ts +119 -58
  162. package/src/math/repeg.ts +16 -6
  163. package/src/math/spotBalance.ts +319 -0
  164. package/src/math/spotMarket.ts +9 -0
  165. package/src/math/spotPosition.ts +47 -0
  166. package/src/math/trade.ts +53 -59
  167. package/src/oracles/pythClient.ts +2 -2
  168. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  169. package/src/oracles/switchboardClient.ts +2 -2
  170. package/src/orderParams.ts +24 -137
  171. package/src/serum/serumSubscriber.ts +80 -0
  172. package/src/serum/types.ts +13 -0
  173. package/src/slot/SlotSubscriber.ts +11 -1
  174. package/src/token/index.js +38 -0
  175. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  176. package/src/tx/retryTxSender.ts +16 -5
  177. package/src/tx/types.js +2 -0
  178. package/src/tx/types.ts +2 -1
  179. package/src/tx/utils.js +17 -0
  180. package/src/tx/utils.ts +1 -1
  181. package/src/types.ts +533 -140
  182. package/src/userMap/userMap.ts +100 -0
  183. package/src/userMap/userStatsMap.ts +110 -0
  184. package/src/util/computeUnits.js +21 -11
  185. package/src/util/computeUnits.ts +1 -1
  186. package/src/util/getTokenAddress.js +9 -0
  187. package/src/util/getTokenAddress.ts +18 -0
  188. package/src/util/promiseTimeout.js +14 -0
  189. package/src/util/tps.js +27 -0
  190. package/tests/bn/test.ts +24 -10
  191. package/tests/dlob/helpers.ts +397 -0
  192. package/tests/dlob/test.ts +3688 -0
  193. package/lib/constants/banks.d.ts +0 -16
  194. package/lib/constants/banks.js +0 -34
  195. package/lib/constants/markets.d.ts +0 -19
  196. package/lib/math/bankBalance.d.ts +0 -9
  197. package/lib/math/bankBalance.js +0 -75
  198. package/lib/math/state.d.ts +0 -8
  199. package/lib/math/state.js +0 -15
  200. package/lib/orders.d.ts +0 -8
  201. package/lib/orders.js +0 -134
  202. package/src/constants/banks.ts +0 -43
  203. package/src/math/bankBalance.ts +0 -112
  204. package/src/math/state.ts +0 -14
  205. package/src/math/utils.js +0 -27
  206. package/src/math/utils.js.map +0 -1
  207. package/src/orders.ts +0 -244
  208. package/src/util/computeUnits.js.map +0 -1
@@ -1,9 +1,20 @@
1
1
  import { ClearingHouseUser } from '../clearingHouseUser';
2
- import { isOneOfVariant, isVariant, Order } from '../types';
2
+ import {
3
+ isOneOfVariant,
4
+ isVariant,
5
+ PerpMarketAccount,
6
+ Order,
7
+ PositionDirection,
8
+ } from '../types';
3
9
  import { ZERO, TWO } from '../constants/numericConstants';
4
10
  import { BN } from '@project-serum/anchor';
5
11
  import { OraclePriceData } from '../oracles/types';
6
- import { getAuctionPrice } from './auction';
12
+ import { getAuctionPrice, isAuctionComplete } from './auction';
13
+ import { calculateAskPrice, calculateBidPrice } from './market';
14
+ import {
15
+ calculateMaxBaseAssetAmountFillable,
16
+ calculateMaxBaseAssetAmountToTrade,
17
+ } from './amm';
7
18
 
8
19
  export function isOrderRiskIncreasing(
9
20
  user: ClearingHouseUser,
@@ -121,16 +132,139 @@ export function standardizeBaseAssetAmount(
121
132
  export function getLimitPrice(
122
133
  order: Order,
123
134
  oraclePriceData: OraclePriceData,
124
- slot: number
135
+ slot: number,
136
+ perpMarket?: PerpMarketAccount
125
137
  ): BN {
126
138
  let limitPrice;
127
139
  if (!order.oraclePriceOffset.eq(ZERO)) {
128
140
  limitPrice = oraclePriceData.price.add(order.oraclePriceOffset);
129
141
  } else if (isOneOfVariant(order.orderType, ['market', 'triggerMarket'])) {
130
- limitPrice = getAuctionPrice(order, slot);
142
+ if (!isAuctionComplete(order, slot)) {
143
+ limitPrice = getAuctionPrice(order, slot);
144
+ } else if (!order.price.eq(ZERO)) {
145
+ limitPrice = order.price;
146
+ } else {
147
+ if (perpMarket) {
148
+ if (isVariant(order.direction, 'long')) {
149
+ const askPrice = calculateAskPrice(perpMarket, oraclePriceData);
150
+ const delta = askPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
151
+ limitPrice = askPrice.add(delta);
152
+ } else {
153
+ const bidPrice = calculateBidPrice(perpMarket, oraclePriceData);
154
+ const delta = bidPrice.div(new BN(perpMarket.amm.maxSlippageRatio));
155
+ limitPrice = bidPrice.sub(delta);
156
+ }
157
+ } else {
158
+ // check oracle validity?
159
+ const oraclePrice1Pct = oraclePriceData.price.div(new BN(100));
160
+ if (isVariant(order.direction, 'long')) {
161
+ limitPrice = oraclePriceData.price.add(oraclePrice1Pct);
162
+ } else {
163
+ limitPrice = oraclePriceData.price.sub(oraclePrice1Pct);
164
+ }
165
+ }
166
+ }
131
167
  } else {
132
168
  limitPrice = order.price;
133
169
  }
134
170
 
135
171
  return limitPrice;
136
172
  }
173
+
174
+ export function isFillableByVAMM(
175
+ order: Order,
176
+ market: PerpMarketAccount,
177
+ oraclePriceData: OraclePriceData,
178
+ slot: number
179
+ ): boolean {
180
+ return (
181
+ (isAuctionComplete(order, slot) &&
182
+ !calculateBaseAssetAmountForAmmToFulfill(
183
+ order,
184
+ market,
185
+ oraclePriceData,
186
+ slot
187
+ ).eq(ZERO)) ||
188
+ isOrderExpired(order, slot)
189
+ );
190
+ }
191
+
192
+ export function calculateBaseAssetAmountForAmmToFulfill(
193
+ order: Order,
194
+ market: PerpMarketAccount,
195
+ oraclePriceData: OraclePriceData,
196
+ slot: number
197
+ ): BN {
198
+ if (
199
+ isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) &&
200
+ order.triggered === false
201
+ ) {
202
+ return ZERO;
203
+ }
204
+
205
+ const limitPrice = getLimitPrice(order, oraclePriceData, slot, market);
206
+ const baseAssetAmount = calculateBaseAssetAmountToFillUpToLimitPrice(
207
+ order,
208
+ market,
209
+ limitPrice,
210
+ oraclePriceData
211
+ );
212
+
213
+ const maxBaseAssetAmount = calculateMaxBaseAssetAmountFillable(
214
+ market.amm,
215
+ order.direction
216
+ );
217
+
218
+ return BN.min(maxBaseAssetAmount, baseAssetAmount);
219
+ }
220
+
221
+ export function calculateBaseAssetAmountToFillUpToLimitPrice(
222
+ order: Order,
223
+ market: PerpMarketAccount,
224
+ limitPrice: BN,
225
+ oraclePriceData: OraclePriceData
226
+ ): BN {
227
+ const [maxAmountToTrade, direction] = calculateMaxBaseAssetAmountToTrade(
228
+ market.amm,
229
+ limitPrice,
230
+ order.direction,
231
+ oraclePriceData
232
+ );
233
+
234
+ const baseAssetAmount = standardizeBaseAssetAmount(
235
+ maxAmountToTrade,
236
+ market.amm.baseAssetAmountStepSize
237
+ );
238
+
239
+ // Check that directions are the same
240
+ const sameDirection = isSameDirection(direction, order.direction);
241
+ if (!sameDirection) {
242
+ return ZERO;
243
+ }
244
+
245
+ return baseAssetAmount.gt(order.baseAssetAmount)
246
+ ? order.baseAssetAmount
247
+ : baseAssetAmount;
248
+ }
249
+
250
+ function isSameDirection(
251
+ firstDirection: PositionDirection,
252
+ secondDirection: PositionDirection
253
+ ): boolean {
254
+ return (
255
+ (isVariant(firstDirection, 'long') && isVariant(secondDirection, 'long')) ||
256
+ (isVariant(firstDirection, 'short') && isVariant(secondDirection, 'short'))
257
+ );
258
+ }
259
+
260
+ export function isOrderExpired(order: Order, slot: number): boolean {
261
+ if (
262
+ isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) ||
263
+ !isVariant(order.status, 'open') ||
264
+ order.timeInForce === 0
265
+ ) {
266
+ return false;
267
+ }
268
+
269
+ return new BN(slot).sub(order.slot).gt(new BN(order.timeInForce));
270
+ }
@@ -1,22 +1,23 @@
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,
5
5
  AMM_TO_QUOTE_PRECISION_RATIO,
6
- FUNDING_PAYMENT_PRECISION,
7
- MARK_PRICE_PRECISION,
6
+ FUNDING_RATE_BUFFER_PRECISION,
7
+ PRICE_PRECISION,
8
8
  ONE,
9
- PRICE_TO_QUOTE_PRECISION,
10
9
  ZERO,
11
10
  } from '../constants/numericConstants';
12
11
  import { OraclePriceData } from '../oracles/types';
13
- import { MarketAccount, PositionDirection, UserPosition } from '../types';
12
+ import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
14
13
  import {
15
14
  calculateUpdatedAMM,
16
15
  calculateUpdatedAMMSpreadReserves,
17
16
  calculateAmmReservesAfterSwap,
18
17
  getSwapDirection,
19
18
  } from './amm';
19
+ import { calculateBaseAssetValueWithOracle } from './margin';
20
+ import { calculateNetUserPnlImbalance } from './market';
20
21
 
21
22
  /**
22
23
  * calculateBaseAssetValue
@@ -27,9 +28,11 @@ import {
27
28
  * @returns Base Asset Value. : Precision QUOTE_PRECISION
28
29
  */
29
30
  export function calculateBaseAssetValue(
30
- market: MarketAccount,
31
- userPosition: UserPosition,
32
- oraclePriceData: OraclePriceData
31
+ market: PerpMarketAccount,
32
+ userPosition: PerpPosition,
33
+ oraclePriceData: OraclePriceData,
34
+ useSpread = true,
35
+ skipUpdate = false
33
36
  ): BN {
34
37
  if (userPosition.baseAssetAmount.eq(ZERO)) {
35
38
  return ZERO;
@@ -38,21 +41,25 @@ export function calculateBaseAssetValue(
38
41
  const directionToClose = findDirectionToClose(userPosition);
39
42
  let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
40
43
 
41
- if (market.amm.baseSpread > 0) {
42
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
43
- calculateUpdatedAMMSpreadReserves(
44
- market.amm,
45
- directionToClose,
46
- oraclePriceData
47
- );
48
- prepegAmm = {
49
- baseAssetReserve,
50
- quoteAssetReserve,
51
- sqrtK: sqrtK,
52
- pegMultiplier: newPeg,
53
- };
44
+ if (!skipUpdate) {
45
+ if (market.amm.baseSpread > 0 && useSpread) {
46
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
47
+ calculateUpdatedAMMSpreadReserves(
48
+ market.amm,
49
+ directionToClose,
50
+ oraclePriceData
51
+ );
52
+ prepegAmm = {
53
+ baseAssetReserve,
54
+ quoteAssetReserve,
55
+ sqrtK: sqrtK,
56
+ pegMultiplier: newPeg,
57
+ };
58
+ } else {
59
+ prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
60
+ }
54
61
  } else {
55
- prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
62
+ prepegAmm = market.amm;
56
63
  }
57
64
 
58
65
  const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
@@ -82,38 +89,36 @@ export function calculateBaseAssetValue(
82
89
  * calculatePositionPNL
83
90
  * = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
84
91
  * @param market
85
- * @param marketPosition
92
+ * @param PerpPosition
86
93
  * @param withFunding (adds unrealized funding payment pnl to result)
94
+ * @param oraclePriceData
87
95
  * @returns BaseAssetAmount : Precision QUOTE_PRECISION
88
96
  */
89
97
  export function calculatePositionPNL(
90
- market: MarketAccount,
91
- marketPosition: UserPosition,
98
+ market: PerpMarketAccount,
99
+ perpPosition: PerpPosition,
92
100
  withFunding = false,
93
101
  oraclePriceData: OraclePriceData
94
102
  ): BN {
95
- if (marketPosition.baseAssetAmount.eq(ZERO)) {
96
- return ZERO;
103
+ if (perpPosition.baseAssetAmount.eq(ZERO)) {
104
+ return perpPosition.quoteAssetAmount;
97
105
  }
98
106
 
99
- const baseAssetValue = calculateBaseAssetValue(
107
+ const baseAssetValue = calculateBaseAssetValueWithOracle(
100
108
  market,
101
- marketPosition,
109
+ perpPosition,
102
110
  oraclePriceData
103
111
  );
104
112
 
105
- let pnl;
106
- if (marketPosition.baseAssetAmount.gt(ZERO)) {
107
- pnl = baseAssetValue.sub(marketPosition.quoteAssetAmount);
108
- } else {
109
- pnl = marketPosition.quoteAssetAmount.sub(baseAssetValue);
110
- }
113
+ const baseAssetValueSign = perpPosition.baseAssetAmount.isNeg()
114
+ ? new BN(-1)
115
+ : new BN(1);
116
+ let pnl = baseAssetValue
117
+ .mul(baseAssetValueSign)
118
+ .add(perpPosition.quoteAssetAmount);
111
119
 
112
120
  if (withFunding) {
113
- const fundingRatePnL = calculatePositionFundingPNL(
114
- market,
115
- marketPosition
116
- ).div(PRICE_TO_QUOTE_PRECISION);
121
+ const fundingRatePnL = calculatePositionFundingPNL(market, perpPosition);
117
122
 
118
123
  pnl = pnl.add(fundingRatePnL);
119
124
  }
@@ -121,60 +126,118 @@ export function calculatePositionPNL(
121
126
  return pnl;
122
127
  }
123
128
 
129
+ export function calculateClaimablePnl(
130
+ market: PerpMarketAccount,
131
+ spotMarket: SpotMarketAccount,
132
+ perpPosition: PerpPosition,
133
+ oraclePriceData: OraclePriceData
134
+ ): BN {
135
+ const unrealizedPnl = calculatePositionPNL(
136
+ market,
137
+ perpPosition,
138
+ true,
139
+ oraclePriceData
140
+ );
141
+
142
+ const fundingPnL = calculatePositionFundingPNL(market, perpPosition);
143
+
144
+ let unsettledPnl = unrealizedPnl.add(fundingPnL);
145
+ if (unrealizedPnl.gt(ZERO)) {
146
+ const excessPnlPool = BN.max(
147
+ ZERO,
148
+ calculateNetUserPnlImbalance(market, spotMarket, oraclePriceData).mul(
149
+ new BN(-1)
150
+ )
151
+ );
152
+
153
+ const maxPositivePnl = BN.max(
154
+ perpPosition.quoteAssetAmount
155
+ .sub(perpPosition.quoteEntryAmount)
156
+ .add(excessPnlPool),
157
+ ZERO
158
+ );
159
+
160
+ unsettledPnl = BN.min(maxPositivePnl, unrealizedPnl);
161
+ }
162
+ return unsettledPnl;
163
+ }
164
+
124
165
  /**
125
166
  *
126
167
  * @param market
127
- * @param marketPosition
168
+ * @param PerpPosition
128
169
  * @returns // TODO-PRECISION
129
170
  */
130
171
  export function calculatePositionFundingPNL(
131
- market: MarketAccount,
132
- marketPosition: UserPosition
172
+ market: PerpMarketAccount,
173
+ perpPosition: PerpPosition
133
174
  ): BN {
134
- if (marketPosition.baseAssetAmount.eq(ZERO)) {
175
+ if (perpPosition.baseAssetAmount.eq(ZERO)) {
135
176
  return ZERO;
136
177
  }
137
178
 
138
179
  let ammCumulativeFundingRate: BN;
139
- if (marketPosition.baseAssetAmount.gt(ZERO)) {
180
+ if (perpPosition.baseAssetAmount.gt(ZERO)) {
140
181
  ammCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
141
182
  } else {
142
183
  ammCumulativeFundingRate = market.amm.cumulativeFundingRateShort;
143
184
  }
144
185
 
145
186
  const perPositionFundingRate = ammCumulativeFundingRate
146
- .sub(marketPosition.lastCumulativeFundingRate)
147
- .mul(marketPosition.baseAssetAmount)
187
+ .sub(perpPosition.lastCumulativeFundingRate)
188
+ .mul(perpPosition.baseAssetAmount)
148
189
  .div(AMM_RESERVE_PRECISION)
149
- .div(FUNDING_PAYMENT_PRECISION)
190
+ .div(FUNDING_RATE_BUFFER_PRECISION)
150
191
  .mul(new BN(-1));
151
192
 
152
193
  return perPositionFundingRate;
153
194
  }
154
195
 
155
- export function positionIsAvailable(position: UserPosition): boolean {
156
- return position.baseAssetAmount.eq(ZERO) && position.openOrders.eq(ZERO);
196
+ export function positionIsAvailable(position: PerpPosition): boolean {
197
+ return (
198
+ position.baseAssetAmount.eq(ZERO) &&
199
+ position.openOrders === 0 &&
200
+ position.quoteAssetAmount.eq(ZERO) &&
201
+ position.lpShares.eq(ZERO)
202
+ );
157
203
  }
158
204
 
159
205
  /**
160
206
  *
161
207
  * @param userPosition
162
- * @returns Precision: MARK_PRICE_PRECISION (10^10)
208
+ * @returns Precision: PRICE_PRECISION (10^10)
163
209
  */
164
- export function calculateEntryPrice(userPosition: UserPosition): BN {
210
+ export function calculateEntryPrice(userPosition: PerpPosition): BN {
211
+ if (userPosition.baseAssetAmount.eq(ZERO)) {
212
+ return ZERO;
213
+ }
214
+
215
+ return userPosition.quoteEntryAmount
216
+ .mul(PRICE_PRECISION)
217
+ .mul(AMM_TO_QUOTE_PRECISION_RATIO)
218
+ .div(userPosition.baseAssetAmount)
219
+ .abs();
220
+ }
221
+
222
+ /**
223
+ *
224
+ * @param userPosition
225
+ * @returns Precision: PRICE_PRECISION (10^10)
226
+ */
227
+ export function calculateCostBasis(userPosition: PerpPosition): BN {
165
228
  if (userPosition.baseAssetAmount.eq(ZERO)) {
166
229
  return ZERO;
167
230
  }
168
231
 
169
232
  return userPosition.quoteAssetAmount
170
- .mul(MARK_PRICE_PRECISION)
233
+ .mul(PRICE_PRECISION)
171
234
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)
172
235
  .div(userPosition.baseAssetAmount)
173
236
  .abs();
174
237
  }
175
238
 
176
239
  export function findDirectionToClose(
177
- userPosition: UserPosition
240
+ userPosition: PerpPosition
178
241
  ): PositionDirection {
179
242
  return userPosition.baseAssetAmount.gt(ZERO)
180
243
  ? PositionDirection.SHORT
@@ -182,15 +245,13 @@ export function findDirectionToClose(
182
245
  }
183
246
 
184
247
  export function positionCurrentDirection(
185
- userPosition: UserPosition
248
+ userPosition: PerpPosition
186
249
  ): PositionDirection {
187
250
  return userPosition.baseAssetAmount.gte(ZERO)
188
251
  ? PositionDirection.LONG
189
252
  : PositionDirection.SHORT;
190
253
  }
191
254
 
192
- export function isEmptyPosition(userPosition: UserPosition): boolean {
193
- return (
194
- userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders.eq(ZERO)
195
- );
255
+ export function isEmptyPosition(userPosition: PerpPosition): boolean {
256
+ return userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders === 0;
196
257
  }
package/src/math/repeg.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { BN } from '@project-serum/anchor';
2
2
  import { assert } from '../assert/assert';
3
3
  import {
4
- MARK_PRICE_PRECISION,
4
+ PRICE_PRECISION,
5
5
  AMM_RESERVE_PRECISION,
6
6
  PEG_PRECISION,
7
7
  AMM_TO_QUOTE_PRECISION_RATIO,
@@ -31,15 +31,15 @@ export function calculateAdjustKCost(
31
31
 
32
32
  const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
33
33
 
34
- const p = numerator.mul(MARK_PRICE_PRECISION).div(denomenator);
34
+ const p = numerator.mul(PRICE_PRECISION).div(denomenator);
35
35
 
36
36
  const cost = quoteScale
37
37
  .div(x.add(d))
38
38
  .sub(
39
39
  quoteScale
40
40
  .mul(p)
41
- .div(MARK_PRICE_PRECISION)
42
- .div(x.mul(p).div(MARK_PRICE_PRECISION).add(d))
41
+ .div(PRICE_PRECISION)
42
+ .div(x.mul(p).div(PRICE_PRECISION).add(d))
43
43
  )
44
44
  .div(AMM_TO_QUOTE_PRECISION_RATIO)
45
45
  .div(PEG_PRECISION);
@@ -98,6 +98,16 @@ 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.abs().gt(denom2.abs())) {
105
+ console.log('denom1 > denom2', denom1.toString(), denom2.toString());
106
+ console.log('budget cost exceeds stable K solution');
107
+ return [new BN(10000), new BN(1)];
108
+ }
109
+ }
110
+
101
111
  const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
102
112
  const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
103
113
 
@@ -165,11 +175,11 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
165
175
  return targetPeg;
166
176
  }
167
177
 
168
- const deltaPegMultiplier = C.mul(MARK_PRICE_PRECISION).div(
178
+ const deltaPegMultiplier = C.mul(PRICE_PRECISION).div(
169
179
  deltaQuoteAssetReserves.div(AMM_TO_QUOTE_PRECISION_RATIO)
170
180
  );
171
181
  const newPeg = Q.sub(
172
- deltaPegMultiplier.mul(PEG_PRECISION).div(MARK_PRICE_PRECISION)
182
+ deltaPegMultiplier.mul(PEG_PRECISION).div(PRICE_PRECISION)
173
183
  );
174
184
 
175
185
  return newPeg;