@drift-labs/sdk 0.1.36-master.7 → 0.2.0-master.10

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 (254) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +6 -6
  2. package/lib/accounts/bulkAccountLoader.js +81 -95
  3. package/lib/accounts/bulkUserSubscription.js +13 -57
  4. package/lib/accounts/fetch.d.ts +4 -0
  5. package/lib/accounts/fetch.js +18 -0
  6. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
  8. package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
  9. package/lib/accounts/pollingOracleSubscriber.js +37 -49
  10. package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
  11. package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
  12. package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
  13. package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
  14. package/lib/accounts/types.d.ts +34 -41
  15. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
  16. package/lib/accounts/webSocketAccountSubscriber.js +39 -35
  17. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
  18. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
  19. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
  20. package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
  21. package/lib/addresses/marketAddresses.d.ts +4 -0
  22. package/lib/addresses/marketAddresses.js +15 -0
  23. package/lib/addresses/pda.d.ts +12 -0
  24. package/lib/addresses/pda.js +83 -0
  25. package/lib/admin.d.ts +12 -18
  26. package/lib/admin.js +398 -558
  27. package/lib/clearingHouse.d.ts +83 -109
  28. package/lib/clearingHouse.js +832 -893
  29. package/lib/clearingHouseConfig.d.ts +34 -0
  30. package/lib/clearingHouseConfig.js +2 -0
  31. package/lib/clearingHouseUser.d.ts +19 -22
  32. package/lib/clearingHouseUser.js +155 -141
  33. package/lib/clearingHouseUserConfig.d.ts +14 -0
  34. package/lib/clearingHouseUserConfig.js +2 -0
  35. package/lib/config.d.ts +12 -0
  36. package/lib/config.js +35 -4
  37. package/lib/constants/banks.d.ts +16 -0
  38. package/lib/constants/banks.js +41 -0
  39. package/lib/constants/markets.d.ts +8 -3
  40. package/lib/constants/markets.js +13 -206
  41. package/lib/constants/numericConstants.d.ts +17 -0
  42. package/lib/constants/numericConstants.js +23 -6
  43. package/lib/events/eventList.d.ts +22 -0
  44. package/lib/events/eventList.js +77 -0
  45. package/lib/events/eventSubscriber.d.ts +34 -0
  46. package/lib/events/eventSubscriber.js +126 -0
  47. package/lib/events/fetchLogs.d.ts +13 -0
  48. package/lib/events/fetchLogs.js +39 -0
  49. package/lib/events/pollingLogProvider.d.ts +15 -0
  50. package/lib/events/pollingLogProvider.js +53 -0
  51. package/lib/events/sort.d.ts +2 -0
  52. package/lib/events/sort.js +44 -0
  53. package/lib/events/txEventCache.d.ts +24 -0
  54. package/lib/events/txEventCache.js +71 -0
  55. package/lib/events/types.d.ts +49 -0
  56. package/lib/events/types.js +20 -0
  57. package/lib/events/webSocketLogProvider.d.ts +12 -0
  58. package/lib/events/webSocketLogProvider.js +30 -0
  59. package/lib/examples/makeTradeExample.js +26 -27
  60. package/lib/factory/bigNum.d.ts +118 -0
  61. package/lib/factory/bigNum.js +364 -0
  62. package/lib/factory/oracleClient.d.ts +1 -2
  63. package/lib/factory/oracleClient.js +6 -2
  64. package/lib/idl/clearing_house.json +2258 -2774
  65. package/lib/index.d.ts +14 -5
  66. package/lib/index.js +18 -5
  67. package/lib/math/amm.d.ts +24 -29
  68. package/lib/math/amm.js +209 -176
  69. package/lib/math/auction.d.ts +5 -0
  70. package/lib/math/auction.js +42 -0
  71. package/lib/math/bankBalance.d.ts +9 -0
  72. package/lib/math/bankBalance.js +75 -0
  73. package/lib/math/conversion.d.ts +0 -1
  74. package/lib/math/conversion.js +1 -5
  75. package/lib/math/funding.d.ts +6 -6
  76. package/lib/math/funding.js +158 -175
  77. package/lib/math/market.d.ts +6 -6
  78. package/lib/math/market.js +10 -9
  79. package/lib/math/orders.d.ts +6 -1
  80. package/lib/math/orders.js +38 -1
  81. package/lib/math/position.d.ts +7 -5
  82. package/lib/math/position.js +29 -27
  83. package/lib/math/repeg.d.ts +22 -0
  84. package/lib/math/repeg.js +128 -0
  85. package/lib/math/trade.d.ts +5 -4
  86. package/lib/math/trade.js +29 -24
  87. package/lib/mockUSDCFaucet.js +87 -116
  88. package/lib/oracles/oracleClientCache.d.ts +8 -0
  89. package/lib/oracles/oracleClientCache.js +19 -0
  90. package/lib/oracles/pythClient.d.ts +3 -5
  91. package/lib/oracles/pythClient.js +12 -31
  92. package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
  93. package/lib/oracles/quoteAssetOracleClient.js +21 -0
  94. package/lib/oracles/switchboardClient.d.ts +3 -5
  95. package/lib/oracles/switchboardClient.js +29 -50
  96. package/lib/oracles/types.d.ts +6 -1
  97. package/lib/orderParams.d.ts +14 -5
  98. package/lib/orderParams.js +8 -96
  99. package/lib/orders.d.ts +6 -7
  100. package/lib/orders.js +11 -89
  101. package/lib/slot/SlotSubscriber.d.ts +19 -0
  102. package/lib/slot/SlotSubscriber.js +26 -0
  103. package/lib/tx/retryTxSender.d.ts +2 -2
  104. package/lib/tx/retryTxSender.js +108 -123
  105. package/lib/tx/types.d.ts +5 -1
  106. package/lib/tx/utils.d.ts +1 -1
  107. package/lib/tx/utils.js +11 -2
  108. package/lib/types.d.ts +180 -110
  109. package/lib/types.js +54 -1
  110. package/lib/userName.d.ts +4 -0
  111. package/lib/userName.js +20 -0
  112. package/lib/util/computeUnits.js +10 -21
  113. package/lib/util/tps.js +11 -22
  114. package/lib/wallet.js +7 -20
  115. package/package.json +11 -4
  116. package/src/accounts/bulkAccountLoader.js +197 -0
  117. package/src/accounts/bulkAccountLoader.ts +21 -15
  118. package/src/accounts/bulkUserSubscription.js +33 -0
  119. package/src/accounts/bulkUserSubscription.ts +1 -45
  120. package/src/accounts/fetch.js +29 -0
  121. package/src/accounts/fetch.ts +33 -0
  122. package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
  123. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
  124. package/src/accounts/pollingOracleSubscriber.js +93 -0
  125. package/src/accounts/pollingOracleSubscriber.ts +16 -8
  126. package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
  127. package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
  128. package/src/accounts/pollingUserAccountSubscriber.js +132 -0
  129. package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
  130. package/src/accounts/types.js +10 -0
  131. package/src/accounts/types.ts +41 -70
  132. package/src/accounts/utils.js +7 -0
  133. package/src/accounts/webSocketAccountSubscriber.js +93 -0
  134. package/src/accounts/webSocketAccountSubscriber.ts +33 -16
  135. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
  136. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
  137. package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
  138. package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
  139. package/src/addresses/marketAddresses.js +26 -0
  140. package/src/addresses/marketAddresses.ts +18 -0
  141. package/{lib/addresses.js → src/addresses/pda.js} +45 -34
  142. package/src/addresses/pda.ts +118 -0
  143. package/src/admin.ts +247 -336
  144. package/src/assert/assert.js +9 -0
  145. package/src/clearingHouse.ts +1023 -1026
  146. package/src/clearingHouseConfig.ts +37 -0
  147. package/src/clearingHouseUser.ts +275 -185
  148. package/src/clearingHouseUserConfig.ts +18 -0
  149. package/src/config.ts +54 -1
  150. package/src/constants/banks.ts +50 -0
  151. package/src/constants/markets.ts +16 -207
  152. package/src/constants/numericConstants.ts +34 -5
  153. package/src/events/eventList.js +77 -0
  154. package/src/events/eventList.ts +94 -0
  155. package/src/events/eventSubscriber.js +139 -0
  156. package/src/events/eventSubscriber.ts +194 -0
  157. package/src/events/fetchLogs.js +50 -0
  158. package/src/events/fetchLogs.ts +80 -0
  159. package/src/events/pollingLogProvider.js +64 -0
  160. package/src/events/pollingLogProvider.ts +79 -0
  161. package/src/events/sort.js +44 -0
  162. package/src/events/sort.ts +65 -0
  163. package/src/events/txEventCache.js +71 -0
  164. package/src/events/txEventCache.ts +74 -0
  165. package/src/events/types.js +20 -0
  166. package/src/events/types.ts +98 -0
  167. package/src/events/webSocketLogProvider.js +41 -0
  168. package/src/events/webSocketLogProvider.ts +38 -0
  169. package/src/examples/makeTradeExample.js +80 -0
  170. package/src/examples/makeTradeExample.ts +20 -11
  171. package/src/factory/bigNum.js +364 -0
  172. package/src/factory/bigNum.ts +524 -0
  173. package/src/factory/oracleClient.js +20 -0
  174. package/src/factory/oracleClient.ts +7 -4
  175. package/src/idl/clearing_house.json +2258 -2774
  176. package/src/index.js +69 -0
  177. package/src/index.ts +14 -5
  178. package/src/math/amm.js +369 -0
  179. package/src/math/amm.ts +382 -243
  180. package/src/math/auction.js +42 -0
  181. package/src/math/auction.ts +43 -0
  182. package/src/math/bankBalance.js +75 -0
  183. package/src/math/bankBalance.ts +112 -0
  184. package/src/math/conversion.js +11 -0
  185. package/src/math/conversion.ts +1 -11
  186. package/src/math/funding.js +248 -0
  187. package/src/math/funding.ts +12 -9
  188. package/src/math/market.js +57 -0
  189. package/src/math/market.ts +37 -30
  190. package/src/math/oracles.js +26 -0
  191. package/src/math/orders.js +110 -0
  192. package/src/math/orders.ts +43 -1
  193. package/src/math/position.js +140 -0
  194. package/src/math/position.ts +52 -35
  195. package/src/math/repeg.js +128 -0
  196. package/src/math/repeg.ts +176 -0
  197. package/src/math/state.js +15 -0
  198. package/src/math/trade.js +253 -0
  199. package/src/math/trade.ts +55 -47
  200. package/src/math/utils.js +26 -0
  201. package/src/math/utils.js.map +1 -0
  202. package/src/mockUSDCFaucet.js +171 -0
  203. package/src/oracles/oracleClientCache.js +19 -0
  204. package/src/oracles/oracleClientCache.ts +20 -0
  205. package/src/oracles/pythClient.js +46 -0
  206. package/src/oracles/pythClient.ts +4 -11
  207. package/src/oracles/quoteAssetOracleClient.js +32 -0
  208. package/src/oracles/quoteAssetOracleClient.ts +25 -0
  209. package/src/oracles/switchboardClient.js +69 -0
  210. package/src/oracles/switchboardClient.ts +11 -24
  211. package/src/oracles/types.js +2 -0
  212. package/src/oracles/types.ts +7 -1
  213. package/src/orderParams.js +20 -0
  214. package/src/orderParams.ts +20 -141
  215. package/src/orders.js +134 -0
  216. package/src/orders.ts +25 -134
  217. package/src/slot/SlotSubscriber.js +39 -0
  218. package/src/slot/SlotSubscriber.ts +42 -0
  219. package/src/token/index.js +38 -0
  220. package/src/tx/retryTxSender.js +188 -0
  221. package/src/tx/retryTxSender.ts +6 -4
  222. package/src/tx/types.js +2 -0
  223. package/src/tx/types.ts +6 -1
  224. package/src/tx/utils.js +17 -0
  225. package/src/tx/utils.ts +22 -3
  226. package/src/types.js +114 -0
  227. package/src/types.ts +176 -124
  228. package/src/userName.js +20 -0
  229. package/src/userName.ts +20 -0
  230. package/src/util/promiseTimeout.js +14 -0
  231. package/src/util/tps.js +27 -0
  232. package/src/wallet.js +35 -0
  233. package/tests/bn/test.ts +255 -0
  234. package/tsconfig.json +12 -12
  235. package/lib/addresses.d.ts +0 -10
  236. package/lib/constants/accounts.d.ts +0 -15
  237. package/lib/constants/accounts.js +0 -18
  238. package/lib/factory/clearingHouse.d.ts +0 -35
  239. package/lib/factory/clearingHouse.js +0 -81
  240. package/lib/factory/clearingHouseUser.d.ts +0 -19
  241. package/lib/factory/clearingHouseUser.js +0 -34
  242. package/lib/math/insuranceFund.d.ts +0 -15
  243. package/lib/math/insuranceFund.js +0 -33
  244. package/lib/settlement.d.ts +0 -4
  245. package/lib/settlement.js +0 -10
  246. package/lib/tx/defaultTxSender.d.ts +0 -8
  247. package/lib/tx/defaultTxSender.js +0 -12
  248. package/src/addresses.ts +0 -82
  249. package/src/constants/accounts.ts +0 -26
  250. package/src/factory/clearingHouse.ts +0 -173
  251. package/src/factory/clearingHouseUser.ts +0 -73
  252. package/src/math/insuranceFund.ts +0 -29
  253. package/src/settlement.ts +0 -9
  254. package/src/tx/defaultTxSender.ts +0 -24
package/src/math/amm.ts CHANGED
@@ -4,50 +4,257 @@ import {
4
4
  MARK_PRICE_PRECISION,
5
5
  PEG_PRECISION,
6
6
  ZERO,
7
- AMM_TO_QUOTE_PRECISION_RATIO,
8
- QUOTE_PRECISION,
9
- AMM_RESERVE_PRECISION,
10
7
  BID_ASK_SPREAD_PRECISION,
11
8
  ONE,
9
+ AMM_TO_QUOTE_PRECISION_RATIO,
10
+ QUOTE_PRECISION,
11
+ MARGIN_PRECISION,
12
+ PRICE_DIV_PEG,
12
13
  } from '../constants/numericConstants';
13
- import { calculateBaseAssetValue } from './position';
14
14
  import {
15
15
  AMM,
16
16
  PositionDirection,
17
17
  SwapDirection,
18
- Market,
18
+ MarketAccount,
19
19
  isVariant,
20
20
  } from '../types';
21
21
  import { assert } from '../assert/assert';
22
+ import { squareRootBN } from '..';
23
+
24
+ import { OraclePriceData } from '../oracles/types';
22
25
  import {
23
- calculatePositionPNL,
24
- calculateMarkPrice,
25
- convertToNumber,
26
- squareRootBN,
27
- } from '..';
26
+ calculateRepegCost,
27
+ calculateAdjustKCost,
28
+ calculateBudgetedPeg,
29
+ } from './repeg';
30
+
31
+ export function calculatePegFromTargetPrice(
32
+ targetPrice: BN,
33
+ baseAssetReserve: BN,
34
+ quoteAssetReserve: BN
35
+ ): BN {
36
+ return targetPrice
37
+ .mul(baseAssetReserve)
38
+ .div(quoteAssetReserve)
39
+ .add(PRICE_DIV_PEG.div(new BN(2)))
40
+ .div(PRICE_DIV_PEG);
41
+ }
42
+
43
+ export function calculateOptimalPegAndBudget(
44
+ amm: AMM,
45
+ oraclePriceData: OraclePriceData
46
+ ): [BN, BN, BN, boolean] {
47
+ const markPriceBefore = calculatePrice(
48
+ amm.baseAssetReserve,
49
+ amm.quoteAssetReserve,
50
+ amm.pegMultiplier
51
+ );
52
+ const targetPrice = oraclePriceData.price;
53
+ const newPeg = calculatePegFromTargetPrice(
54
+ targetPrice,
55
+ amm.baseAssetReserve,
56
+ amm.quoteAssetReserve
57
+ );
58
+ const prePegCost = calculateRepegCost(amm, newPeg);
59
+
60
+ const totalFeeLB = amm.totalExchangeFee.div(new BN(2));
61
+ const budget = BN.max(ZERO, amm.totalFeeMinusDistributions.sub(totalFeeLB));
62
+ if (budget.lt(prePegCost)) {
63
+ const maxPriceSpread = new BN(amm.maxSpread)
64
+ .mul(targetPrice)
65
+ .div(BID_ASK_SPREAD_PRECISION);
66
+
67
+ let newTargetPrice: BN;
68
+ let newOptimalPeg: BN;
69
+ let newBudget: BN;
70
+ const targetPriceGap = markPriceBefore.sub(targetPrice);
71
+
72
+ if (targetPriceGap.abs().gt(maxPriceSpread)) {
73
+ const markAdj = targetPriceGap.abs().sub(maxPriceSpread);
74
+
75
+ if (targetPriceGap.lt(new BN(0))) {
76
+ newTargetPrice = markPriceBefore.add(markAdj);
77
+ } else {
78
+ newTargetPrice = markPriceBefore.sub(markAdj);
79
+ }
80
+
81
+ newOptimalPeg = calculatePegFromTargetPrice(
82
+ newTargetPrice,
83
+ amm.baseAssetReserve,
84
+ amm.quoteAssetReserve
85
+ );
86
+
87
+ newBudget = calculateRepegCost(amm, newOptimalPeg);
88
+ return [newTargetPrice, newOptimalPeg, newBudget, false];
89
+ }
90
+ }
91
+
92
+ return [targetPrice, newPeg, budget, true];
93
+ }
94
+
95
+ export function calculateNewAmm(
96
+ amm: AMM,
97
+ oraclePriceData: OraclePriceData
98
+ ): [BN, BN, BN, BN] {
99
+ let pKNumer = new BN(1);
100
+ let pKDenom = new BN(1);
101
+
102
+ const [targetPrice, _newPeg, budget, checkLowerBound] =
103
+ calculateOptimalPegAndBudget(amm, oraclePriceData);
104
+ let prePegCost = calculateRepegCost(amm, _newPeg);
105
+ let newPeg = _newPeg;
106
+
107
+ if (prePegCost.gt(budget) && checkLowerBound) {
108
+ [pKNumer, pKDenom] = [new BN(999), new BN(1000)];
109
+ const deficitMadeup = calculateAdjustKCost(amm, pKNumer, pKDenom);
110
+ assert(deficitMadeup.lte(new BN(0)));
111
+ prePegCost = budget.add(deficitMadeup.abs());
112
+ const newAmm = Object.assign({}, amm);
113
+ newAmm.baseAssetReserve = newAmm.baseAssetReserve.mul(pKNumer).div(pKDenom);
114
+ newAmm.sqrtK = newAmm.sqrtK.mul(pKNumer).div(pKDenom);
115
+ const invariant = newAmm.sqrtK.mul(newAmm.sqrtK);
116
+ newAmm.quoteAssetReserve = invariant.div(newAmm.baseAssetReserve);
117
+ const directionToClose = amm.netBaseAssetAmount.gt(ZERO)
118
+ ? PositionDirection.SHORT
119
+ : PositionDirection.LONG;
120
+
121
+ const [newQuoteAssetReserve, _newBaseAssetReserve] =
122
+ calculateAmmReservesAfterSwap(
123
+ newAmm,
124
+ 'base',
125
+ amm.netBaseAssetAmount.abs(),
126
+ getSwapDirection('base', directionToClose)
127
+ );
128
+
129
+ newAmm.terminalQuoteAssetReserve = newQuoteAssetReserve;
130
+
131
+ newPeg = calculateBudgetedPeg(newAmm, prePegCost, targetPrice);
132
+ prePegCost = calculateRepegCost(newAmm, newPeg);
133
+ }
134
+
135
+ return [prePegCost, pKNumer, pKDenom, newPeg];
136
+ }
137
+
138
+ export function calculateUpdatedAMM(
139
+ amm: AMM,
140
+ oraclePriceData: OraclePriceData
141
+ ): AMM {
142
+ if (amm.curveUpdateIntensity == 0) {
143
+ return amm;
144
+ }
145
+ const newAmm = Object.assign({}, amm);
146
+ const [prepegCost, pKNumer, pKDenom, newPeg] = calculateNewAmm(
147
+ amm,
148
+ oraclePriceData
149
+ );
150
+
151
+ newAmm.baseAssetReserve = newAmm.baseAssetReserve.mul(pKNumer).div(pKDenom);
152
+ newAmm.sqrtK = newAmm.sqrtK.mul(pKNumer).div(pKDenom);
153
+ const invariant = newAmm.sqrtK.mul(newAmm.sqrtK);
154
+ newAmm.quoteAssetReserve = invariant.div(newAmm.baseAssetReserve);
155
+ newAmm.pegMultiplier = newPeg;
156
+
157
+ const directionToClose = amm.netBaseAssetAmount.gt(ZERO)
158
+ ? PositionDirection.SHORT
159
+ : PositionDirection.LONG;
160
+
161
+ const [newQuoteAssetReserve, _newBaseAssetReserve] =
162
+ calculateAmmReservesAfterSwap(
163
+ newAmm,
164
+ 'base',
165
+ amm.netBaseAssetAmount.abs(),
166
+ getSwapDirection('base', directionToClose)
167
+ );
168
+
169
+ newAmm.terminalQuoteAssetReserve = newQuoteAssetReserve;
170
+
171
+ newAmm.totalFeeMinusDistributions =
172
+ newAmm.totalFeeMinusDistributions.sub(prepegCost);
173
+
174
+ return newAmm;
175
+ }
176
+
177
+ export function calculateUpdatedAMMSpreadReserves(
178
+ amm: AMM,
179
+ direction: PositionDirection,
180
+ oraclePriceData: OraclePriceData
181
+ ): { baseAssetReserve: BN; quoteAssetReserve: BN; sqrtK: BN; newPeg: BN } {
182
+ const newAmm = calculateUpdatedAMM(amm, oraclePriceData);
183
+ const dirReserves = calculateSpreadReserves(
184
+ newAmm,
185
+ direction,
186
+ oraclePriceData
187
+ );
188
+ const result = {
189
+ baseAssetReserve: dirReserves.baseAssetReserve,
190
+ quoteAssetReserve: dirReserves.quoteAssetReserve,
191
+ sqrtK: newAmm.sqrtK,
192
+ newPeg: newAmm.pegMultiplier,
193
+ };
194
+
195
+ return result;
196
+ }
197
+
198
+ export function calculateBidAskPrice(
199
+ amm: AMM,
200
+ oraclePriceData: OraclePriceData,
201
+ withUpdate = true
202
+ ): [BN, BN] {
203
+ let newAmm: AMM;
204
+ if (withUpdate) {
205
+ newAmm = calculateUpdatedAMM(amm, oraclePriceData);
206
+ } else {
207
+ newAmm = amm;
208
+ }
209
+
210
+ const askReserves = calculateSpreadReserves(
211
+ newAmm,
212
+ PositionDirection.LONG,
213
+ oraclePriceData
214
+ );
215
+ const bidReserves = calculateSpreadReserves(
216
+ newAmm,
217
+ PositionDirection.SHORT,
218
+ oraclePriceData
219
+ );
220
+
221
+ const askPrice = calculatePrice(
222
+ askReserves.baseAssetReserve,
223
+ askReserves.quoteAssetReserve,
224
+ newAmm.pegMultiplier
225
+ );
226
+
227
+ const bidPrice = calculatePrice(
228
+ bidReserves.baseAssetReserve,
229
+ bidReserves.quoteAssetReserve,
230
+ newAmm.pegMultiplier
231
+ );
232
+
233
+ return [bidPrice, askPrice];
234
+ }
28
235
 
29
236
  /**
30
237
  * Calculates a price given an arbitrary base and quote amount (they must have the same precision)
31
238
  *
32
- * @param baseAssetAmount
33
- * @param quoteAssetAmount
34
- * @param peg_multiplier
239
+ * @param baseAssetReserves
240
+ * @param quoteAssetReserves
241
+ * @param pegMultiplier
35
242
  * @returns price : Precision MARK_PRICE_PRECISION
36
243
  */
37
244
  export function calculatePrice(
38
- baseAssetAmount: BN,
39
- quoteAssetAmount: BN,
40
- peg_multiplier: BN
245
+ baseAssetReserves: BN,
246
+ quoteAssetReserves: BN,
247
+ pegMultiplier: BN
41
248
  ): BN {
42
- if (baseAssetAmount.abs().lte(ZERO)) {
249
+ if (baseAssetReserves.abs().lte(ZERO)) {
43
250
  return new BN(0);
44
251
  }
45
252
 
46
- return quoteAssetAmount
253
+ return quoteAssetReserves
47
254
  .mul(MARK_PRICE_PRECISION)
48
- .mul(peg_multiplier)
255
+ .mul(pegMultiplier)
49
256
  .div(PEG_PRECISION)
50
- .div(baseAssetAmount);
257
+ .div(baseAssetReserves);
51
258
  }
52
259
 
53
260
  export type AssetType = 'quote' | 'base';
@@ -98,17 +305,154 @@ export function calculateAmmReservesAfterSwap(
98
305
  return [newQuoteAssetReserve, newBaseAssetReserve];
99
306
  }
100
307
 
308
+ export function calculateEffectiveLeverage(
309
+ baseSpread: number,
310
+ quoteAssetReserve: BN,
311
+ terminalQuoteAssetReserve: BN,
312
+ pegMultiplier: BN,
313
+ netBaseAssetAmount: BN,
314
+ markPrice: BN,
315
+ totalFeeMinusDistributions: BN
316
+ ): number {
317
+ // inventory skew
318
+ const netBaseAssetValue = quoteAssetReserve
319
+ .sub(terminalQuoteAssetReserve)
320
+ .mul(pegMultiplier)
321
+ .div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
322
+
323
+ const localBaseAssetValue = netBaseAssetAmount
324
+ .mul(markPrice)
325
+ .div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
326
+
327
+ const effectiveLeverage =
328
+ localBaseAssetValue.sub(netBaseAssetValue).toNumber() /
329
+ (Math.max(0, totalFeeMinusDistributions.toNumber()) + 1) +
330
+ 1 / QUOTE_PRECISION.toNumber();
331
+
332
+ return effectiveLeverage;
333
+ }
334
+
335
+ export function calculateMaxSpread(marginRatioInitial: number): number {
336
+ const maxTargetSpread: number = new BN(marginRatioInitial)
337
+ .mul(BID_ASK_SPREAD_PRECISION.div(MARGIN_PRECISION))
338
+ .toNumber();
339
+
340
+ return maxTargetSpread;
341
+ }
342
+
343
+ export function calculateSpreadBN(
344
+ baseSpread: number,
345
+ lastOracleMarkSpreadPct: BN,
346
+ lastOracleConfPct: BN,
347
+ maxSpread: number,
348
+ quoteAssetReserve: BN,
349
+ terminalQuoteAssetReserve: BN,
350
+ pegMultiplier: BN,
351
+ netBaseAssetAmount: BN,
352
+ markPrice: BN,
353
+ totalFeeMinusDistributions: BN
354
+ ): [number, number] {
355
+ let longSpread = baseSpread / 2;
356
+ let shortSpread = baseSpread / 2;
357
+
358
+ if (lastOracleMarkSpreadPct.gt(ZERO)) {
359
+ shortSpread = Math.max(
360
+ shortSpread,
361
+ lastOracleMarkSpreadPct.abs().toNumber() + lastOracleConfPct.toNumber()
362
+ );
363
+ } else if (lastOracleMarkSpreadPct.lt(ZERO)) {
364
+ longSpread = Math.max(
365
+ longSpread,
366
+ lastOracleMarkSpreadPct.abs().toNumber() + lastOracleConfPct.toNumber()
367
+ );
368
+ }
369
+
370
+ const maxTargetSpread: number = maxSpread;
371
+
372
+ const MAX_INVENTORY_SKEW = 5;
373
+
374
+ const effectiveLeverage = calculateEffectiveLeverage(
375
+ baseSpread,
376
+ quoteAssetReserve,
377
+ terminalQuoteAssetReserve,
378
+ pegMultiplier,
379
+ netBaseAssetAmount,
380
+ markPrice,
381
+ totalFeeMinusDistributions
382
+ );
383
+
384
+ if (totalFeeMinusDistributions.gt(ZERO)) {
385
+ const spreadScale = Math.min(MAX_INVENTORY_SKEW, 1 + effectiveLeverage);
386
+ if (netBaseAssetAmount.gt(ZERO)) {
387
+ longSpread *= spreadScale;
388
+ } else {
389
+ shortSpread *= spreadScale;
390
+ }
391
+ } else {
392
+ longSpread *= MAX_INVENTORY_SKEW;
393
+ shortSpread *= MAX_INVENTORY_SKEW;
394
+ }
395
+
396
+ const totalSpread = longSpread + shortSpread;
397
+ if (totalSpread > maxTargetSpread) {
398
+ if (longSpread > shortSpread) {
399
+ longSpread = Math.min(longSpread, maxTargetSpread);
400
+ shortSpread = maxTargetSpread - longSpread;
401
+ } else {
402
+ shortSpread = Math.min(shortSpread, maxTargetSpread);
403
+ longSpread = maxTargetSpread - shortSpread;
404
+ }
405
+ }
406
+
407
+ return [longSpread, shortSpread];
408
+ }
409
+
101
410
  export function calculateSpread(
102
411
  amm: AMM,
103
- direction: PositionDirection
412
+ direction: PositionDirection,
413
+ oraclePriceData: OraclePriceData
104
414
  ): number {
105
- let spread;
415
+ if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
416
+ return amm.baseSpread / 2;
417
+ }
418
+
419
+ const markPrice = calculatePrice(
420
+ amm.baseAssetReserve,
421
+ amm.quoteAssetReserve,
422
+ amm.pegMultiplier
423
+ );
424
+
425
+ const targetPrice = oraclePriceData?.price || markPrice;
426
+ const confInterval = oraclePriceData.confidence || ZERO;
427
+
428
+ const targetMarkSpreadPct = markPrice
429
+ .sub(targetPrice)
430
+ .mul(BID_ASK_SPREAD_PRECISION)
431
+ .div(markPrice);
432
+
433
+ const confIntervalPct = confInterval
434
+ .mul(BID_ASK_SPREAD_PRECISION)
435
+ .div(markPrice);
436
+
437
+ const [longSpread, shortSpread] = calculateSpreadBN(
438
+ amm.baseSpread,
439
+ targetMarkSpreadPct,
440
+ confIntervalPct,
441
+ amm.maxSpread,
442
+ amm.quoteAssetReserve,
443
+ amm.terminalQuoteAssetReserve,
444
+ amm.pegMultiplier,
445
+ amm.netBaseAssetAmount,
446
+ markPrice,
447
+ amm.totalFeeMinusDistributions
448
+ );
449
+
450
+ let spread: number;
106
451
 
107
- // future logic
108
452
  if (isVariant(direction, 'long')) {
109
- spread = amm.baseSpread;
453
+ spread = longSpread;
110
454
  } else {
111
- spread = amm.baseSpread;
455
+ spread = shortSpread;
112
456
  }
113
457
 
114
458
  return spread;
@@ -116,12 +460,13 @@ export function calculateSpread(
116
460
 
117
461
  export function calculateSpreadReserves(
118
462
  amm: AMM,
119
- direction: PositionDirection
463
+ direction: PositionDirection,
464
+ oraclePriceData: OraclePriceData
120
465
  ): {
121
466
  baseAssetReserve: BN;
122
467
  quoteAssetReserve: BN;
123
468
  } {
124
- const spread = calculateSpread(amm, direction);
469
+ const spread = calculateSpread(amm, direction, oraclePriceData);
125
470
 
126
471
  if (spread === 0) {
127
472
  return {
@@ -131,7 +476,7 @@ export function calculateSpreadReserves(
131
476
  }
132
477
 
133
478
  const quoteAsserReserveDelta = amm.quoteAssetReserve.div(
134
- BID_ASK_SPREAD_PRECISION.div(new BN(spread / 4))
479
+ BID_ASK_SPREAD_PRECISION.div(new BN(spread / 2))
135
480
  );
136
481
 
137
482
  let quoteAssetReserve;
@@ -194,133 +539,14 @@ export function getSwapDirection(
194
539
  return SwapDirection.ADD;
195
540
  }
196
541
 
197
- /**
198
- * Helper function calculating adjust k cost
199
- * @param market
200
- * @param marketIndex
201
- * @param numerator
202
- * @param denomenator
203
- * @returns cost : Precision QUOTE_ASSET_PRECISION
204
- */
205
- export function calculateAdjustKCost(
206
- market: Market,
207
- marketIndex: BN,
208
- numerator: BN,
209
- denomenator: BN
210
- ): BN {
211
- const netUserPosition = {
212
- baseAssetAmount: market.baseAssetAmount,
213
- lastCumulativeFundingRate: market.amm.cumulativeFundingRate,
214
- marketIndex: new BN(marketIndex),
215
- quoteAssetAmount: new BN(0),
216
- openOrders: new BN(0),
217
- };
218
-
219
- const currentValue = calculateBaseAssetValue(market, netUserPosition);
220
-
221
- const marketNewK = Object.assign({}, market);
222
- marketNewK.amm = Object.assign({}, market.amm);
223
-
224
- marketNewK.amm.baseAssetReserve = market.amm.baseAssetReserve
225
- .mul(numerator)
226
- .div(denomenator);
227
- marketNewK.amm.quoteAssetReserve = market.amm.quoteAssetReserve
228
- .mul(numerator)
229
- .div(denomenator);
230
- marketNewK.amm.sqrtK = market.amm.sqrtK.mul(numerator).div(denomenator);
231
-
232
- netUserPosition.quoteAssetAmount = currentValue;
233
-
234
- const cost = calculatePositionPNL(marketNewK, netUserPosition);
235
-
236
- const p = PEG_PRECISION.mul(numerator).div(denomenator);
237
- const x = market.amm.baseAssetReserve;
238
- const y = market.amm.quoteAssetReserve;
239
- const delta = market.baseAssetAmount;
240
- const k = market.amm.sqrtK.mul(market.amm.sqrtK);
241
-
242
- const numer1 = PEG_PRECISION.sub(p).mul(y).div(PEG_PRECISION);
243
- const numer20 = k
244
- .mul(p)
245
- .mul(p)
246
- .div(PEG_PRECISION)
247
- .div(PEG_PRECISION)
248
- .div(x.mul(p).div(PEG_PRECISION).add(delta));
249
- const numer21 = k.div(x.add(delta));
250
-
251
- const formulaCost = numer21
252
- .sub(numer20)
253
- .sub(numer1)
254
- .mul(market.amm.pegMultiplier)
255
- .div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
256
- console.log(convertToNumber(formulaCost, QUOTE_PRECISION));
257
-
258
- // p.div(p.mul(x).add(delta)).sub()
259
-
260
- return cost;
261
- }
262
-
263
- /**
264
- * Helper function calculating adjust pegMultiplier (repeg) cost
265
- *
266
- * @param market
267
- * @param marketIndex
268
- * @param newPeg
269
- * @returns cost : Precision QUOTE_ASSET_PRECISION
270
- */
271
- export function calculateRepegCost(
272
- market: Market,
273
- marketIndex: BN,
274
- newPeg: BN
275
- ): BN {
276
- const netUserPosition = {
277
- baseAssetAmount: market.baseAssetAmount,
278
- lastCumulativeFundingRate: market.amm.cumulativeFundingRate,
279
- marketIndex: new BN(marketIndex),
280
- quoteAssetAmount: new BN(0),
281
- openOrders: new BN(0),
282
- };
283
-
284
- const currentValue = calculateBaseAssetValue(market, netUserPosition);
285
- netUserPosition.quoteAssetAmount = currentValue;
286
- const prevMarketPrice = calculateMarkPrice(market);
287
- const marketNewPeg = Object.assign({}, market);
288
- marketNewPeg.amm = Object.assign({}, market.amm);
289
-
290
- // const marketNewPeg = JSON.parse(JSON.stringify(market));
291
- marketNewPeg.amm.pegMultiplier = newPeg;
292
-
293
- console.log(
294
- 'Price moves from',
295
- convertToNumber(prevMarketPrice),
296
- 'to',
297
- convertToNumber(calculateMarkPrice(marketNewPeg))
298
- );
299
-
300
- const cost = calculatePositionPNL(marketNewPeg, netUserPosition);
301
-
302
- const k = market.amm.sqrtK.mul(market.amm.sqrtK);
303
- const newQuoteAssetReserve = k.div(
304
- market.amm.baseAssetReserve.add(netUserPosition.baseAssetAmount)
305
- );
306
- const deltaQuoteAssetReserves = newQuoteAssetReserve.sub(
307
- market.amm.quoteAssetReserve
308
- );
309
- const cost2 = deltaQuoteAssetReserves
310
- .mul(market.amm.pegMultiplier.sub(newPeg))
311
- .div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
312
- console.log(convertToNumber(cost2, QUOTE_PRECISION));
313
- return cost;
314
- }
315
-
316
542
  /**
317
543
  * Helper function calculating terminal price of amm
318
544
  *
319
545
  * @param market
320
546
  * @returns cost : Precision MARK_PRICE_PRECISION
321
547
  */
322
- export function calculateTerminalPrice(market: Market) {
323
- const directionToClose = market.baseAssetAmount.gt(ZERO)
548
+ export function calculateTerminalPrice(market: MarketAccount) {
549
+ const directionToClose = market.amm.netBaseAssetAmount.gt(ZERO)
324
550
  ? PositionDirection.SHORT
325
551
  : PositionDirection.LONG;
326
552
 
@@ -328,7 +554,7 @@ export function calculateTerminalPrice(market: Market) {
328
554
  calculateAmmReservesAfterSwap(
329
555
  market.amm,
330
556
  'base',
331
- market.baseAssetAmount.abs(),
557
+ market.amm.netBaseAssetAmount.abs(),
332
558
  getSwapDirection('base', directionToClose)
333
559
  );
334
560
 
@@ -345,7 +571,7 @@ export function calculateMaxBaseAssetAmountToTrade(
345
571
  amm: AMM,
346
572
  limit_price: BN,
347
573
  direction: PositionDirection,
348
- useSpread: boolean
574
+ oraclePriceData?: OraclePriceData
349
575
  ): [BN, PositionDirection] {
350
576
  const invariant = amm.sqrtK.mul(amm.sqrtK);
351
577
 
@@ -357,15 +583,11 @@ export function calculateMaxBaseAssetAmountToTrade(
357
583
 
358
584
  const newBaseAssetReserve = squareRootBN(newBaseAssetReserveSquared);
359
585
 
360
- let baseAssetReserveBefore;
361
- if (useSpread) {
362
- baseAssetReserveBefore = calculateSpreadReserves(
363
- amm,
364
- direction
365
- ).baseAssetReserve;
366
- } else {
367
- baseAssetReserveBefore = amm.baseAssetReserve;
368
- }
586
+ const baseAssetReserveBefore = calculateSpreadReserves(
587
+ amm,
588
+ direction,
589
+ oraclePriceData
590
+ ).baseAssetReserve;
369
591
 
370
592
  if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
371
593
  return [
@@ -383,89 +605,6 @@ export function calculateMaxBaseAssetAmountToTrade(
383
605
  }
384
606
  }
385
607
 
386
- export function calculateBudgetedK(market: Market, cost: BN): [BN, BN] {
387
- // wolframalpha.com
388
- // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
389
- // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
390
-
391
- // todo: assumes k = x * y
392
- // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
393
-
394
- // const k = market.amm.sqrtK.mul(market.amm.sqrtK);
395
- const x = market.amm.baseAssetReserve;
396
- const y = market.amm.quoteAssetReserve;
397
-
398
- const d = market.baseAssetAmount;
399
- const Q = market.amm.pegMultiplier;
400
-
401
- const C = cost.mul(new BN(-1));
402
-
403
- const numer1 = y.mul(d).mul(Q).div(AMM_RESERVE_PRECISION).div(PEG_PRECISION);
404
- const numer2 = C.mul(x.add(d)).div(QUOTE_PRECISION);
405
- const denom1 = C.mul(x)
406
- .mul(x.add(d))
407
- .div(AMM_RESERVE_PRECISION)
408
- .div(QUOTE_PRECISION);
409
- const denom2 = y
410
- .mul(d)
411
- .mul(d)
412
- .mul(Q)
413
- .div(AMM_RESERVE_PRECISION)
414
- .div(AMM_RESERVE_PRECISION)
415
- .div(PEG_PRECISION);
416
-
417
- const numerator = d
418
- .mul(numer1.add(numer2))
419
- .div(AMM_RESERVE_PRECISION)
420
- .div(AMM_RESERVE_PRECISION)
421
- .div(AMM_TO_QUOTE_PRECISION_RATIO);
422
- const denominator = denom1
423
- .add(denom2)
424
- .div(AMM_RESERVE_PRECISION)
425
- .div(AMM_TO_QUOTE_PRECISION_RATIO);
426
- console.log(numerator, denominator);
427
- // const p = (numerator).div(denominator);
428
-
429
- // const formulaCost = (numer21.sub(numer20).sub(numer1)).mul(market.amm.pegMultiplier).div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
430
- // console.log(convertToNumber(formulaCost, QUOTE_PRECISION))
431
-
432
- return [numerator, denominator];
433
- }
434
-
435
- export function calculateBudgetedPeg(market: Market, cost: BN): BN {
436
- // wolframalpha.com
437
- // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
438
- // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
439
-
440
- // todo: assumes k = x * y
441
- // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
442
-
443
- const k = market.amm.sqrtK.mul(market.amm.sqrtK);
444
- const x = market.amm.baseAssetReserve;
445
- const y = market.amm.quoteAssetReserve;
446
-
447
- const d = market.baseAssetAmount;
448
- const Q = market.amm.pegMultiplier;
449
-
450
- const C = cost.mul(new BN(-1));
451
-
452
- const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
453
- const deltaPegMultiplier = C.mul(MARK_PRICE_PRECISION)
454
- .div(deltaQuoteAssetReserves.div(AMM_TO_QUOTE_PRECISION_RATIO))
455
- .mul(PEG_PRECISION)
456
- .div(QUOTE_PRECISION);
457
- console.log(
458
- Q.toNumber(),
459
- 'change by',
460
- deltaPegMultiplier.toNumber() / MARK_PRICE_PRECISION.toNumber()
461
- );
462
- const newPeg = Q.sub(
463
- deltaPegMultiplier.mul(PEG_PRECISION).div(MARK_PRICE_PRECISION)
464
- );
465
-
466
- return newPeg;
467
- }
468
-
469
608
  export function calculateQuoteAssetAmountSwapped(
470
609
  quoteAssetReserves: BN,
471
610
  pegMultiplier: BN,