@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
@@ -1,62 +1,63 @@
1
1
  import {
2
2
  ClearingHouseAccountSubscriber,
3
3
  ClearingHouseAccountEvents,
4
- ClearingHouseAccountTypes,
4
+ DataAndSlot,
5
5
  } from './types';
6
6
  import { AccountSubscriber, NotSubscribedError } from './types';
7
- import {
8
- DepositHistoryAccount,
9
- ExtendedCurveHistoryAccount,
10
- FundingPaymentHistoryAccount,
11
- FundingRateHistoryAccount,
12
- LiquidationHistoryAccount,
13
- MarketsAccount,
14
- OrderHistoryAccount,
15
- OrderStateAccount,
16
- StateAccount,
17
- TradeHistoryAccount,
18
- } from '../types';
19
- import { Program } from '@project-serum/anchor';
7
+ import { BankAccount, MarketAccount, StateAccount } from '../types';
8
+ import { BN, Program } from '@project-serum/anchor';
20
9
  import StrictEventEmitter from 'strict-event-emitter-types';
21
10
  import { EventEmitter } from 'events';
22
- import { getClearingHouseStateAccountPublicKey } from '../addresses';
11
+ import {
12
+ getClearingHouseStateAccountPublicKey,
13
+ getBankPublicKey,
14
+ getMarketPublicKey,
15
+ } from '../addresses/pda';
23
16
  import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
24
- import { ClearingHouseConfigType } from '../factory/clearingHouse';
17
+ import { PublicKey } from '@solana/web3.js';
18
+ import { OracleInfo, OraclePriceData } from '../oracles/types';
19
+ import { OracleClientCache } from '../oracles/oracleClientCache';
20
+ import * as Buffer from 'buffer';
21
+ import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
25
22
 
26
23
  export class WebSocketClearingHouseAccountSubscriber
27
24
  implements ClearingHouseAccountSubscriber
28
25
  {
29
26
  isSubscribed: boolean;
30
27
  program: Program;
28
+ marketIndexes: BN[];
29
+ bankIndexes: BN[];
30
+ oracleInfos: OracleInfo[];
31
+ oracleClientCache = new OracleClientCache();
32
+
31
33
  eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
32
34
  stateAccountSubscriber?: AccountSubscriber<StateAccount>;
33
- marketsAccountSubscriber?: AccountSubscriber<MarketsAccount>;
34
- tradeHistoryAccountSubscriber?: AccountSubscriber<TradeHistoryAccount>;
35
- depositHistoryAccountSubscriber?: AccountSubscriber<DepositHistoryAccount>;
36
- fundingPaymentHistoryAccountSubscriber?: AccountSubscriber<FundingPaymentHistoryAccount>;
37
- fundingRateHistoryAccountSubscriber?: AccountSubscriber<FundingRateHistoryAccount>;
38
- curveHistoryAccountSubscriber?: AccountSubscriber<ExtendedCurveHistoryAccount>;
39
- liquidationHistoryAccountSubscriber?: AccountSubscriber<LiquidationHistoryAccount>;
40
- orderStateAccountSubscriber?: AccountSubscriber<OrderStateAccount>;
41
- orderHistoryAccountSubscriber?: AccountSubscriber<OrderHistoryAccount>;
42
-
43
- optionalExtraSubscriptions: ClearingHouseAccountTypes[] = [];
44
-
45
- type: ClearingHouseConfigType = 'websocket';
35
+ marketAccountSubscribers = new Map<
36
+ number,
37
+ AccountSubscriber<MarketAccount>
38
+ >();
39
+ bankAccountSubscribers = new Map<number, AccountSubscriber<BankAccount>>();
40
+ oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
46
41
 
47
42
  private isSubscribing = false;
48
43
  private subscriptionPromise: Promise<boolean>;
49
44
  private subscriptionPromiseResolver: (val: boolean) => void;
50
45
 
51
- public constructor(program: Program) {
46
+ public constructor(
47
+ program: Program,
48
+ marketIndexes: BN[],
49
+ bankIndexes: BN[],
50
+ oracleInfos: OracleInfo[]
51
+ ) {
52
52
  this.isSubscribed = false;
53
53
  this.program = program;
54
54
  this.eventEmitter = new EventEmitter();
55
+ this.marketIndexes = marketIndexes;
56
+ this.bankIndexes = bankIndexes;
57
+ this.oracleInfos = oracleInfos;
55
58
  }
56
59
 
57
- public async subscribe(
58
- optionalSubscriptions?: ClearingHouseAccountTypes[]
59
- ): Promise<boolean> {
60
+ public async subscribe(): Promise<boolean> {
60
61
  if (this.isSubscribed) {
61
62
  return true;
62
63
  }
@@ -86,146 +87,129 @@ export class WebSocketClearingHouseAccountSubscriber
86
87
  this.eventEmitter.emit('update');
87
88
  });
88
89
 
89
- const state = this.stateAccountSubscriber.data;
90
+ // subscribe to market accounts
91
+ await this.subscribeToMarketAccounts();
90
92
 
91
- this.marketsAccountSubscriber = new WebSocketAccountSubscriber(
92
- 'markets',
93
- this.program,
94
- state.markets
95
- );
93
+ // subscribe to bank accounts
94
+ await this.subscribeToBankAccounts();
96
95
 
97
- await this.marketsAccountSubscriber.subscribe((data: MarketsAccount) => {
98
- this.eventEmitter.emit('marketsAccountUpdate', data);
99
- this.eventEmitter.emit('update');
100
- });
96
+ // subscribe to oracles
97
+ await this.subscribeToOracles();
101
98
 
102
- this.orderStateAccountSubscriber = new WebSocketAccountSubscriber(
103
- 'orderState',
104
- this.program,
105
- state.orderState
106
- );
99
+ this.eventEmitter.emit('update');
107
100
 
108
- await this.orderStateAccountSubscriber.subscribe(
109
- (data: OrderStateAccount) => {
110
- this.eventEmitter.emit('orderStateAccountUpdate', data);
111
- this.eventEmitter.emit('update');
112
- }
113
- );
101
+ this.isSubscribing = false;
102
+ this.isSubscribed = true;
103
+ this.subscriptionPromiseResolver(true);
114
104
 
115
- const orderState = this.orderStateAccountSubscriber.data;
105
+ return true;
106
+ }
116
107
 
117
- // create subscribers for other state accounts
108
+ async subscribeToMarketAccounts(): Promise<boolean> {
109
+ for (const marketIndex of this.marketIndexes) {
110
+ await this.subscribeToMarketAccount(marketIndex);
111
+ }
112
+ return true;
113
+ }
118
114
 
119
- this.tradeHistoryAccountSubscriber = new WebSocketAccountSubscriber(
120
- 'tradeHistory',
121
- this.program,
122
- state.tradeHistory
115
+ async subscribeToMarketAccount(marketIndex: BN): Promise<boolean> {
116
+ const marketPublicKey = await getMarketPublicKey(
117
+ this.program.programId,
118
+ marketIndex
123
119
  );
124
-
125
- this.depositHistoryAccountSubscriber = new WebSocketAccountSubscriber(
126
- 'depositHistory',
120
+ const accountSubscriber = new WebSocketAccountSubscriber<MarketAccount>(
121
+ 'market',
127
122
  this.program,
128
- state.depositHistory
123
+ marketPublicKey
124
+ );
125
+ await accountSubscriber.subscribe((data: MarketAccount) => {
126
+ this.eventEmitter.emit('marketAccountUpdate', data);
127
+ this.eventEmitter.emit('update');
128
+ });
129
+ this.marketAccountSubscribers.set(
130
+ marketIndex.toNumber(),
131
+ accountSubscriber
129
132
  );
133
+ return true;
134
+ }
130
135
 
131
- this.fundingPaymentHistoryAccountSubscriber =
132
- new WebSocketAccountSubscriber(
133
- 'fundingPaymentHistory',
134
- this.program,
135
- state.fundingPaymentHistory
136
- );
136
+ async subscribeToBankAccounts(): Promise<boolean> {
137
+ for (const bankIndex of this.bankIndexes) {
138
+ await this.subscribeToBankAccount(bankIndex);
139
+ }
140
+ return true;
141
+ }
137
142
 
138
- this.fundingRateHistoryAccountSubscriber = new WebSocketAccountSubscriber(
139
- 'fundingRateHistory',
140
- this.program,
141
- state.fundingRateHistory
143
+ async subscribeToBankAccount(bankIndex: BN): Promise<boolean> {
144
+ const bankPublicKey = await getBankPublicKey(
145
+ this.program.programId,
146
+ bankIndex
142
147
  );
143
-
144
- this.liquidationHistoryAccountSubscriber = new WebSocketAccountSubscriber(
145
- 'liquidationHistory',
148
+ const accountSubscriber = new WebSocketAccountSubscriber<BankAccount>(
149
+ 'bank',
146
150
  this.program,
147
- state.liquidationHistory
151
+ bankPublicKey
148
152
  );
153
+ await accountSubscriber.subscribe((data: BankAccount) => {
154
+ this.eventEmitter.emit('bankAccountUpdate', data);
155
+ this.eventEmitter.emit('update');
156
+ });
157
+ this.bankAccountSubscribers.set(bankIndex.toNumber(), accountSubscriber);
158
+ return true;
159
+ }
149
160
 
150
- this.curveHistoryAccountSubscriber = new WebSocketAccountSubscriber(
151
- 'extendedCurveHistory',
152
- this.program,
153
- state.extendedCurveHistory
154
- );
161
+ async subscribeToOracles(): Promise<boolean> {
162
+ for (const oracleInfo of this.oracleInfos) {
163
+ if (!oracleInfo.publicKey.equals(PublicKey.default)) {
164
+ await this.subscribeToOracle(oracleInfo);
165
+ }
166
+ }
155
167
 
156
- this.orderHistoryAccountSubscriber = new WebSocketAccountSubscriber(
157
- 'orderHistory',
168
+ return true;
169
+ }
170
+
171
+ async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
172
+ const client = this.oracleClientCache.get(
173
+ oracleInfo.source,
174
+ this.program.provider.connection
175
+ );
176
+ const accountSubscriber = new WebSocketAccountSubscriber<OraclePriceData>(
177
+ 'oracle',
158
178
  this.program,
159
- orderState.orderHistory
179
+ oracleInfo.publicKey,
180
+ (buffer: Buffer) => {
181
+ return client.getOraclePriceDataFromBuffer(buffer);
182
+ }
160
183
  );
161
184
 
162
- const extraSusbcribersToUse: {
163
- subscriber: AccountSubscriber<any>;
164
- eventType: keyof ClearingHouseAccountEvents;
165
- }[] = [];
166
-
167
- if (optionalSubscriptions?.includes('tradeHistoryAccount'))
168
- extraSusbcribersToUse.push({
169
- subscriber: this.tradeHistoryAccountSubscriber,
170
- eventType: 'tradeHistoryAccountUpdate',
171
- });
172
-
173
- if (optionalSubscriptions?.includes('depositHistoryAccount'))
174
- extraSusbcribersToUse.push({
175
- subscriber: this.depositHistoryAccountSubscriber,
176
- eventType: 'depositHistoryAccountUpdate',
177
- });
178
-
179
- if (optionalSubscriptions?.includes('fundingPaymentHistoryAccount'))
180
- extraSusbcribersToUse.push({
181
- subscriber: this.fundingPaymentHistoryAccountSubscriber,
182
- eventType: 'fundingPaymentHistoryAccountUpdate',
183
- });
184
-
185
- if (optionalSubscriptions?.includes('fundingRateHistoryAccount'))
186
- extraSusbcribersToUse.push({
187
- subscriber: this.fundingRateHistoryAccountSubscriber,
188
- eventType: 'fundingRateHistoryAccountUpdate',
189
- });
190
-
191
- if (optionalSubscriptions?.includes('liquidationHistoryAccount'))
192
- extraSusbcribersToUse.push({
193
- subscriber: this.liquidationHistoryAccountSubscriber,
194
- eventType: 'liquidationHistoryAccountUpdate',
195
- });
196
-
197
- if (optionalSubscriptions?.includes('curveHistoryAccount'))
198
- extraSusbcribersToUse.push({
199
- subscriber: this.curveHistoryAccountSubscriber,
200
- eventType: 'curveHistoryAccountUpdate',
201
- });
202
-
203
- if (optionalSubscriptions?.includes('orderHistoryAccount'))
204
- extraSusbcribersToUse.push({
205
- subscriber: this.orderHistoryAccountSubscriber,
206
- eventType: 'orderHistoryAccountUpdate',
207
- });
208
-
209
- this.optionalExtraSubscriptions = optionalSubscriptions ?? [];
210
-
211
- // await all subcriptions in parallel to boost performance
212
- //// the state account subscription above can't happen in here, because some of these susbcriptions are dependent on clearing house state being available
213
- await Promise.all(
214
- extraSusbcribersToUse.map(({ subscriber, eventType }) =>
215
- subscriber.subscribe((data) => {
216
- this.eventEmitter.emit(eventType, data);
217
- this.eventEmitter.emit('update');
218
- })
219
- )
185
+ await accountSubscriber.subscribe((data: OraclePriceData) => {
186
+ this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
187
+ this.eventEmitter.emit('update');
188
+ });
189
+
190
+ this.oracleSubscribers.set(
191
+ oracleInfo.publicKey.toString(),
192
+ accountSubscriber
220
193
  );
194
+ return true;
195
+ }
221
196
 
222
- this.eventEmitter.emit('update');
197
+ async unsubscribeFromMarketAccounts(): Promise<void> {
198
+ for (const accountSubscriber of this.marketAccountSubscribers.values()) {
199
+ await accountSubscriber.unsubscribe();
200
+ }
201
+ }
223
202
 
224
- this.isSubscribing = false;
225
- this.isSubscribed = true;
226
- this.subscriptionPromiseResolver(true);
203
+ async unsubscribeFromBankAccounts(): Promise<void> {
204
+ for (const accountSubscriber of this.bankAccountSubscribers.values()) {
205
+ await accountSubscriber.unsubscribe();
206
+ }
207
+ }
227
208
 
228
- return true;
209
+ async unsubscribeFromOracles(): Promise<void> {
210
+ for (const accountSubscriber of this.oracleSubscribers.values()) {
211
+ await accountSubscriber.unsubscribe();
212
+ }
229
213
  }
230
214
 
231
215
  public async fetch(): Promise<void> {
@@ -233,15 +217,17 @@ export class WebSocketClearingHouseAccountSubscriber
233
217
  return;
234
218
  }
235
219
 
236
- const promises = this.optionalExtraSubscriptions
237
- .map((optionalSubscription) => {
238
- const subscriber = `${optionalSubscription}Subscriber`;
239
- return this[subscriber].fetch();
240
- })
241
- .concat([
242
- this.stateAccountSubscriber.fetch(),
243
- this.marketsAccountSubscriber.fetch(),
244
- ]);
220
+ const promises = [this.stateAccountSubscriber.fetch()]
221
+ .concat(
222
+ Array.from(this.marketAccountSubscribers.values()).map((subscriber) =>
223
+ subscriber.fetch()
224
+ )
225
+ )
226
+ .concat(
227
+ Array.from(this.bankAccountSubscribers.values()).map((subscriber) =>
228
+ subscriber.fetch()
229
+ )
230
+ );
245
231
 
246
232
  await Promise.all(promises);
247
233
  }
@@ -252,40 +238,38 @@ export class WebSocketClearingHouseAccountSubscriber
252
238
  }
253
239
 
254
240
  await this.stateAccountSubscriber.unsubscribe();
255
- await this.marketsAccountSubscriber.unsubscribe();
256
- await this.orderStateAccountSubscriber.unsubscribe();
257
241
 
258
- if (this.optionalExtraSubscriptions.includes('tradeHistoryAccount')) {
259
- await this.tradeHistoryAccountSubscriber.unsubscribe();
260
- }
242
+ await this.unsubscribeFromMarketAccounts();
243
+ await this.unsubscribeFromBankAccounts();
244
+ await this.unsubscribeFromOracles();
261
245
 
262
- if (this.optionalExtraSubscriptions.includes('fundingRateHistoryAccount')) {
263
- await this.fundingRateHistoryAccountSubscriber.unsubscribe();
264
- }
265
-
266
- if (
267
- this.optionalExtraSubscriptions.includes('fundingPaymentHistoryAccount')
268
- ) {
269
- await this.fundingPaymentHistoryAccountSubscriber.unsubscribe();
270
- }
246
+ this.isSubscribed = false;
247
+ }
271
248
 
272
- if (this.optionalExtraSubscriptions.includes('depositHistoryAccount')) {
273
- await this.depositHistoryAccountSubscriber.unsubscribe();
249
+ async addBank(bankIndex: BN): Promise<boolean> {
250
+ if (this.bankAccountSubscribers.has(bankIndex.toNumber())) {
251
+ return true;
274
252
  }
253
+ return this.subscribeToBankAccount(bankIndex);
254
+ }
275
255
 
276
- if (this.optionalExtraSubscriptions.includes('curveHistoryAccount')) {
277
- await this.curveHistoryAccountSubscriber.unsubscribe();
256
+ async addMarket(marketIndex: BN): Promise<boolean> {
257
+ if (this.marketAccountSubscribers.has(marketIndex.toNumber())) {
258
+ return true;
278
259
  }
260
+ return this.subscribeToMarketAccount(marketIndex);
261
+ }
279
262
 
280
- if (this.optionalExtraSubscriptions.includes('liquidationHistoryAccount')) {
281
- await this.liquidationHistoryAccountSubscriber.unsubscribe();
263
+ async addOracle(oracleInfo: OracleInfo): Promise<boolean> {
264
+ if (this.oracleSubscribers.has(oracleInfo.publicKey.toString())) {
265
+ return true;
282
266
  }
283
267
 
284
- if (this.optionalExtraSubscriptions.includes('orderHistoryAccount')) {
285
- await this.orderHistoryAccountSubscriber.unsubscribe();
268
+ if (oracleInfo.publicKey.equals(PublicKey.default)) {
269
+ return true;
286
270
  }
287
271
 
288
- this.isSubscribed = false;
272
+ return this.subscribeToOracle(oracleInfo);
289
273
  }
290
274
 
291
275
  assertIsSubscribed(): void {
@@ -296,76 +280,42 @@ export class WebSocketClearingHouseAccountSubscriber
296
280
  }
297
281
  }
298
282
 
299
- assertOptionalIsSubscribed(
300
- optionalSubscription: ClearingHouseAccountTypes
301
- ): void {
302
- if (!this.isSubscribed) {
303
- throw new NotSubscribedError(
304
- 'You must call `subscribe` before using this function'
305
- );
306
- }
307
-
308
- if (!this.optionalExtraSubscriptions.includes(optionalSubscription)) {
309
- throw new NotSubscribedError(
310
- `You need to subscribe to the optional Clearing House account "${optionalSubscription}" to use this method`
311
- );
312
- }
313
- }
314
-
315
- public getStateAccount(): StateAccount {
283
+ public getStateAccountAndSlot(): DataAndSlot<StateAccount> {
316
284
  this.assertIsSubscribed();
317
- return this.stateAccountSubscriber.data;
285
+ return this.stateAccountSubscriber.dataAndSlot;
318
286
  }
319
287
 
320
- public getMarketsAccount(): MarketsAccount {
288
+ public getMarketAccountAndSlot(
289
+ marketIndex: BN
290
+ ): DataAndSlot<MarketAccount> | undefined {
321
291
  this.assertIsSubscribed();
322
- return this.marketsAccountSubscriber.data;
292
+ return this.marketAccountSubscribers.get(marketIndex.toNumber())
293
+ .dataAndSlot;
323
294
  }
324
295
 
325
- public getTradeHistoryAccount(): TradeHistoryAccount {
326
- this.assertIsSubscribed();
327
- this.assertOptionalIsSubscribed('tradeHistoryAccount');
328
- return this.tradeHistoryAccountSubscriber.data;
329
- }
330
-
331
- public getDepositHistoryAccount(): DepositHistoryAccount {
332
- this.assertIsSubscribed();
333
- this.assertOptionalIsSubscribed('depositHistoryAccount');
334
- return this.depositHistoryAccountSubscriber.data;
335
- }
336
-
337
- public getFundingPaymentHistoryAccount(): FundingPaymentHistoryAccount {
338
- this.assertIsSubscribed();
339
- this.assertOptionalIsSubscribed('fundingPaymentHistoryAccount');
340
- return this.fundingPaymentHistoryAccountSubscriber.data;
341
- }
342
-
343
- public getFundingRateHistoryAccount(): FundingRateHistoryAccount {
344
- this.assertIsSubscribed();
345
- this.assertOptionalIsSubscribed('fundingRateHistoryAccount');
346
- return this.fundingRateHistoryAccountSubscriber.data;
347
- }
348
-
349
- public getCurveHistoryAccount(): ExtendedCurveHistoryAccount {
350
- this.assertIsSubscribed();
351
- this.assertOptionalIsSubscribed('curveHistoryAccount');
352
- return this.curveHistoryAccountSubscriber.data;
353
- }
354
-
355
- public getLiquidationHistoryAccount(): LiquidationHistoryAccount {
356
- this.assertIsSubscribed();
357
- this.assertOptionalIsSubscribed('liquidationHistoryAccount');
358
- return this.liquidationHistoryAccountSubscriber.data;
296
+ public getMarketAccountsAndSlots(): DataAndSlot<MarketAccount>[] {
297
+ return Array.from(this.marketAccountSubscribers.values()).map(
298
+ (subscriber) => subscriber.dataAndSlot
299
+ );
359
300
  }
360
301
 
361
- public getOrderHistoryAccount(): OrderHistoryAccount {
302
+ public getBankAccountAndSlot(
303
+ bankIndex: BN
304
+ ): DataAndSlot<BankAccount> | undefined {
362
305
  this.assertIsSubscribed();
363
- this.assertOptionalIsSubscribed('orderHistoryAccount');
364
- return this.orderHistoryAccountSubscriber.data;
306
+ return this.bankAccountSubscribers.get(bankIndex.toNumber()).dataAndSlot;
365
307
  }
366
308
 
367
- public getOrderStateAccount(): OrderStateAccount {
309
+ public getOraclePriceDataAndSlot(
310
+ oraclePublicKey: PublicKey
311
+ ): DataAndSlot<OraclePriceData> | undefined {
368
312
  this.assertIsSubscribed();
369
- return this.orderStateAccountSubscriber.data;
313
+ if (oraclePublicKey.equals(PublicKey.default)) {
314
+ return {
315
+ data: QUOTE_ORACLE_PRICE_DATA,
316
+ slot: 0,
317
+ };
318
+ }
319
+ return this.oracleSubscribers.get(oraclePublicKey.toString()).dataAndSlot;
370
320
  }
371
321
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ DataAndSlot,
2
3
  AccountSubscriber,
3
4
  NotSubscribedError,
4
5
  UserAccountEvents,
@@ -8,30 +9,21 @@ import { Program } from '@project-serum/anchor';
8
9
  import StrictEventEmitter from 'strict-event-emitter-types';
9
10
  import { EventEmitter } from 'events';
10
11
  import { PublicKey } from '@solana/web3.js';
11
- import {
12
- getUserAccountPublicKey,
13
- getUserOrdersAccountPublicKey,
14
- } from '../addresses';
15
12
  import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
16
- import { UserAccount, UserOrdersAccount, UserPositionsAccount } from '../types';
17
- import { ClearingHouseConfigType } from '../factory/clearingHouse';
13
+ import { UserAccount } from '../types';
18
14
 
19
15
  export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
20
16
  isSubscribed: boolean;
21
17
  program: Program;
22
18
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
23
- authority: PublicKey;
19
+ userAccountPublicKey: PublicKey;
24
20
 
25
21
  userDataAccountSubscriber: AccountSubscriber<UserAccount>;
26
- userPositionsAccountSubscriber: AccountSubscriber<UserPositionsAccount>;
27
- userOrdersAccountSubscriber: AccountSubscriber<UserOrdersAccount>;
28
-
29
- type: ClearingHouseConfigType = 'websocket';
30
22
 
31
- public constructor(program: Program, authority: PublicKey) {
23
+ public constructor(program: Program, userAccountPublicKey: PublicKey) {
32
24
  this.isSubscribed = false;
33
25
  this.program = program;
34
- this.authority = authority;
26
+ this.userAccountPublicKey = userAccountPublicKey;
35
27
  this.eventEmitter = new EventEmitter();
36
28
  }
37
29
 
@@ -40,62 +32,23 @@ export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
40
32
  return true;
41
33
  }
42
34
 
43
- const userPublicKey = await getUserAccountPublicKey(
44
- this.program.programId,
45
- this.authority
46
- );
47
35
  this.userDataAccountSubscriber = new WebSocketAccountSubscriber(
48
36
  'user',
49
37
  this.program,
50
- userPublicKey
38
+ this.userAccountPublicKey
51
39
  );
52
40
  await this.userDataAccountSubscriber.subscribe((data: UserAccount) => {
53
- this.eventEmitter.emit('userAccountData', data);
41
+ this.eventEmitter.emit('userAccountUpdate', data);
54
42
  this.eventEmitter.emit('update');
55
43
  });
56
44
 
57
- const userAccountData = this.userDataAccountSubscriber.data;
58
- this.userPositionsAccountSubscriber = new WebSocketAccountSubscriber(
59
- 'userPositions',
60
- this.program,
61
- userAccountData.positions
62
- );
63
-
64
- await this.userPositionsAccountSubscriber.subscribe(
65
- (data: UserPositionsAccount) => {
66
- this.eventEmitter.emit('userPositionsData', data);
67
- this.eventEmitter.emit('update');
68
- }
69
- );
70
-
71
- const userOrdersPublicKey = await getUserOrdersAccountPublicKey(
72
- this.program.programId,
73
- userPublicKey
74
- );
75
-
76
- this.userOrdersAccountSubscriber = new WebSocketAccountSubscriber(
77
- 'userOrders',
78
- this.program,
79
- userOrdersPublicKey
80
- );
81
- await this.userOrdersAccountSubscriber.subscribe(
82
- (data: UserOrdersAccount) => {
83
- this.eventEmitter.emit('userOrdersData', data);
84
- this.eventEmitter.emit('update');
85
- }
86
- );
87
-
88
45
  this.eventEmitter.emit('update');
89
46
  this.isSubscribed = true;
90
47
  return true;
91
48
  }
92
49
 
93
50
  async fetch(): Promise<void> {
94
- await Promise.all([
95
- this.userDataAccountSubscriber.fetch(),
96
- this.userPositionsAccountSubscriber.fetch(),
97
- this.userOrdersAccountSubscriber.fetch(),
98
- ]);
51
+ await Promise.all([this.userDataAccountSubscriber.fetch()]);
99
52
  }
100
53
 
101
54
  async unsubscribe(): Promise<void> {
@@ -103,11 +56,7 @@ export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
103
56
  return;
104
57
  }
105
58
 
106
- await Promise.all([
107
- this.userDataAccountSubscriber.unsubscribe(),
108
- this.userPositionsAccountSubscriber.unsubscribe(),
109
- await this.userOrdersAccountSubscriber.unsubscribe(),
110
- ]);
59
+ await Promise.all([this.userDataAccountSubscriber.unsubscribe()]);
111
60
 
112
61
  this.isSubscribed = false;
113
62
  }
@@ -120,17 +69,8 @@ export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
120
69
  }
121
70
  }
122
71
 
123
- public getUserAccount(): UserAccount {
72
+ public getUserAccountAndSlot(): DataAndSlot<UserAccount> {
124
73
  this.assertIsSubscribed();
125
- return this.userDataAccountSubscriber.data;
126
- }
127
-
128
- public getUserPositionsAccount(): UserPositionsAccount {
129
- this.assertIsSubscribed();
130
- return this.userPositionsAccountSubscriber.data;
131
- }
132
-
133
- public getUserOrdersAccount(): UserOrdersAccount {
134
- return this.userOrdersAccountSubscriber.data;
74
+ return this.userDataAccountSubscriber.dataAndSlot;
135
75
  }
136
76
  }
@@ -0,0 +1,18 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { BN } from '@project-serum/anchor';
3
+ import { getMarketPublicKey } from './pda';
4
+
5
+ const CACHE = new Map<string, PublicKey>();
6
+ export async function getMarketAddress(
7
+ programId: PublicKey,
8
+ marketIndex: BN
9
+ ): Promise<PublicKey> {
10
+ const cacheKey = `${programId.toString()}-${marketIndex.toString()}`;
11
+ if (CACHE.has(cacheKey)) {
12
+ return CACHE.get(cacheKey);
13
+ }
14
+
15
+ const publicKey = await getMarketPublicKey(programId, marketIndex);
16
+ CACHE.set(cacheKey, publicKey);
17
+ return publicKey;
18
+ }