@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
@@ -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
+ spotMarket.imfFactor,
107
+ spotMarket.initialAssetWeight
108
+ );
109
+ break;
110
+ case 'Maintenance':
111
+ assetWeight = calculateSizeDiscountAssetWeight(
112
+ sizeInAmmReservePrecision,
113
+ spotMarket.imfFactor,
114
+ spotMarket.maintenanceAssetWeight
115
+ );
116
+ break;
117
+ default:
118
+ assetWeight = 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
+ spotMarket.imfFactor,
149
+ spotMarket.initialLiabilityWeight,
150
+ SPOT_MARKET_WEIGHT_PRECISION
151
+ );
152
+ break;
153
+ case 'Maintenance':
154
+ assetWeight = calculateSizePremiumLiabilityWeight(
155
+ sizeInAmmReservePrecision,
156
+ spotMarket.imfFactor,
157
+ 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(sinceLast));
291
+
292
+ const depositTokenTwapLive = spotMarket.depositTokenTwap
293
+ .mul(sinceStart)
294
+ .add(marketDepositTokenAmount.mul(sinceLast))
295
+ .div(sinceLast.add(sinceLast));
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(10)))
303
+ ); // between ~15-90% 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
+ }
@@ -0,0 +1,9 @@
1
+ import { BN } from '@project-serum/anchor';
2
+ import { SpotMarketAccount } from '../types';
3
+
4
+ export function castNumberToSpotPrecision(
5
+ value: number,
6
+ spotMarket: SpotMarketAccount
7
+ ): BN {
8
+ return new BN(value * Math.pow(10, spotMarket.decimals));
9
+ }
@@ -0,0 +1,47 @@
1
+ import { SpotMarketAccount, SpotPosition } from '../types';
2
+ import { ZERO } from '../constants/numericConstants';
3
+ import { BN } from '@project-serum/anchor';
4
+ import {
5
+ getSignedTokenAmount,
6
+ getTokenAmount,
7
+ getTokenValue,
8
+ } from './spotBalance';
9
+ import { OraclePriceData } from '../oracles/types';
10
+
11
+ export function isSpotPositionAvailable(position: SpotPosition): boolean {
12
+ return position.balance.eq(ZERO) && position.openOrders === 0;
13
+ }
14
+
15
+ export function getWorstCaseTokenAmounts(
16
+ spotPosition: SpotPosition,
17
+ spotMarketAccount: SpotMarketAccount,
18
+ oraclePriceData: OraclePriceData
19
+ ): [BN, BN] {
20
+ const tokenAmount = getSignedTokenAmount(
21
+ getTokenAmount(
22
+ spotPosition.balance,
23
+ spotMarketAccount,
24
+ spotPosition.balanceType
25
+ ),
26
+ spotPosition.balanceType
27
+ );
28
+
29
+ const tokenAmountAllBidsFill = tokenAmount.add(spotPosition.openBids);
30
+ const tokenAmountAllAsksFill = tokenAmount.add(spotPosition.openAsks);
31
+
32
+ if (tokenAmountAllAsksFill.abs().gt(tokenAmountAllBidsFill.abs())) {
33
+ const worstCaseQuoteTokenAmount = getTokenValue(
34
+ spotPosition.openAsks.neg(),
35
+ spotMarketAccount.decimals,
36
+ oraclePriceData
37
+ );
38
+ return [tokenAmountAllBidsFill, worstCaseQuoteTokenAmount];
39
+ } else {
40
+ const worstCaseQuoteTokenAmount = getTokenValue(
41
+ spotPosition.openBids.neg(),
42
+ spotMarketAccount.decimals,
43
+ oraclePriceData
44
+ );
45
+ return [tokenAmountAllAsksFill, worstCaseQuoteTokenAmount];
46
+ }
47
+ }
package/src/math/trade.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { MarketAccount, PositionDirection, SwapDirection } from '../types';
1
+ import { PerpMarketAccount, PositionDirection } from '../types';
2
2
  import { BN } from '@project-serum/anchor';
3
3
  import { assert } from '../assert/assert';
4
4
  import {
5
- MARK_PRICE_PRECISION,
5
+ PRICE_PRECISION,
6
6
  PEG_PRECISION,
7
7
  AMM_TO_QUOTE_PRECISION_RATIO,
8
8
  ZERO,
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  calculateBidPrice,
12
12
  calculateAskPrice,
13
- calculateMarkPrice,
13
+ calculateReservePrice,
14
14
  } from './market';
15
15
  import {
16
16
  calculateAmmReservesAfterSwap,
@@ -48,18 +48,18 @@ export type PriceImpactUnit =
48
48
  * @param useSpread whether to consider spread with calculating slippage
49
49
  * @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
50
50
  *
51
- * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
51
+ * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision PRICE_PRECISION
52
52
  *
53
- * 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision MARK_PRICE_PRECISION
53
+ * 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision PRICE_PRECISION
54
54
  *
55
- * 'entryPrice' => the average price of the trade : Precision MARK_PRICE_PRECISION
55
+ * 'entryPrice' => the average price of the trade : Precision PRICE_PRECISION
56
56
  *
57
- * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
57
+ * 'newPrice' => the price of the asset after the trade : Precision PRICE_PRECISION
58
58
  */
59
59
  export function calculateTradeSlippage(
60
60
  direction: PositionDirection,
61
61
  amount: BN,
62
- market: MarketAccount,
62
+ market: PerpMarketAccount,
63
63
  inputAssetType: AssetType = 'quote',
64
64
  oraclePriceData?: OraclePriceData,
65
65
  useSpread = true
@@ -73,33 +73,25 @@ export function calculateTradeSlippage(
73
73
  oldPrice = calculateBidPrice(market, oraclePriceData);
74
74
  }
75
75
  } else {
76
- oldPrice = calculateMarkPrice(market, oraclePriceData);
76
+ oldPrice = calculateReservePrice(market, oraclePriceData);
77
77
  }
78
78
  if (amount.eq(ZERO)) {
79
79
  return [ZERO, ZERO, oldPrice, oldPrice];
80
80
  }
81
- const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(
82
- direction,
83
- amount,
84
- market,
85
- inputAssetType,
86
- oraclePriceData,
87
- useSpread
88
- );
89
-
90
- const swapDirection = isVariant(direction, 'long')
91
- ? SwapDirection.REMOVE
92
- : SwapDirection.ADD;
93
- const quoteAssetAmountAcquired = calculateQuoteAssetAmountSwapped(
94
- acquiredQuote.abs(),
95
- market.amm.pegMultiplier,
96
- swapDirection
97
- );
81
+ const [acquiredBaseReserve, acquiredQuoteReserve, acquiredQuoteAssetAmount] =
82
+ calculateTradeAcquiredAmounts(
83
+ direction,
84
+ amount,
85
+ market,
86
+ inputAssetType,
87
+ oraclePriceData,
88
+ useSpread
89
+ );
98
90
 
99
- const entryPrice = quoteAssetAmountAcquired
91
+ const entryPrice = acquiredQuoteAssetAmount
100
92
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)
101
- .mul(MARK_PRICE_PRECISION)
102
- .div(acquiredBase.abs());
93
+ .mul(PRICE_PRECISION)
94
+ .div(acquiredBaseReserve.abs());
103
95
 
104
96
  let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
105
97
  if (useSpread && market.amm.baseSpread > 0) {
@@ -116,8 +108,8 @@ export function calculateTradeSlippage(
116
108
  }
117
109
 
118
110
  const newPrice = calculatePrice(
119
- amm.baseAssetReserve.sub(acquiredBase),
120
- amm.quoteAssetReserve.sub(acquiredQuote),
111
+ amm.baseAssetReserve.sub(acquiredBaseReserve),
112
+ amm.quoteAssetReserve.sub(acquiredQuoteReserve),
121
113
  amm.pegMultiplier
122
114
  );
123
115
 
@@ -129,12 +121,12 @@ export function calculateTradeSlippage(
129
121
 
130
122
  const pctMaxSlippage = newPrice
131
123
  .sub(oldPrice)
132
- .mul(MARK_PRICE_PRECISION)
124
+ .mul(PRICE_PRECISION)
133
125
  .div(oldPrice)
134
126
  .abs();
135
127
  const pctAvgSlippage = entryPrice
136
128
  .sub(oldPrice)
137
- .mul(MARK_PRICE_PRECISION)
129
+ .mul(PRICE_PRECISION)
138
130
  .div(oldPrice)
139
131
  .abs();
140
132
 
@@ -155,13 +147,13 @@ export function calculateTradeSlippage(
155
147
  export function calculateTradeAcquiredAmounts(
156
148
  direction: PositionDirection,
157
149
  amount: BN,
158
- market: MarketAccount,
150
+ market: PerpMarketAccount,
159
151
  inputAssetType: AssetType = 'quote',
160
152
  oraclePriceData: OraclePriceData,
161
153
  useSpread = true
162
- ): [BN, BN] {
154
+ ): [BN, BN, BN] {
163
155
  if (amount.eq(ZERO)) {
164
- return [ZERO, ZERO];
156
+ return [ZERO, ZERO, ZERO];
165
157
  }
166
158
 
167
159
  const swapDirection = getSwapDirection(inputAssetType, direction);
@@ -185,7 +177,13 @@ export function calculateTradeAcquiredAmounts(
185
177
 
186
178
  const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
187
179
  const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
188
- return [acquiredBase, acquiredQuote];
180
+ const acquiredQuoteAssetAmount = calculateQuoteAssetAmountSwapped(
181
+ acquiredQuote.abs(),
182
+ amm.pegMultiplier,
183
+ swapDirection
184
+ );
185
+
186
+ return [acquiredBase, acquiredQuote, acquiredQuoteAssetAmount];
189
187
  }
190
188
 
191
189
  /**
@@ -201,12 +199,12 @@ export function calculateTradeAcquiredAmounts(
201
199
  * [
202
200
  * direction => direction of trade required, PositionDirection
203
201
  * tradeSize => size of trade required, TODO-PRECISION
204
- * entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
205
- * targetPrice => the target price MARK_PRICE_PRECISION
202
+ * entryPrice => the entry price for the trade, PRICE_PRECISION
203
+ * targetPrice => the target price PRICE_PRECISION
206
204
  * ]
207
205
  */
208
206
  export function calculateTargetPriceTrade(
209
- market: MarketAccount,
207
+ market: PerpMarketAccount,
210
208
  targetPrice: BN,
211
209
  pct: BN = MAXPCT,
212
210
  outputAssetType: AssetType = 'quote',
@@ -217,20 +215,20 @@ export function calculateTargetPriceTrade(
217
215
  assert(targetPrice.gt(ZERO));
218
216
  assert(pct.lte(MAXPCT) && pct.gt(ZERO));
219
217
 
220
- const markPriceBefore = calculateMarkPrice(market, oraclePriceData);
218
+ const reservePriceBefore = calculateReservePrice(market, oraclePriceData);
221
219
  const bidPriceBefore = calculateBidPrice(market, oraclePriceData);
222
220
  const askPriceBefore = calculateAskPrice(market, oraclePriceData);
223
221
 
224
222
  let direction;
225
- if (targetPrice.gt(markPriceBefore)) {
226
- const priceGap = targetPrice.sub(markPriceBefore);
223
+ if (targetPrice.gt(reservePriceBefore)) {
224
+ const priceGap = targetPrice.sub(reservePriceBefore);
227
225
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
228
- targetPrice = markPriceBefore.add(priceGapScaled);
226
+ targetPrice = reservePriceBefore.add(priceGapScaled);
229
227
  direction = PositionDirection.LONG;
230
228
  } else {
231
- const priceGap = markPriceBefore.sub(targetPrice);
229
+ const priceGap = reservePriceBefore.sub(targetPrice);
232
230
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
233
- targetPrice = markPriceBefore.sub(priceGapScaled);
231
+ targetPrice = reservePriceBefore.sub(priceGapScaled);
234
232
  direction = PositionDirection.SHORT;
235
233
  }
236
234
 
@@ -254,7 +252,7 @@ export function calculateTargetPriceTrade(
254
252
  }
255
253
 
256
254
  const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
257
- const k = invariant.mul(MARK_PRICE_PRECISION);
255
+ const k = invariant.mul(PRICE_PRECISION);
258
256
 
259
257
  let baseAssetReserveAfter;
260
258
  let quoteAssetReserveAfter;
@@ -267,21 +265,19 @@ export function calculateTargetPriceTrade(
267
265
  targetPrice.gt(bidPriceBefore)
268
266
  ) {
269
267
  // no trade, market is at target
270
- if (markPriceBefore.gt(targetPrice)) {
268
+ if (reservePriceBefore.gt(targetPrice)) {
271
269
  direction = PositionDirection.SHORT;
272
270
  } else {
273
271
  direction = PositionDirection.LONG;
274
272
  }
275
273
  tradeSize = ZERO;
276
274
  return [direction, tradeSize, targetPrice, targetPrice];
277
- } else if (markPriceBefore.gt(targetPrice)) {
275
+ } else if (reservePriceBefore.gt(targetPrice)) {
278
276
  // overestimate y2
279
277
  baseAssetReserveAfter = squareRootBN(
280
278
  k.div(targetPrice).mul(peg).div(PEG_PRECISION).sub(biasModifier)
281
279
  ).sub(new BN(1));
282
- quoteAssetReserveAfter = k
283
- .div(MARK_PRICE_PRECISION)
284
- .div(baseAssetReserveAfter);
280
+ quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
285
281
 
286
282
  markPriceAfter = calculatePrice(
287
283
  baseAssetReserveAfter,
@@ -295,14 +291,12 @@ export function calculateTargetPriceTrade(
295
291
  .div(PEG_PRECISION)
296
292
  .div(AMM_TO_QUOTE_PRECISION_RATIO);
297
293
  baseSize = baseAssetReserveAfter.sub(baseAssetReserveBefore);
298
- } else if (markPriceBefore.lt(targetPrice)) {
294
+ } else if (reservePriceBefore.lt(targetPrice)) {
299
295
  // underestimate y2
300
296
  baseAssetReserveAfter = squareRootBN(
301
297
  k.div(targetPrice).mul(peg).div(PEG_PRECISION).add(biasModifier)
302
298
  ).add(new BN(1));
303
- quoteAssetReserveAfter = k
304
- .div(MARK_PRICE_PRECISION)
305
- .div(baseAssetReserveAfter);
299
+ quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
306
300
 
307
301
  markPriceAfter = calculatePrice(
308
302
  baseAssetReserveAfter,
@@ -326,17 +320,17 @@ export function calculateTargetPriceTrade(
326
320
 
327
321
  let tp1 = targetPrice;
328
322
  let tp2 = markPriceAfter;
329
- let originalDiff = targetPrice.sub(markPriceBefore);
323
+ let originalDiff = targetPrice.sub(reservePriceBefore);
330
324
 
331
325
  if (direction == PositionDirection.SHORT) {
332
326
  tp1 = markPriceAfter;
333
327
  tp2 = targetPrice;
334
- originalDiff = markPriceBefore.sub(targetPrice);
328
+ originalDiff = reservePriceBefore.sub(targetPrice);
335
329
  }
336
330
 
337
331
  const entryPrice = tradeSize
338
332
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)
339
- .mul(MARK_PRICE_PRECISION)
333
+ .mul(PRICE_PRECISION)
340
334
  .div(baseSize.abs());
341
335
 
342
336
  assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
@@ -2,7 +2,7 @@ import { parsePriceData } from '@pythnetwork/client';
2
2
  import { Connection, PublicKey } from '@solana/web3.js';
3
3
  import { OracleClient, OraclePriceData } from './types';
4
4
  import { BN } from '@project-serum/anchor';
5
- import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
5
+ import { PRICE_PRECISION, TEN } from '../constants/numericConstants';
6
6
 
7
7
  export class PythClient implements OracleClient {
8
8
  private connection: Connection;
@@ -38,6 +38,6 @@ export function convertPythPrice(price: number, exponent: number): BN {
38
38
  exponent = Math.abs(exponent);
39
39
  const pythPrecision = TEN.pow(new BN(exponent).abs());
40
40
  return new BN(price * Math.pow(10, exponent))
41
- .mul(MARK_PRICE_PRECISION)
41
+ .mul(PRICE_PRECISION)
42
42
  .div(pythPrecision);
43
43
  }
@@ -1,10 +1,10 @@
1
1
  import { PublicKey } from '@solana/web3.js';
2
2
  import { OracleClient, OraclePriceData } from './types';
3
3
  import { BN } from '@project-serum/anchor';
4
- import { MARK_PRICE_PRECISION } from '../constants/numericConstants';
4
+ import { PRICE_PRECISION } from '../constants/numericConstants';
5
5
 
6
6
  export const QUOTE_ORACLE_PRICE_DATA: OraclePriceData = {
7
- price: MARK_PRICE_PRECISION,
7
+ price: PRICE_PRECISION,
8
8
  slot: new BN(0),
9
9
  confidence: new BN(1),
10
10
  hasSufficientNumberOfDataPoints: true,
@@ -1,7 +1,7 @@
1
1
  import { SwitchboardDecimal } from '@switchboard-xyz/switchboard-v2';
2
2
  import { Connection, Keypair, PublicKey } from '@solana/web3.js';
3
3
  import { BN, Program, Idl, AnchorProvider } from '@project-serum/anchor';
4
- import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
4
+ import { PRICE_PRECISION, TEN } from '../constants/numericConstants';
5
5
  import { OracleClient, OraclePriceData } from './types';
6
6
  import { Wallet } from '../wallet';
7
7
  import switchboardV2Idl from '../idl/switchboard_v2.json';
@@ -74,6 +74,6 @@ function getSwitchboardProgram(connection: Connection): Program {
74
74
  function convertSwitchboardDecimal(switchboardDecimal: SwitchboardDecimal): BN {
75
75
  const switchboardPrecision = TEN.pow(new BN(switchboardDecimal.scale));
76
76
  return switchboardDecimal.mantissa
77
- .mul(MARK_PRICE_PRECISION)
77
+ .mul(PRICE_PRECISION)
78
78
  .div(switchboardPrecision);
79
79
  }