@drift-labs/sdk 2.103.0-beta.4 → 2.103.0-beta.6

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 (46) hide show
  1. package/VERSION +1 -1
  2. package/lib/browser/accounts/grpcDriftClientAccountSubscriber.js +5 -4
  3. package/lib/browser/accounts/pollingDriftClientAccountSubscriber.d.ts +1 -1
  4. package/lib/browser/accounts/pollingDriftClientAccountSubscriber.js +30 -27
  5. package/lib/browser/accounts/types.d.ts +2 -2
  6. package/lib/browser/accounts/utils.d.ts +2 -2
  7. package/lib/browser/accounts/utils.js +13 -3
  8. package/lib/browser/accounts/webSocketDriftClientAccountSubscriber.d.ts +1 -1
  9. package/lib/browser/accounts/webSocketDriftClientAccountSubscriber.js +31 -25
  10. package/lib/browser/config.js +5 -4
  11. package/lib/browser/driftClient.d.ts +2 -2
  12. package/lib/browser/driftClient.js +6 -5
  13. package/lib/browser/oracles/oracleId.d.ts +4 -0
  14. package/lib/browser/oracles/oracleId.js +36 -0
  15. package/lib/browser/types.d.ts +14 -0
  16. package/lib/browser/types.js +16 -1
  17. package/lib/node/accounts/grpcDriftClientAccountSubscriber.js +5 -4
  18. package/lib/node/accounts/pollingDriftClientAccountSubscriber.d.ts +1 -1
  19. package/lib/node/accounts/pollingDriftClientAccountSubscriber.js +30 -27
  20. package/lib/node/accounts/types.d.ts +2 -2
  21. package/lib/node/accounts/utils.d.ts +2 -2
  22. package/lib/node/accounts/utils.js +13 -3
  23. package/lib/node/accounts/webSocketDriftClientAccountSubscriber.d.ts +1 -1
  24. package/lib/node/accounts/webSocketDriftClientAccountSubscriber.js +31 -25
  25. package/lib/node/config.js +5 -4
  26. package/lib/node/driftClient.d.ts +2 -2
  27. package/lib/node/driftClient.js +6 -5
  28. package/lib/node/oracles/oracleId.d.ts +4 -0
  29. package/lib/node/oracles/oracleId.js +36 -0
  30. package/lib/node/types.d.ts +14 -0
  31. package/lib/node/types.js +16 -1
  32. package/package.json +1 -1
  33. package/src/accounts/grpcDriftClientAccountSubscriber.ts +10 -4
  34. package/src/accounts/pollingDriftClientAccountSubscriber.ts +47 -33
  35. package/src/accounts/types.ts +6 -2
  36. package/src/accounts/utils.ts +23 -6
  37. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +39 -27
  38. package/src/config.ts +11 -7
  39. package/src/driftClient.ts +12 -6
  40. package/src/oracles/oracleId.ts +27 -0
  41. package/src/types.ts +15 -0
  42. package/tests/auctions/test.ts +6 -2
  43. package/tests/decode/test.ts +3 -3
  44. package/tests/dlob/helpers.ts +6 -0
  45. package/tests/subscriber/openbook.ts +1 -1
  46. package/tests/user/helpers.ts +2 -0
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.103.0-beta.4
1
+ 2.103.0-beta.6
@@ -5,6 +5,7 @@ const webSocketDriftClientAccountSubscriber_1 = require("./webSocketDriftClientA
5
5
  const config_1 = require("../config");
6
6
  const pda_1 = require("../addresses/pda");
7
7
  const grpcAccountSubscriber_1 = require("./grpcAccountSubscriber");
8
+ const oracleId_1 = require("../oracles/oracleId");
8
9
  class gprcDriftClientAccountSubscriber extends webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber {
9
10
  constructor(grpcConfigs, program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts) {
10
11
  super(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts);
@@ -80,17 +81,17 @@ class gprcDriftClientAccountSubscriber extends webSocketDriftClientAccountSubscr
80
81
  return true;
81
82
  }
82
83
  async subscribeToOracle(oracleInfo) {
83
- const oracleString = oracleInfo.publicKey.toString();
84
+ const oracleId = (0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source);
84
85
  const client = this.oracleClientCache.get(oracleInfo.source, this.program.provider.connection, this.program);
85
86
  const accountSubscriber = new grpcAccountSubscriber_1.grpcAccountSubscriber(this.grpcConfigs, 'oracle', this.program, oracleInfo.publicKey, (buffer) => {
86
87
  return client.getOraclePriceDataFromBuffer(buffer);
87
88
  }, this.resubOpts);
88
- accountSubscriber.setData(this.initialOraclePriceData.get(oracleString));
89
+ accountSubscriber.setData(this.initialOraclePriceData.get(oracleId));
89
90
  await accountSubscriber.subscribe((data) => {
90
- this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
91
+ this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, oracleInfo.source, data);
91
92
  this.eventEmitter.emit('update');
92
93
  });
93
- this.oracleSubscribers.set(oracleString, accountSubscriber);
94
+ this.oracleSubscribers.set(oracleId, accountSubscriber);
94
95
  return true;
95
96
  }
96
97
  }
@@ -62,7 +62,7 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
62
62
  getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
63
63
  getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
64
64
  getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
65
- getOraclePriceDataAndSlot(oraclePublicKey: PublicKey | string): DataAndSlot<OraclePriceData> | undefined;
65
+ getOraclePriceDataAndSlot(oracleId: string): DataAndSlot<OraclePriceData> | undefined;
66
66
  getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
67
67
  getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
68
68
  updateAccountLoaderPollingFrequency(pollingFrequency: number): void;
@@ -3,13 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PollingDriftClientAccountSubscriber = void 0;
4
4
  const types_1 = require("./types");
5
5
  const events_1 = require("events");
6
+ const types_2 = require("../types");
6
7
  const pda_1 = require("../addresses/pda");
7
8
  const utils_1 = require("./utils");
8
9
  const web3_js_1 = require("@solana/web3.js");
9
10
  const oracleClientCache_1 = require("../oracles/oracleClientCache");
10
11
  const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
11
12
  const config_1 = require("../config");
12
- const ORACLE_DEFAULT_KEY = web3_js_1.PublicKey.default.toBase58();
13
+ const oracleId_1 = require("../oracles/oracleId");
14
+ const ORACLE_DEFAULT_ID = (0, oracleId_1.getOracleId)(web3_js_1.PublicKey.default, types_2.OracleSource.QUOTE_ASSET);
13
15
  class PollingDriftClientAccountSubscriber {
14
16
  constructor(program, accountLoader, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting) {
15
17
  this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
@@ -126,7 +128,7 @@ class PollingDriftClientAccountSubscriber {
126
128
  return true;
127
129
  }
128
130
  addOracleToPoll(oracleInfo) {
129
- this.oraclesToPoll.set(oracleInfo.publicKey.toString(), {
131
+ this.oraclesToPoll.set((0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source), {
130
132
  publicKey: oracleInfo.publicKey,
131
133
  source: oracleInfo.source,
132
134
  });
@@ -171,6 +173,7 @@ class PollingDriftClientAccountSubscriber {
171
173
  }
172
174
  async addOracleToAccountLoader(oracleToPoll) {
173
175
  const oracleClient = this.oracleClientCache.get(oracleToPoll.source, this.program.provider.connection, this.program);
176
+ const oracleId = (0, oracleId_1.getOracleId)(oracleToPoll.publicKey, oracleToPoll.source);
174
177
  oracleToPoll.callbackId = await this.accountLoader.addAccount(oracleToPoll.publicKey, (buffer, slot) => {
175
178
  if (!buffer)
176
179
  return;
@@ -179,8 +182,8 @@ class PollingDriftClientAccountSubscriber {
179
182
  data: oraclePriceData,
180
183
  slot,
181
184
  };
182
- this.oracles.set(oracleToPoll.publicKey.toString(), dataAndSlot);
183
- this.eventEmitter.emit('oraclePriceUpdate', oracleToPoll.publicKey, oraclePriceData);
185
+ this.oracles.set(oracleId, dataAndSlot);
186
+ this.eventEmitter.emit('oraclePriceUpdate', oracleToPoll.publicKey, oracleToPoll.source, oraclePriceData);
184
187
  this.eventEmitter.emit('update');
185
188
  });
186
189
  }
@@ -217,7 +220,7 @@ class PollingDriftClientAccountSubscriber {
217
220
  if (buffer) {
218
221
  const oracleClient = this.oracleClientCache.get(oracleToPoll.source, this.program.provider.connection, this.program);
219
222
  const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(buffer);
220
- this.oracles.set(oracleToPoll.publicKey.toString(), {
223
+ this.oracles.set((0, oracleId_1.getOracleId)(oracleToPoll.publicKey, oracleToPoll.source), {
221
224
  data: oraclePriceData,
222
225
  slot,
223
226
  });
@@ -265,19 +268,19 @@ class PollingDriftClientAccountSubscriber {
265
268
  return true;
266
269
  }
267
270
  async addOracle(oracleInfo) {
271
+ const oracleId = (0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source);
268
272
  if (oracleInfo.publicKey.equals(web3_js_1.PublicKey.default) ||
269
- this.oracles.has(oracleInfo.publicKey.toBase58())) {
273
+ this.oracles.has(oracleId)) {
270
274
  return true;
271
275
  }
272
- const oracleString = oracleInfo.publicKey.toBase58();
273
276
  // this func can be called multiple times before the first pauseForOracleToBeAdded finishes
274
277
  // avoid adding to oraclesToPoll multiple time
275
- if (!this.oraclesToPoll.has(oracleString)) {
278
+ if (!this.oraclesToPoll.has(oracleId)) {
276
279
  this.addOracleToPoll(oracleInfo);
277
- const oracleToPoll = this.oraclesToPoll.get(oracleString);
280
+ const oracleToPoll = this.oraclesToPoll.get(oracleId);
278
281
  await this.addOracleToAccountLoader(oracleToPoll);
279
282
  }
280
- await this.pauseForOracleToBeAdded(3, oracleString);
283
+ await this.pauseForOracleToBeAdded(3, oracleInfo.publicKey.toBase58());
281
284
  return true;
282
285
  }
283
286
  async pauseForOracleToBeAdded(tries, oracle) {
@@ -298,14 +301,15 @@ class PollingDriftClientAccountSubscriber {
298
301
  const perpMarketAccount = perpMarket.data;
299
302
  const perpMarketIndex = perpMarketAccount.marketIndex;
300
303
  const oracle = perpMarketAccount.amm.oracle;
301
- if (!this.oracles.has(oracle.toBase58())) {
304
+ const oracleId = (0, oracleId_1.getOracleId)(oracle, perpMarketAccount.amm.oracleSource);
305
+ if (!this.oracles.has(oracleId)) {
302
306
  oraclePromises.push(this.addOracle({
303
307
  publicKey: oracle,
304
308
  source: perpMarketAccount.amm.oracleSource,
305
309
  }));
306
310
  }
307
311
  this.perpOracleMap.set(perpMarketIndex, oracle);
308
- this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
312
+ this.perpOracleStringMap.set(perpMarketIndex, oracleId);
309
313
  }
310
314
  await Promise.all(oraclePromises);
311
315
  }
@@ -316,14 +320,15 @@ class PollingDriftClientAccountSubscriber {
316
320
  const spotMarketAccount = spotMarket.data;
317
321
  const spotMarketIndex = spotMarketAccount.marketIndex;
318
322
  const oracle = spotMarketAccount.oracle;
319
- if (!this.oracles.has(oracle.toBase58())) {
323
+ const oracleId = (0, oracleId_1.getOracleId)(oracle, spotMarketAccount.oracleSource);
324
+ if (!this.oracles.has(oracleId)) {
320
325
  oraclePromises.push(this.addOracle({
321
326
  publicKey: oracle,
322
327
  source: spotMarketAccount.oracleSource,
323
328
  }));
324
329
  }
325
330
  this.spotOracleMap.set(spotMarketIndex, oracle);
326
- this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
331
+ this.spotOracleStringMap.set(spotMarketIndex, oracleId);
327
332
  }
328
333
  await Promise.all(oraclePromises);
329
334
  }
@@ -341,10 +346,11 @@ class PollingDriftClientAccountSubscriber {
341
346
  }
342
347
  }
343
348
  for (const oracle of oracles) {
344
- const callbackId = this.oraclesToPoll.get(oracle.toBase58()).callbackId;
345
- this.accountLoader.removeAccount(oracle, callbackId);
349
+ const oracleId = (0, oracleId_1.getOracleId)(oracle.publicKey, oracle.source);
350
+ const callbackId = this.oraclesToPoll.get(oracleId).callbackId;
351
+ this.accountLoader.removeAccount(oracle.publicKey, callbackId);
346
352
  if (this.delistedMarketSetting === types_1.DelistedMarketSetting.Discard) {
347
- this.oracles.delete(oracle.toBase58());
353
+ this.oracles.delete(oracleId);
348
354
  }
349
355
  }
350
356
  }
@@ -369,23 +375,20 @@ class PollingDriftClientAccountSubscriber {
369
375
  getSpotMarketAccountsAndSlots() {
370
376
  return Array.from(this.spotMarket.values());
371
377
  }
372
- getOraclePriceDataAndSlot(oraclePublicKey) {
378
+ getOraclePriceDataAndSlot(oracleId) {
373
379
  this.assertIsSubscribed();
374
- const oracleString = typeof oraclePublicKey === 'string'
375
- ? oraclePublicKey
376
- : oraclePublicKey.toBase58();
377
- if (oracleString === ORACLE_DEFAULT_KEY) {
380
+ if (oracleId === ORACLE_DEFAULT_ID) {
378
381
  return {
379
382
  data: quoteAssetOracleClient_1.QUOTE_ORACLE_PRICE_DATA,
380
383
  slot: 0,
381
384
  };
382
385
  }
383
- return this.oracles.get(oracleString);
386
+ return this.oracles.get(oracleId);
384
387
  }
385
388
  getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
386
389
  const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
387
390
  const oracle = this.perpOracleMap.get(marketIndex);
388
- const oracleString = this.perpOracleStringMap.get(marketIndex);
391
+ const oracleId = this.perpOracleStringMap.get(marketIndex);
389
392
  if (!perpMarketAccount || !oracle) {
390
393
  return undefined;
391
394
  }
@@ -393,12 +396,12 @@ class PollingDriftClientAccountSubscriber {
393
396
  // If the oracle has changed, we need to update the oracle map in background
394
397
  this.setPerpOracleMap();
395
398
  }
396
- return this.getOraclePriceDataAndSlot(oracleString);
399
+ return this.getOraclePriceDataAndSlot(oracleId);
397
400
  }
398
401
  getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
399
402
  const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
400
403
  const oracle = this.spotOracleMap.get(marketIndex);
401
- const oracleString = this.spotOracleStringMap.get(marketIndex);
404
+ const oracleId = this.spotOracleStringMap.get(marketIndex);
402
405
  if (!spotMarketAccount || !oracle) {
403
406
  return undefined;
404
407
  }
@@ -406,7 +409,7 @@ class PollingDriftClientAccountSubscriber {
406
409
  // If the oracle has changed, we need to update the oracle map in background
407
410
  this.setSpotOracleMap();
408
411
  }
409
- return this.getOraclePriceDataAndSlot(oracleString);
412
+ return this.getOraclePriceDataAndSlot(oracleId);
410
413
  }
411
414
  updateAccountLoaderPollingFrequency(pollingFrequency) {
412
415
  this.accountLoader.updatePollingFrequency(pollingFrequency);
@@ -26,7 +26,7 @@ export interface DriftClientAccountEvents {
26
26
  stateAccountUpdate: (payload: StateAccount) => void;
27
27
  perpMarketAccountUpdate: (payload: PerpMarketAccount) => void;
28
28
  spotMarketAccountUpdate: (payload: SpotMarketAccount) => void;
29
- oraclePriceUpdate: (publicKey: PublicKey, data: OraclePriceData) => void;
29
+ oraclePriceUpdate: (publicKey: PublicKey, oracleSource: OracleSource, data: OraclePriceData) => void;
30
30
  userAccountUpdate: (payload: UserAccount) => void;
31
31
  update: void;
32
32
  error: (e: Error) => void;
@@ -47,7 +47,7 @@ export interface DriftClientAccountSubscriber {
47
47
  getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
48
48
  getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
49
49
  getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
50
- getOraclePriceDataAndSlot(oraclePublicKey: PublicKey | string): DataAndSlot<OraclePriceData> | undefined;
50
+ getOraclePriceDataAndSlot(oracleId: string): DataAndSlot<OraclePriceData> | undefined;
51
51
  getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
52
52
  getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
53
53
  updateAccountLoaderPollingFrequency?: (pollingFrequency: number) => void;
@@ -1,8 +1,8 @@
1
- import { PublicKey } from '@solana/web3.js';
2
1
  import { DataAndSlot } from './types';
3
2
  import { PerpMarketAccount, SpotMarketAccount } from '../types';
3
+ import { OracleInfo } from '../oracles/types';
4
4
  export declare function capitalize(value: string): string;
5
5
  export declare function findDelistedPerpMarketsAndOracles(perpMarkets: DataAndSlot<PerpMarketAccount>[], spotMarkets: DataAndSlot<SpotMarketAccount>[]): {
6
6
  perpMarketIndexes: number[];
7
- oracles: PublicKey[];
7
+ oracles: OracleInfo[];
8
8
  };
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findDelistedPerpMarketsAndOracles = exports.capitalize = void 0;
4
4
  const types_1 = require("../types");
5
+ const oracleId_1 = require("../oracles/oracleId");
5
6
  function capitalize(value) {
6
7
  return value[0].toUpperCase() + value.slice(1);
7
8
  }
@@ -15,21 +16,30 @@ function findDelistedPerpMarketsAndOracles(perpMarkets, spotMarkets) {
15
16
  }
16
17
  if ((0, types_1.isVariant)(perpMarket.data.status, 'delisted')) {
17
18
  delistedPerpMarketIndexes.push(perpMarket.data.marketIndex);
18
- delistedOracles.push(perpMarket.data.amm.oracle);
19
+ delistedOracles.push({
20
+ publicKey: perpMarket.data.amm.oracle,
21
+ source: perpMarket.data.amm.oracleSource,
22
+ });
19
23
  }
20
24
  }
21
25
  // make sure oracle isn't used by spot market
22
26
  const filteredDelistedOracles = [];
23
27
  for (const delistedOracle of delistedOracles) {
28
+ let isUsedBySpotMarket = false;
24
29
  for (const spotMarket of spotMarkets) {
25
30
  if (!spotMarket.data) {
26
31
  continue;
27
32
  }
28
- if (spotMarket.data.oracle.equals(delistedOracle)) {
33
+ const delistedOracleId = (0, oracleId_1.getOracleId)(delistedOracle.publicKey, delistedOracle.source);
34
+ const spotMarketOracleId = (0, oracleId_1.getOracleId)(spotMarket.data.oracle, spotMarket.data.oracleSource);
35
+ if (spotMarketOracleId === delistedOracleId) {
36
+ isUsedBySpotMarket = true;
29
37
  break;
30
38
  }
31
39
  }
32
- filteredDelistedOracles.push(delistedOracle);
40
+ if (!isUsedBySpotMarket) {
41
+ filteredDelistedOracles.push(delistedOracle);
42
+ }
33
43
  }
34
44
  return {
35
45
  perpMarketIndexes: delistedPerpMarketIndexes,
@@ -60,7 +60,7 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
60
60
  getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
61
61
  getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
62
62
  getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
63
- getOraclePriceDataAndSlot(oraclePublicKey: PublicKey | string): DataAndSlot<OraclePriceData> | undefined;
63
+ getOraclePriceDataAndSlot(oracleId: string): DataAndSlot<OraclePriceData> | undefined;
64
64
  getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
65
65
  getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
66
66
  }
@@ -10,7 +10,9 @@ const oracleClientCache_1 = require("../oracles/oracleClientCache");
10
10
  const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
11
11
  const config_1 = require("../config");
12
12
  const utils_1 = require("./utils");
13
- const ORACLE_DEFAULT_KEY = web3_js_1.PublicKey.default.toBase58();
13
+ const oracleId_1 = require("../oracles/oracleId");
14
+ const types_2 = require("../types");
15
+ const ORACLE_DEFAULT_ID = (0, oracleId_1.getOracleId)(web3_js_1.PublicKey.default, types_2.OracleSource.QUOTE_ASSET);
14
16
  class WebSocketDriftClientAccountSubscriber {
15
17
  constructor(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts, commitment) {
16
18
  this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
@@ -109,7 +111,10 @@ class WebSocketDriftClientAccountSubscriber {
109
111
  }
110
112
  const oracleClient = this.oracleClientCache.get(oracleInfo.source, connection, this.program);
111
113
  const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(oracleAccountInfos[i].data);
112
- result.push([oracleInfo.publicKey.toString(), oraclePriceData]);
114
+ result.push([
115
+ (0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source),
116
+ oraclePriceData,
117
+ ]);
113
118
  return result;
114
119
  }, []));
115
120
  }
@@ -155,20 +160,20 @@ class WebSocketDriftClientAccountSubscriber {
155
160
  return true;
156
161
  }
157
162
  async subscribeToOracle(oracleInfo) {
158
- const oracleString = oracleInfo.publicKey.toString();
163
+ const oracleId = (0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source);
159
164
  const client = this.oracleClientCache.get(oracleInfo.source, this.program.provider.connection, this.program);
160
165
  const accountSubscriber = new webSocketAccountSubscriber_1.WebSocketAccountSubscriber('oracle', this.program, oracleInfo.publicKey, (buffer) => {
161
166
  return client.getOraclePriceDataFromBuffer(buffer);
162
167
  }, this.resubOpts, this.commitment);
163
- const initialOraclePriceData = this.initialOraclePriceData.get(oracleString);
168
+ const initialOraclePriceData = this.initialOraclePriceData.get(oracleId);
164
169
  if (initialOraclePriceData) {
165
170
  accountSubscriber.setData(initialOraclePriceData);
166
171
  }
167
172
  await accountSubscriber.subscribe((data) => {
168
- this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
173
+ this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, oracleInfo.source, data);
169
174
  this.eventEmitter.emit('update');
170
175
  });
171
- this.oracleSubscribers.set(oracleString, accountSubscriber);
176
+ this.oracleSubscribers.set(oracleId, accountSubscriber);
172
177
  return true;
173
178
  }
174
179
  async unsubscribeFromMarketAccounts() {
@@ -216,7 +221,8 @@ class WebSocketDriftClientAccountSubscriber {
216
221
  return subscriptionSuccess;
217
222
  }
218
223
  async addOracle(oracleInfo) {
219
- if (this.oracleSubscribers.has(oracleInfo.publicKey.toString())) {
224
+ const oracleId = (0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source);
225
+ if (this.oracleSubscribers.has(oracleId)) {
220
226
  return true;
221
227
  }
222
228
  if (oracleInfo.publicKey.equals(web3_js_1.PublicKey.default)) {
@@ -234,14 +240,15 @@ class WebSocketDriftClientAccountSubscriber {
234
240
  const perpMarketAccount = perpMarket.data;
235
241
  const perpMarketIndex = perpMarketAccount.marketIndex;
236
242
  const oracle = perpMarketAccount.amm.oracle;
237
- if (!this.oracleSubscribers.has(oracle.toBase58())) {
243
+ const oracleId = (0, oracleId_1.getOracleId)(oracle, perpMarket.data.amm.oracleSource);
244
+ if (!this.oracleSubscribers.has(oracleId)) {
238
245
  addOraclePromises.push(this.addOracle({
239
246
  publicKey: oracle,
240
247
  source: perpMarket.data.amm.oracleSource,
241
248
  }));
242
249
  }
243
250
  this.perpOracleMap.set(perpMarketIndex, oracle);
244
- this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
251
+ this.perpOracleStringMap.set(perpMarketIndex, oracleId);
245
252
  }
246
253
  await Promise.all(addOraclePromises);
247
254
  }
@@ -255,14 +262,15 @@ class WebSocketDriftClientAccountSubscriber {
255
262
  const spotMarketAccount = spotMarket.data;
256
263
  const spotMarketIndex = spotMarketAccount.marketIndex;
257
264
  const oracle = spotMarketAccount.oracle;
258
- if (!this.oracleSubscribers.has(oracle.toBase58())) {
265
+ const oracleId = (0, oracleId_1.getOracleId)(oracle, spotMarketAccount.oracleSource);
266
+ if (!this.oracleSubscribers.has(oracleId)) {
259
267
  addOraclePromises.push(this.addOracle({
260
268
  publicKey: oracle,
261
269
  source: spotMarketAccount.oracleSource,
262
270
  }));
263
271
  }
264
272
  this.spotOracleMap.set(spotMarketIndex, oracle);
265
- this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
273
+ this.spotOracleStringMap.set(spotMarketIndex, oracleId);
266
274
  }
267
275
  await Promise.all(addOraclePromises);
268
276
  }
@@ -280,9 +288,10 @@ class WebSocketDriftClientAccountSubscriber {
280
288
  }
281
289
  }
282
290
  for (const oracle of oracles) {
283
- await this.oracleSubscribers.get(oracle.toBase58()).unsubscribe();
291
+ const oracleId = (0, oracleId_1.getOracleId)(oracle.publicKey, oracle.source);
292
+ await this.oracleSubscribers.get(oracleId).unsubscribe();
284
293
  if (this.delistedMarketSetting === types_1.DelistedMarketSetting.Discard) {
285
- this.oracleSubscribers.delete(oracle.toBase58());
294
+ this.oracleSubscribers.delete(oracleId);
286
295
  }
287
296
  }
288
297
  }
@@ -309,44 +318,41 @@ class WebSocketDriftClientAccountSubscriber {
309
318
  getSpotMarketAccountsAndSlots() {
310
319
  return Array.from(this.spotMarketAccountSubscribers.values()).map((subscriber) => subscriber.dataAndSlot);
311
320
  }
312
- getOraclePriceDataAndSlot(oraclePublicKey) {
321
+ getOraclePriceDataAndSlot(oracleId) {
313
322
  this.assertIsSubscribed();
314
- const oracleString = typeof oraclePublicKey === 'string'
315
- ? oraclePublicKey
316
- : oraclePublicKey.toBase58();
317
- if (oracleString === ORACLE_DEFAULT_KEY) {
323
+ if (oracleId === ORACLE_DEFAULT_ID) {
318
324
  return {
319
325
  data: quoteAssetOracleClient_1.QUOTE_ORACLE_PRICE_DATA,
320
326
  slot: 0,
321
327
  };
322
328
  }
323
- return this.oracleSubscribers.get(oracleString).dataAndSlot;
329
+ return this.oracleSubscribers.get(oracleId).dataAndSlot;
324
330
  }
325
331
  getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
326
332
  const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
327
333
  const oracle = this.perpOracleMap.get(marketIndex);
328
- const oracleString = this.perpOracleStringMap.get(marketIndex);
329
- if (!perpMarketAccount || !oracle) {
334
+ const oracleId = this.perpOracleStringMap.get(marketIndex);
335
+ if (!perpMarketAccount || !oracleId) {
330
336
  return undefined;
331
337
  }
332
338
  if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
333
339
  // If the oracle has changed, we need to update the oracle map in background
334
340
  this.setPerpOracleMap();
335
341
  }
336
- return this.getOraclePriceDataAndSlot(oracleString);
342
+ return this.getOraclePriceDataAndSlot(oracleId);
337
343
  }
338
344
  getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
339
345
  const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
340
346
  const oracle = this.spotOracleMap.get(marketIndex);
341
- const oracleString = this.spotOracleStringMap.get(marketIndex);
342
- if (!spotMarketAccount || !oracle) {
347
+ const oracleId = this.spotOracleStringMap.get(marketIndex);
348
+ if (!spotMarketAccount || !oracleId) {
343
349
  return undefined;
344
350
  }
345
351
  if (!spotMarketAccount.data.oracle.equals(oracle)) {
346
352
  // If the oracle has changed, we need to update the oracle map in background
347
353
  this.setSpotOracleMap();
348
354
  }
349
- return this.getOraclePriceDataAndSlot(oracleString);
355
+ return this.getOraclePriceDataAndSlot(oracleId);
350
356
  }
351
357
  }
352
358
  exports.WebSocketDriftClientAccountSubscriber = WebSocketDriftClientAccountSubscriber;
@@ -4,6 +4,7 @@ exports.findAllMarketAndOracles = exports.getMarketsAndOraclesForSubscription =
4
4
  const perpMarkets_1 = require("./constants/perpMarkets");
5
5
  const spotMarkets_1 = require("./constants/spotMarkets");
6
6
  const on_demand_1 = require("@switchboard-xyz/on-demand");
7
+ const oracleId_1 = require("./oracles/oracleId");
7
8
  exports.DRIFT_PROGRAM_ID = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH';
8
9
  exports.DRIFT_ORACLE_RECEIVER_ID = 'G6EoTTTgpkNBtVXo96EQp2m6uwwVh2Kt6YidjkmQqoha';
9
10
  exports.SWIFT_ID = 'SW1fThqrxLzVprnCMpiybiqYQfoNCdduC5uWsSUKChS';
@@ -74,14 +75,14 @@ function getMarketsAndOraclesForSubscription(env, perpMarkets, spotMarkets) {
74
75
  const oracleInfos = new Map();
75
76
  for (const market of perpMarketsToUse) {
76
77
  perpMarketIndexes.push(market.marketIndex);
77
- oracleInfos.set(market.oracle.toString(), {
78
+ oracleInfos.set((0, oracleId_1.getOracleId)(market.oracle, market.oracleSource), {
78
79
  publicKey: market.oracle,
79
80
  source: market.oracleSource,
80
81
  });
81
82
  }
82
83
  for (const spotMarket of spotMarketsToUse) {
83
84
  spotMarketIndexes.push(spotMarket.marketIndex);
84
- oracleInfos.set(spotMarket.oracle.toString(), {
85
+ oracleInfos.set((0, oracleId_1.getOracleId)(spotMarket.oracle, spotMarket.oracleSource), {
85
86
  publicKey: spotMarket.oracle,
86
87
  source: spotMarket.oracleSource,
87
88
  });
@@ -102,7 +103,7 @@ async function findAllMarketAndOracles(program) {
102
103
  for (const perpMarketProgramAccount of perpMarketProgramAccounts) {
103
104
  const perpMarket = perpMarketProgramAccount.account;
104
105
  perpMarketIndexes.push(perpMarket.marketIndex);
105
- oracleInfos.set(perpMarket.amm.oracle.toString(), {
106
+ oracleInfos.set((0, oracleId_1.getOracleId)(perpMarket.amm.oracle, perpMarket.amm.oracleSource), {
106
107
  publicKey: perpMarket.amm.oracle,
107
108
  source: perpMarket.amm.oracleSource,
108
109
  });
@@ -110,7 +111,7 @@ async function findAllMarketAndOracles(program) {
110
111
  for (const spotMarketProgramAccount of spotMarketProgramAccounts) {
111
112
  const spotMarket = spotMarketProgramAccount.account;
112
113
  spotMarketIndexes.push(spotMarket.marketIndex);
113
- oracleInfos.set(spotMarket.oracle.toString(), {
114
+ oracleInfos.set((0, oracleId_1.getOracleId)(spotMarket.oracle, spotMarket.oracleSource), {
114
115
  publicKey: spotMarket.oracle,
115
116
  source: spotMarket.oracleSource,
116
117
  });
@@ -5,7 +5,7 @@
5
5
  import * as anchor from '@coral-xyz/anchor';
6
6
  import { AnchorProvider, BN, Program, ProgramAccount } from '@coral-xyz/anchor';
7
7
  import { Idl as Idl30, Program as Program30 } from '@coral-xyz/anchor-30';
8
- import { DriftClientMetricsEvents, HighLeverageModeConfig, IWallet, MakerInfo, MappedRecord, MarketType, ModifyOrderPolicy, OpenbookV2FulfillmentConfigAccount, OptionalOrderParams, Order, OrderParams, OrderTriggerCondition, PerpMarketAccount, PerpMarketExtendedInfo, PhoenixV1FulfillmentConfigAccount, PlaceAndTakeOrderSuccessCondition, PositionDirection, ReferrerInfo, ReferrerNameAccount, RFQMakerOrderParams, RFQMatch, SerumV3FulfillmentConfigAccount, SettlePnlMode, SignedTxData, SpotMarketAccount, SpotPosition, StateAccount, SwapReduceOnly, SwiftOrderParamsMessage, SwiftServerMessage, TakerInfo, TxParams, UserAccount, UserStatsAccount } from './types';
8
+ import { DriftClientMetricsEvents, HighLeverageModeConfig, IWallet, MakerInfo, MappedRecord, MarketType, ModifyOrderPolicy, OpenbookV2FulfillmentConfigAccount, OptionalOrderParams, OracleSource, Order, OrderParams, OrderTriggerCondition, PerpMarketAccount, PerpMarketExtendedInfo, PhoenixV1FulfillmentConfigAccount, PlaceAndTakeOrderSuccessCondition, PositionDirection, ReferrerInfo, ReferrerNameAccount, RFQMakerOrderParams, RFQMatch, SerumV3FulfillmentConfigAccount, SettlePnlMode, SignedTxData, SpotMarketAccount, SpotPosition, StateAccount, SwapReduceOnly, SwiftOrderParamsMessage, SwiftServerMessage, TakerInfo, TxParams, UserAccount, UserStatsAccount } from './types';
9
9
  import { AccountMeta, AddressLookupTableAccount, BlockhashWithExpiryBlockHeight, ConfirmOptions, Connection, Keypair, PublicKey, Signer, Transaction, TransactionInstruction, TransactionSignature, TransactionVersion, VersionedTransaction } from '@solana/web3.js';
10
10
  import { TokenFaucet } from './tokenFaucet';
11
11
  import { EventEmitter } from 'events';
@@ -109,7 +109,7 @@ export declare class DriftClient {
109
109
  forceGetSpotMarketAccount(marketIndex: number): Promise<SpotMarketAccount | undefined>;
110
110
  getSpotMarketAccounts(): SpotMarketAccount[];
111
111
  getQuoteSpotMarketAccount(): SpotMarketAccount;
112
- getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
112
+ getOraclePriceDataAndSlot(oraclePublicKey: PublicKey, oracleSource: OracleSource): DataAndSlot<OraclePriceData> | undefined;
113
113
  getSerumV3FulfillmentConfig(serumMarket: PublicKey): Promise<SerumV3FulfillmentConfigAccount>;
114
114
  getSerumV3FulfillmentConfigs(): Promise<SerumV3FulfillmentConfigAccount[]>;
115
115
  getPhoenixV1FulfillmentConfig(phoenixMarket: PublicKey): Promise<PhoenixV1FulfillmentConfigAccount>;
@@ -70,6 +70,7 @@ const on_demand_1 = require("@switchboard-xyz/on-demand");
70
70
  const grpcDriftClientAccountSubscriber_1 = require("./accounts/grpcDriftClientAccountSubscriber");
71
71
  const tweetnacl_1 = __importDefault(require("tweetnacl"));
72
72
  const digest_1 = require("./util/digest");
73
+ const oracleId_1 = require("./oracles/oracleId");
73
74
  /**
74
75
  * # DriftClient
75
76
  * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
@@ -338,8 +339,8 @@ class DriftClient {
338
339
  getQuoteSpotMarketAccount() {
339
340
  return this.accountSubscriber.getSpotMarketAccountAndSlot(numericConstants_1.QUOTE_SPOT_MARKET_INDEX).data;
340
341
  }
341
- getOraclePriceDataAndSlot(oraclePublicKey) {
342
- return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey.toBase58());
342
+ getOraclePriceDataAndSlot(oraclePublicKey, oracleSource) {
343
+ return this.accountSubscriber.getOraclePriceDataAndSlot((0, oracleId_1.getOracleId)(oraclePublicKey, oracleSource));
343
344
  }
344
345
  async getSerumV3FulfillmentConfig(serumMarket) {
345
346
  const address = await (0, pda_1.getSerumFulfillmentConfigPublicKey)(this.program.programId, serumMarket);
@@ -3158,8 +3159,8 @@ class DriftClient {
3158
3159
  return this.signMessage(swiftServerMessage);
3159
3160
  }
3160
3161
  signSwiftOrderParamsMessage(orderParamsMessage) {
3161
- const takerOrderParamsMessage = Uint8Array.from((0, digest_1.digest)(this.encodeSwiftOrderParamsMessage(orderParamsMessage)));
3162
- return this.signMessage(takerOrderParamsMessage);
3162
+ const takerOrderParamsMessage = this.encodeSwiftOrderParamsMessage(orderParamsMessage);
3163
+ return this.signMessage(new TextEncoder().encode((0, digest_1.digest)(takerOrderParamsMessage).toString('hex')));
3163
3164
  }
3164
3165
  encodeSwiftOrderParamsMessage(orderParamsMessage) {
3165
3166
  return this.program.coder.types.encode('SwiftOrderParamsMessage', orderParamsMessage);
@@ -3189,7 +3190,7 @@ class DriftClient {
3189
3190
  const swiftOrderParamsSignatureIx = web3_js_1.Ed25519Program.createInstructionWithPublicKey({
3190
3191
  publicKey: takerInfo.takerUserAccount.authority.toBytes(),
3191
3192
  signature: Uint8Array.from(swiftOrderParamsSignature),
3192
- message: Uint8Array.from((0, digest_1.digest)(encodedSwiftOrderParamsMessage)),
3193
+ message: new TextEncoder().encode((0, digest_1.digest)(encodedSwiftOrderParamsMessage).toString('hex')),
3193
3194
  });
3194
3195
  const placeTakerSwiftPerpOrderIx = await this.program.instruction.placeSwiftTakerOrder(encodedSwiftServerMessage, encodedSwiftOrderParamsMessage, {
3195
3196
  accounts: {
@@ -0,0 +1,4 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { OracleSource } from '../types';
3
+ export declare function getOracleSourceNum(source: OracleSource): number;
4
+ export declare function getOracleId(publicKey: PublicKey, source: OracleSource): string;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOracleId = exports.getOracleSourceNum = void 0;
4
+ const types_1 = require("../types");
5
+ function getOracleSourceNum(source) {
6
+ if ('pyth' in source)
7
+ return types_1.OracleSourceNum.PYTH;
8
+ if ('pyth1K' in source)
9
+ return types_1.OracleSourceNum.PYTH_1K;
10
+ if ('pyth1M' in source)
11
+ return types_1.OracleSourceNum.PYTH_1M;
12
+ if ('pythPull' in source)
13
+ return types_1.OracleSourceNum.PYTH_PULL;
14
+ if ('pyth1KPull' in source)
15
+ return types_1.OracleSourceNum.PYTH_1K_PULL;
16
+ if ('pyth1MPull' in source)
17
+ return types_1.OracleSourceNum.PYTH_1M_PULL;
18
+ if ('switchboard' in source)
19
+ return types_1.OracleSourceNum.SWITCHBOARD;
20
+ if ('quoteAsset' in source)
21
+ return types_1.OracleSourceNum.QUOTE_ASSET;
22
+ if ('pythStableCoin' in source)
23
+ return types_1.OracleSourceNum.PYTH_STABLE_COIN;
24
+ if ('pythStableCoinPull' in source)
25
+ return types_1.OracleSourceNum.PYTH_STABLE_COIN_PULL;
26
+ if ('prelaunch' in source)
27
+ return types_1.OracleSourceNum.PRELAUNCH;
28
+ if ('switchboardOnDemand' in source)
29
+ return types_1.OracleSourceNum.SWITCHBOARD_ON_DEMAND;
30
+ throw new Error('Invalid oracle source');
31
+ }
32
+ exports.getOracleSourceNum = getOracleSourceNum;
33
+ function getOracleId(publicKey, source) {
34
+ return `${publicKey.toBase58()}-${getOracleSourceNum(source)}`;
35
+ }
36
+ exports.getOracleId = getOracleId;
@@ -198,6 +198,20 @@ export declare class OracleSource {
198
198
  switchboardOnDemand: {};
199
199
  };
200
200
  }
201
+ export declare class OracleSourceNum {
202
+ static readonly PYTH = 0;
203
+ static readonly PYTH_1K = 1;
204
+ static readonly PYTH_1M = 2;
205
+ static readonly PYTH_PULL = 3;
206
+ static readonly PYTH_1K_PULL = 4;
207
+ static readonly PYTH_1M_PULL = 5;
208
+ static readonly SWITCHBOARD = 6;
209
+ static readonly QUOTE_ASSET = 7;
210
+ static readonly PYTH_STABLE_COIN = 8;
211
+ static readonly PYTH_STABLE_COIN_PULL = 9;
212
+ static readonly PRELAUNCH = 10;
213
+ static readonly SWITCHBOARD_ON_DEMAND = 11;
214
+ }
201
215
  export declare class OrderType {
202
216
  static readonly LIMIT: {
203
217
  limit: {};