@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +13 -13
  2. package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
  3. package/lib/accounts/bulkUserStatsSubscription.js +21 -0
  4. package/lib/accounts/bulkUserSubscription.js +0 -1
  5. package/lib/accounts/fetch.d.ts +2 -1
  6. package/lib/accounts/fetch.js +9 -1
  7. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
  8. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
  9. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
  10. package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
  11. package/lib/accounts/types.d.ts +22 -11
  12. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
  13. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
  16. package/lib/addresses/marketAddresses.d.ts +1 -3
  17. package/lib/addresses/pda.d.ts +10 -4
  18. package/lib/addresses/pda.js +51 -14
  19. package/lib/admin.d.ts +42 -26
  20. package/lib/admin.js +228 -81
  21. package/lib/clearingHouse.d.ts +130 -49
  22. package/lib/clearingHouse.js +1256 -367
  23. package/lib/clearingHouseConfig.d.ts +4 -4
  24. package/lib/clearingHouseUser.d.ts +51 -39
  25. package/lib/clearingHouseUser.js +408 -191
  26. package/lib/clearingHouseUserStats.d.ts +18 -0
  27. package/lib/clearingHouseUserStats.js +49 -0
  28. package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
  29. package/lib/clearingHouseUserStatsConfig.js +2 -0
  30. package/lib/config.d.ts +7 -9
  31. package/lib/config.js +21 -21
  32. package/lib/constants/numericConstants.d.ts +25 -12
  33. package/lib/constants/numericConstants.js +35 -21
  34. package/lib/constants/perpMarkets.d.ts +18 -0
  35. package/lib/constants/{markets.js → perpMarkets.js} +7 -7
  36. package/lib/constants/spotMarkets.d.ts +19 -0
  37. package/lib/constants/spotMarkets.js +53 -0
  38. package/lib/dlob/DLOB.d.ts +74 -0
  39. package/lib/dlob/DLOB.js +595 -0
  40. package/lib/dlob/DLOBNode.d.ts +54 -0
  41. package/lib/dlob/DLOBNode.js +85 -0
  42. package/lib/dlob/NodeList.d.ts +26 -0
  43. package/lib/dlob/NodeList.js +139 -0
  44. package/lib/events/eventList.js +3 -0
  45. package/lib/events/eventSubscriber.d.ts +4 -2
  46. package/lib/events/eventSubscriber.js +16 -9
  47. package/lib/events/fetchLogs.d.ts +10 -1
  48. package/lib/events/fetchLogs.js +27 -7
  49. package/lib/events/pollingLogProvider.d.ts +2 -1
  50. package/lib/events/pollingLogProvider.js +6 -2
  51. package/lib/events/sort.js +8 -11
  52. package/lib/events/types.d.ts +8 -2
  53. package/lib/events/types.js +6 -0
  54. package/lib/examples/makeTradeExample.js +20 -8
  55. package/lib/factory/bigNum.d.ts +2 -0
  56. package/lib/factory/bigNum.js +48 -10
  57. package/lib/idl/clearing_house.json +4889 -1529
  58. package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  59. package/lib/index.d.ts +21 -6
  60. package/lib/index.js +25 -6
  61. package/lib/math/amm.d.ts +9 -6
  62. package/lib/math/amm.js +91 -66
  63. package/lib/math/auction.js +4 -1
  64. package/lib/math/conversion.js +1 -1
  65. package/lib/math/funding.d.ts +6 -6
  66. package/lib/math/funding.js +11 -10
  67. package/lib/math/insurance.d.ts +4 -0
  68. package/lib/math/insurance.js +27 -0
  69. package/lib/math/margin.d.ts +11 -0
  70. package/lib/math/margin.js +77 -0
  71. package/lib/math/market.d.ts +14 -9
  72. package/lib/math/market.js +72 -10
  73. package/lib/math/oracles.d.ts +4 -0
  74. package/lib/math/oracles.js +36 -8
  75. package/lib/math/orders.d.ts +6 -2
  76. package/lib/math/orders.js +78 -3
  77. package/lib/math/position.d.ts +21 -13
  78. package/lib/math/position.js +76 -36
  79. package/lib/math/repeg.js +14 -5
  80. package/lib/math/spotBalance.d.ts +22 -0
  81. package/lib/math/spotBalance.js +192 -0
  82. package/lib/math/spotMarket.d.ts +4 -0
  83. package/lib/math/spotMarket.js +8 -0
  84. package/lib/math/spotPosition.d.ts +6 -0
  85. package/lib/math/spotPosition.js +23 -0
  86. package/lib/math/trade.d.ts +10 -10
  87. package/lib/math/trade.js +32 -39
  88. package/lib/oracles/pythClient.js +1 -1
  89. package/lib/oracles/quoteAssetOracleClient.js +1 -1
  90. package/lib/oracles/switchboardClient.js +1 -1
  91. package/lib/orderParams.d.ts +14 -5
  92. package/lib/orderParams.js +12 -92
  93. package/lib/serum/serumSubscriber.d.ts +23 -0
  94. package/lib/serum/serumSubscriber.js +41 -0
  95. package/lib/serum/types.d.ts +11 -0
  96. package/lib/serum/types.js +2 -0
  97. package/lib/slot/SlotSubscriber.d.ts +7 -0
  98. package/lib/slot/SlotSubscriber.js +3 -0
  99. package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
  100. package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
  101. package/lib/tx/retryTxSender.d.ts +1 -1
  102. package/lib/tx/retryTxSender.js +13 -4
  103. package/lib/tx/types.d.ts +1 -1
  104. package/lib/tx/utils.js +1 -1
  105. package/lib/types.d.ts +566 -138
  106. package/lib/types.js +129 -5
  107. package/lib/userMap/userMap.d.ts +25 -0
  108. package/lib/userMap/userMap.js +73 -0
  109. package/lib/userMap/userStatsMap.d.ts +19 -0
  110. package/lib/userMap/userStatsMap.js +68 -0
  111. package/lib/util/computeUnits.js +1 -1
  112. package/lib/util/getTokenAddress.d.ts +2 -0
  113. package/lib/util/getTokenAddress.js +9 -0
  114. package/package.json +12 -6
  115. package/src/accounts/bulkUserStatsSubscription.ts +33 -0
  116. package/src/accounts/bulkUserSubscription.ts +0 -1
  117. package/src/accounts/fetch.ts +27 -2
  118. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
  119. package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
  120. package/src/accounts/types.ts +31 -11
  121. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
  122. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
  123. package/src/addresses/marketAddresses.ts +1 -2
  124. package/src/addresses/pda.ts +88 -14
  125. package/src/admin.ts +452 -147
  126. package/src/assert/assert.js +9 -0
  127. package/src/clearingHouse.ts +2066 -467
  128. package/src/clearingHouseConfig.ts +4 -3
  129. package/src/clearingHouseUser.ts +747 -294
  130. package/src/clearingHouseUserStats.ts +75 -0
  131. package/src/clearingHouseUserStatsConfig.ts +18 -0
  132. package/src/config.ts +30 -31
  133. package/src/constants/numericConstants.ts +48 -25
  134. package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
  135. package/src/constants/spotMarkets.ts +73 -0
  136. package/src/dlob/DLOB.ts +953 -0
  137. package/src/dlob/DLOBNode.ts +167 -0
  138. package/src/dlob/NodeList.ts +189 -0
  139. package/src/events/eventList.js +77 -0
  140. package/src/events/eventList.ts +3 -0
  141. package/src/events/eventSubscriber.ts +20 -12
  142. package/src/events/fetchLogs.ts +35 -8
  143. package/src/events/pollingLogProvider.ts +10 -2
  144. package/src/events/sort.ts +11 -15
  145. package/src/events/types.ts +19 -1
  146. package/src/examples/makeTradeExample.js +157 -0
  147. package/src/examples/makeTradeExample.ts +32 -14
  148. package/src/factory/bigNum.ts +65 -13
  149. package/src/idl/clearing_house.json +4889 -1529
  150. package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
  151. package/src/index.ts +21 -6
  152. package/src/math/amm.ts +171 -88
  153. package/src/math/auction.ts +5 -1
  154. package/src/math/conversion.ts +2 -2
  155. package/src/math/funding.ts +20 -18
  156. package/src/math/insurance.ts +35 -0
  157. package/src/math/margin.ts +127 -0
  158. package/src/math/market.ts +145 -14
  159. package/src/math/oracles.ts +63 -9
  160. package/src/math/orders.ts +138 -4
  161. package/src/math/position.ts +119 -58
  162. package/src/math/repeg.ts +16 -6
  163. package/src/math/spotBalance.ts +319 -0
  164. package/src/math/spotMarket.ts +9 -0
  165. package/src/math/spotPosition.ts +47 -0
  166. package/src/math/trade.ts +53 -59
  167. package/src/oracles/pythClient.ts +2 -2
  168. package/src/oracles/quoteAssetOracleClient.ts +2 -2
  169. package/src/oracles/switchboardClient.ts +2 -2
  170. package/src/orderParams.ts +24 -137
  171. package/src/serum/serumSubscriber.ts +80 -0
  172. package/src/serum/types.ts +13 -0
  173. package/src/slot/SlotSubscriber.ts +11 -1
  174. package/src/token/index.js +38 -0
  175. package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
  176. package/src/tx/retryTxSender.ts +16 -5
  177. package/src/tx/types.js +2 -0
  178. package/src/tx/types.ts +2 -1
  179. package/src/tx/utils.js +17 -0
  180. package/src/tx/utils.ts +1 -1
  181. package/src/types.ts +533 -140
  182. package/src/userMap/userMap.ts +100 -0
  183. package/src/userMap/userStatsMap.ts +110 -0
  184. package/src/util/computeUnits.js +21 -11
  185. package/src/util/computeUnits.ts +1 -1
  186. package/src/util/getTokenAddress.js +9 -0
  187. package/src/util/getTokenAddress.ts +18 -0
  188. package/src/util/promiseTimeout.js +14 -0
  189. package/src/util/tps.js +27 -0
  190. package/tests/bn/test.ts +24 -10
  191. package/tests/dlob/helpers.ts +397 -0
  192. package/tests/dlob/test.ts +3688 -0
  193. package/lib/constants/banks.d.ts +0 -16
  194. package/lib/constants/banks.js +0 -34
  195. package/lib/constants/markets.d.ts +0 -19
  196. package/lib/math/bankBalance.d.ts +0 -9
  197. package/lib/math/bankBalance.js +0 -75
  198. package/lib/math/state.d.ts +0 -8
  199. package/lib/math/state.js +0 -15
  200. package/lib/orders.d.ts +0 -8
  201. package/lib/orders.js +0 -134
  202. package/src/constants/banks.ts +0 -43
  203. package/src/math/bankBalance.ts +0 -112
  204. package/src/math/state.ts +0 -14
  205. package/src/math/utils.js +0 -27
  206. package/src/math/utils.js.map +0 -1
  207. package/src/orders.ts +0 -244
  208. package/src/util/computeUnits.js.map +0 -1
@@ -6,18 +6,18 @@ import {
6
6
  NotSubscribedError,
7
7
  OraclesToPoll,
8
8
  } from './types';
9
- import { BN, Program } from '@project-serum/anchor';
9
+ import { Program } from '@project-serum/anchor';
10
10
  import StrictEventEmitter from 'strict-event-emitter-types';
11
11
  import { EventEmitter } from 'events';
12
12
  import {
13
- BankAccount,
14
- MarketAccount,
13
+ SpotMarketAccount,
14
+ PerpMarketAccount,
15
15
  StateAccount,
16
16
  UserAccount,
17
17
  } from '../types';
18
18
  import {
19
19
  getClearingHouseStateAccountPublicKey,
20
- getBankPublicKey,
20
+ getSpotMarketPublicKey,
21
21
  getMarketPublicKey,
22
22
  } from '../addresses/pda';
23
23
  import { BulkAccountLoader } from './bulkAccountLoader';
@@ -32,8 +32,8 @@ export class PollingClearingHouseAccountSubscriber
32
32
  {
33
33
  isSubscribed: boolean;
34
34
  program: Program;
35
- marketIndexes: BN[];
36
- bankIndexes: BN[];
35
+ perpMarketIndexes: number[];
36
+ spotMarketIndexes: number[];
37
37
  oracleInfos: OracleInfo[];
38
38
  oracleClientCache = new OracleClientCache();
39
39
 
@@ -45,8 +45,8 @@ export class PollingClearingHouseAccountSubscriber
45
45
  errorCallbackId?: string;
46
46
 
47
47
  state?: DataAndSlot<StateAccount>;
48
- market = new Map<number, DataAndSlot<MarketAccount>>();
49
- bank = new Map<number, DataAndSlot<BankAccount>>();
48
+ perpMarket = new Map<number, DataAndSlot<PerpMarketAccount>>();
49
+ spotMarket = new Map<number, DataAndSlot<SpotMarketAccount>>();
50
50
  oracles = new Map<string, DataAndSlot<OraclePriceData>>();
51
51
  user?: DataAndSlot<UserAccount>;
52
52
 
@@ -57,16 +57,16 @@ export class PollingClearingHouseAccountSubscriber
57
57
  public constructor(
58
58
  program: Program,
59
59
  accountLoader: BulkAccountLoader,
60
- marketIndexes: BN[],
61
- bankIndexes: BN[],
60
+ perpMarketIndexes: number[],
61
+ spotMarketIndexes: number[],
62
62
  oracleInfos: OracleInfo[]
63
63
  ) {
64
64
  this.isSubscribed = false;
65
65
  this.program = program;
66
66
  this.eventEmitter = new EventEmitter();
67
67
  this.accountLoader = accountLoader;
68
- this.marketIndexes = marketIndexes;
69
- this.bankIndexes = bankIndexes;
68
+ this.perpMarketIndexes = perpMarketIndexes;
69
+ this.spotMarketIndexes = spotMarketIndexes;
70
70
  this.oracleInfos = oracleInfos;
71
71
  }
72
72
 
@@ -122,51 +122,51 @@ export class PollingClearingHouseAccountSubscriber
122
122
  });
123
123
 
124
124
  await this.updateMarketAccountsToPoll();
125
- await this.updateBankAccountsToPoll();
125
+ await this.updateSpotMarketAccountsToPoll();
126
126
  }
127
127
 
128
128
  async updateMarketAccountsToPoll(): Promise<boolean> {
129
- for (const marketIndex of this.marketIndexes) {
129
+ for (const marketIndex of this.perpMarketIndexes) {
130
130
  await this.addMarketAccountToPoll(marketIndex);
131
131
  }
132
132
  return true;
133
133
  }
134
134
 
135
- async addMarketAccountToPoll(marketIndex: BN): Promise<boolean> {
135
+ async addMarketAccountToPoll(marketIndex: number): Promise<boolean> {
136
136
  const marketPublicKey = await getMarketPublicKey(
137
137
  this.program.programId,
138
138
  marketIndex
139
139
  );
140
140
 
141
141
  this.accountsToPoll.set(marketPublicKey.toString(), {
142
- key: 'market',
142
+ key: 'perpMarket',
143
143
  publicKey: marketPublicKey,
144
- eventType: 'marketAccountUpdate',
145
- mapKey: marketIndex.toNumber(),
144
+ eventType: 'perpMarketAccountUpdate',
145
+ mapKey: marketIndex,
146
146
  });
147
147
 
148
148
  return true;
149
149
  }
150
150
 
151
- async updateBankAccountsToPoll(): Promise<boolean> {
152
- for (const bankIndex of this.bankIndexes) {
153
- await this.addBankAccountToPoll(bankIndex);
151
+ async updateSpotMarketAccountsToPoll(): Promise<boolean> {
152
+ for (const marketIndex of this.spotMarketIndexes) {
153
+ await this.addSpotMarketAccountToPoll(marketIndex);
154
154
  }
155
155
 
156
156
  return true;
157
157
  }
158
158
 
159
- async addBankAccountToPoll(bankIndex: BN): Promise<boolean> {
160
- const bankPublicKey = await getBankPublicKey(
159
+ async addSpotMarketAccountToPoll(marketIndex: number): Promise<boolean> {
160
+ const marketPublicKey = await getSpotMarketPublicKey(
161
161
  this.program.programId,
162
- bankIndex
162
+ marketIndex
163
163
  );
164
164
 
165
- this.accountsToPoll.set(bankPublicKey.toString(), {
166
- key: 'bank',
167
- publicKey: bankPublicKey,
168
- eventType: 'bankAccountUpdate',
169
- mapKey: bankIndex.toNumber(),
165
+ this.accountsToPoll.set(marketPublicKey.toString(), {
166
+ key: 'spotMarket',
167
+ publicKey: marketPublicKey,
168
+ eventType: 'spotMarketAccountUpdate',
169
+ mapKey: marketIndex,
170
170
  });
171
171
  return true;
172
172
  }
@@ -353,14 +353,14 @@ export class PollingClearingHouseAccountSubscriber
353
353
  this.isSubscribed = false;
354
354
  }
355
355
 
356
- async addBank(bankIndex: BN): Promise<boolean> {
357
- await this.addBankAccountToPoll(bankIndex);
358
- const accountToPoll = this.accountsToPoll.get(bankIndex.toString());
356
+ async addSpotMarket(marketIndex: number): Promise<boolean> {
357
+ await this.addSpotMarketAccountToPoll(marketIndex);
358
+ const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
359
359
  this.addAccountToAccountLoader(accountToPoll);
360
360
  return true;
361
361
  }
362
362
 
363
- async addMarket(marketIndex: BN): Promise<boolean> {
363
+ async addPerpMarket(marketIndex: number): Promise<boolean> {
364
364
  await this.addMarketAccountToPoll(marketIndex);
365
365
  const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
366
366
  this.addAccountToAccountLoader(accountToPoll);
@@ -394,19 +394,23 @@ export class PollingClearingHouseAccountSubscriber
394
394
  }
395
395
 
396
396
  public getMarketAccountAndSlot(
397
- marketIndex: BN
398
- ): DataAndSlot<MarketAccount> | undefined {
399
- return this.market.get(marketIndex.toNumber());
397
+ marketIndex: number
398
+ ): DataAndSlot<PerpMarketAccount> | undefined {
399
+ return this.perpMarket.get(marketIndex);
400
+ }
401
+
402
+ public getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[] {
403
+ return Array.from(this.perpMarket.values());
400
404
  }
401
405
 
402
- public getMarketAccountsAndSlots(): DataAndSlot<MarketAccount>[] {
403
- return Array.from(this.market.values());
406
+ public getSpotMarketAccountAndSlot(
407
+ marketIndex: number
408
+ ): DataAndSlot<SpotMarketAccount> | undefined {
409
+ return this.spotMarket.get(marketIndex);
404
410
  }
405
411
 
406
- public getBankAccountAndSlot(
407
- bankIndex: BN
408
- ): DataAndSlot<BankAccount> | undefined {
409
- return this.bank.get(bankIndex.toNumber());
412
+ public getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[] {
413
+ return Array.from(this.spotMarket.values());
410
414
  }
411
415
 
412
416
  public getOraclePriceDataAndSlot(
@@ -0,0 +1,172 @@
1
+ import {
2
+ DataAndSlot,
3
+ AccountToPoll,
4
+ NotSubscribedError,
5
+ UserStatsAccountSubscriber,
6
+ UserStatsAccountEvents,
7
+ } from './types';
8
+ import { Program } from '@project-serum/anchor';
9
+ import StrictEventEmitter from 'strict-event-emitter-types';
10
+ import { EventEmitter } from 'events';
11
+ import { PublicKey } from '@solana/web3.js';
12
+ import { UserStatsAccount } from '../types';
13
+ import { BulkAccountLoader } from './bulkAccountLoader';
14
+ import { capitalize } from './utils';
15
+
16
+ export class PollingUserStatsAccountSubscriber
17
+ implements UserStatsAccountSubscriber
18
+ {
19
+ isSubscribed: boolean;
20
+ program: Program;
21
+ eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
22
+ userStatsAccountPublicKey: PublicKey;
23
+
24
+ accountLoader: BulkAccountLoader;
25
+ accountsToPoll = new Map<string, AccountToPoll>();
26
+ errorCallbackId?: string;
27
+
28
+ userStats?: DataAndSlot<UserStatsAccount>;
29
+
30
+ public constructor(
31
+ program: Program,
32
+ userStatsAccountPublicKey: PublicKey,
33
+ accountLoader: BulkAccountLoader
34
+ ) {
35
+ this.isSubscribed = false;
36
+ this.program = program;
37
+ this.accountLoader = accountLoader;
38
+ this.eventEmitter = new EventEmitter();
39
+ this.userStatsAccountPublicKey = userStatsAccountPublicKey;
40
+ }
41
+
42
+ async subscribe(): Promise<boolean> {
43
+ if (this.isSubscribed) {
44
+ return true;
45
+ }
46
+
47
+ await this.addToAccountLoader();
48
+
49
+ let subscriptionSucceeded = false;
50
+ let retries = 0;
51
+ while (!subscriptionSucceeded && retries < 5) {
52
+ await this.fetchIfUnloaded();
53
+ subscriptionSucceeded = this.didSubscriptionSucceed();
54
+ retries++;
55
+ }
56
+
57
+ if (subscriptionSucceeded) {
58
+ this.eventEmitter.emit('update');
59
+ }
60
+
61
+ this.isSubscribed = subscriptionSucceeded;
62
+ return subscriptionSucceeded;
63
+ }
64
+
65
+ async addToAccountLoader(): Promise<void> {
66
+ if (this.accountsToPoll.size > 0) {
67
+ return;
68
+ }
69
+
70
+ this.accountsToPoll.set(this.userStatsAccountPublicKey.toString(), {
71
+ key: 'userStats',
72
+ publicKey: this.userStatsAccountPublicKey,
73
+ eventType: 'userStatsAccountUpdate',
74
+ });
75
+
76
+ for (const [_, accountToPoll] of this.accountsToPoll) {
77
+ accountToPoll.callbackId = this.accountLoader.addAccount(
78
+ accountToPoll.publicKey,
79
+ (buffer, slot) => {
80
+ if (!buffer) {
81
+ return;
82
+ }
83
+
84
+ const account = this.program.account[
85
+ accountToPoll.key
86
+ ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
87
+ this[accountToPoll.key] = { data: account, slot };
88
+ // @ts-ignore
89
+ this.eventEmitter.emit(accountToPoll.eventType, account);
90
+ this.eventEmitter.emit('update');
91
+ }
92
+ );
93
+ }
94
+
95
+ this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
96
+ this.eventEmitter.emit('error', error);
97
+ });
98
+ }
99
+
100
+ async fetchIfUnloaded(): Promise<void> {
101
+ let shouldFetch = false;
102
+ for (const [_, accountToPoll] of this.accountsToPoll) {
103
+ if (this[accountToPoll.key] === undefined) {
104
+ shouldFetch = true;
105
+ break;
106
+ }
107
+ }
108
+
109
+ if (shouldFetch) {
110
+ await this.fetch();
111
+ }
112
+ }
113
+
114
+ async fetch(): Promise<void> {
115
+ await this.accountLoader.load();
116
+ for (const [_, accountToPoll] of this.accountsToPoll) {
117
+ const { buffer, slot } = this.accountLoader.getBufferAndSlot(
118
+ accountToPoll.publicKey
119
+ );
120
+ if (buffer) {
121
+ const account = this.program.account[
122
+ accountToPoll.key
123
+ ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
124
+ this[accountToPoll.key] = { data: account, slot };
125
+ }
126
+ }
127
+ }
128
+
129
+ didSubscriptionSucceed(): boolean {
130
+ let success = true;
131
+ for (const [_, accountToPoll] of this.accountsToPoll) {
132
+ if (!this[accountToPoll.key]) {
133
+ success = false;
134
+ break;
135
+ }
136
+ }
137
+ return success;
138
+ }
139
+
140
+ async unsubscribe(): Promise<void> {
141
+ if (!this.isSubscribed) {
142
+ return;
143
+ }
144
+
145
+ for (const [_, accountToPoll] of this.accountsToPoll) {
146
+ this.accountLoader.removeAccount(
147
+ accountToPoll.publicKey,
148
+ accountToPoll.callbackId
149
+ );
150
+ }
151
+
152
+ this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
153
+ this.errorCallbackId = undefined;
154
+
155
+ this.accountsToPoll.clear();
156
+
157
+ this.isSubscribed = false;
158
+ }
159
+
160
+ assertIsSubscribed(): void {
161
+ if (!this.isSubscribed) {
162
+ throw new NotSubscribedError(
163
+ 'You must call `subscribe` before using this function'
164
+ );
165
+ }
166
+ }
167
+
168
+ public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
169
+ this.assertIsSubscribed();
170
+ return this.userStats;
171
+ }
172
+ }
@@ -1,16 +1,16 @@
1
1
  import {
2
- BankAccount,
3
- MarketAccount,
2
+ SpotMarketAccount,
3
+ PerpMarketAccount,
4
4
  OracleSource,
5
5
  StateAccount,
6
6
  UserAccount,
7
+ UserStatsAccount,
7
8
  } from '../types';
8
9
  import StrictEventEmitter from 'strict-event-emitter-types';
9
10
  import { EventEmitter } from 'events';
10
11
  import { PublicKey } from '@solana/web3.js';
11
12
  import { AccountInfo } from '@solana/spl-token';
12
13
  import { OracleInfo, OraclePriceData } from '..';
13
- import { BN } from '@project-serum/anchor';
14
14
 
15
15
  export interface AccountSubscriber<T> {
16
16
  dataAndSlot?: DataAndSlot<T>;
@@ -25,8 +25,8 @@ export class NotSubscribedError extends Error {
25
25
 
26
26
  export interface ClearingHouseAccountEvents {
27
27
  stateAccountUpdate: (payload: StateAccount) => void;
28
- marketAccountUpdate: (payload: MarketAccount) => void;
29
- bankAccountUpdate: (payload: BankAccount) => void;
28
+ perpMarketAccountUpdate: (payload: PerpMarketAccount) => void;
29
+ spotMarketAccountUpdate: (payload: SpotMarketAccount) => void;
30
30
  oraclePriceUpdate: (publicKey: PublicKey, data: OraclePriceData) => void;
31
31
  userAccountUpdate: (payload: UserAccount) => void;
32
32
  update: void;
@@ -41,16 +41,19 @@ export interface ClearingHouseAccountSubscriber {
41
41
  fetch(): Promise<void>;
42
42
  unsubscribe(): Promise<void>;
43
43
 
44
- addMarket(marketIndex: BN): Promise<boolean>;
45
- addBank(bankIndex: BN): Promise<boolean>;
44
+ addPerpMarket(marketIndex: number): Promise<boolean>;
45
+ addSpotMarket(marketIndex: number): Promise<boolean>;
46
46
  addOracle(oracleInfo: OracleInfo): Promise<boolean>;
47
47
 
48
48
  getStateAccountAndSlot(): DataAndSlot<StateAccount>;
49
49
  getMarketAccountAndSlot(
50
- marketIndex: BN
51
- ): DataAndSlot<MarketAccount> | undefined;
52
- getMarketAccountsAndSlots(): DataAndSlot<MarketAccount>[];
53
- getBankAccountAndSlot(bankIndex: BN): DataAndSlot<BankAccount> | undefined;
50
+ marketIndex: number
51
+ ): DataAndSlot<PerpMarketAccount> | undefined;
52
+ getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
53
+ getSpotMarketAccountAndSlot(
54
+ marketIndex: number
55
+ ): DataAndSlot<SpotMarketAccount> | undefined;
56
+ getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
54
57
  getOraclePriceDataAndSlot(
55
58
  oraclePublicKey: PublicKey
56
59
  ): DataAndSlot<OraclePriceData> | undefined;
@@ -130,3 +133,20 @@ export type DataAndSlot<T> = {
130
133
  data: T;
131
134
  slot: number;
132
135
  };
136
+
137
+ export interface UserStatsAccountEvents {
138
+ userStatsAccountUpdate: (payload: UserStatsAccount) => void;
139
+ update: void;
140
+ error: (e: Error) => void;
141
+ }
142
+
143
+ export interface UserStatsAccountSubscriber {
144
+ eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
145
+ isSubscribed: boolean;
146
+
147
+ subscribe(): Promise<boolean>;
148
+ fetch(): Promise<void>;
149
+ unsubscribe(): Promise<void>;
150
+
151
+ getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
152
+ }
@@ -4,13 +4,13 @@ import {
4
4
  DataAndSlot,
5
5
  } from './types';
6
6
  import { AccountSubscriber, NotSubscribedError } from './types';
7
- import { BankAccount, MarketAccount, StateAccount } from '../types';
8
- import { BN, Program } from '@project-serum/anchor';
7
+ import { SpotMarketAccount, PerpMarketAccount, StateAccount } from '../types';
8
+ import { Program } from '@project-serum/anchor';
9
9
  import StrictEventEmitter from 'strict-event-emitter-types';
10
10
  import { EventEmitter } from 'events';
11
11
  import {
12
12
  getClearingHouseStateAccountPublicKey,
13
- getBankPublicKey,
13
+ getSpotMarketPublicKey,
14
14
  getMarketPublicKey,
15
15
  } from '../addresses/pda';
16
16
  import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
@@ -25,18 +25,21 @@ export class WebSocketClearingHouseAccountSubscriber
25
25
  {
26
26
  isSubscribed: boolean;
27
27
  program: Program;
28
- marketIndexes: BN[];
29
- bankIndexes: BN[];
28
+ perpMarketIndexes: number[];
29
+ spotMarketIndexes: number[];
30
30
  oracleInfos: OracleInfo[];
31
31
  oracleClientCache = new OracleClientCache();
32
32
 
33
33
  eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
34
34
  stateAccountSubscriber?: AccountSubscriber<StateAccount>;
35
- marketAccountSubscribers = new Map<
35
+ perpMarketAccountSubscribers = new Map<
36
36
  number,
37
- AccountSubscriber<MarketAccount>
37
+ AccountSubscriber<PerpMarketAccount>
38
+ >();
39
+ spotMarketAccountSubscribers = new Map<
40
+ number,
41
+ AccountSubscriber<SpotMarketAccount>
38
42
  >();
39
- bankAccountSubscribers = new Map<number, AccountSubscriber<BankAccount>>();
40
43
  oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
41
44
 
42
45
  private isSubscribing = false;
@@ -45,15 +48,15 @@ export class WebSocketClearingHouseAccountSubscriber
45
48
 
46
49
  public constructor(
47
50
  program: Program,
48
- marketIndexes: BN[],
49
- bankIndexes: BN[],
51
+ perpMarketIndexes: number[],
52
+ spotMarketIndexes: number[],
50
53
  oracleInfos: OracleInfo[]
51
54
  ) {
52
55
  this.isSubscribed = false;
53
56
  this.program = program;
54
57
  this.eventEmitter = new EventEmitter();
55
- this.marketIndexes = marketIndexes;
56
- this.bankIndexes = bankIndexes;
58
+ this.perpMarketIndexes = perpMarketIndexes;
59
+ this.spotMarketIndexes = spotMarketIndexes;
57
60
  this.oracleInfos = oracleInfos;
58
61
  }
59
62
 
@@ -90,8 +93,8 @@ export class WebSocketClearingHouseAccountSubscriber
90
93
  // subscribe to market accounts
91
94
  await this.subscribeToMarketAccounts();
92
95
 
93
- // subscribe to bank accounts
94
- await this.subscribeToBankAccounts();
96
+ // subscribe to spot market accounts
97
+ await this.subscribeToSpotMarketAccounts();
95
98
 
96
99
  // subscribe to oracles
97
100
  await this.subscribeToOracles();
@@ -106,55 +109,52 @@ export class WebSocketClearingHouseAccountSubscriber
106
109
  }
107
110
 
108
111
  async subscribeToMarketAccounts(): Promise<boolean> {
109
- for (const marketIndex of this.marketIndexes) {
112
+ for (const marketIndex of this.perpMarketIndexes) {
110
113
  await this.subscribeToMarketAccount(marketIndex);
111
114
  }
112
115
  return true;
113
116
  }
114
117
 
115
- async subscribeToMarketAccount(marketIndex: BN): Promise<boolean> {
118
+ async subscribeToMarketAccount(marketIndex: number): Promise<boolean> {
116
119
  const marketPublicKey = await getMarketPublicKey(
117
120
  this.program.programId,
118
121
  marketIndex
119
122
  );
120
- const accountSubscriber = new WebSocketAccountSubscriber<MarketAccount>(
121
- 'market',
123
+ const accountSubscriber = new WebSocketAccountSubscriber<PerpMarketAccount>(
124
+ 'perpMarket',
122
125
  this.program,
123
126
  marketPublicKey
124
127
  );
125
- await accountSubscriber.subscribe((data: MarketAccount) => {
126
- this.eventEmitter.emit('marketAccountUpdate', data);
128
+ await accountSubscriber.subscribe((data: PerpMarketAccount) => {
129
+ this.eventEmitter.emit('perpMarketAccountUpdate', data);
127
130
  this.eventEmitter.emit('update');
128
131
  });
129
- this.marketAccountSubscribers.set(
130
- marketIndex.toNumber(),
131
- accountSubscriber
132
- );
132
+ this.perpMarketAccountSubscribers.set(marketIndex, accountSubscriber);
133
133
  return true;
134
134
  }
135
135
 
136
- async subscribeToBankAccounts(): Promise<boolean> {
137
- for (const bankIndex of this.bankIndexes) {
138
- await this.subscribeToBankAccount(bankIndex);
136
+ async subscribeToSpotMarketAccounts(): Promise<boolean> {
137
+ for (const marketIndex of this.spotMarketIndexes) {
138
+ await this.subscribeToSpotMarketAccount(marketIndex);
139
139
  }
140
140
  return true;
141
141
  }
142
142
 
143
- async subscribeToBankAccount(bankIndex: BN): Promise<boolean> {
144
- const bankPublicKey = await getBankPublicKey(
143
+ async subscribeToSpotMarketAccount(marketIndex: number): Promise<boolean> {
144
+ const marketPublicKey = await getSpotMarketPublicKey(
145
145
  this.program.programId,
146
- bankIndex
146
+ marketIndex
147
147
  );
148
- const accountSubscriber = new WebSocketAccountSubscriber<BankAccount>(
149
- 'bank',
148
+ const accountSubscriber = new WebSocketAccountSubscriber<SpotMarketAccount>(
149
+ 'spotMarket',
150
150
  this.program,
151
- bankPublicKey
151
+ marketPublicKey
152
152
  );
153
- await accountSubscriber.subscribe((data: BankAccount) => {
154
- this.eventEmitter.emit('bankAccountUpdate', data);
153
+ await accountSubscriber.subscribe((data: SpotMarketAccount) => {
154
+ this.eventEmitter.emit('spotMarketAccountUpdate', data);
155
155
  this.eventEmitter.emit('update');
156
156
  });
157
- this.bankAccountSubscribers.set(bankIndex.toNumber(), accountSubscriber);
157
+ this.spotMarketAccountSubscribers.set(marketIndex, accountSubscriber);
158
158
  return true;
159
159
  }
160
160
 
@@ -195,13 +195,13 @@ export class WebSocketClearingHouseAccountSubscriber
195
195
  }
196
196
 
197
197
  async unsubscribeFromMarketAccounts(): Promise<void> {
198
- for (const accountSubscriber of this.marketAccountSubscribers.values()) {
198
+ for (const accountSubscriber of this.perpMarketAccountSubscribers.values()) {
199
199
  await accountSubscriber.unsubscribe();
200
200
  }
201
201
  }
202
202
 
203
- async unsubscribeFromBankAccounts(): Promise<void> {
204
- for (const accountSubscriber of this.bankAccountSubscribers.values()) {
203
+ async unsubscribeFromSpotMarketAccounts(): Promise<void> {
204
+ for (const accountSubscriber of this.spotMarketAccountSubscribers.values()) {
205
205
  await accountSubscriber.unsubscribe();
206
206
  }
207
207
  }
@@ -219,13 +219,13 @@ export class WebSocketClearingHouseAccountSubscriber
219
219
 
220
220
  const promises = [this.stateAccountSubscriber.fetch()]
221
221
  .concat(
222
- Array.from(this.marketAccountSubscribers.values()).map((subscriber) =>
223
- subscriber.fetch()
222
+ Array.from(this.perpMarketAccountSubscribers.values()).map(
223
+ (subscriber) => subscriber.fetch()
224
224
  )
225
225
  )
226
226
  .concat(
227
- Array.from(this.bankAccountSubscribers.values()).map((subscriber) =>
228
- subscriber.fetch()
227
+ Array.from(this.spotMarketAccountSubscribers.values()).map(
228
+ (subscriber) => subscriber.fetch()
229
229
  )
230
230
  );
231
231
 
@@ -240,21 +240,21 @@ export class WebSocketClearingHouseAccountSubscriber
240
240
  await this.stateAccountSubscriber.unsubscribe();
241
241
 
242
242
  await this.unsubscribeFromMarketAccounts();
243
- await this.unsubscribeFromBankAccounts();
243
+ await this.unsubscribeFromSpotMarketAccounts();
244
244
  await this.unsubscribeFromOracles();
245
245
 
246
246
  this.isSubscribed = false;
247
247
  }
248
248
 
249
- async addBank(bankIndex: BN): Promise<boolean> {
250
- if (this.bankAccountSubscribers.has(bankIndex.toNumber())) {
249
+ async addSpotMarket(marketIndex: number): Promise<boolean> {
250
+ if (this.spotMarketAccountSubscribers.has(marketIndex)) {
251
251
  return true;
252
252
  }
253
- return this.subscribeToBankAccount(bankIndex);
253
+ return this.subscribeToSpotMarketAccount(marketIndex);
254
254
  }
255
255
 
256
- async addMarket(marketIndex: BN): Promise<boolean> {
257
- if (this.marketAccountSubscribers.has(marketIndex.toNumber())) {
256
+ async addPerpMarket(marketIndex: number): Promise<boolean> {
257
+ if (this.perpMarketAccountSubscribers.has(marketIndex)) {
258
258
  return true;
259
259
  }
260
260
  return this.subscribeToMarketAccount(marketIndex);
@@ -286,24 +286,29 @@ export class WebSocketClearingHouseAccountSubscriber
286
286
  }
287
287
 
288
288
  public getMarketAccountAndSlot(
289
- marketIndex: BN
290
- ): DataAndSlot<MarketAccount> | undefined {
289
+ marketIndex: number
290
+ ): DataAndSlot<PerpMarketAccount> | undefined {
291
291
  this.assertIsSubscribed();
292
- return this.marketAccountSubscribers.get(marketIndex.toNumber())
293
- .dataAndSlot;
292
+ return this.perpMarketAccountSubscribers.get(marketIndex).dataAndSlot;
294
293
  }
295
294
 
296
- public getMarketAccountsAndSlots(): DataAndSlot<MarketAccount>[] {
297
- return Array.from(this.marketAccountSubscribers.values()).map(
295
+ public getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[] {
296
+ return Array.from(this.perpMarketAccountSubscribers.values()).map(
298
297
  (subscriber) => subscriber.dataAndSlot
299
298
  );
300
299
  }
301
300
 
302
- public getBankAccountAndSlot(
303
- bankIndex: BN
304
- ): DataAndSlot<BankAccount> | undefined {
301
+ public getSpotMarketAccountAndSlot(
302
+ marketIndex: number
303
+ ): DataAndSlot<SpotMarketAccount> | undefined {
305
304
  this.assertIsSubscribed();
306
- return this.bankAccountSubscribers.get(bankIndex.toNumber()).dataAndSlot;
305
+ return this.spotMarketAccountSubscribers.get(marketIndex).dataAndSlot;
306
+ }
307
+
308
+ public getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[] {
309
+ return Array.from(this.spotMarketAccountSubscribers.values()).map(
310
+ (subscriber) => subscriber.dataAndSlot
311
+ );
307
312
  }
308
313
 
309
314
  public getOraclePriceDataAndSlot(