@drift-labs/sdk 0.1.36-master.5 → 0.2.0-master.0

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 (197) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +7 -6
  2. package/lib/accounts/bulkAccountLoader.js +83 -93
  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 +8 -12
  26. package/lib/admin.js +366 -490
  27. package/lib/clearingHouse.d.ts +84 -103
  28. package/lib/clearingHouse.js +779 -810
  29. package/lib/clearingHouseConfig.d.ts +34 -0
  30. package/lib/clearingHouseConfig.js +2 -0
  31. package/lib/clearingHouseUser.d.ts +19 -18
  32. package/lib/clearingHouseUser.js +157 -115
  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 +34 -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 +16 -0
  42. package/lib/constants/numericConstants.js +22 -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 +112 -0
  61. package/lib/factory/bigNum.js +356 -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 +1739 -2287
  65. package/lib/index.d.ts +13 -4
  66. package/lib/index.js +13 -4
  67. package/lib/math/amm.d.ts +19 -29
  68. package/lib/math/amm.js +129 -179
  69. package/lib/math/auction.d.ts +5 -0
  70. package/lib/math/auction.js +39 -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/oracles.d.ts +3 -0
  80. package/lib/math/oracles.js +26 -0
  81. package/lib/math/orders.d.ts +5 -0
  82. package/lib/math/orders.js +31 -1
  83. package/lib/math/position.d.ts +7 -4
  84. package/lib/math/position.js +27 -9
  85. package/lib/math/repeg.d.ts +22 -0
  86. package/lib/math/repeg.js +128 -0
  87. package/lib/math/trade.d.ts +13 -8
  88. package/lib/math/trade.js +85 -22
  89. package/lib/mockUSDCFaucet.js +87 -116
  90. package/lib/oracles/oracleClientCache.d.ts +8 -0
  91. package/lib/oracles/oracleClientCache.js +19 -0
  92. package/lib/oracles/pythClient.d.ts +3 -5
  93. package/lib/oracles/pythClient.js +12 -30
  94. package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
  95. package/lib/oracles/quoteAssetOracleClient.js +21 -0
  96. package/lib/oracles/switchboardClient.d.ts +3 -5
  97. package/lib/oracles/switchboardClient.js +29 -47
  98. package/lib/oracles/types.d.ts +7 -1
  99. package/lib/orders.d.ts +6 -6
  100. package/lib/orders.js +10 -9
  101. package/lib/slot/SlotSubscriber.d.ts +12 -0
  102. package/lib/slot/SlotSubscriber.js +23 -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 +105 -98
  109. package/lib/types.js +13 -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 +10 -3
  116. package/src/accounts/bulkAccountLoader.ts +26 -15
  117. package/src/accounts/bulkUserSubscription.ts +1 -45
  118. package/src/accounts/fetch.ts +33 -0
  119. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
  120. package/src/accounts/pollingOracleSubscriber.ts +16 -8
  121. package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
  122. package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
  123. package/src/accounts/types.ts +41 -70
  124. package/src/accounts/webSocketAccountSubscriber.ts +33 -16
  125. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
  126. package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
  127. package/src/addresses/marketAddresses.ts +18 -0
  128. package/src/addresses/pda.ts +118 -0
  129. package/src/admin.ts +209 -267
  130. package/src/clearingHouse.ts +921 -829
  131. package/src/clearingHouseConfig.ts +37 -0
  132. package/src/clearingHouseUser.ts +280 -127
  133. package/src/clearingHouseUserConfig.ts +18 -0
  134. package/src/config.ts +54 -1
  135. package/src/constants/banks.ts +43 -0
  136. package/src/constants/markets.ts +16 -207
  137. package/src/constants/numericConstants.ts +33 -5
  138. package/src/events/eventList.ts +94 -0
  139. package/src/events/eventSubscriber.ts +194 -0
  140. package/src/events/fetchLogs.ts +80 -0
  141. package/src/events/pollingLogProvider.ts +79 -0
  142. package/src/events/sort.ts +65 -0
  143. package/src/events/txEventCache.ts +74 -0
  144. package/src/events/types.ts +98 -0
  145. package/src/events/webSocketLogProvider.ts +38 -0
  146. package/src/examples/makeTradeExample.ts +20 -11
  147. package/src/factory/bigNum.ts +507 -0
  148. package/src/factory/oracleClient.ts +7 -4
  149. package/src/idl/clearing_house.json +1739 -2287
  150. package/src/index.ts +13 -4
  151. package/src/math/amm.ts +229 -245
  152. package/src/math/auction.ts +39 -0
  153. package/src/math/bankBalance.ts +112 -0
  154. package/src/math/conversion.ts +1 -11
  155. package/src/math/funding.ts +12 -9
  156. package/src/math/market.ts +37 -30
  157. package/src/math/oracles.ts +36 -0
  158. package/src/math/orders.ts +38 -0
  159. package/src/math/position.ts +48 -13
  160. package/src/math/repeg.ts +175 -0
  161. package/src/math/trade.ts +114 -36
  162. package/src/math/utils.js +27 -0
  163. package/src/math/utils.js.map +1 -0
  164. package/src/oracles/oracleClientCache.ts +20 -0
  165. package/src/oracles/pythClient.ts +5 -11
  166. package/src/oracles/quoteAssetOracleClient.ts +25 -0
  167. package/src/oracles/switchboardClient.ts +16 -24
  168. package/src/oracles/types.ts +8 -1
  169. package/src/orders.ts +35 -20
  170. package/src/slot/SlotSubscriber.ts +32 -0
  171. package/src/tx/retryTxSender.ts +6 -4
  172. package/src/tx/types.ts +6 -1
  173. package/src/tx/utils.ts +22 -3
  174. package/src/types.ts +108 -110
  175. package/src/userName.ts +20 -0
  176. package/src/util/computeUnits.js +17 -0
  177. package/src/util/computeUnits.js.map +1 -0
  178. package/tests/bn/test.ts +255 -0
  179. package/tsconfig.json +12 -12
  180. package/lib/addresses.d.ts +0 -9
  181. package/lib/addresses.js +0 -87
  182. package/lib/constants/accounts.d.ts +0 -15
  183. package/lib/constants/accounts.js +0 -18
  184. package/lib/factory/clearingHouse.d.ts +0 -35
  185. package/lib/factory/clearingHouse.js +0 -81
  186. package/lib/factory/clearingHouseUser.d.ts +0 -19
  187. package/lib/factory/clearingHouseUser.js +0 -34
  188. package/lib/math/insuranceFund.d.ts +0 -15
  189. package/lib/math/insuranceFund.js +0 -33
  190. package/lib/tx/defaultTxSender.d.ts +0 -8
  191. package/lib/tx/defaultTxSender.js +0 -12
  192. package/src/addresses.ts +0 -71
  193. package/src/constants/accounts.ts +0 -26
  194. package/src/factory/clearingHouse.ts +0 -173
  195. package/src/factory/clearingHouseUser.ts +0 -73
  196. package/src/math/insuranceFund.ts +0 -29
  197. package/src/tx/defaultTxSender.ts +0 -24
package/src/math/trade.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Market, PositionDirection } from '../types';
1
+ import { MarketAccount, PositionDirection, SwapDirection } from '../types';
2
2
  import { BN } from '@project-serum/anchor';
3
3
  import { assert } from '../assert/assert';
4
4
  import {
@@ -7,15 +7,22 @@ import {
7
7
  AMM_TO_QUOTE_PRECISION_RATIO,
8
8
  ZERO,
9
9
  } from '../constants/numericConstants';
10
- import { calculateMarkPrice } from './market';
10
+ import {
11
+ calculateBidPrice,
12
+ calculateAskPrice,
13
+ calculateMarkPrice,
14
+ } from './market';
11
15
  import {
12
16
  calculateAmmReservesAfterSwap,
13
17
  calculatePrice,
14
18
  getSwapDirection,
15
19
  AssetType,
16
- calculateSpreadReserves,
20
+ calculateUpdatedAMMSpreadReserves,
21
+ calculateQuoteAssetAmountSwapped,
17
22
  } from './amm';
18
23
  import { squareRootBN } from './utils';
24
+ import { isVariant } from '../types';
25
+ import { OraclePriceData } from '../oracles/types';
19
26
 
20
27
  const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
21
28
 
@@ -37,6 +44,8 @@ export type PriceImpactUnit =
37
44
  * @param direction
38
45
  * @param amount
39
46
  * @param market
47
+ * @param inputAssetType which asset is being traded
48
+ * @param useSpread whether to consider spread with calculating slippage
40
49
  * @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
41
50
  *
42
51
  * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
@@ -50,10 +59,22 @@ export type PriceImpactUnit =
50
59
  export function calculateTradeSlippage(
51
60
  direction: PositionDirection,
52
61
  amount: BN,
53
- market: Market,
54
- inputAssetType: AssetType = 'quote'
62
+ market: MarketAccount,
63
+ inputAssetType: AssetType = 'quote',
64
+ oraclePriceData?: OraclePriceData,
65
+ useSpread = true
55
66
  ): [BN, BN, BN, BN] {
56
- const oldPrice = calculateMarkPrice(market);
67
+ let oldPrice: BN;
68
+
69
+ if (useSpread && market.amm.baseSpread > 0) {
70
+ if (isVariant(direction, 'long')) {
71
+ oldPrice = calculateAskPrice(market, oraclePriceData);
72
+ } else {
73
+ oldPrice = calculateBidPrice(market, oraclePriceData);
74
+ }
75
+ } else {
76
+ oldPrice = calculateMarkPrice(market, oraclePriceData);
77
+ }
57
78
  if (amount.eq(ZERO)) {
58
79
  return [ZERO, ZERO, oldPrice, oldPrice];
59
80
  }
@@ -61,25 +82,49 @@ export function calculateTradeSlippage(
61
82
  direction,
62
83
  amount,
63
84
  market,
64
- inputAssetType
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
65
97
  );
66
98
 
67
- const entryPrice = calculatePrice(
68
- acquiredBase,
69
- acquiredQuote,
70
- market.amm.pegMultiplier
71
- ).mul(new BN(-1));
99
+ const entryPrice = quoteAssetAmountAcquired
100
+ .mul(AMM_TO_QUOTE_PRECISION_RATIO)
101
+ .mul(MARK_PRICE_PRECISION)
102
+ .div(acquiredBase.abs());
103
+
104
+ let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
105
+ if (useSpread && market.amm.baseSpread > 0) {
106
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
107
+ calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
108
+ amm = {
109
+ baseAssetReserve,
110
+ quoteAssetReserve,
111
+ sqrtK: sqrtK,
112
+ pegMultiplier: newPeg,
113
+ };
114
+ } else {
115
+ amm = market.amm;
116
+ }
72
117
 
73
118
  const newPrice = calculatePrice(
74
- market.amm.baseAssetReserve.sub(acquiredBase),
75
- market.amm.quoteAssetReserve.sub(acquiredQuote),
76
- market.amm.pegMultiplier
119
+ amm.baseAssetReserve.sub(acquiredBase),
120
+ amm.quoteAssetReserve.sub(acquiredQuote),
121
+ amm.pegMultiplier
77
122
  );
78
123
 
79
124
  if (direction == PositionDirection.SHORT) {
80
- assert(newPrice.lt(oldPrice));
125
+ assert(newPrice.lte(oldPrice));
81
126
  } else {
82
- assert(oldPrice.lt(newPrice));
127
+ assert(oldPrice.lte(newPrice));
83
128
  }
84
129
 
85
130
  const pctMaxSlippage = newPrice
@@ -104,14 +149,15 @@ export function calculateTradeSlippage(
104
149
  * @param inputAssetType
105
150
  * @param useSpread
106
151
  * @return
107
- * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
152
+ * | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
108
153
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
109
154
  */
110
155
  export function calculateTradeAcquiredAmounts(
111
156
  direction: PositionDirection,
112
157
  amount: BN,
113
- market: Market,
158
+ market: MarketAccount,
114
159
  inputAssetType: AssetType = 'quote',
160
+ oraclePriceData: OraclePriceData,
115
161
  useSpread = true
116
162
  ): [BN, BN] {
117
163
  if (amount.eq(ZERO)) {
@@ -122,15 +168,13 @@ export function calculateTradeAcquiredAmounts(
122
168
 
123
169
  let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
124
170
  if (useSpread && market.amm.baseSpread > 0) {
125
- const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
126
- market.amm,
127
- direction
128
- );
171
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
172
+ calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
129
173
  amm = {
130
174
  baseAssetReserve,
131
175
  quoteAssetReserve,
132
- sqrtK: market.amm.sqrtK,
133
- pegMultiplier: market.amm.pegMultiplier,
176
+ sqrtK: sqrtK,
177
+ pegMultiplier: newPeg,
134
178
  };
135
179
  } else {
136
180
  amm = market.amm;
@@ -150,44 +194,65 @@ export function calculateTradeAcquiredAmounts(
150
194
  * @param market
151
195
  * @param targetPrice
152
196
  * @param pct optional default is 100% gap filling, can set smaller.
197
+ * @param outputAssetType which asset to trade.
198
+ * @param useSpread whether or not to consider the spread when calculating the trade size
153
199
  * @returns trade direction/size in order to push price to a targetPrice,
154
200
  *
155
201
  * [
156
- * direction => direction of trade required, TODO-PRECISION
202
+ * direction => direction of trade required, PositionDirection
157
203
  * tradeSize => size of trade required, TODO-PRECISION
158
- * entryPrice => the entry price for the trade, TODO-PRECISION
159
- * targetPrice => the target price TODO-PRECISION
204
+ * entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
205
+ * targetPrice => the target price MARK_PRICE_PRECISION
160
206
  * ]
161
207
  */
162
208
  export function calculateTargetPriceTrade(
163
- market: Market,
209
+ market: MarketAccount,
164
210
  targetPrice: BN,
165
211
  pct: BN = MAXPCT,
166
- outputAssetType: AssetType = 'quote'
212
+ outputAssetType: AssetType = 'quote',
213
+ oraclePriceData?: OraclePriceData,
214
+ useSpread = true
167
215
  ): [PositionDirection, BN, BN, BN] {
168
216
  assert(market.amm.baseAssetReserve.gt(ZERO));
169
217
  assert(targetPrice.gt(ZERO));
170
218
  assert(pct.lte(MAXPCT) && pct.gt(ZERO));
171
219
 
172
- const markPriceBefore = calculateMarkPrice(market);
220
+ const markPriceBefore = calculateMarkPrice(market, oraclePriceData);
221
+ const bidPriceBefore = calculateBidPrice(market, oraclePriceData);
222
+ const askPriceBefore = calculateAskPrice(market, oraclePriceData);
173
223
 
224
+ let direction;
174
225
  if (targetPrice.gt(markPriceBefore)) {
175
226
  const priceGap = targetPrice.sub(markPriceBefore);
176
227
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
177
228
  targetPrice = markPriceBefore.add(priceGapScaled);
229
+ direction = PositionDirection.LONG;
178
230
  } else {
179
231
  const priceGap = markPriceBefore.sub(targetPrice);
180
232
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
181
233
  targetPrice = markPriceBefore.sub(priceGapScaled);
234
+ direction = PositionDirection.SHORT;
182
235
  }
183
236
 
184
- let direction;
185
237
  let tradeSize;
186
238
  let baseSize;
187
239
 
188
- const baseAssetReserveBefore = market.amm.baseAssetReserve;
189
- const quoteAssetReserveBefore = market.amm.quoteAssetReserve;
190
- const peg = market.amm.pegMultiplier;
240
+ let baseAssetReserveBefore: BN;
241
+ let quoteAssetReserveBefore: BN;
242
+
243
+ let peg = market.amm.pegMultiplier;
244
+
245
+ if (useSpread && market.amm.baseSpread > 0) {
246
+ const { baseAssetReserve, quoteAssetReserve, newPeg } =
247
+ calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
248
+ baseAssetReserveBefore = baseAssetReserve;
249
+ quoteAssetReserveBefore = quoteAssetReserve;
250
+ peg = newPeg;
251
+ } else {
252
+ baseAssetReserveBefore = market.amm.baseAssetReserve;
253
+ quoteAssetReserveBefore = market.amm.quoteAssetReserve;
254
+ }
255
+
191
256
  const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
192
257
  const k = invariant.mul(MARK_PRICE_PRECISION);
193
258
 
@@ -196,7 +261,20 @@ export function calculateTargetPriceTrade(
196
261
  const biasModifier = new BN(1);
197
262
  let markPriceAfter;
198
263
 
199
- if (markPriceBefore.gt(targetPrice)) {
264
+ if (
265
+ useSpread &&
266
+ targetPrice.lt(askPriceBefore) &&
267
+ targetPrice.gt(bidPriceBefore)
268
+ ) {
269
+ // no trade, market is at target
270
+ if (markPriceBefore.gt(targetPrice)) {
271
+ direction = PositionDirection.SHORT;
272
+ } else {
273
+ direction = PositionDirection.LONG;
274
+ }
275
+ tradeSize = ZERO;
276
+ return [direction, tradeSize, targetPrice, targetPrice];
277
+ } else if (markPriceBefore.gt(targetPrice)) {
200
278
  // overestimate y2
201
279
  baseAssetReserveAfter = squareRootBN(
202
280
  k.div(targetPrice).mul(peg).div(PEG_PRECISION).sub(biasModifier)
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.squareRootBN = void 0;
4
+ const __1 = require("../");
5
+ const squareRootBN = (n, closeness = new __1.BN(1)) => {
6
+ // Assuming the sqrt of n as n only
7
+ let x = n;
8
+ // The closed guess will be stored in the root
9
+ let root;
10
+ // To count the number of iterations
11
+ let count = 0;
12
+ const TWO = new __1.BN(2);
13
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
14
+ while (count < Number.MAX_SAFE_INTEGER) {
15
+ count++;
16
+ // Calculate more closed x
17
+ root = x.add(n.div(x)).div(TWO);
18
+ // Check for closeness
19
+ if (x.sub(root).abs().lte(closeness))
20
+ break;
21
+ // Update root
22
+ x = root;
23
+ }
24
+ return root;
25
+ };
26
+ exports.squareRootBN = squareRootBN;
27
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":";;;AAAA,2BAAyB;AAElB,MAAM,YAAY,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,IAAI,MAAE,CAAC,CAAC,CAAC,EAAE,EAAE;IACxD,mCAAmC;IACnC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,8CAA8C;IAC9C,IAAI,IAAI,CAAC;IAET,oCAAoC;IACpC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,GAAG,GAAG,IAAI,MAAE,CAAC,CAAC,CAAC,CAAC;IAEtB,6DAA6D;IAC7D,OAAO,KAAK,GAAG,MAAM,CAAC,gBAAgB,EAAE;QACvC,KAAK,EAAE,CAAC;QAER,0BAA0B;QAC1B,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEhC,sBAAsB;QACtB,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,MAAM;QAE5C,cAAc;QACd,CAAC,GAAG,IAAI,CAAC;KACT;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AA1BW,QAAA,YAAY,gBA0BvB"}
@@ -0,0 +1,20 @@
1
+ import { OracleClient } from './types';
2
+ import { OracleSource } from '../types';
3
+ import { getOracleClient } from '../factory/oracleClient';
4
+ import { Connection } from '@solana/web3.js';
5
+
6
+ export class OracleClientCache {
7
+ cache = new Map<string, OracleClient>();
8
+ public constructor() {}
9
+
10
+ public get(oracleSource: OracleSource, connection: Connection) {
11
+ const key = Object.keys(oracleSource)[0];
12
+ if (this.cache.has(key)) {
13
+ return this.cache.get(key);
14
+ }
15
+
16
+ const client = getOracleClient(oracleSource, connection);
17
+ this.cache.set(key, client);
18
+ return client;
19
+ }
20
+ }
@@ -1,21 +1,16 @@
1
- import { parsePriceData, PriceData } from '@pythnetwork/client';
1
+ import { parsePriceData } from '@pythnetwork/client';
2
2
  import { Connection, PublicKey } from '@solana/web3.js';
3
- import { OraclePriceData } from './types';
3
+ import { OracleClient, OraclePriceData } from './types';
4
4
  import { BN } from '@project-serum/anchor';
5
5
  import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
6
6
 
7
- export class PythClient {
7
+ export class PythClient implements OracleClient {
8
8
  private connection: Connection;
9
9
 
10
10
  public constructor(connection: Connection) {
11
11
  this.connection = connection;
12
12
  }
13
13
 
14
- public async getPriceData(pricePublicKey: PublicKey): Promise<PriceData> {
15
- const account = await this.connection.getAccountInfo(pricePublicKey);
16
- return parsePriceData(account.data);
17
- }
18
-
19
14
  public async getOraclePriceData(
20
15
  pricePublicKey: PublicKey
21
16
  ): Promise<OraclePriceData> {
@@ -23,9 +18,7 @@ export class PythClient {
23
18
  return this.getOraclePriceDataFromBuffer(accountInfo.data);
24
19
  }
25
20
 
26
- public async getOraclePriceDataFromBuffer(
27
- buffer: Buffer
28
- ): Promise<OraclePriceData> {
21
+ public getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData {
29
22
  const priceData = parsePriceData(buffer);
30
23
  return {
31
24
  price: convertPythPrice(priceData.aggregate.price, priceData.exponent),
@@ -36,6 +29,7 @@ export class PythClient {
36
29
  priceData.twac.value,
37
30
  priceData.exponent
38
31
  ),
32
+ hasSufficientNumberOfDataPoints: true,
39
33
  };
40
34
  }
41
35
  }
@@ -0,0 +1,25 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { OracleClient, OraclePriceData } from './types';
3
+ import { BN } from '@project-serum/anchor';
4
+ import { MARK_PRICE_PRECISION } from '../constants/numericConstants';
5
+
6
+ export const QUOTE_ORACLE_PRICE_DATA: OraclePriceData = {
7
+ price: MARK_PRICE_PRECISION,
8
+ slot: new BN(0),
9
+ confidence: new BN(1),
10
+ hasSufficientNumberOfDataPoints: true,
11
+ };
12
+
13
+ export class QuoteAssetOracleClient implements OracleClient {
14
+ public constructor() {}
15
+
16
+ public async getOraclePriceData(
17
+ _pricePublicKey: PublicKey
18
+ ): Promise<OraclePriceData> {
19
+ return Promise.resolve(QUOTE_ORACLE_PRICE_DATA);
20
+ }
21
+
22
+ public getOraclePriceDataFromBuffer(_buffer: Buffer): OraclePriceData {
23
+ return QUOTE_ORACLE_PRICE_DATA;
24
+ }
25
+ }
@@ -1,25 +1,18 @@
1
- import {
2
- getSwitchboardPid,
3
- SwitchboardDecimal,
4
- } from '@switchboard-xyz/switchboard-v2';
1
+ import { SwitchboardDecimal } from '@switchboard-xyz/switchboard-v2';
5
2
  import { Connection, Keypair, PublicKey } from '@solana/web3.js';
6
- import { DriftEnv } from '../config';
7
3
  import { BN, Program, Idl, AnchorProvider } from '@project-serum/anchor';
8
4
  import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
9
5
  import { OracleClient, OraclePriceData } from './types';
10
6
  import { Wallet } from '../wallet';
11
7
  import switchboardV2Idl from '../idl/switchboard_v2.json';
12
8
 
13
- // cache switchboard program for every client object since itll always be the same
14
- const programMap = new Map<string, Program>();
9
+ let program: Program | undefined;
15
10
 
16
11
  export class SwitchboardClient implements OracleClient {
17
12
  connection: Connection;
18
- env: DriftEnv;
19
13
 
20
- public constructor(connection: Connection, env: DriftEnv) {
14
+ public constructor(connection: Connection) {
21
15
  this.connection = connection;
22
- this.env = env;
23
16
  }
24
17
 
25
18
  public async getOraclePriceData(
@@ -29,10 +22,8 @@ export class SwitchboardClient implements OracleClient {
29
22
  return this.getOraclePriceDataFromBuffer(accountInfo.data);
30
23
  }
31
24
 
32
- public async getOraclePriceDataFromBuffer(
33
- buffer: Buffer
34
- ): Promise<OraclePriceData> {
35
- const program = await this.getProgram();
25
+ public getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData {
26
+ const program = this.getProgram();
36
27
 
37
28
  const aggregatorAccountData =
38
29
  program.account.aggregatorAccountData.coder.accounts.decode(
@@ -48,31 +39,32 @@ export class SwitchboardClient implements OracleClient {
48
39
  .stdDeviation as SwitchboardDecimal
49
40
  );
50
41
 
42
+ const hasSufficientNumberOfDataPoints =
43
+ aggregatorAccountData.latestConfirmedRound.numSuccess >=
44
+ aggregatorAccountData.minOracleResults;
45
+
51
46
  const slot: BN = aggregatorAccountData.latestConfirmedRound.roundOpenSlot;
52
47
  return {
53
48
  price,
54
49
  slot,
55
50
  confidence,
51
+ hasSufficientNumberOfDataPoints,
56
52
  };
57
53
  }
58
54
 
59
- public async getProgram(): Promise<Program> {
60
- if (programMap.has(this.env)) {
61
- return programMap.get(this.env);
55
+ public getProgram(): Program {
56
+ if (program) {
57
+ return program;
62
58
  }
63
59
 
64
- const program = await getSwitchboardProgram(this.env, this.connection);
65
- programMap.set(this.env, program);
60
+ program = getSwitchboardProgram(this.connection);
66
61
  return program;
67
62
  }
68
63
  }
69
64
 
70
- async function getSwitchboardProgram(
71
- env: DriftEnv,
72
- connection: Connection
73
- ): Promise<Program> {
65
+ function getSwitchboardProgram(connection: Connection): Program {
74
66
  const DEFAULT_KEYPAIR = Keypair.fromSeed(new Uint8Array(32).fill(1));
75
- const programId = getSwitchboardPid(env);
67
+ const programId = PublicKey.default;
76
68
  const wallet = new Wallet(DEFAULT_KEYPAIR);
77
69
  const provider = new AnchorProvider(connection, wallet, {});
78
70
 
@@ -1,15 +1,22 @@
1
1
  import { BN } from '@project-serum/anchor';
2
2
  import { PublicKey } from '@solana/web3.js';
3
+ import { OracleSource } from '../types';
3
4
 
4
5
  export type OraclePriceData = {
5
6
  price: BN;
6
7
  slot: BN;
7
8
  confidence: BN;
9
+ hasSufficientNumberOfDataPoints: boolean;
8
10
  twap?: BN;
9
11
  twapConfidence?: BN;
10
12
  };
11
13
 
14
+ export type OracleInfo = {
15
+ publicKey: PublicKey;
16
+ source: OracleSource;
17
+ };
18
+
12
19
  export interface OracleClient {
13
- getOraclePriceDataFromBuffer(buffer: Buffer): Promise<OraclePriceData>;
20
+ getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
14
21
  getOraclePriceData(publicKey: PublicKey): Promise<OraclePriceData>;
15
22
  }
package/src/orders.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isVariant,
3
- Market,
3
+ MarketAccount,
4
4
  Order,
5
5
  PositionDirection,
6
6
  SwapDirection,
@@ -14,6 +14,7 @@ import {
14
14
  calculateSpreadReserves,
15
15
  ClearingHouseUser,
16
16
  isOrderRiskIncreasingInSameDirection,
17
+ standardizeBaseAssetAmount,
17
18
  TEN_THOUSAND,
18
19
  } from '.';
19
20
  import {
@@ -36,9 +37,9 @@ import { OraclePriceData } from '.';
36
37
  export function calculateNewStateAfterOrder(
37
38
  userAccount: UserAccount,
38
39
  userPosition: UserPosition,
39
- market: Market,
40
+ market: MarketAccount,
40
41
  order: Order
41
- ): [UserAccount, UserPosition, Market] | null {
42
+ ): [UserAccount, UserPosition, MarketAccount] | null {
42
43
  if (isVariant(order.status, 'init')) {
43
44
  return null;
44
45
  }
@@ -47,7 +48,7 @@ export function calculateNewStateAfterOrder(
47
48
  market,
48
49
  order
49
50
  );
50
- if (baseAssetAmountToTrade.lt(market.amm.minimumBaseAssetTradeSize)) {
51
+ if (baseAssetAmountToTrade.lt(market.amm.baseAssetAmountStepSize)) {
51
52
  return null;
52
53
  }
53
54
 
@@ -155,8 +156,8 @@ export function calculateNewStateAfterOrder(
155
156
  }
156
157
 
157
158
  function calculateAmountSwapped(
158
- marketBefore: Market,
159
- marketAfter: Market
159
+ marketBefore: MarketAccount,
160
+ marketAfter: MarketAccount
160
161
  ): { quoteAssetAmountSwapped: BN; baseAssetAmountSwapped: BN } {
161
162
  return {
162
163
  quoteAssetAmountSwapped: marketBefore.amm.quoteAssetReserve
@@ -172,7 +173,7 @@ function calculateAmountSwapped(
172
173
  }
173
174
 
174
175
  export function calculateBaseAssetAmountMarketCanExecute(
175
- market: Market,
176
+ market: MarketAccount,
176
177
  order: Order,
177
178
  oraclePriceData?: OraclePriceData
178
179
  ): BN {
@@ -189,7 +190,7 @@ export function calculateBaseAssetAmountMarketCanExecute(
189
190
  }
190
191
 
191
192
  export function calculateAmountToTradeForLimit(
192
- market: Market,
193
+ market: MarketAccount,
193
194
  order: Order,
194
195
  oraclePriceData?: OraclePriceData
195
196
  ): BN {
@@ -213,8 +214,12 @@ export function calculateAmountToTradeForLimit(
213
214
  const [maxAmountToTrade, direction] = calculateMaxBaseAssetAmountToTrade(
214
215
  market.amm,
215
216
  limitPrice,
216
- order.direction,
217
- !order.postOnly
217
+ order.direction
218
+ );
219
+
220
+ const baseAssetAmount = standardizeBaseAssetAmount(
221
+ maxAmountToTrade,
222
+ market.amm.baseAssetAmountStepSize
218
223
  );
219
224
 
220
225
  // Check that directions are the same
@@ -223,13 +228,13 @@ export function calculateAmountToTradeForLimit(
223
228
  return ZERO;
224
229
  }
225
230
 
226
- return maxAmountToTrade.gt(order.baseAssetAmount)
231
+ return baseAssetAmount.gt(order.baseAssetAmount)
227
232
  ? order.baseAssetAmount
228
- : maxAmountToTrade;
233
+ : baseAssetAmount;
229
234
  }
230
235
 
231
236
  export function calculateAmountToTradeForTriggerLimit(
232
- market: Market,
237
+ market: MarketAccount,
233
238
  order: Order
234
239
  ): BN {
235
240
  if (order.baseAssetAmountFilled.eq(ZERO)) {
@@ -256,7 +261,7 @@ function isSameDirection(
256
261
  }
257
262
 
258
263
  function calculateAmountToTradeForTriggerMarket(
259
- market: Market,
264
+ market: MarketAccount,
260
265
  order: Order
261
266
  ): BN {
262
267
  return isTriggerConditionSatisfied(market, order)
@@ -264,8 +269,12 @@ function calculateAmountToTradeForTriggerMarket(
264
269
  : ZERO;
265
270
  }
266
271
 
267
- function isTriggerConditionSatisfied(market: Market, order: Order): boolean {
268
- const markPrice = calculateMarkPrice(market);
272
+ function isTriggerConditionSatisfied(
273
+ market: MarketAccount,
274
+ order: Order,
275
+ oraclePriceData?: OraclePriceData
276
+ ): boolean {
277
+ const markPrice = calculateMarkPrice(market, oraclePriceData);
269
278
  if (isVariant(order.triggerCondition, 'above')) {
270
279
  return markPrice.gt(order.triggerPrice);
271
280
  } else {
@@ -274,9 +283,10 @@ function isTriggerConditionSatisfied(market: Market, order: Order): boolean {
274
283
  }
275
284
 
276
285
  export function calculateBaseAssetAmountUserCanExecute(
277
- market: Market,
286
+ market: MarketAccount,
278
287
  order: Order,
279
- user: ClearingHouseUser
288
+ user: ClearingHouseUser,
289
+ oraclePriceData?: OraclePriceData
280
290
  ): BN {
281
291
  const maxLeverage = user.getMaxLeverage(order.marketIndex, 'Initial');
282
292
  const freeCollateral = user.getFreeCollateral();
@@ -287,7 +297,11 @@ export function calculateBaseAssetAmountUserCanExecute(
287
297
  const position =
288
298
  user.getUserPosition(order.marketIndex) ||
289
299
  user.getEmptyPosition(order.marketIndex);
290
- const positionValue = calculateBaseAssetValue(market, position);
300
+ const positionValue = calculateBaseAssetValue(
301
+ market,
302
+ position,
303
+ oraclePriceData
304
+ );
291
305
  quoteAssetAmount = freeCollateral
292
306
  .mul(maxLeverage)
293
307
  .div(TEN_THOUSAND)
@@ -307,7 +321,8 @@ export function calculateBaseAssetAmountUserCanExecute(
307
321
  if (useSpread) {
308
322
  const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
309
323
  market.amm,
310
- order.direction
324
+ order.direction,
325
+ oraclePriceData
311
326
  );
312
327
  amm = {
313
328
  baseAssetReserve,
@@ -0,0 +1,32 @@
1
+ import { Connection } from '@solana/web3.js';
2
+
3
+ // eslint-disable-next-line @typescript-eslint/ban-types
4
+ type SlotSubscriberConfig = {}; // for future customization
5
+
6
+ export class SlotSubscriber {
7
+ currentSlot: number;
8
+ subscriptionId: number;
9
+
10
+ public constructor(
11
+ private connection: Connection,
12
+ _config?: SlotSubscriberConfig
13
+ ) {}
14
+
15
+ public async subscribe(): Promise<void> {
16
+ this.currentSlot = await this.connection.getSlot('confirmed');
17
+
18
+ this.subscriptionId = this.connection.onSlotChange((slotInfo) => {
19
+ this.currentSlot = slotInfo.slot;
20
+ });
21
+ }
22
+
23
+ public getSlot(): number {
24
+ return this.currentSlot;
25
+ }
26
+
27
+ public async unsubscribe(): Promise<void> {
28
+ if (this.subscriptionId) {
29
+ await this.connection.removeSlotChangeListener(this.subscriptionId);
30
+ }
31
+ }
32
+ }