@drift-labs/sdk 0.2.0-master.4 → 0.2.0-master.41

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 (247) hide show
  1. package/README.md +27 -27
  2. package/lib/accounts/bulkAccountLoader.d.ts +2 -0
  3. package/lib/accounts/bulkAccountLoader.js +36 -29
  4. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  5. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  6. package/lib/accounts/bulkUserSubscription.d.ts +2 -2
  7. package/lib/accounts/bulkUserSubscription.js +0 -1
  8. package/lib/accounts/fetch.d.ts +2 -1
  9. package/lib/accounts/fetch.js +9 -1
  10. package/lib/accounts/{pollingClearingHouseAccountSubscriber.d.ts → pollingDriftClientAccountSubscriber.d.ts} +20 -25
  11. package/lib/accounts/{pollingClearingHouseAccountSubscriber.js → pollingDriftClientAccountSubscriber.js} +45 -49
  12. package/lib/accounts/{pollingOracleSubscriber.d.ts → pollingOracleAccountSubscriber.d.ts} +2 -2
  13. package/lib/accounts/{pollingOracleSubscriber.js → pollingOracleAccountSubscriber.js} +3 -3
  14. package/lib/accounts/pollingUserAccountSubscriber.d.ts +1 -1
  15. package/lib/accounts/pollingUserAccountSubscriber.js +5 -11
  16. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  17. package/lib/accounts/pollingUserStatsAccountSubscriber.js +107 -0
  18. package/lib/accounts/types.d.ts +26 -15
  19. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +49 -0
  20. package/lib/accounts/{webSocketClearingHouseAccountSubscriber.js → webSocketDriftClientAccountSubscriber.js} +47 -45
  21. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  22. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  23. package/lib/addresses/marketAddresses.d.ts +1 -3
  24. package/lib/addresses/marketAddresses.js +1 -1
  25. package/lib/addresses/pda.d.ts +15 -9
  26. package/lib/addresses/pda.js +73 -35
  27. package/lib/adminClient.d.ts +65 -0
  28. package/lib/adminClient.js +637 -0
  29. package/lib/config.d.ts +9 -9
  30. package/lib/config.js +25 -21
  31. package/lib/constants/numericConstants.d.ts +30 -12
  32. package/lib/constants/numericConstants.js +41 -21
  33. package/lib/constants/perpMarkets.d.ts +18 -0
  34. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  35. package/lib/constants/spotMarkets.d.ts +19 -0
  36. package/lib/constants/spotMarkets.js +53 -0
  37. package/lib/dlob/DLOB.d.ts +82 -0
  38. package/lib/dlob/DLOB.js +694 -0
  39. package/lib/dlob/DLOBNode.d.ts +54 -0
  40. package/lib/dlob/DLOBNode.js +77 -0
  41. package/lib/dlob/NodeList.d.ts +27 -0
  42. package/lib/dlob/NodeList.js +144 -0
  43. package/lib/driftClient.d.ts +234 -0
  44. package/lib/driftClient.js +2108 -0
  45. package/lib/{clearingHouseConfig.d.ts → driftClientConfig.d.ts} +9 -9
  46. package/lib/{clearingHouseConfig.js → driftClientConfig.js} +0 -0
  47. package/lib/events/eventList.js +3 -0
  48. package/lib/events/eventSubscriber.d.ts +5 -2
  49. package/lib/events/eventSubscriber.js +25 -11
  50. package/lib/events/fetchLogs.d.ts +13 -2
  51. package/lib/events/fetchLogs.js +40 -12
  52. package/lib/events/pollingLogProvider.d.ts +2 -1
  53. package/lib/events/pollingLogProvider.js +7 -3
  54. package/lib/events/sort.js +8 -11
  55. package/lib/events/types.d.ts +11 -3
  56. package/lib/events/types.js +8 -0
  57. package/lib/events/webSocketLogProvider.js +1 -1
  58. package/lib/examples/makeTradeExample.js +30 -18
  59. package/lib/factory/bigNum.d.ts +8 -4
  60. package/lib/factory/bigNum.js +109 -19
  61. package/lib/idl/drift.json +8386 -0
  62. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  63. package/lib/index.d.ts +30 -13
  64. package/lib/index.js +30 -13
  65. package/lib/math/amm.d.ts +9 -6
  66. package/lib/math/amm.js +91 -38
  67. package/lib/math/conversion.js +1 -1
  68. package/lib/math/exchangeStatus.d.ts +4 -0
  69. package/lib/math/exchangeStatus.js +18 -0
  70. package/lib/math/funding.d.ts +6 -6
  71. package/lib/math/funding.js +23 -21
  72. package/lib/math/insurance.d.ts +4 -0
  73. package/lib/math/insurance.js +27 -0
  74. package/lib/math/margin.d.ts +11 -0
  75. package/lib/math/margin.js +82 -0
  76. package/lib/math/market.d.ts +14 -9
  77. package/lib/math/market.js +70 -10
  78. package/lib/math/oracles.d.ts +4 -0
  79. package/lib/math/oracles.js +36 -8
  80. package/lib/math/orders.d.ts +16 -6
  81. package/lib/math/orders.js +97 -17
  82. package/lib/math/position.d.ts +27 -13
  83. package/lib/math/position.js +92 -36
  84. package/lib/math/repeg.js +17 -8
  85. package/lib/math/spotBalance.d.ts +22 -0
  86. package/lib/math/spotBalance.js +192 -0
  87. package/lib/math/spotMarket.d.ts +4 -0
  88. package/lib/math/spotMarket.js +8 -0
  89. package/lib/math/spotPosition.d.ts +6 -0
  90. package/lib/math/spotPosition.js +23 -0
  91. package/lib/math/trade.d.ts +10 -10
  92. package/lib/math/trade.js +27 -31
  93. package/lib/oracles/pythClient.js +1 -1
  94. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  95. package/lib/oracles/switchboardClient.js +1 -1
  96. package/lib/orderParams.d.ts +4 -4
  97. package/lib/orderParams.js +12 -4
  98. package/lib/serum/serumFulfillmentConfigMap.d.ts +10 -0
  99. package/lib/serum/serumFulfillmentConfigMap.js +17 -0
  100. package/lib/serum/serumSubscriber.d.ts +27 -0
  101. package/lib/serum/serumSubscriber.js +56 -0
  102. package/lib/serum/types.d.ts +11 -0
  103. package/lib/{clearingHouseUserConfig.js → serum/types.js} +0 -0
  104. package/lib/slot/SlotSubscriber.d.ts +7 -0
  105. package/lib/slot/SlotSubscriber.js +3 -0
  106. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  107. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  108. package/lib/tx/retryTxSender.d.ts +1 -1
  109. package/lib/tx/retryTxSender.js +13 -4
  110. package/lib/tx/types.d.ts +1 -1
  111. package/lib/tx/utils.js +1 -1
  112. package/lib/types.d.ts +688 -216
  113. package/lib/types.js +153 -24
  114. package/lib/user.d.ts +228 -0
  115. package/lib/user.js +959 -0
  116. package/lib/userConfig.d.ts +14 -0
  117. package/lib/userConfig.js +2 -0
  118. package/lib/userMap/userMap.d.ts +41 -0
  119. package/lib/userMap/userMap.js +85 -0
  120. package/lib/userMap/userStatsMap.d.ts +19 -0
  121. package/lib/userMap/userStatsMap.js +68 -0
  122. package/lib/userName.d.ts +1 -0
  123. package/lib/userName.js +3 -2
  124. package/lib/userStats.d.ts +18 -0
  125. package/lib/userStats.js +49 -0
  126. package/lib/userStatsConfig.d.ts +14 -0
  127. package/lib/userStatsConfig.js +2 -0
  128. package/lib/util/computeUnits.js +1 -1
  129. package/lib/util/getTokenAddress.d.ts +2 -0
  130. package/lib/util/getTokenAddress.js +9 -0
  131. package/package.json +11 -4
  132. package/src/accounts/bulkAccountLoader.ts +44 -34
  133. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  134. package/src/accounts/bulkUserSubscription.ts +2 -3
  135. package/src/accounts/fetch.ts +27 -2
  136. package/src/accounts/{pollingClearingHouseAccountSubscriber.ts → pollingDriftClientAccountSubscriber.ts} +65 -75
  137. package/src/accounts/{pollingOracleSubscriber.ts → pollingOracleAccountSubscriber.ts} +2 -2
  138. package/src/accounts/pollingUserAccountSubscriber.ts +5 -12
  139. package/src/accounts/pollingUserStatsAccountSubscriber.ts +166 -0
  140. package/src/accounts/types.ts +35 -15
  141. package/src/accounts/{webSocketClearingHouseAccountSubscriber.ts → webSocketDriftClientAccountSubscriber.ts} +78 -73
  142. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  143. package/src/addresses/marketAddresses.ts +3 -4
  144. package/src/addresses/pda.ts +105 -33
  145. package/src/adminClient.ts +1207 -0
  146. package/src/assert/assert.js +9 -0
  147. package/src/config.ts +37 -31
  148. package/src/constants/numericConstants.ts +58 -24
  149. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  150. package/src/constants/spotMarkets.ts +73 -0
  151. package/src/dlob/DLOB.ts +1120 -0
  152. package/src/dlob/DLOBNode.ts +155 -0
  153. package/src/dlob/NodeList.ts +195 -0
  154. package/src/driftClient.ts +3594 -0
  155. package/src/{clearingHouseConfig.ts → driftClientConfig.ts} +9 -8
  156. package/src/events/eventList.js +77 -0
  157. package/src/events/eventList.ts +3 -0
  158. package/src/events/eventSubscriber.ts +36 -14
  159. package/src/events/fetchLogs.ts +55 -13
  160. package/src/events/pollingLogProvider.ts +11 -3
  161. package/src/events/sort.ts +11 -15
  162. package/src/events/types.ts +27 -2
  163. package/src/events/webSocketLogProvider.ts +1 -1
  164. package/src/examples/makeTradeExample.js +157 -0
  165. package/src/examples/makeTradeExample.ts +44 -28
  166. package/src/factory/bigNum.ts +150 -22
  167. package/src/idl/drift.json +8386 -0
  168. package/src/idl/pyth.json +98 -2
  169. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  170. package/src/index.ts +30 -13
  171. package/src/math/amm.ts +161 -48
  172. package/src/math/conversion.ts +2 -2
  173. package/src/math/exchangeStatus.ts +31 -0
  174. package/src/math/funding.ts +41 -31
  175. package/src/math/insurance.ts +35 -0
  176. package/src/math/margin.ts +133 -0
  177. package/src/math/market.ts +143 -14
  178. package/src/math/oracles.ts +63 -9
  179. package/src/math/orders.ts +168 -26
  180. package/src/math/position.ts +136 -58
  181. package/src/math/repeg.ts +19 -9
  182. package/src/math/spotBalance.ts +319 -0
  183. package/src/math/spotMarket.ts +9 -0
  184. package/src/math/spotPosition.ts +47 -0
  185. package/src/math/trade.ts +33 -37
  186. package/src/oracles/pythClient.ts +2 -2
  187. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  188. package/src/oracles/switchboardClient.ts +2 -2
  189. package/src/orderParams.ts +16 -8
  190. package/src/serum/serumFulfillmentConfigMap.ts +26 -0
  191. package/src/serum/serumSubscriber.ts +99 -0
  192. package/src/serum/types.ts +13 -0
  193. package/src/slot/SlotSubscriber.ts +11 -1
  194. package/src/token/index.js +38 -0
  195. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  196. package/src/tx/retryTxSender.ts +16 -5
  197. package/src/tx/types.js +2 -0
  198. package/src/tx/types.ts +2 -1
  199. package/src/tx/utils.js +17 -0
  200. package/src/tx/utils.ts +1 -1
  201. package/src/types.ts +650 -189
  202. package/src/user.ts +1599 -0
  203. package/src/{clearingHouseUserConfig.ts → userConfig.ts} +5 -5
  204. package/src/userMap/userMap.ts +124 -0
  205. package/src/userMap/userStatsMap.ts +108 -0
  206. package/src/userName.ts +2 -1
  207. package/src/userStats.ts +75 -0
  208. package/src/userStatsConfig.ts +18 -0
  209. package/src/util/computeUnits.js +21 -11
  210. package/src/util/computeUnits.ts +1 -1
  211. package/src/util/getTokenAddress.js +9 -0
  212. package/src/util/getTokenAddress.ts +18 -0
  213. package/src/util/promiseTimeout.js +14 -0
  214. package/src/util/tps.js +27 -0
  215. package/tests/bn/test.ts +46 -11
  216. package/tests/dlob/helpers.ts +620 -0
  217. package/tests/dlob/test.ts +4586 -0
  218. package/yarn-error.log +3160 -0
  219. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +0 -49
  220. package/lib/admin.d.ts +0 -44
  221. package/lib/admin.js +0 -433
  222. package/lib/clearingHouse.d.ts +0 -133
  223. package/lib/clearingHouse.js +0 -931
  224. package/lib/clearingHouseUser.d.ts +0 -187
  225. package/lib/clearingHouseUser.js +0 -643
  226. package/lib/clearingHouseUserConfig.d.ts +0 -14
  227. package/lib/constants/banks.d.ts +0 -16
  228. package/lib/constants/banks.js +0 -34
  229. package/lib/constants/markets.d.ts +0 -19
  230. package/lib/idl/clearing_house.json +0 -3998
  231. package/lib/math/bankBalance.d.ts +0 -9
  232. package/lib/math/bankBalance.js +0 -75
  233. package/lib/math/state.d.ts +0 -8
  234. package/lib/math/state.js +0 -15
  235. package/lib/orders.d.ts +0 -8
  236. package/lib/orders.js +0 -134
  237. package/src/admin.ts +0 -722
  238. package/src/clearingHouse.ts +0 -1451
  239. package/src/clearingHouseUser.ts +0 -989
  240. package/src/constants/banks.ts +0 -43
  241. package/src/idl/clearing_house.json +0 -3998
  242. package/src/math/bankBalance.ts +0 -112
  243. package/src/math/state.ts +0 -14
  244. package/src/math/utils.js +0 -27
  245. package/src/math/utils.js.map +0 -1
  246. package/src/orders.ts +0 -244
  247. package/src/util/computeUnits.js.map +0 -1
@@ -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,135 @@ 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^6)
163
209
  */
164
- export function calculateEntryPrice(userPosition: UserPosition): BN {
210
+ export function calculateBreakEvenPrice(userPosition: PerpPosition): BN {
211
+ if (userPosition.baseAssetAmount.eq(ZERO)) {
212
+ return ZERO;
213
+ }
214
+
215
+ return userPosition.quoteBreakEvenAmount
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^6)
226
+ */
227
+ export function calculateEntryPrice(userPosition: PerpPosition): BN {
228
+ if (userPosition.baseAssetAmount.eq(ZERO)) {
229
+ return ZERO;
230
+ }
231
+
232
+ return userPosition.quoteEntryAmount
233
+ .mul(PRICE_PRECISION)
234
+ .mul(AMM_TO_QUOTE_PRECISION_RATIO)
235
+ .div(userPosition.baseAssetAmount)
236
+ .abs();
237
+ }
238
+
239
+ /**
240
+ *
241
+ * @param userPosition
242
+ * @returns Precision: PRICE_PRECISION (10^10)
243
+ */
244
+ export function calculateCostBasis(userPosition: PerpPosition): BN {
165
245
  if (userPosition.baseAssetAmount.eq(ZERO)) {
166
246
  return ZERO;
167
247
  }
168
248
 
169
249
  return userPosition.quoteAssetAmount
170
- .mul(MARK_PRICE_PRECISION)
250
+ .mul(PRICE_PRECISION)
171
251
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)
172
252
  .div(userPosition.baseAssetAmount)
173
253
  .abs();
174
254
  }
175
255
 
176
256
  export function findDirectionToClose(
177
- userPosition: UserPosition
257
+ userPosition: PerpPosition
178
258
  ): PositionDirection {
179
259
  return userPosition.baseAssetAmount.gt(ZERO)
180
260
  ? PositionDirection.SHORT
@@ -182,15 +262,13 @@ export function findDirectionToClose(
182
262
  }
183
263
 
184
264
  export function positionCurrentDirection(
185
- userPosition: UserPosition
265
+ userPosition: PerpPosition
186
266
  ): PositionDirection {
187
267
  return userPosition.baseAssetAmount.gte(ZERO)
188
268
  ? PositionDirection.LONG
189
269
  : PositionDirection.SHORT;
190
270
  }
191
271
 
192
- export function isEmptyPosition(userPosition: UserPosition): boolean {
193
- return (
194
- userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders.eq(ZERO)
195
- );
272
+ export function isEmptyPosition(userPosition: PerpPosition): boolean {
273
+ return userPosition.baseAssetAmount.eq(ZERO) && userPosition.openOrders === 0;
196
274
  }
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,
@@ -26,20 +26,20 @@ export function calculateAdjustKCost(
26
26
  const x = amm.baseAssetReserve;
27
27
  const y = amm.quoteAssetReserve;
28
28
 
29
- const d = amm.netBaseAssetAmount;
29
+ const d = amm.baseAssetAmountWithAmm;
30
30
  const Q = amm.pegMultiplier;
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
 
@@ -125,7 +135,7 @@ export function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN] {
125
135
  const x = amm.baseAssetReserve;
126
136
  const y = amm.quoteAssetReserve;
127
137
 
128
- const d = amm.netBaseAssetAmount;
138
+ const d = amm.baseAssetAmountWithAmm;
129
139
  const Q = amm.pegMultiplier;
130
140
 
131
141
  const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
@@ -149,7 +159,7 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
149
159
  const x = amm.baseAssetReserve;
150
160
  const y = amm.quoteAssetReserve;
151
161
 
152
- const d = amm.netBaseAssetAmount;
162
+ const d = amm.baseAssetAmountWithAmm;
153
163
  const Q = amm.pegMultiplier;
154
164
 
155
165
  const C = cost.mul(new BN(-1));
@@ -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;
@@ -0,0 +1,319 @@
1
+ import {
2
+ SpotMarketAccount,
3
+ SpotBalanceType,
4
+ isVariant,
5
+ MarginCategory,
6
+ } from '../types';
7
+ import { BN } from '@project-serum/anchor';
8
+ import {
9
+ SPOT_MARKET_UTILIZATION_PRECISION,
10
+ ONE,
11
+ TEN,
12
+ ZERO,
13
+ SPOT_MARKET_RATE_PRECISION,
14
+ SPOT_MARKET_WEIGHT_PRECISION,
15
+ ONE_YEAR,
16
+ AMM_RESERVE_PRECISION,
17
+ } from '../constants/numericConstants';
18
+ import {
19
+ calculateSizeDiscountAssetWeight,
20
+ calculateSizePremiumLiabilityWeight,
21
+ } from './margin';
22
+ import { OraclePriceData } from '../oracles/types';
23
+
24
+ export function getBalance(
25
+ tokenAmount: BN,
26
+ spotMarket: SpotMarketAccount,
27
+ balanceType: SpotBalanceType
28
+ ): BN {
29
+ const precisionIncrease = TEN.pow(new BN(19 - spotMarket.decimals));
30
+
31
+ const cumulativeInterest = isVariant(balanceType, 'deposit')
32
+ ? spotMarket.cumulativeDepositInterest
33
+ : spotMarket.cumulativeBorrowInterest;
34
+
35
+ let balance = tokenAmount.mul(precisionIncrease).div(cumulativeInterest);
36
+
37
+ if (!balance.eq(ZERO) && isVariant(balanceType, 'borrow')) {
38
+ balance = balance.add(ONE);
39
+ }
40
+
41
+ return balance;
42
+ }
43
+
44
+ export function getTokenAmount(
45
+ balanceAmount: BN,
46
+ spotMarket: SpotMarketAccount,
47
+ balanceType: SpotBalanceType
48
+ ): BN {
49
+ const precisionDecrease = TEN.pow(new BN(19 - spotMarket.decimals));
50
+
51
+ const cumulativeInterest = isVariant(balanceType, 'deposit')
52
+ ? spotMarket.cumulativeDepositInterest
53
+ : spotMarket.cumulativeBorrowInterest;
54
+
55
+ return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
56
+ }
57
+
58
+ export function getSignedTokenAmount(
59
+ tokenAmount: BN,
60
+ balanceType: SpotBalanceType
61
+ ): BN {
62
+ if (isVariant(balanceType, 'deposit')) {
63
+ return tokenAmount;
64
+ } else {
65
+ return tokenAmount.abs().neg();
66
+ }
67
+ }
68
+
69
+ export function getTokenValue(
70
+ tokenAmount: BN,
71
+ spotDecimals: number,
72
+ oraclePriceData: OraclePriceData
73
+ ): BN {
74
+ if (tokenAmount.eq(ZERO)) {
75
+ return ZERO;
76
+ }
77
+
78
+ const precisionDecrease = TEN.pow(new BN(spotDecimals));
79
+
80
+ return tokenAmount.mul(oraclePriceData.price).div(precisionDecrease);
81
+ }
82
+
83
+ export function calculateAssetWeight(
84
+ balanceAmount: BN,
85
+ spotMarket: SpotMarketAccount,
86
+ marginCategory: MarginCategory
87
+ ): BN {
88
+ const sizePrecision = TEN.pow(new BN(spotMarket.decimals));
89
+ let sizeInAmmReservePrecision;
90
+ if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
91
+ sizeInAmmReservePrecision = balanceAmount.div(
92
+ sizePrecision.div(AMM_RESERVE_PRECISION)
93
+ );
94
+ } else {
95
+ sizeInAmmReservePrecision = balanceAmount
96
+ .mul(AMM_RESERVE_PRECISION)
97
+ .div(sizePrecision);
98
+ }
99
+
100
+ let assetWeight;
101
+
102
+ switch (marginCategory) {
103
+ case 'Initial':
104
+ assetWeight = calculateSizeDiscountAssetWeight(
105
+ sizeInAmmReservePrecision,
106
+ new BN(spotMarket.imfFactor),
107
+ new BN(spotMarket.initialAssetWeight)
108
+ );
109
+ break;
110
+ case 'Maintenance':
111
+ assetWeight = calculateSizeDiscountAssetWeight(
112
+ sizeInAmmReservePrecision,
113
+ new BN(spotMarket.imfFactor),
114
+ new BN(spotMarket.maintenanceAssetWeight)
115
+ );
116
+ break;
117
+ default:
118
+ assetWeight = new BN(spotMarket.initialAssetWeight);
119
+ break;
120
+ }
121
+
122
+ return assetWeight;
123
+ }
124
+
125
+ export function calculateLiabilityWeight(
126
+ balanceAmount: BN,
127
+ spotMarket: SpotMarketAccount,
128
+ marginCategory: MarginCategory
129
+ ): BN {
130
+ const sizePrecision = TEN.pow(new BN(spotMarket.decimals));
131
+ let sizeInAmmReservePrecision;
132
+ if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
133
+ sizeInAmmReservePrecision = balanceAmount.div(
134
+ sizePrecision.div(AMM_RESERVE_PRECISION)
135
+ );
136
+ } else {
137
+ sizeInAmmReservePrecision = balanceAmount
138
+ .mul(AMM_RESERVE_PRECISION)
139
+ .div(sizePrecision);
140
+ }
141
+
142
+ let assetWeight;
143
+
144
+ switch (marginCategory) {
145
+ case 'Initial':
146
+ assetWeight = calculateSizePremiumLiabilityWeight(
147
+ sizeInAmmReservePrecision,
148
+ new BN(spotMarket.imfFactor),
149
+ new BN(spotMarket.initialLiabilityWeight),
150
+ SPOT_MARKET_WEIGHT_PRECISION
151
+ );
152
+ break;
153
+ case 'Maintenance':
154
+ assetWeight = calculateSizePremiumLiabilityWeight(
155
+ sizeInAmmReservePrecision,
156
+ new BN(spotMarket.imfFactor),
157
+ new BN(spotMarket.maintenanceLiabilityWeight),
158
+ SPOT_MARKET_WEIGHT_PRECISION
159
+ );
160
+ break;
161
+ default:
162
+ assetWeight = spotMarket.initialLiabilityWeight;
163
+ break;
164
+ }
165
+
166
+ return assetWeight;
167
+ }
168
+
169
+ export function calculateUtilization(bank: SpotMarketAccount): BN {
170
+ const tokenDepositAmount = getTokenAmount(
171
+ bank.depositBalance,
172
+ bank,
173
+ SpotBalanceType.DEPOSIT
174
+ );
175
+ const tokenBorrowAmount = getTokenAmount(
176
+ bank.borrowBalance,
177
+ bank,
178
+ SpotBalanceType.BORROW
179
+ );
180
+
181
+ let utilization: BN;
182
+ if (tokenBorrowAmount.eq(ZERO) && tokenDepositAmount.eq(ZERO)) {
183
+ utilization = ZERO;
184
+ } else if (tokenDepositAmount.eq(ZERO)) {
185
+ utilization = SPOT_MARKET_UTILIZATION_PRECISION;
186
+ } else {
187
+ utilization = tokenBorrowAmount
188
+ .mul(SPOT_MARKET_UTILIZATION_PRECISION)
189
+ .div(tokenDepositAmount);
190
+ }
191
+
192
+ return utilization;
193
+ }
194
+
195
+ export function calculateInterestRate(bank: SpotMarketAccount): BN {
196
+ const utilization = calculateUtilization(bank);
197
+
198
+ let interestRate: BN;
199
+ if (utilization.gt(new BN(bank.optimalUtilization))) {
200
+ const surplusUtilization = utilization.sub(new BN(bank.optimalUtilization));
201
+ const borrowRateSlope = new BN(bank.maxBorrowRate - bank.optimalBorrowRate)
202
+ .mul(SPOT_MARKET_UTILIZATION_PRECISION)
203
+ .div(
204
+ SPOT_MARKET_UTILIZATION_PRECISION.sub(new BN(bank.optimalUtilization))
205
+ );
206
+
207
+ interestRate = new BN(bank.optimalBorrowRate).add(
208
+ surplusUtilization
209
+ .mul(borrowRateSlope)
210
+ .div(SPOT_MARKET_UTILIZATION_PRECISION)
211
+ );
212
+ } else {
213
+ const borrowRateSlope = new BN(bank.optimalBorrowRate)
214
+ .mul(SPOT_MARKET_UTILIZATION_PRECISION)
215
+ .div(
216
+ SPOT_MARKET_UTILIZATION_PRECISION.sub(new BN(bank.optimalUtilization))
217
+ );
218
+
219
+ interestRate = utilization
220
+ .mul(borrowRateSlope)
221
+ .div(SPOT_MARKET_UTILIZATION_PRECISION);
222
+ }
223
+
224
+ return interestRate;
225
+ }
226
+
227
+ export function calculateDepositRate(bank: SpotMarketAccount): BN {
228
+ const utilization = calculateUtilization(bank);
229
+ const borrowRate = calculateBorrowRate(bank);
230
+ const depositRate = borrowRate
231
+ .mul(utilization)
232
+ .div(SPOT_MARKET_UTILIZATION_PRECISION);
233
+ return depositRate;
234
+ }
235
+
236
+ export function calculateBorrowRate(bank: SpotMarketAccount): BN {
237
+ return calculateInterestRate(bank);
238
+ }
239
+
240
+ export function calculateInterestAccumulated(
241
+ bank: SpotMarketAccount,
242
+ now: BN
243
+ ): { borrowInterest: BN; depositInterest: BN } {
244
+ const interestRate = calculateInterestRate(bank);
245
+
246
+ const timeSinceLastUpdate = now.sub(bank.lastInterestTs);
247
+
248
+ const modifiedBorrowRate = interestRate.mul(timeSinceLastUpdate);
249
+
250
+ const utilization = calculateUtilization(bank);
251
+
252
+ const modifiedDepositRate = modifiedBorrowRate
253
+ .mul(utilization)
254
+ .div(SPOT_MARKET_UTILIZATION_PRECISION);
255
+
256
+ const borrowInterest = bank.cumulativeBorrowInterest
257
+ .mul(modifiedBorrowRate)
258
+ .div(ONE_YEAR)
259
+ .div(SPOT_MARKET_RATE_PRECISION)
260
+ .add(ONE);
261
+ const depositInterest = bank.cumulativeDepositInterest
262
+ .mul(modifiedDepositRate)
263
+ .div(ONE_YEAR)
264
+ .div(SPOT_MARKET_RATE_PRECISION);
265
+
266
+ return { borrowInterest, depositInterest };
267
+ }
268
+
269
+ export function calculateWithdrawLimit(
270
+ spotMarket: SpotMarketAccount,
271
+ now: BN
272
+ ): { borrowLimit: BN; withdrawLimit: BN } {
273
+ const marketDepositTokenAmount = getTokenAmount(
274
+ spotMarket.depositBalance,
275
+ spotMarket,
276
+ SpotBalanceType.DEPOSIT
277
+ );
278
+ const marketBorrowTokenAmount = getTokenAmount(
279
+ spotMarket.borrowBalance,
280
+ spotMarket,
281
+ SpotBalanceType.BORROW
282
+ );
283
+
284
+ const twentyFourHours = new BN(60 * 60 * 24);
285
+ const sinceLast = now.sub(spotMarket.lastTwapTs);
286
+ const sinceStart = BN.max(ZERO, twentyFourHours.sub(sinceLast));
287
+ const borrowTokenTwapLive = spotMarket.borrowTokenTwap
288
+ .mul(sinceStart)
289
+ .add(marketBorrowTokenAmount.mul(sinceLast))
290
+ .div(sinceLast.add(sinceStart));
291
+
292
+ const depositTokenTwapLive = spotMarket.depositTokenTwap
293
+ .mul(sinceStart)
294
+ .add(marketDepositTokenAmount.mul(sinceLast))
295
+ .div(sinceLast.add(sinceStart));
296
+
297
+ const maxBorrowTokens = BN.min(
298
+ BN.max(
299
+ marketDepositTokenAmount.div(new BN(6)),
300
+ borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
301
+ ),
302
+ marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(5)))
303
+ ); // between ~15-80% utilization with friction on twap
304
+
305
+ const minDepositTokens = depositTokenTwapLive.sub(
306
+ BN.min(
307
+ BN.max(
308
+ depositTokenTwapLive.div(new BN(5)),
309
+ spotMarket.withdrawGuardThreshold
310
+ ),
311
+ depositTokenTwapLive
312
+ )
313
+ );
314
+
315
+ return {
316
+ borrowLimit: maxBorrowTokens.sub(marketBorrowTokenAmount),
317
+ withdrawLimit: marketDepositTokenAmount.sub(minDepositTokens),
318
+ };
319
+ }