@drift-labs/sdk 2.142.0-beta.14 → 2.142.0-beta.15

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.
@@ -44,12 +44,13 @@ function commitmentLevelToCommitment(commitmentLevel) {
44
44
  }
45
45
  }
46
46
  class grpcMultiAccountSubscriber {
47
- constructor(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe) {
47
+ constructor(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe, accountPropsMap) {
48
48
  this.isUnsubscribing = false;
49
49
  this.receivingData = false;
50
50
  this.subscribedAccounts = new Set();
51
51
  this.onChangeMap = new Map();
52
52
  this.dataMap = new Map();
53
+ this.accountPropsMap = new Map();
53
54
  this.client = client;
54
55
  this.commitmentLevel = commitmentLevel;
55
56
  this.accountName = accountName;
@@ -57,8 +58,9 @@ class grpcMultiAccountSubscriber {
57
58
  this.decodeBufferFn = decodeBuffer;
58
59
  this.resubOpts = resubOpts;
59
60
  this.onUnsubscribe = onUnsubscribe;
61
+ this.accountPropsMap = accountPropsMap;
60
62
  }
61
- static async create(grpcConfigs, accountName, program, decodeBuffer, resubOpts, clientProp, onUnsubscribe) {
63
+ static async create(grpcConfigs, accountName, program, decodeBuffer, resubOpts, clientProp, onUnsubscribe, accountPropsMap) {
62
64
  var _a, _b;
63
65
  const client = clientProp
64
66
  ? clientProp
@@ -66,7 +68,7 @@ class grpcMultiAccountSubscriber {
66
68
  const commitmentLevel =
67
69
  // @ts-ignore :: isomorphic exported enum fails typescript but will work at runtime
68
70
  (_b = grpcConfigs.commitmentLevel) !== null && _b !== void 0 ? _b : grpc_1.CommitmentLevel.CONFIRMED;
69
- return new grpcMultiAccountSubscriber(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe);
71
+ return new grpcMultiAccountSubscriber(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe, accountPropsMap);
70
72
  }
71
73
  setAccountData(accountPubkey, data, slot) {
72
74
  this.dataMap.set(accountPubkey, { data, slot });
@@ -119,9 +121,9 @@ class grpcMultiAccountSubscriber {
119
121
  for (const pk of accounts) {
120
122
  const key = pk.toBase58();
121
123
  this.subscribedAccounts.add(key);
122
- this.onChangeMap.set(key, (data, ctx, buffer) => {
124
+ this.onChangeMap.set(key, (data, ctx, buffer, accountProps) => {
123
125
  this.setAccountData(key, data, ctx.slot);
124
- onChange(new web3_js_1.PublicKey(key), data, ctx, buffer);
126
+ onChange(new web3_js_1.PublicKey(key), data, ctx, buffer, accountProps);
125
127
  });
126
128
  }
127
129
  this.stream =
@@ -163,21 +165,33 @@ class grpcMultiAccountSubscriber {
163
165
  };
164
166
  const context = { slot };
165
167
  const buffer = accountInfo.data;
166
- const data = this.decodeBufferFn
167
- ? this.decodeBufferFn(buffer, accountPubkey)
168
- : this.program.account[this.accountName].coder.accounts.decode(this.capitalize(this.accountName), buffer);
169
- const handler = this.onChangeMap.get(accountPubkey);
170
- if (handler) {
171
- if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
172
- this.receivingData = true;
173
- clearTimeout(this.timeoutId);
174
- handler(data, context, buffer);
175
- this.setTimeout();
168
+ const accountProps = (_a = this.accountPropsMap) === null || _a === void 0 ? void 0 : _a.get(accountPubkey);
169
+ const handleDataBuffer = (context, buffer, accountProps) => {
170
+ var _a;
171
+ const data = this.decodeBufferFn
172
+ ? this.decodeBufferFn(buffer, accountPubkey, accountProps)
173
+ : this.program.account[this.accountName].coder.accounts.decode(this.capitalize(this.accountName), buffer);
174
+ const handler = this.onChangeMap.get(accountPubkey);
175
+ if (handler) {
176
+ if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
177
+ this.receivingData = true;
178
+ clearTimeout(this.timeoutId);
179
+ handler(data, context, buffer, accountProps);
180
+ this.setTimeout();
181
+ }
182
+ else {
183
+ handler(data, context, buffer, accountProps);
184
+ }
176
185
  }
177
- else {
178
- handler(data, context, buffer);
186
+ };
187
+ if (Array.isArray(accountProps)) {
188
+ for (const props of accountProps) {
189
+ handleDataBuffer(context, buffer, props);
179
190
  }
180
191
  }
192
+ else {
193
+ handleDataBuffer(context, buffer, accountProps);
194
+ }
181
195
  });
182
196
  return new Promise((resolve, reject) => {
183
197
  this.stream.write(request, (err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.142.0-beta.14",
3
+ "version": "2.142.0-beta.15",
4
4
  "main": "lib/node/index.js",
5
5
  "types": "lib/node/index.d.ts",
6
6
  "module": "./lib/browser/index.js",
@@ -1,12 +1,14 @@
1
1
  import { DriftClient } from '../src/driftClient';
2
2
  import { grpcDriftClientAccountSubscriberV2 } from '../src/accounts/grpcDriftClientAccountSubscriberV2';
3
+ import { grpcDriftClientAccountSubscriber } from '../src/accounts/grpcDriftClientAccountSubscriber';
3
4
  import { Connection, Keypair, PublicKey } from '@solana/web3.js';
4
5
  import { DriftClientConfig } from '../src/driftClientConfig';
5
6
  import {
6
- decodeName,
7
7
  DRIFT_PROGRAM_ID,
8
8
  PerpMarketAccount,
9
+ SpotMarketAccount,
9
10
  Wallet,
11
+ OracleInfo,
10
12
  } from '../src';
11
13
  import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
12
14
  import dotenv from 'dotenv';
@@ -21,8 +23,8 @@ import driftIDL from '../src/idl/drift.json';
21
23
  const GRPC_ENDPOINT = process.env.GRPC_ENDPOINT;
22
24
  const TOKEN = process.env.TOKEN;
23
25
 
24
- async function initializeGrpcDriftClientV2() {
25
- const connection = new Connection('https://api.mainnet-beta.solana.com');
26
+ async function initializeGrpcDriftClientV2VersusV1() {
27
+ const connection = new Connection('');
26
28
  const wallet = new Wallet(new Keypair());
27
29
  dotenv.config({ path: '../' });
28
30
 
@@ -38,177 +40,136 @@ async function initializeGrpcDriftClientV2() {
38
40
 
39
41
  const program = new Program(driftIDL as Idl, programId, provider);
40
42
 
41
- const perpMarketProgramAccounts =
42
- (await program.account.perpMarket.all()) as ProgramAccount<PerpMarketAccount>[];
43
- const solPerpMarket = perpMarketProgramAccounts.find(
44
- (account) => account.account.marketIndex === 0
45
- );
46
- const solOracleInfo = {
47
- publicKey: solPerpMarket.account.amm.oracle,
48
- source: solPerpMarket.account.amm.oracleSource,
49
- };
50
- const ethPerpMarket = perpMarketProgramAccounts.find(
51
- (account) => account.account.marketIndex === 2
52
- );
53
- const ethOracleInfo = {
54
- publicKey: ethPerpMarket.account.amm.oracle,
55
- source: ethPerpMarket.account.amm.oracleSource,
56
- };
57
- const btcPerpMarket = perpMarketProgramAccounts.find(
58
- (account) => account.account.marketIndex === 1
59
- );
60
- const btcOracleInfo = {
61
- publicKey: btcPerpMarket.account.amm.oracle,
62
- source: btcPerpMarket.account.amm.oracleSource,
43
+ const perpMarketIndexes = [4];
44
+ const spotMarketIndexes = [32];
45
+
46
+ const perpMarketProgramAccounts = (
47
+ await program.account.perpMarket.all()
48
+ ).filter((a) =>
49
+ perpMarketIndexes.includes(a.account.marketIndex as number)
50
+ ) as ProgramAccount<PerpMarketAccount>[];
51
+ const spotMarketProgramAccounts = (
52
+ await program.account.spotMarket.all()
53
+ ).filter((a) =>
54
+ spotMarketIndexes.includes(a.account.marketIndex as number)
55
+ ) as ProgramAccount<SpotMarketAccount>[];
56
+
57
+ // const perpMarketIndexes = perpMarketProgramAccounts.map(
58
+ // (a) => a.account.marketIndex
59
+ // );
60
+ // const spotMarketIndexes = spotMarketProgramAccounts.map(
61
+ // (a) => a.account.marketIndex
62
+ // );
63
+ // const oracleInfos = [
64
+ // {
65
+ // publicKey: new PublicKey('BERaNi6cpEresbq6HC1EQGaB1H1UjvEo4NGnmYSSJof4'),
66
+ // source: OracleSource.PYTH_LAZER,
67
+ // },
68
+ // {
69
+ // publicKey: new PublicKey('BERaNi6cpEresbq6HC1EQGaB1H1UjvEo4NGnmYSSJof4'),
70
+ // source: OracleSource.PYTH_LAZER_1M,
71
+ // },
72
+ // ];
73
+
74
+ const seen = new Set<string>();
75
+ const oracleInfos: OracleInfo[] = [];
76
+ for (const acct of perpMarketProgramAccounts) {
77
+ const key = `${acct.account.amm.oracle.toBase58()}-${Object.keys(
78
+ acct.account.amm.oracleSource ?? {}
79
+ )?.[0]}`;
80
+ if (!seen.has(key)) {
81
+ seen.add(key);
82
+ oracleInfos.push({
83
+ publicKey: acct.account.amm.oracle,
84
+ source: acct.account.amm.oracleSource,
85
+ });
86
+ }
87
+ }
88
+ for (const acct of spotMarketProgramAccounts) {
89
+ const key = `${acct.account.oracle.toBase58()}-${Object.keys(
90
+ acct.account.oracleSource ?? {}
91
+ )?.[0]}`;
92
+ if (!seen.has(key)) {
93
+ seen.add(key);
94
+ oracleInfos.push({
95
+ publicKey: acct.account.oracle,
96
+ source: acct.account.oracleSource,
97
+ });
98
+ }
99
+ }
100
+
101
+ const baseAccountSubscription = {
102
+ type: 'grpc' as const,
103
+ grpcConfigs: {
104
+ endpoint: GRPC_ENDPOINT,
105
+ token: TOKEN,
106
+ commitmentLevel: 'confirmed' as unknown as CommitmentLevel,
107
+ channelOptions: {
108
+ 'grpc.keepalive_time_ms': 10_000,
109
+ 'grpc.keepalive_timeout_ms': 1_000,
110
+ 'grpc.keepalive_permit_without_calls': 1,
111
+ },
112
+ },
63
113
  };
64
114
 
65
- const config: DriftClientConfig = {
115
+ const configV2: DriftClientConfig = {
66
116
  connection,
67
117
  wallet,
68
118
  programID: new PublicKey(DRIFT_PROGRAM_ID),
69
119
  accountSubscription: {
70
- type: 'grpc',
71
- grpcConfigs: {
72
- endpoint: GRPC_ENDPOINT,
73
- token: TOKEN,
74
- commitmentLevel: 'confirmed' as unknown as CommitmentLevel,
75
- channelOptions: {
76
- 'grpc.keepalive_time_ms': 10_000,
77
- 'grpc.keepalive_timeout_ms': 1_000,
78
- 'grpc.keepalive_permit_without_calls': 1,
79
- },
80
- },
120
+ ...baseAccountSubscription,
81
121
  driftClientAccountSubscriber: grpcDriftClientAccountSubscriberV2,
82
122
  },
83
- perpMarketIndexes: [0, 1, 2],
84
- spotMarketIndexes: [0, 1, 2],
85
- oracleInfos: [solOracleInfo, ethOracleInfo, btcOracleInfo],
123
+ perpMarketIndexes,
124
+ spotMarketIndexes,
125
+ oracleInfos,
86
126
  };
87
127
 
88
- const driftClient = new DriftClient(config);
89
-
90
- let perpMarketUpdateCount = 0;
91
- let spotMarketUpdateCount = 0;
92
- let oraclePriceUpdateCount = 0;
93
- let userAccountUpdateCount = 0;
94
-
95
- const updatePromise = new Promise<void>((resolve) => {
96
- driftClient.accountSubscriber.eventEmitter.on(
97
- 'perpMarketAccountUpdate',
98
- (data) => {
99
- console.log(
100
- 'Perp market account update:',
101
- decodeName(data.name),
102
- 'mmOracleSequenceId:',
103
- data.amm.mmOracleSequenceId.toString()
104
- );
105
- // const perpMarketData = driftClient.getPerpMarketAccount(
106
- // data.marketIndex
107
- // );
108
- // console.log(
109
- // 'Perp market data market index:',
110
- // perpMarketData?.marketIndex
111
- // );
112
- // const oracle = driftClient.getOracleDataForPerpMarket(data.marketIndex);
113
- // const mmOracle = driftClient.getMMOracleDataForPerpMarket(
114
- // data.marketIndex
115
- // );
116
- // console.log('Perp oracle price:', oracle.price.toString());
117
- // console.log('Perp MM oracle price:', mmOracle.price.toString());
118
- // console.log(
119
- // 'Perp MM oracle sequence id:',
120
- // perpMarketData?.amm?.mmOracleSequenceId?.toString()
121
- // );
122
- perpMarketUpdateCount++;
123
- if (
124
- perpMarketUpdateCount >= 10 &&
125
- spotMarketUpdateCount >= 10 &&
126
- oraclePriceUpdateCount >= 10 &&
127
- userAccountUpdateCount >= 2
128
- ) {
129
- resolve();
130
- }
131
- }
132
- );
133
-
134
- driftClient.accountSubscriber.eventEmitter.on(
135
- 'spotMarketAccountUpdate',
136
- (data) => {
137
- console.log('Spot market account update:', decodeName(data.name));
138
- const spotMarketData = driftClient.getSpotMarketAccount(
139
- data.marketIndex
140
- );
141
- console.log(
142
- 'Spot market data market index:',
143
- spotMarketData?.marketIndex
144
- );
145
- const oracle = driftClient.getOracleDataForSpotMarket(data.marketIndex);
146
- console.log('Spot oracle price:', oracle.price.toString());
147
- spotMarketUpdateCount++;
148
- if (
149
- perpMarketUpdateCount >= 10 &&
150
- spotMarketUpdateCount >= 10 &&
151
- oraclePriceUpdateCount >= 10 &&
152
- userAccountUpdateCount >= 2
153
- ) {
154
- resolve();
155
- }
156
- }
157
- );
158
-
159
- driftClient.accountSubscriber.eventEmitter.on(
160
- 'oraclePriceUpdate',
161
- (data) => {
162
- console.log('Oracle price update:', data.toBase58());
163
- oraclePriceUpdateCount++;
164
- if (
165
- perpMarketUpdateCount >= 10 &&
166
- spotMarketUpdateCount >= 10 &&
167
- oraclePriceUpdateCount >= 10 &&
168
- userAccountUpdateCount >= 2
169
- ) {
170
- resolve();
171
- }
172
- }
173
- );
174
-
175
- driftClient.accountSubscriber.eventEmitter.on(
176
- 'userAccountUpdate',
177
- (data) => {
178
- console.log('User account update:', decodeName(data.name));
179
- userAccountUpdateCount++;
180
- if (
181
- perpMarketUpdateCount >= 10 &&
182
- spotMarketUpdateCount >= 10 &&
183
- oraclePriceUpdateCount >= 10 &&
184
- userAccountUpdateCount >= 2
185
- ) {
186
- resolve();
187
- }
188
- }
189
- );
190
- });
191
-
192
- await driftClient.subscribe();
193
- console.log('DriftClient initialized and listening for updates.');
194
-
195
- for (const marketIndex of config.perpMarketIndexes) {
196
- const oracle = driftClient.getOracleDataForPerpMarket(marketIndex);
197
- const mmOracle = driftClient.getMMOracleDataForPerpMarket(marketIndex);
198
- console.log('Initial perp oracle price:', oracle.price.toString());
199
- console.log('Initial perp MM oracle price:', mmOracle.price.toString());
200
- }
128
+ const configV1: DriftClientConfig = {
129
+ connection,
130
+ wallet,
131
+ programID: new PublicKey(DRIFT_PROGRAM_ID),
132
+ accountSubscription: {
133
+ ...baseAccountSubscription,
134
+ driftClientAccountSubscriber: grpcDriftClientAccountSubscriber,
135
+ },
136
+ perpMarketIndexes,
137
+ spotMarketIndexes,
138
+ oracleInfos,
139
+ };
201
140
 
202
- for (const marketIndex of config.spotMarketIndexes) {
203
- const oracle = driftClient.getOracleDataForSpotMarket(marketIndex);
204
- console.log('Initial spot oracle price:', oracle.price.toString());
205
- }
141
+ const clientV2 = new DriftClient(configV2);
142
+ const clientV1 = new DriftClient(configV1);
143
+
144
+ await Promise.all([clientV1.subscribe(), clientV2.subscribe()]);
145
+ const compare = () => {
146
+ for (const idx of perpMarketIndexes) {
147
+ const p1 = clientV1.getOracleDataForPerpMarket(idx).price;
148
+ const p2 = clientV2.getOracleDataForPerpMarket(idx).price;
149
+ console.log(
150
+ `perp mkt ${idx} | v1 ${p1.toString()} | v2 ${p2.toString()}`
151
+ );
152
+ }
153
+ for (const idx of spotMarketIndexes) {
154
+ const s1 = clientV1.getOracleDataForSpotMarket(idx).price;
155
+ const s2 = clientV2.getOracleDataForSpotMarket(idx).price;
156
+ console.log(
157
+ `spot mkt ${idx} | v1 ${s1.toString()} | v2 ${s2.toString()}`
158
+ );
159
+ }
160
+ };
161
+
162
+ compare();
163
+ const interval = setInterval(compare, 1000);
206
164
 
207
- const stateAccount = driftClient.getStateAccount();
208
- console.log('Initial state account:', stateAccount.toString());
165
+ const cleanup = async () => {
166
+ clearInterval(interval);
167
+ await Promise.all([clientV1.unsubscribe(), clientV2.unsubscribe()]);
168
+ process.exit(0);
169
+ };
209
170
 
210
- await updatePromise;
211
- console.log('Received required number of updates.');
171
+ process.on('SIGINT', cleanup);
172
+ process.on('SIGTERM', cleanup);
212
173
  }
213
174
 
214
- initializeGrpcDriftClientV2().catch(console.error);
175
+ initializeGrpcDriftClientV2VersusV1().catch(console.error);
@@ -37,7 +37,10 @@ export class grpcDriftClientAccountSubscriberV2
37
37
  private grpcConfigs: GrpcConfigs;
38
38
  private perpMarketsSubscriber?: grpcMultiAccountSubscriber<PerpMarketAccount>;
39
39
  private spotMarketsSubscriber?: grpcMultiAccountSubscriber<SpotMarketAccount>;
40
- private oracleMultiSubscriber?: grpcMultiAccountSubscriber<OraclePriceData>;
40
+ private oracleMultiSubscriber?: grpcMultiAccountSubscriber<
41
+ OraclePriceData,
42
+ OracleInfo
43
+ >;
41
44
  private perpMarketIndexToAccountPubkeyMap = new Map<number, string>();
42
45
  private spotMarketIndexToAccountPubkeyMap = new Map<number, string>();
43
46
  private delistedMarketSetting: DelistedMarketSetting;
@@ -60,6 +63,10 @@ export class grpcDriftClientAccountSubscriberV2
60
63
  public perpOracleStringMap = new Map<number, string>();
61
64
  public spotOracleMap = new Map<number, PublicKey>();
62
65
  public spotOracleStringMap = new Map<number, string>();
66
+ private oracleIdToOracleDataMap = new Map<
67
+ string,
68
+ DataAndSlot<OraclePriceData>
69
+ >();
63
70
  public stateAccountSubscriber?: AccountSubscriber<StateAccount>;
64
71
  oracleClientCache = new OracleClientCache();
65
72
  private resubOpts?: ResubOpts;
@@ -360,8 +367,9 @@ export class grpcDriftClientAccountSubscriberV2
360
367
  oracleId: string
361
368
  ): DataAndSlot<OraclePriceData> | undefined {
362
369
  this.assertIsSubscribed();
363
- const { publicKey } = getPublicKeyAndSourceFromOracleId(oracleId);
364
- return this.oracleMultiSubscriber?.getAccountData(publicKey.toBase58());
370
+ // we need to rely on a map we store in this class because the grpcMultiAccountSubscriber does not track a mapping or oracle ID.
371
+ // 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).
372
+ return this.oracleIdToOracleDataMap.get(oracleId);
365
373
  }
366
374
 
367
375
  public getOraclePriceDataAndSlotForPerpMarket(
@@ -577,80 +585,80 @@ export class grpcDriftClientAccountSubscriberV2
577
585
  }
578
586
 
579
587
  async subscribeToOracles(): Promise<boolean> {
580
- const pubkeyToSources = new Map<string, Set<OracleInfo['source']>>();
588
+ const oraclePubkeyToInfosMap = new Map<string, OracleInfo[]>();
581
589
  for (const info of this.oracleInfos) {
582
- if (info.publicKey.equals((PublicKey as any).default)) {
583
- continue;
590
+ const pubkey = info.publicKey.toBase58();
591
+ if (!oraclePubkeyToInfosMap.has(pubkey)) {
592
+ oraclePubkeyToInfosMap.set(pubkey, []);
584
593
  }
585
- const key = info.publicKey.toBase58();
586
- let sources = pubkeyToSources.get(key);
587
- if (!sources) {
588
- sources = new Set<OracleInfo['source']>();
589
- pubkeyToSources.set(key, sources);
590
- }
591
- sources.add(info.source);
594
+ oraclePubkeyToInfosMap.get(pubkey).push(info);
592
595
  }
593
596
 
594
- const oraclePubkeys = Array.from(pubkeyToSources.keys()).map(
595
- (k) => new PublicKey(k)
597
+ const oraclePubkeys = Array.from(
598
+ new Set(this.oracleInfos.map((info) => info.publicKey))
596
599
  );
597
600
 
598
- this.oracleMultiSubscriber =
599
- await grpcMultiAccountSubscriber.create<OraclePriceData>(
600
- this.grpcConfigs,
601
- 'oracle',
602
- this.program,
603
- (buffer: Buffer, pubkey?: string) => {
604
- if (!pubkey) {
605
- throw new Error('Oracle pubkey missing in decode');
606
- }
607
- const sources = pubkeyToSources.get(pubkey);
608
- if (!sources || sources.size === 0) {
609
- throw new Error('Oracle sources missing for pubkey in decode');
610
- }
611
- const primarySource = sources.values().next().value;
612
- const client = this.oracleClientCache.get(
613
- primarySource,
614
- this.program.provider.connection,
615
- this.program
616
- );
617
- return client.getOraclePriceDataFromBuffer(buffer);
618
- },
619
- this.resubOpts,
620
- undefined,
621
- async () => {
622
- try {
623
- if (this.resubOpts?.logResubMessages) {
624
- console.log(
625
- '[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing'
626
- );
627
- }
628
- await this.subscribeToOracles();
629
- } catch (e) {
630
- console.error('Oracle resubscribe failed:', e);
601
+ this.oracleMultiSubscriber = await grpcMultiAccountSubscriber.create<
602
+ OraclePriceData,
603
+ OracleInfo
604
+ >(
605
+ this.grpcConfigs,
606
+ 'oracle',
607
+ this.program,
608
+ (buffer: Buffer, pubkey?: string, accountProps?: OracleInfo) => {
609
+ if (!pubkey) {
610
+ throw new Error('Oracle pubkey missing in decode');
611
+ }
612
+
613
+ const client = this.oracleClientCache.get(
614
+ accountProps.source,
615
+ this.program.provider.connection,
616
+ this.program
617
+ );
618
+ const price = client.getOraclePriceDataFromBuffer(buffer);
619
+ return price;
620
+ },
621
+ this.resubOpts,
622
+ undefined,
623
+ async () => {
624
+ try {
625
+ if (this.resubOpts?.logResubMessages) {
626
+ console.log(
627
+ '[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing'
628
+ );
631
629
  }
630
+ await this.subscribeToOracles();
631
+ } catch (e) {
632
+ console.error('Oracle resubscribe failed:', e);
632
633
  }
633
- );
634
+ },
635
+ oraclePubkeyToInfosMap
636
+ );
634
637
 
635
638
  for (const data of this.initialOraclePriceData.entries()) {
636
639
  const { publicKey } = getPublicKeyAndSourceFromOracleId(data[0]);
637
640
  this.oracleMultiSubscriber.setAccountData(publicKey.toBase58(), data[1]);
641
+ this.oracleIdToOracleDataMap.set(data[0], {
642
+ data: data[1],
643
+ slot: 0,
644
+ });
638
645
  }
639
646
 
640
647
  await this.oracleMultiSubscriber.subscribe(
641
648
  oraclePubkeys,
642
- (accountId, data) => {
643
- const sources = pubkeyToSources.get(accountId.toBase58());
644
- if (sources) {
645
- for (const source of sources.values()) {
646
- this.eventEmitter.emit(
647
- 'oraclePriceUpdate',
648
- accountId,
649
- source,
650
- data
651
- );
652
- }
653
- }
649
+ (accountId, data, context, _b, accountProps) => {
650
+ const oracleId = getOracleId(accountId, accountProps.source);
651
+ this.oracleIdToOracleDataMap.set(oracleId, {
652
+ data,
653
+ slot: context.slot,
654
+ });
655
+ this.eventEmitter.emit(
656
+ 'oraclePriceUpdate',
657
+ accountId,
658
+ accountProps.source,
659
+ data
660
+ );
661
+
654
662
  this.eventEmitter.emit('update');
655
663
  }
656
664
  );