@drift-labs/sdk 2.142.0-beta.8 → 2.142.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 (58) hide show
  1. package/VERSION +1 -1
  2. package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.d.ts +46 -5
  3. package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.js +245 -44
  4. package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +7 -4
  5. package/lib/browser/accounts/grpcMultiAccountSubscriber.js +115 -19
  6. package/lib/browser/adminClient.d.ts +4 -0
  7. package/lib/browser/adminClient.js +34 -0
  8. package/lib/browser/constants/perpMarkets.js +35 -0
  9. package/lib/browser/constants/spotMarkets.js +4 -4
  10. package/lib/browser/driftClient.d.ts +35 -5
  11. package/lib/browser/driftClient.js +41 -14
  12. package/lib/browser/events/parse.d.ts +2 -0
  13. package/lib/browser/events/parse.js +94 -1
  14. package/lib/browser/events/types.d.ts +22 -3
  15. package/lib/browser/idl/drift.json +105 -6
  16. package/lib/browser/math/amm.d.ts +1 -0
  17. package/lib/browser/math/amm.js +28 -4
  18. package/lib/browser/types.d.ts +20 -0
  19. package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts +46 -5
  20. package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts.map +1 -1
  21. package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.js +245 -44
  22. package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +7 -4
  23. package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -1
  24. package/lib/node/accounts/grpcMultiAccountSubscriber.js +115 -19
  25. package/lib/node/adminClient.d.ts +4 -0
  26. package/lib/node/adminClient.d.ts.map +1 -1
  27. package/lib/node/adminClient.js +34 -0
  28. package/lib/node/constants/perpMarkets.d.ts.map +1 -1
  29. package/lib/node/constants/perpMarkets.js +35 -0
  30. package/lib/node/constants/spotMarkets.js +4 -4
  31. package/lib/node/driftClient.d.ts +35 -5
  32. package/lib/node/driftClient.d.ts.map +1 -1
  33. package/lib/node/driftClient.js +41 -14
  34. package/lib/node/events/parse.d.ts +2 -0
  35. package/lib/node/events/parse.d.ts.map +1 -1
  36. package/lib/node/events/parse.js +94 -1
  37. package/lib/node/events/types.d.ts +22 -3
  38. package/lib/node/events/types.d.ts.map +1 -1
  39. package/lib/node/idl/drift.json +105 -6
  40. package/lib/node/math/amm.d.ts +1 -0
  41. package/lib/node/math/amm.d.ts.map +1 -1
  42. package/lib/node/math/amm.js +28 -4
  43. package/lib/node/types.d.ts +20 -0
  44. package/lib/node/types.d.ts.map +1 -1
  45. package/package.json +2 -1
  46. package/scripts/client-test.ts +294 -126
  47. package/src/accounts/grpcDriftClientAccountSubscriberV2.ts +401 -75
  48. package/src/accounts/grpcMultiAccountSubscriber.ts +167 -34
  49. package/src/adminClient.ts +74 -0
  50. package/src/constants/perpMarkets.ts +37 -0
  51. package/src/constants/spotMarkets.ts +4 -4
  52. package/src/driftClient.ts +65 -14
  53. package/src/events/parse.ts +115 -0
  54. package/src/events/types.ts +26 -2
  55. package/src/idl/drift.json +105 -6
  56. package/src/math/amm.ts +52 -8
  57. package/src/types.ts +22 -0
  58. package/tests/events/parseLogsForCuUsage.ts +139 -0
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.142.0-beta.8
1
+ 2.142.0-beta.27
@@ -1,24 +1,65 @@
1
- import { WebSocketDriftClientAccountSubscriber } from './webSocketDriftClientAccountSubscriber';
2
- import { OracleInfo } from '../oracles/types';
1
+ /// <reference types="node" />
2
+ import StrictEventEmitter from 'strict-event-emitter-types';
3
+ import { EventEmitter } from 'events';
4
+ import { OracleInfo, OraclePriceData } from '../oracles/types';
3
5
  import { Program } from '@coral-xyz/anchor';
4
- import { DataAndSlot, DelistedMarketSetting, GrpcConfigs, ResubOpts } from './types';
5
- import { PerpMarketAccount, SpotMarketAccount } from '../types';
6
- export declare class grpcDriftClientAccountSubscriberV2 extends WebSocketDriftClientAccountSubscriber {
6
+ import { PublicKey } from '@solana/web3.js';
7
+ import { AccountSubscriber, DataAndSlot, DelistedMarketSetting, DriftClientAccountEvents, DriftClientAccountSubscriber, GrpcConfigs, ResubOpts } from './types';
8
+ import { PerpMarketAccount, SpotMarketAccount, StateAccount } from '../types';
9
+ import { OracleClientCache } from '../oracles/oracleClientCache';
10
+ export declare class grpcDriftClientAccountSubscriberV2 implements DriftClientAccountSubscriber {
7
11
  private grpcConfigs;
8
12
  private perpMarketsSubscriber?;
9
13
  private spotMarketsSubscriber?;
10
14
  private oracleMultiSubscriber?;
11
15
  private perpMarketIndexToAccountPubkeyMap;
12
16
  private spotMarketIndexToAccountPubkeyMap;
17
+ private delistedMarketSetting;
18
+ eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
19
+ isSubscribed: boolean;
20
+ isSubscribing: boolean;
21
+ program: Program;
22
+ perpMarketIndexes: number[];
23
+ spotMarketIndexes: number[];
24
+ shouldFindAllMarketsAndOracles: boolean;
25
+ oracleInfos: OracleInfo[];
26
+ initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
27
+ initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
28
+ initialOraclePriceData: Map<string, OraclePriceData>;
29
+ perpOracleMap: Map<number, PublicKey>;
30
+ perpOracleStringMap: Map<number, string>;
31
+ spotOracleMap: Map<number, PublicKey>;
32
+ spotOracleStringMap: Map<number, string>;
33
+ private oracleIdToOracleDataMap;
34
+ stateAccountSubscriber?: AccountSubscriber<StateAccount>;
35
+ oracleClientCache: OracleClientCache;
36
+ private resubOpts?;
37
+ private subscriptionPromise;
38
+ protected subscriptionPromiseResolver: (val: boolean) => void;
13
39
  constructor(grpcConfigs: GrpcConfigs, program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean, delistedMarketSetting: DelistedMarketSetting, resubOpts?: ResubOpts);
40
+ chunks: <T>(array: readonly T[], size: number) => T[][];
41
+ setInitialData(): Promise<void>;
42
+ addPerpMarket(_marketIndex: number): Promise<boolean>;
43
+ addSpotMarket(_marketIndex: number): Promise<boolean>;
44
+ addOracle(oracleInfo: OracleInfo): Promise<boolean>;
14
45
  subscribe(): Promise<boolean>;
46
+ fetch(): Promise<void>;
47
+ private assertIsSubscribed;
48
+ getStateAccountAndSlot(): DataAndSlot<StateAccount>;
49
+ getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
50
+ getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
15
51
  getMarketAccountAndSlot(marketIndex: number): DataAndSlot<PerpMarketAccount> | undefined;
16
52
  getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
53
+ getOraclePriceDataAndSlot(oracleId: string): DataAndSlot<OraclePriceData> | undefined;
54
+ getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
55
+ getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
17
56
  setPerpOracleMap(): Promise<void>;
18
57
  setSpotOracleMap(): Promise<void>;
19
58
  subscribeToPerpMarketAccounts(): Promise<boolean>;
20
59
  subscribeToSpotMarketAccounts(): Promise<boolean>;
21
60
  subscribeToOracles(): Promise<boolean>;
61
+ handleDelistedMarkets(): Promise<void>;
62
+ removeInitialData(): void;
22
63
  unsubscribeFromOracles(): Promise<void>;
23
64
  unsubscribe(): Promise<void>;
24
65
  }
@@ -1,19 +1,116 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.grpcDriftClientAccountSubscriberV2 = void 0;
4
- const webSocketDriftClientAccountSubscriber_1 = require("./webSocketDriftClientAccountSubscriber");
4
+ const events_1 = require("events");
5
5
  const web3_js_1 = require("@solana/web3.js");
6
6
  const config_1 = require("../config");
7
7
  const pda_1 = require("../addresses/pda");
8
+ const types_1 = require("./types");
8
9
  const grpcAccountSubscriber_1 = require("./grpcAccountSubscriber");
9
10
  const grpcMultiAccountSubscriber_1 = require("./grpcMultiAccountSubscriber");
10
11
  const oracleId_1 = require("../oracles/oracleId");
11
- class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber {
12
+ const oracleClientCache_1 = require("../oracles/oracleClientCache");
13
+ const utils_1 = require("./utils");
14
+ class grpcDriftClientAccountSubscriberV2 {
12
15
  constructor(grpcConfigs, program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts) {
13
- super(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts);
14
16
  this.perpMarketIndexToAccountPubkeyMap = new Map();
15
17
  this.spotMarketIndexToAccountPubkeyMap = new Map();
18
+ this.perpOracleMap = new Map();
19
+ this.perpOracleStringMap = new Map();
20
+ this.spotOracleMap = new Map();
21
+ this.spotOracleStringMap = new Map();
22
+ this.oracleIdToOracleDataMap = new Map();
23
+ this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
24
+ this.chunks = (array, size) => {
25
+ return new Array(Math.ceil(array.length / size))
26
+ .fill(null)
27
+ .map((_, index) => index * size)
28
+ .map((begin) => array.slice(begin, begin + size));
29
+ };
30
+ this.eventEmitter = new events_1.EventEmitter();
31
+ this.isSubscribed = false;
32
+ this.isSubscribing = false;
33
+ this.program = program;
34
+ this.perpMarketIndexes = perpMarketIndexes;
35
+ this.spotMarketIndexes = spotMarketIndexes;
36
+ this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
37
+ this.oracleInfos = oracleInfos;
38
+ this.initialPerpMarketAccountData = new Map();
39
+ this.initialSpotMarketAccountData = new Map();
40
+ this.initialOraclePriceData = new Map();
41
+ this.perpOracleMap = new Map();
42
+ this.perpOracleStringMap = new Map();
43
+ this.spotOracleMap = new Map();
44
+ this.spotOracleStringMap = new Map();
16
45
  this.grpcConfigs = grpcConfigs;
46
+ this.resubOpts = resubOpts;
47
+ this.delistedMarketSetting = delistedMarketSetting;
48
+ }
49
+ async setInitialData() {
50
+ const connection = this.program.provider.connection;
51
+ if (!this.initialPerpMarketAccountData ||
52
+ this.initialPerpMarketAccountData.size === 0) {
53
+ const perpMarketPublicKeys = this.perpMarketIndexes.map((marketIndex) => (0, pda_1.getPerpMarketPublicKeySync)(this.program.programId, marketIndex));
54
+ const perpMarketPublicKeysChunks = this.chunks(perpMarketPublicKeys, 75);
55
+ const perpMarketAccountInfos = (await Promise.all(perpMarketPublicKeysChunks.map((perpMarketPublicKeysChunk) => connection.getMultipleAccountsInfo(perpMarketPublicKeysChunk)))).flat();
56
+ this.initialPerpMarketAccountData = new Map(perpMarketAccountInfos
57
+ .filter((accountInfo) => !!accountInfo)
58
+ .map((accountInfo) => {
59
+ const perpMarket = this.program.coder.accounts.decode('PerpMarket', accountInfo.data);
60
+ return [perpMarket.marketIndex, perpMarket];
61
+ }));
62
+ }
63
+ if (!this.initialSpotMarketAccountData ||
64
+ this.initialSpotMarketAccountData.size === 0) {
65
+ const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) => (0, pda_1.getSpotMarketPublicKeySync)(this.program.programId, marketIndex));
66
+ const spotMarketPublicKeysChunks = this.chunks(spotMarketPublicKeys, 75);
67
+ const spotMarketAccountInfos = (await Promise.all(spotMarketPublicKeysChunks.map((spotMarketPublicKeysChunk) => connection.getMultipleAccountsInfo(spotMarketPublicKeysChunk)))).flat();
68
+ this.initialSpotMarketAccountData = new Map(spotMarketAccountInfos
69
+ .filter((accountInfo) => !!accountInfo)
70
+ .map((accountInfo) => {
71
+ const spotMarket = this.program.coder.accounts.decode('SpotMarket', accountInfo.data);
72
+ return [spotMarket.marketIndex, spotMarket];
73
+ }));
74
+ }
75
+ const oracleAccountPubkeyChunks = this.chunks(this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey), 75);
76
+ const oracleAccountInfos = (await Promise.all(oracleAccountPubkeyChunks.map((oracleAccountPublicKeysChunk) => connection.getMultipleAccountsInfo(oracleAccountPublicKeysChunk)))).flat();
77
+ this.initialOraclePriceData = new Map(this.oracleInfos.reduce((result, oracleInfo, i) => {
78
+ if (!oracleAccountInfos[i]) {
79
+ return result;
80
+ }
81
+ const oracleClient = this.oracleClientCache.get(oracleInfo.source, connection, this.program);
82
+ const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(oracleAccountInfos[i].data);
83
+ result.push([
84
+ (0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source),
85
+ oraclePriceData,
86
+ ]);
87
+ return result;
88
+ }, []));
89
+ }
90
+ async addPerpMarket(_marketIndex) {
91
+ if (!this.perpMarketIndexes.includes(_marketIndex)) {
92
+ this.perpMarketIndexes = this.perpMarketIndexes.concat(_marketIndex);
93
+ }
94
+ return true;
95
+ }
96
+ async addSpotMarket(_marketIndex) {
97
+ return true;
98
+ }
99
+ async addOracle(oracleInfo) {
100
+ var _a, _c;
101
+ if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
102
+ console.log('[grpcDriftClientAccountSubscriberV2] addOracle');
103
+ }
104
+ if (oracleInfo.publicKey.equals(web3_js_1.PublicKey.default)) {
105
+ return true;
106
+ }
107
+ const exists = this.oracleInfos.some((o) => o.source === oracleInfo.source &&
108
+ o.publicKey.equals(oracleInfo.publicKey));
109
+ if (!exists) {
110
+ this.oracleInfos = this.oracleInfos.concat(oracleInfo);
111
+ }
112
+ (_c = this.oracleMultiSubscriber) === null || _c === void 0 ? void 0 : _c.addAccounts([oracleInfo.publicKey]);
113
+ return true;
17
114
  }
18
115
  async subscribe() {
19
116
  if (this.isSubscribed) {
@@ -61,6 +158,32 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
61
158
  this.removeInitialData();
62
159
  return true;
63
160
  }
161
+ async fetch() {
162
+ var _a, _c, _d, _e;
163
+ await ((_a = this.stateAccountSubscriber) === null || _a === void 0 ? void 0 : _a.fetch());
164
+ await ((_c = this.perpMarketsSubscriber) === null || _c === void 0 ? void 0 : _c.fetch());
165
+ await ((_d = this.spotMarketsSubscriber) === null || _d === void 0 ? void 0 : _d.fetch());
166
+ await ((_e = this.oracleMultiSubscriber) === null || _e === void 0 ? void 0 : _e.fetch());
167
+ }
168
+ assertIsSubscribed() {
169
+ if (!this.isSubscribed) {
170
+ throw new types_1.NotSubscribedError('You must call `subscribe` before using this function');
171
+ }
172
+ }
173
+ getStateAccountAndSlot() {
174
+ this.assertIsSubscribed();
175
+ return this.stateAccountSubscriber.dataAndSlot;
176
+ }
177
+ getMarketAccountsAndSlots() {
178
+ var _a, _c;
179
+ const map = (_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
180
+ return Array.from((_c = map === null || map === void 0 ? void 0 : map.values()) !== null && _c !== void 0 ? _c : []);
181
+ }
182
+ getSpotMarketAccountsAndSlots() {
183
+ var _a, _c;
184
+ const map = (_a = this.spotMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
185
+ return Array.from((_c = map === null || map === void 0 ? void 0 : map.values()) !== null && _c !== void 0 ? _c : []);
186
+ }
64
187
  getMarketAccountAndSlot(marketIndex) {
65
188
  var _a;
66
189
  return (_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountData(this.perpMarketIndexToAccountPubkeyMap.get(marketIndex));
@@ -69,8 +192,40 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
69
192
  var _a;
70
193
  return (_a = this.spotMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountData(this.spotMarketIndexToAccountPubkeyMap.get(marketIndex));
71
194
  }
195
+ getOraclePriceDataAndSlot(oracleId) {
196
+ this.assertIsSubscribed();
197
+ // we need to rely on a map we store in this class because the grpcMultiAccountSubscriber does not track a mapping or oracle ID.
198
+ // DO NOT call getAccountData on the oracleMultiSubscriber, it will not return the correct data in certain cases(BONK spot and perp market subscribed too at once).
199
+ return this.oracleIdToOracleDataMap.get(oracleId);
200
+ }
201
+ getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
202
+ const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
203
+ const oracle = this.perpOracleMap.get(marketIndex);
204
+ const oracleId = this.perpOracleStringMap.get(marketIndex);
205
+ if (!perpMarketAccount || !oracleId) {
206
+ return undefined;
207
+ }
208
+ if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
209
+ // If the oracle has changed, we need to update the oracle map in background
210
+ this.setPerpOracleMap();
211
+ }
212
+ return this.getOraclePriceDataAndSlot(oracleId);
213
+ }
214
+ getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
215
+ const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
216
+ const oracle = this.spotOracleMap.get(marketIndex);
217
+ const oracleId = this.spotOracleStringMap.get(marketIndex);
218
+ if (!spotMarketAccount || !oracleId) {
219
+ return undefined;
220
+ }
221
+ if (!spotMarketAccount.data.oracle.equals(oracle)) {
222
+ // If the oracle has changed, we need to update the oracle map in background
223
+ this.setSpotOracleMap();
224
+ }
225
+ return this.getOraclePriceDataAndSlot(oracleId);
226
+ }
72
227
  async setPerpOracleMap() {
73
- var _a;
228
+ var _a, _c;
74
229
  const perpMarketsMap = (_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
75
230
  const perpMarkets = Array.from(perpMarketsMap.values());
76
231
  const addOraclePromises = [];
@@ -82,7 +237,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
82
237
  const perpMarketIndex = perpMarketAccount.marketIndex;
83
238
  const oracle = perpMarketAccount.amm.oracle;
84
239
  const oracleId = (0, oracleId_1.getOracleId)(oracle, perpMarket.data.amm.oracleSource);
85
- if (!this.oracleSubscribers.has(oracleId)) {
240
+ if (!((_c = this.oracleMultiSubscriber) === null || _c === void 0 ? void 0 : _c.getAccountDataMap().has(oracleId))) {
86
241
  addOraclePromises.push(this.addOracle({
87
242
  publicKey: oracle,
88
243
  source: perpMarket.data.amm.oracleSource,
@@ -94,7 +249,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
94
249
  await Promise.all(addOraclePromises);
95
250
  }
96
251
  async setSpotOracleMap() {
97
- var _a;
252
+ var _a, _c;
98
253
  const spotMarketsMap = (_a = this.spotMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
99
254
  const spotMarkets = Array.from(spotMarketsMap.values());
100
255
  const addOraclePromises = [];
@@ -106,7 +261,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
106
261
  const spotMarketIndex = spotMarketAccount.marketIndex;
107
262
  const oracle = spotMarketAccount.oracle;
108
263
  const oracleId = (0, oracleId_1.getOracleId)(oracle, spotMarketAccount.oracleSource);
109
- if (!this.oracleSubscribers.has(oracleId)) {
264
+ if (!((_c = this.oracleMultiSubscriber) === null || _c === void 0 ? void 0 : _c.getAccountDataMap().has(oracleId))) {
110
265
  addOraclePromises.push(this.addOracle({
111
266
  publicKey: oracle,
112
267
  source: spotMarketAccount.oracleSource,
@@ -118,6 +273,10 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
118
273
  await Promise.all(addOraclePromises);
119
274
  }
120
275
  async subscribeToPerpMarketAccounts() {
276
+ var _a;
277
+ if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
278
+ console.log('[grpcDriftClientAccountSubscriberV2] subscribeToPerpMarketAccounts');
279
+ }
121
280
  const perpMarketIndexToAccountPubkeys = await Promise.all(this.perpMarketIndexes.map(async (marketIndex) => [
122
281
  marketIndex,
123
282
  await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, marketIndex),
@@ -140,7 +299,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
140
299
  }
141
300
  });
142
301
  for (const data of this.initialPerpMarketAccountData.values()) {
143
- this.perpMarketsSubscriber.setAccountData(data.pubkey, data);
302
+ this.perpMarketsSubscriber.setAccountData(data.pubkey.toBase58(), data);
144
303
  }
145
304
  await this.perpMarketsSubscriber.subscribe(perpMarketPubkeys, (_accountId, data) => {
146
305
  this.eventEmitter.emit('perpMarketAccountUpdate', data);
@@ -149,6 +308,10 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
149
308
  return true;
150
309
  }
151
310
  async subscribeToSpotMarketAccounts() {
311
+ var _a;
312
+ if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
313
+ console.log('[grpcDriftClientAccountSubscriberV2] subscribeToSpotMarketAccounts');
314
+ }
152
315
  const spotMarketIndexToAccountPubkeys = await Promise.all(this.spotMarketIndexes.map(async (marketIndex) => [
153
316
  marketIndex,
154
317
  await (0, pda_1.getSpotMarketPublicKey)(this.program.programId, marketIndex),
@@ -171,7 +334,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
171
334
  }
172
335
  });
173
336
  for (const data of this.initialSpotMarketAccountData.values()) {
174
- this.spotMarketsSubscriber.setAccountData(data.pubkey, data);
337
+ this.spotMarketsSubscriber.setAccountData(data.pubkey.toBase58(), data);
175
338
  }
176
339
  await this.spotMarketsSubscriber.subscribe(spotMarketPubkeys, (_accountId, data) => {
177
340
  this.eventEmitter.emit('spotMarketAccountUpdate', data);
@@ -180,64 +343,102 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
180
343
  return true;
181
344
  }
182
345
  async subscribeToOracles() {
183
- // Build list of unique oracle pubkeys and a lookup for sources
184
- const uniqueOraclePubkeys = new Map();
346
+ var _a;
347
+ if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
348
+ console.log('grpcDriftClientAccountSubscriberV2 subscribeToOracles');
349
+ }
350
+ const oraclePubkeyToInfosMap = new Map();
185
351
  for (const info of this.oracleInfos) {
186
- const id = (0, oracleId_1.getOracleId)(info.publicKey, info.source);
187
- if (!uniqueOraclePubkeys.has(id) &&
188
- !info.publicKey.equals(web3_js_1.PublicKey.default)) {
189
- uniqueOraclePubkeys.set(id, info);
352
+ const pubkey = info.publicKey.toBase58();
353
+ if (!oraclePubkeyToInfosMap.has(pubkey)) {
354
+ oraclePubkeyToInfosMap.set(pubkey, []);
190
355
  }
356
+ oraclePubkeyToInfosMap.get(pubkey).push(info);
191
357
  }
192
- const oraclePubkeys = Array.from(uniqueOraclePubkeys.values()).map((i) => i.publicKey);
193
- const pubkeyToSource = new Map(Array.from(uniqueOraclePubkeys.values()).map((i) => [
194
- i.publicKey.toBase58(),
195
- i.source,
196
- ]));
197
- this.oracleMultiSubscriber =
198
- await grpcMultiAccountSubscriber_1.grpcMultiAccountSubscriber.create(this.grpcConfigs, 'oracle', this.program, (buffer, pubkey) => {
199
- if (!pubkey) {
200
- throw new Error('Oracle pubkey missing in decode');
201
- }
202
- const source = pubkeyToSource.get(pubkey);
203
- const client = this.oracleClientCache.get(source, this.program.provider.connection, this.program);
204
- return client.getOraclePriceDataFromBuffer(buffer);
205
- }, this.resubOpts, undefined, async () => {
206
- var _a;
207
- try {
208
- if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
209
- console.log('[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing');
210
- }
211
- await this.subscribeToOracles();
212
- }
213
- catch (e) {
214
- console.error('Oracle resubscribe failed:', e);
358
+ const oraclePubkeys = Array.from(new Set(this.oracleInfos.map((info) => info.publicKey)));
359
+ this.oracleMultiSubscriber = await grpcMultiAccountSubscriber_1.grpcMultiAccountSubscriber.create(this.grpcConfigs, 'oracle', this.program, (buffer, pubkey, accountProps) => {
360
+ if (!pubkey) {
361
+ throw new Error('Oracle pubkey missing in decode');
362
+ }
363
+ const client = this.oracleClientCache.get(accountProps.source, this.program.provider.connection, this.program);
364
+ const price = client.getOraclePriceDataFromBuffer(buffer);
365
+ return price;
366
+ }, this.resubOpts, undefined, async () => {
367
+ var _a;
368
+ try {
369
+ if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
370
+ console.log('[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing');
215
371
  }
216
- });
372
+ await this.subscribeToOracles();
373
+ }
374
+ catch (e) {
375
+ console.error('Oracle resubscribe failed:', e);
376
+ }
377
+ }, oraclePubkeyToInfosMap);
217
378
  for (const data of this.initialOraclePriceData.entries()) {
218
379
  const { publicKey } = (0, oracleId_1.getPublicKeyAndSourceFromOracleId)(data[0]);
219
- this.oracleMultiSubscriber.setAccountData(publicKey, data[1]);
380
+ this.oracleMultiSubscriber.setAccountData(publicKey.toBase58(), data[1]);
381
+ this.oracleIdToOracleDataMap.set(data[0], {
382
+ data: data[1],
383
+ slot: 0,
384
+ });
220
385
  }
221
- await this.oracleMultiSubscriber.subscribe(oraclePubkeys, (accountId, data) => {
222
- const source = pubkeyToSource.get(accountId.toBase58());
223
- this.eventEmitter.emit('oraclePriceUpdate', accountId, source, data);
386
+ await this.oracleMultiSubscriber.subscribe(oraclePubkeys, (accountId, data, context, _b, accountProps) => {
387
+ const oracleId = (0, oracleId_1.getOracleId)(accountId, accountProps.source);
388
+ this.oracleIdToOracleDataMap.set(oracleId, {
389
+ data,
390
+ slot: context.slot,
391
+ });
392
+ this.eventEmitter.emit('oraclePriceUpdate', accountId, accountProps.source, data);
224
393
  this.eventEmitter.emit('update');
225
394
  });
226
395
  return true;
227
396
  }
397
+ async handleDelistedMarkets() {
398
+ var _a, _c;
399
+ if (this.delistedMarketSetting === types_1.DelistedMarketSetting.Subscribe) {
400
+ return;
401
+ }
402
+ const { perpMarketIndexes, oracles } = (0, utils_1.findDelistedPerpMarketsAndOracles)(Array.from(((_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap().values()) || []), Array.from(((_c = this.spotMarketsSubscriber) === null || _c === void 0 ? void 0 : _c.getAccountDataMap().values()) || []));
403
+ // Build array of perp market pubkeys to remove
404
+ const perpMarketPubkeysToRemove = perpMarketIndexes
405
+ .map((marketIndex) => {
406
+ const pubkeyString = this.perpMarketIndexToAccountPubkeyMap.get(marketIndex);
407
+ return pubkeyString ? new web3_js_1.PublicKey(pubkeyString) : null;
408
+ })
409
+ .filter((pubkey) => pubkey !== null);
410
+ // Build array of oracle pubkeys to remove
411
+ const oraclePubkeysToRemove = oracles.map((oracle) => oracle.publicKey);
412
+ // Remove accounts in batches - perp markets
413
+ if (perpMarketPubkeysToRemove.length > 0) {
414
+ await this.perpMarketsSubscriber.removeAccounts(perpMarketPubkeysToRemove);
415
+ }
416
+ // Remove accounts in batches - oracles
417
+ if (oraclePubkeysToRemove.length > 0) {
418
+ await this.oracleMultiSubscriber.removeAccounts(oraclePubkeysToRemove);
419
+ }
420
+ }
421
+ removeInitialData() {
422
+ this.initialPerpMarketAccountData = new Map();
423
+ this.initialSpotMarketAccountData = new Map();
424
+ this.initialOraclePriceData = new Map();
425
+ }
228
426
  async unsubscribeFromOracles() {
229
427
  if (this.oracleMultiSubscriber) {
230
428
  await this.oracleMultiSubscriber.unsubscribe();
231
429
  this.oracleMultiSubscriber = undefined;
232
430
  return;
233
431
  }
234
- await super.unsubscribeFromOracles();
235
432
  }
236
433
  async unsubscribe() {
434
+ var _a, _c;
237
435
  if (this.isSubscribed) {
238
436
  return;
239
437
  }
240
438
  await this.stateAccountSubscriber.unsubscribe();
439
+ await this.unsubscribeFromOracles();
440
+ await ((_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.unsubscribe());
441
+ await ((_c = this.spotMarketsSubscriber) === null || _c === void 0 ? void 0 : _c.unsubscribe());
241
442
  }
242
443
  }
243
444
  exports.grpcDriftClientAccountSubscriberV2 = grpcDriftClientAccountSubscriberV2;
@@ -4,7 +4,7 @@ import { Program } from '@coral-xyz/anchor';
4
4
  import { Context, PublicKey } from '@solana/web3.js';
5
5
  import { Client } from '../isomorphic/grpc';
6
6
  import { DataAndSlot, GrpcConfigs, ResubOpts } from './types';
7
- export declare class grpcMultiAccountSubscriber<T> {
7
+ export declare class grpcMultiAccountSubscriber<T, U = undefined> {
8
8
  private client;
9
9
  private stream;
10
10
  private commitmentLevel;
@@ -20,12 +20,15 @@ export declare class grpcMultiAccountSubscriber<T> {
20
20
  private subscribedAccounts;
21
21
  private onChangeMap;
22
22
  private dataMap;
23
+ private accountPropsMap;
24
+ private bufferMap;
23
25
  private constructor();
24
- static create<U>(grpcConfigs: GrpcConfigs, accountName: string, program: Program, decodeBuffer?: (buffer: Buffer, pubkey?: string) => U, resubOpts?: ResubOpts, clientProp?: Client, onUnsubscribe?: () => Promise<void>): Promise<grpcMultiAccountSubscriber<U>>;
25
- setAccountData(accountPubkey: PublicKey, data: T, slot?: number): void;
26
+ static create<T, U = undefined>(grpcConfigs: GrpcConfigs, accountName: string, program: Program, decodeBuffer?: (buffer: Buffer, pubkey?: string, accountProps?: U) => T, resubOpts?: ResubOpts, clientProp?: Client, onUnsubscribe?: () => Promise<void>, accountPropsMap?: Map<string, U | Array<U>>): Promise<grpcMultiAccountSubscriber<T, U>>;
27
+ setAccountData(accountPubkey: string, data: T, slot?: number): void;
26
28
  getAccountData(accountPubkey: string): DataAndSlot<T> | undefined;
27
29
  getAccountDataMap(): Map<string, DataAndSlot<T>>;
28
- subscribe(accounts: PublicKey[], onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void): Promise<void>;
30
+ fetch(): Promise<void>;
31
+ subscribe(accounts: PublicKey[], onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer, accountProps: U) => void): Promise<void>;
29
32
  addAccounts(accounts: PublicKey[]): Promise<void>;
30
33
  removeAccounts(accounts: PublicKey[]): Promise<void>;
31
34
  unsubscribe(): Promise<void>;