@drift-labs/sdk 0.1.36-master.7 → 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 +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 +8 -17
  26. package/lib/admin.js +366 -558
  27. package/lib/clearingHouse.d.ts +84 -109
  28. package/lib/clearingHouse.js +778 -899
  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 +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 +2213 -2951
  65. package/lib/index.d.ts +12 -4
  66. package/lib/index.js +12 -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/orders.d.ts +5 -0
  80. package/lib/math/orders.js +31 -1
  81. package/lib/math/position.d.ts +7 -5
  82. package/lib/math/position.js +27 -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 -21
  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/orders.d.ts +6 -6
  98. package/lib/orders.js +10 -9
  99. package/lib/slot/SlotSubscriber.d.ts +12 -0
  100. package/lib/slot/SlotSubscriber.js +23 -0
  101. package/lib/tx/retryTxSender.d.ts +2 -2
  102. package/lib/tx/retryTxSender.js +108 -123
  103. package/lib/tx/types.d.ts +5 -1
  104. package/lib/tx/utils.d.ts +1 -1
  105. package/lib/tx/utils.js +11 -2
  106. package/lib/types.d.ts +105 -109
  107. package/lib/types.js +13 -1
  108. package/lib/userName.d.ts +4 -0
  109. package/lib/userName.js +20 -0
  110. package/lib/util/computeUnits.js +10 -21
  111. package/lib/util/tps.js +11 -22
  112. package/lib/wallet.js +7 -20
  113. package/package.json +10 -3
  114. package/src/accounts/bulkAccountLoader.ts +21 -15
  115. package/src/accounts/bulkUserSubscription.ts +1 -45
  116. package/src/accounts/fetch.ts +33 -0
  117. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
  118. package/src/accounts/pollingOracleSubscriber.ts +16 -8
  119. package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
  120. package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
  121. package/src/accounts/types.ts +41 -70
  122. package/src/accounts/webSocketAccountSubscriber.ts +33 -16
  123. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
  124. package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
  125. package/src/addresses/marketAddresses.ts +18 -0
  126. package/src/addresses/pda.ts +118 -0
  127. package/src/admin.ts +205 -346
  128. package/src/clearingHouse.ts +918 -961
  129. package/src/clearingHouseConfig.ts +37 -0
  130. package/src/clearingHouseUser.ts +275 -185
  131. package/src/clearingHouseUserConfig.ts +18 -0
  132. package/src/config.ts +54 -1
  133. package/src/constants/banks.ts +43 -0
  134. package/src/constants/markets.ts +16 -207
  135. package/src/constants/numericConstants.ts +33 -5
  136. package/src/events/eventList.ts +94 -0
  137. package/src/events/eventSubscriber.ts +194 -0
  138. package/src/events/fetchLogs.ts +80 -0
  139. package/src/events/pollingLogProvider.ts +79 -0
  140. package/src/events/sort.ts +65 -0
  141. package/src/events/txEventCache.ts +74 -0
  142. package/src/events/types.ts +98 -0
  143. package/src/events/webSocketLogProvider.ts +38 -0
  144. package/src/examples/makeTradeExample.ts +20 -11
  145. package/src/factory/bigNum.ts +507 -0
  146. package/src/factory/oracleClient.ts +7 -4
  147. package/src/idl/clearing_house.json +2213 -2951
  148. package/src/index.ts +12 -4
  149. package/src/math/amm.ts +229 -245
  150. package/src/math/auction.ts +39 -0
  151. package/src/math/bankBalance.ts +112 -0
  152. package/src/math/conversion.ts +1 -11
  153. package/src/math/funding.ts +12 -9
  154. package/src/math/market.ts +37 -30
  155. package/src/math/orders.ts +38 -0
  156. package/src/math/position.ts +48 -35
  157. package/src/math/repeg.ts +175 -0
  158. package/src/math/trade.ts +45 -35
  159. package/src/math/utils.js +27 -0
  160. package/src/math/utils.js.map +1 -0
  161. package/src/oracles/oracleClientCache.ts +20 -0
  162. package/src/oracles/pythClient.ts +4 -11
  163. package/src/oracles/quoteAssetOracleClient.ts +25 -0
  164. package/src/oracles/switchboardClient.ts +11 -24
  165. package/src/oracles/types.ts +7 -1
  166. package/src/orders.ts +35 -20
  167. package/src/slot/SlotSubscriber.ts +32 -0
  168. package/src/tx/retryTxSender.ts +6 -4
  169. package/src/tx/types.ts +6 -1
  170. package/src/tx/utils.ts +22 -3
  171. package/src/types.ts +108 -122
  172. package/src/userName.ts +20 -0
  173. package/src/util/computeUnits.js +17 -0
  174. package/src/util/computeUnits.js.map +1 -0
  175. package/tests/bn/test.ts +255 -0
  176. package/tsconfig.json +12 -12
  177. package/lib/addresses.d.ts +0 -10
  178. package/lib/addresses.js +0 -93
  179. package/lib/constants/accounts.d.ts +0 -15
  180. package/lib/constants/accounts.js +0 -18
  181. package/lib/factory/clearingHouse.d.ts +0 -35
  182. package/lib/factory/clearingHouse.js +0 -81
  183. package/lib/factory/clearingHouseUser.d.ts +0 -19
  184. package/lib/factory/clearingHouseUser.js +0 -34
  185. package/lib/math/insuranceFund.d.ts +0 -15
  186. package/lib/math/insuranceFund.js +0 -33
  187. package/lib/settlement.d.ts +0 -4
  188. package/lib/settlement.js +0 -10
  189. package/lib/tx/defaultTxSender.d.ts +0 -8
  190. package/lib/tx/defaultTxSender.js +0 -12
  191. package/src/addresses.ts +0 -82
  192. package/src/constants/accounts.ts +0 -26
  193. package/src/factory/clearingHouse.ts +0 -173
  194. package/src/factory/clearingHouseUser.ts +0 -73
  195. package/src/math/insuranceFund.ts +0 -29
  196. package/src/settlement.ts +0 -9
  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 {
@@ -17,10 +17,12 @@ import {
17
17
  calculatePrice,
18
18
  getSwapDirection,
19
19
  AssetType,
20
- calculateSpreadReserves,
20
+ calculateUpdatedAMMSpreadReserves,
21
+ calculateQuoteAssetAmountSwapped,
21
22
  } from './amm';
22
23
  import { squareRootBN } from './utils';
23
24
  import { isVariant } from '../types';
25
+ import { OraclePriceData } from '../oracles/types';
24
26
 
25
27
  const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
26
28
 
@@ -57,20 +59,21 @@ export type PriceImpactUnit =
57
59
  export function calculateTradeSlippage(
58
60
  direction: PositionDirection,
59
61
  amount: BN,
60
- market: Market,
62
+ market: MarketAccount,
61
63
  inputAssetType: AssetType = 'quote',
64
+ oraclePriceData?: OraclePriceData,
62
65
  useSpread = true
63
66
  ): [BN, BN, BN, BN] {
64
67
  let oldPrice: BN;
65
68
 
66
69
  if (useSpread && market.amm.baseSpread > 0) {
67
70
  if (isVariant(direction, 'long')) {
68
- oldPrice = calculateAskPrice(market);
71
+ oldPrice = calculateAskPrice(market, oraclePriceData);
69
72
  } else {
70
- oldPrice = calculateBidPrice(market);
73
+ oldPrice = calculateBidPrice(market, oraclePriceData);
71
74
  }
72
75
  } else {
73
- oldPrice = calculateMarkPrice(market);
76
+ oldPrice = calculateMarkPrice(market, oraclePriceData);
74
77
  }
75
78
  if (amount.eq(ZERO)) {
76
79
  return [ZERO, ZERO, oldPrice, oldPrice];
@@ -80,26 +83,33 @@ export function calculateTradeSlippage(
80
83
  amount,
81
84
  market,
82
85
  inputAssetType,
86
+ oraclePriceData,
83
87
  useSpread
84
88
  );
85
89
 
86
- const entryPrice = calculatePrice(
87
- acquiredBase,
88
- acquiredQuote,
89
- market.amm.pegMultiplier
90
- ).mul(new BN(-1));
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
+ );
98
+
99
+ const entryPrice = quoteAssetAmountAcquired
100
+ .mul(AMM_TO_QUOTE_PRECISION_RATIO)
101
+ .mul(MARK_PRICE_PRECISION)
102
+ .div(acquiredBase.abs());
91
103
 
92
104
  let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
93
105
  if (useSpread && market.amm.baseSpread > 0) {
94
- const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
95
- market.amm,
96
- direction
97
- );
106
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
107
+ calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
98
108
  amm = {
99
109
  baseAssetReserve,
100
110
  quoteAssetReserve,
101
- sqrtK: market.amm.sqrtK,
102
- pegMultiplier: market.amm.pegMultiplier,
111
+ sqrtK: sqrtK,
112
+ pegMultiplier: newPeg,
103
113
  };
104
114
  } else {
105
115
  amm = market.amm;
@@ -112,9 +122,9 @@ export function calculateTradeSlippage(
112
122
  );
113
123
 
114
124
  if (direction == PositionDirection.SHORT) {
115
- assert(newPrice.lt(oldPrice));
125
+ assert(newPrice.lte(oldPrice));
116
126
  } else {
117
- assert(oldPrice.lt(newPrice));
127
+ assert(oldPrice.lte(newPrice));
118
128
  }
119
129
 
120
130
  const pctMaxSlippage = newPrice
@@ -145,8 +155,9 @@ export function calculateTradeSlippage(
145
155
  export function calculateTradeAcquiredAmounts(
146
156
  direction: PositionDirection,
147
157
  amount: BN,
148
- market: Market,
158
+ market: MarketAccount,
149
159
  inputAssetType: AssetType = 'quote',
160
+ oraclePriceData: OraclePriceData,
150
161
  useSpread = true
151
162
  ): [BN, BN] {
152
163
  if (amount.eq(ZERO)) {
@@ -157,15 +168,13 @@ export function calculateTradeAcquiredAmounts(
157
168
 
158
169
  let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
159
170
  if (useSpread && market.amm.baseSpread > 0) {
160
- const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
161
- market.amm,
162
- direction
163
- );
171
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
172
+ calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
164
173
  amm = {
165
174
  baseAssetReserve,
166
175
  quoteAssetReserve,
167
- sqrtK: market.amm.sqrtK,
168
- pegMultiplier: market.amm.pegMultiplier,
176
+ sqrtK: sqrtK,
177
+ pegMultiplier: newPeg,
169
178
  };
170
179
  } else {
171
180
  amm = market.amm;
@@ -197,19 +206,20 @@ export function calculateTradeAcquiredAmounts(
197
206
  * ]
198
207
  */
199
208
  export function calculateTargetPriceTrade(
200
- market: Market,
209
+ market: MarketAccount,
201
210
  targetPrice: BN,
202
211
  pct: BN = MAXPCT,
203
212
  outputAssetType: AssetType = 'quote',
213
+ oraclePriceData?: OraclePriceData,
204
214
  useSpread = true
205
215
  ): [PositionDirection, BN, BN, BN] {
206
216
  assert(market.amm.baseAssetReserve.gt(ZERO));
207
217
  assert(targetPrice.gt(ZERO));
208
218
  assert(pct.lte(MAXPCT) && pct.gt(ZERO));
209
219
 
210
- const markPriceBefore = calculateMarkPrice(market);
211
- const bidPriceBefore = calculateBidPrice(market);
212
- const askPriceBefore = calculateAskPrice(market);
220
+ const markPriceBefore = calculateMarkPrice(market, oraclePriceData);
221
+ const bidPriceBefore = calculateBidPrice(market, oraclePriceData);
222
+ const askPriceBefore = calculateAskPrice(market, oraclePriceData);
213
223
 
214
224
  let direction;
215
225
  if (targetPrice.gt(markPriceBefore)) {
@@ -230,19 +240,19 @@ export function calculateTargetPriceTrade(
230
240
  let baseAssetReserveBefore: BN;
231
241
  let quoteAssetReserveBefore: BN;
232
242
 
243
+ let peg = market.amm.pegMultiplier;
244
+
233
245
  if (useSpread && market.amm.baseSpread > 0) {
234
- const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
235
- market.amm,
236
- direction
237
- );
246
+ const { baseAssetReserve, quoteAssetReserve, newPeg } =
247
+ calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
238
248
  baseAssetReserveBefore = baseAssetReserve;
239
249
  quoteAssetReserveBefore = quoteAssetReserve;
250
+ peg = newPeg;
240
251
  } else {
241
252
  baseAssetReserveBefore = market.amm.baseAssetReserve;
242
253
  quoteAssetReserveBefore = market.amm.quoteAssetReserve;
243
254
  }
244
255
 
245
- const peg = market.amm.pegMultiplier;
246
256
  const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
247
257
  const k = invariant.mul(MARK_PRICE_PRECISION);
248
258
 
@@ -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),
@@ -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(
@@ -61,23 +52,19 @@ export class SwitchboardClient implements OracleClient {
61
52
  };
62
53
  }
63
54
 
64
- public async getProgram(): Promise<Program> {
65
- if (programMap.has(this.env)) {
66
- return programMap.get(this.env);
55
+ public getProgram(): Program {
56
+ if (program) {
57
+ return program;
67
58
  }
68
59
 
69
- const program = await getSwitchboardProgram(this.env, this.connection);
70
- programMap.set(this.env, program);
60
+ program = getSwitchboardProgram(this.connection);
71
61
  return program;
72
62
  }
73
63
  }
74
64
 
75
- async function getSwitchboardProgram(
76
- env: DriftEnv,
77
- connection: Connection
78
- ): Promise<Program> {
65
+ function getSwitchboardProgram(connection: Connection): Program {
79
66
  const DEFAULT_KEYPAIR = Keypair.fromSeed(new Uint8Array(32).fill(1));
80
- const programId = getSwitchboardPid(env);
67
+ const programId = PublicKey.default;
81
68
  const wallet = new Wallet(DEFAULT_KEYPAIR);
82
69
  const provider = new AnchorProvider(connection, wallet, {});
83
70
 
@@ -1,5 +1,6 @@
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;
@@ -10,7 +11,12 @@ export type OraclePriceData = {
10
11
  twapConfidence?: BN;
11
12
  };
12
13
 
14
+ export type OracleInfo = {
15
+ publicKey: PublicKey;
16
+ source: OracleSource;
17
+ };
18
+
13
19
  export interface OracleClient {
14
- getOraclePriceDataFromBuffer(buffer: Buffer): Promise<OraclePriceData>;
20
+ getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
15
21
  getOraclePriceData(publicKey: PublicKey): Promise<OraclePriceData>;
16
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
+ }
@@ -1,4 +1,4 @@
1
- import { TxSender } from './types';
1
+ import { TxSender, TxSigAndSlot } from './types';
2
2
  import {
3
3
  Commitment,
4
4
  ConfirmOptions,
@@ -43,7 +43,7 @@ export class RetryTxSender implements TxSender {
43
43
  tx: Transaction,
44
44
  additionalSigners?: Array<Signer>,
45
45
  opts?: ConfirmOptions
46
- ): Promise<TransactionSignature> {
46
+ ): Promise<TxSigAndSlot> {
47
47
  if (additionalSigners === undefined) {
48
48
  additionalSigners = [];
49
49
  }
@@ -86,8 +86,10 @@ export class RetryTxSender implements TxSender {
86
86
  }
87
87
  })();
88
88
 
89
+ let slot: number;
89
90
  try {
90
- await this.confirmTransaction(txid, opts.commitment);
91
+ const result = await this.confirmTransaction(txid, opts.commitment);
92
+ slot = result.context.slot;
91
93
  } catch (e) {
92
94
  console.error(e);
93
95
  throw e;
@@ -95,7 +97,7 @@ export class RetryTxSender implements TxSender {
95
97
  stopWaiting();
96
98
  }
97
99
 
98
- return txid;
100
+ return { txSig: txid, slot };
99
101
  }
100
102
 
101
103
  async prepareTx(
package/src/tx/types.ts CHANGED
@@ -6,6 +6,11 @@ import {
6
6
  TransactionSignature,
7
7
  } from '@solana/web3.js';
8
8
 
9
+ export type TxSigAndSlot = {
10
+ txSig: TransactionSignature;
11
+ slot: number;
12
+ };
13
+
9
14
  export interface TxSender {
10
15
  provider: Provider;
11
16
 
@@ -13,5 +18,5 @@ export interface TxSender {
13
18
  tx: Transaction,
14
19
  additionalSigners?: Array<Signer>,
15
20
  opts?: ConfirmOptions
16
- ): Promise<TransactionSignature>;
21
+ ): Promise<TxSigAndSlot>;
17
22
  }
package/src/tx/utils.ts CHANGED
@@ -1,5 +1,24 @@
1
- import { Transaction, TransactionInstruction } from '@solana/web3.js';
1
+ import {
2
+ Transaction,
3
+ TransactionInstruction,
4
+ ComputeBudgetProgram,
5
+ } from '@solana/web3.js';
2
6
 
3
- export function wrapInTx(instruction: TransactionInstruction): Transaction {
4
- return new Transaction().add(instruction);
7
+ const COMPUTE_UNITS_DEFAULT = 200_000;
8
+
9
+ export function wrapInTx(
10
+ instruction: TransactionInstruction,
11
+ computeUnits = 500_000 // TODO, requires less code change
12
+ ): Transaction {
13
+ const tx = new Transaction();
14
+ if (computeUnits != COMPUTE_UNITS_DEFAULT) {
15
+ tx.add(
16
+ ComputeBudgetProgram.requestUnits({
17
+ units: computeUnits,
18
+ additionalFee: 0,
19
+ })
20
+ );
21
+ }
22
+
23
+ return tx.add(instruction);
5
24
  }