@drift-labs/sdk 2.142.0-beta.1 → 2.142.0-beta.3

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 (41) hide show
  1. package/VERSION +1 -1
  2. package/bun.lock +25 -10
  3. package/lib/browser/accounts/grpcAccountSubscriber.d.ts +2 -1
  4. package/lib/browser/accounts/grpcAccountSubscriber.js +4 -2
  5. package/lib/browser/accounts/grpcDriftClientAccountSubscriber.d.ts +1 -1
  6. package/lib/browser/accounts/grpcDriftClientAccountSubscriber.js +3 -3
  7. package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.d.ts +22 -0
  8. package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.js +194 -0
  9. package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +33 -0
  10. package/lib/browser/accounts/grpcMultiAccountSubscriber.js +278 -0
  11. package/lib/browser/driftClient.js +11 -10
  12. package/lib/browser/driftClientConfig.d.ts +3 -0
  13. package/lib/node/accounts/grpcAccountSubscriber.d.ts +2 -1
  14. package/lib/node/accounts/grpcAccountSubscriber.d.ts.map +1 -1
  15. package/lib/node/accounts/grpcAccountSubscriber.js +4 -2
  16. package/lib/node/accounts/grpcDriftClientAccountSubscriber.d.ts +1 -1
  17. package/lib/node/accounts/grpcDriftClientAccountSubscriber.js +3 -3
  18. package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts +23 -0
  19. package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts.map +1 -0
  20. package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.js +194 -0
  21. package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +34 -0
  22. package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -0
  23. package/lib/node/accounts/grpcMultiAccountSubscriber.js +278 -0
  24. package/lib/node/driftClient.d.ts.map +1 -1
  25. package/lib/node/driftClient.js +11 -10
  26. package/lib/node/driftClientConfig.d.ts +3 -0
  27. package/lib/node/driftClientConfig.d.ts.map +1 -1
  28. package/lib/node/isomorphic/grpc.d.ts +5 -3
  29. package/lib/node/isomorphic/grpc.js +1 -3
  30. package/lib/node/isomorphic/grpc.node.d.ts +5 -3
  31. package/lib/node/isomorphic/grpc.node.d.ts.map +1 -1
  32. package/lib/node/isomorphic/grpc.node.js +1 -3
  33. package/package.json +3 -3
  34. package/scripts/client-test.ts +133 -0
  35. package/src/accounts/grpcAccountSubscriber.ts +9 -6
  36. package/src/accounts/grpcDriftClientAccountSubscriber.ts +1 -1
  37. package/src/accounts/grpcDriftClientAccountSubscriberV2.ts +358 -0
  38. package/src/accounts/grpcMultiAccountSubscriber.ts +338 -0
  39. package/src/driftClient.ts +5 -2
  40. package/src/driftClientConfig.ts +13 -0
  41. package/src/isomorphic/grpc.node.ts +11 -7
@@ -1,8 +1,10 @@
1
1
  import type Client from '@triton-one/yellowstone-grpc';
2
2
  import type { SubscribeRequest, SubscribeUpdate } from '@triton-one/yellowstone-grpc';
3
3
  import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
4
- import { ClientDuplexStream, ChannelOptions } from '@grpc/grpc-js';
5
- import { CommitmentLevel as LaserCommitmentLevel, subscribe as LaserSubscribe, LaserstreamConfig, SubscribeRequest as LaserSubscribeRequest, SubscribeUpdate as LaserSubscribeUpdate, CompressionAlgorithms } from 'helius-laserstream';
6
- export { ClientDuplexStream, ChannelOptions, SubscribeRequest, SubscribeUpdate, CommitmentLevel, Client, LaserSubscribe, LaserCommitmentLevel, LaserstreamConfig, LaserSubscribeRequest, LaserSubscribeUpdate, CompressionAlgorithms, };
4
+ import type { ClientDuplexStream, ChannelOptions } from '@grpc/grpc-js';
5
+ import { CommitmentLevel as LaserCommitmentLevel, subscribe as LaserSubscribe, CompressionAlgorithms } from 'helius-laserstream';
6
+ import type { LaserstreamConfig, SubscribeRequest as LaserSubscribeRequest, SubscribeUpdate as LaserSubscribeUpdate } from 'helius-laserstream';
7
+ export { CommitmentLevel, Client, LaserSubscribe, LaserCommitmentLevel, CompressionAlgorithms, };
8
+ export type { ClientDuplexStream, ChannelOptions, SubscribeRequest, SubscribeUpdate, LaserstreamConfig, LaserSubscribeRequest, LaserSubscribeUpdate, };
7
9
  export declare function createClient(...args: ConstructorParameters<typeof Client>): Promise<Client>;
8
10
  //# sourceMappingURL=grpc.node.d.ts.map
@@ -23,14 +23,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.createClient = exports.CompressionAlgorithms = exports.LaserSubscribeUpdate = exports.LaserSubscribeRequest = exports.LaserCommitmentLevel = exports.LaserSubscribe = exports.CommitmentLevel = void 0;
26
+ exports.createClient = exports.CompressionAlgorithms = exports.LaserCommitmentLevel = exports.LaserSubscribe = exports.CommitmentLevel = void 0;
27
27
  const yellowstone_grpc_1 = require("@triton-one/yellowstone-grpc");
28
28
  Object.defineProperty(exports, "CommitmentLevel", { enumerable: true, get: function () { return yellowstone_grpc_1.CommitmentLevel; } });
29
29
  const helius_laserstream_1 = require("helius-laserstream");
30
30
  Object.defineProperty(exports, "LaserCommitmentLevel", { enumerable: true, get: function () { return helius_laserstream_1.CommitmentLevel; } });
31
31
  Object.defineProperty(exports, "LaserSubscribe", { enumerable: true, get: function () { return helius_laserstream_1.subscribe; } });
32
- Object.defineProperty(exports, "LaserSubscribeRequest", { enumerable: true, get: function () { return helius_laserstream_1.SubscribeRequest; } });
33
- Object.defineProperty(exports, "LaserSubscribeUpdate", { enumerable: true, get: function () { return helius_laserstream_1.SubscribeUpdate; } });
34
32
  Object.defineProperty(exports, "CompressionAlgorithms", { enumerable: true, get: function () { return helius_laserstream_1.CompressionAlgorithms; } });
35
33
  // Export a function to create a new Client instance
36
34
  async function createClient(...args) {
@@ -1,8 +1,10 @@
1
1
  import type Client from '@triton-one/yellowstone-grpc';
2
2
  import type { SubscribeRequest, SubscribeUpdate } from '@triton-one/yellowstone-grpc';
3
3
  import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
4
- import { ClientDuplexStream, ChannelOptions } from '@grpc/grpc-js';
5
- import { CommitmentLevel as LaserCommitmentLevel, subscribe as LaserSubscribe, LaserstreamConfig, SubscribeRequest as LaserSubscribeRequest, SubscribeUpdate as LaserSubscribeUpdate, CompressionAlgorithms } from 'helius-laserstream';
6
- export { ClientDuplexStream, ChannelOptions, SubscribeRequest, SubscribeUpdate, CommitmentLevel, Client, LaserSubscribe, LaserCommitmentLevel, LaserstreamConfig, LaserSubscribeRequest, LaserSubscribeUpdate, CompressionAlgorithms, };
4
+ import type { ClientDuplexStream, ChannelOptions } from '@grpc/grpc-js';
5
+ import { CommitmentLevel as LaserCommitmentLevel, subscribe as LaserSubscribe, CompressionAlgorithms } from 'helius-laserstream';
6
+ import type { LaserstreamConfig, SubscribeRequest as LaserSubscribeRequest, SubscribeUpdate as LaserSubscribeUpdate } from 'helius-laserstream';
7
+ export { CommitmentLevel, Client, LaserSubscribe, LaserCommitmentLevel, CompressionAlgorithms, };
8
+ export type { ClientDuplexStream, ChannelOptions, SubscribeRequest, SubscribeUpdate, LaserstreamConfig, LaserSubscribeRequest, LaserSubscribeUpdate, };
7
9
  export declare function createClient(...args: ConstructorParameters<typeof Client>): Promise<Client>;
8
10
  //# sourceMappingURL=grpc.node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"grpc.node.d.ts","sourceRoot":"","sources":["../../../src/isomorphic/grpc.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,8BAA8B,CAAC;AACvD,OAAO,KAAK,EACX,gBAAgB,EAChB,eAAe,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,EACN,eAAe,IAAI,oBAAoB,EACvC,SAAS,IAAI,cAAc,EAC3B,iBAAiB,EACjB,gBAAgB,IAAI,qBAAqB,EACzC,eAAe,IAAI,oBAAoB,EACvC,qBAAqB,EACrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACN,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,MAAM,EACN,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,GACrB,CAAC;AAGF,wBAAsB,YAAY,CACjC,GAAG,IAAI,EAAE,qBAAqB,CAAC,OAAO,MAAM,CAAC,GAC3C,OAAO,CAAC,MAAM,CAAC,CAGjB"}
1
+ {"version":3,"file":"grpc.node.d.ts","sourceRoot":"","sources":["../../../src/isomorphic/grpc.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,8BAA8B,CAAC;AACvD,OAAO,KAAK,EACX,gBAAgB,EAChB,eAAe,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EACN,eAAe,IAAI,oBAAoB,EACvC,SAAS,IAAI,cAAc,EAC3B,qBAAqB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,IAAI,qBAAqB,EACzC,eAAe,IAAI,oBAAoB,EACvC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACN,eAAe,EACf,MAAM,EACN,cAAc,EACd,oBAAoB,EACpB,qBAAqB,GACrB,CAAC;AACF,YAAY,EACX,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,GACpB,CAAC;AAGF,wBAAsB,YAAY,CACjC,GAAG,IAAI,EAAE,qBAAqB,CAAC,OAAO,MAAM,CAAC,GAC3C,OAAO,CAAC,MAAM,CAAC,CAGjB"}
@@ -23,14 +23,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.createClient = exports.CompressionAlgorithms = exports.LaserSubscribeUpdate = exports.LaserSubscribeRequest = exports.LaserCommitmentLevel = exports.LaserSubscribe = exports.CommitmentLevel = void 0;
26
+ exports.createClient = exports.CompressionAlgorithms = exports.LaserCommitmentLevel = exports.LaserSubscribe = exports.CommitmentLevel = void 0;
27
27
  const yellowstone_grpc_1 = require("@triton-one/yellowstone-grpc");
28
28
  Object.defineProperty(exports, "CommitmentLevel", { enumerable: true, get: function () { return yellowstone_grpc_1.CommitmentLevel; } });
29
29
  const helius_laserstream_1 = require("helius-laserstream");
30
30
  Object.defineProperty(exports, "LaserCommitmentLevel", { enumerable: true, get: function () { return helius_laserstream_1.CommitmentLevel; } });
31
31
  Object.defineProperty(exports, "LaserSubscribe", { enumerable: true, get: function () { return helius_laserstream_1.subscribe; } });
32
- Object.defineProperty(exports, "LaserSubscribeRequest", { enumerable: true, get: function () { return helius_laserstream_1.SubscribeRequest; } });
33
- Object.defineProperty(exports, "LaserSubscribeUpdate", { enumerable: true, get: function () { return helius_laserstream_1.SubscribeUpdate; } });
34
32
  Object.defineProperty(exports, "CompressionAlgorithms", { enumerable: true, get: function () { return helius_laserstream_1.CompressionAlgorithms; } });
35
33
  // Export a function to create a new Client instance
36
34
  async function createClient(...args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.142.0-beta.1",
3
+ "version": "2.142.0-beta.3",
4
4
  "main": "lib/node/index.js",
5
5
  "types": "lib/node/index.d.ts",
6
6
  "browser": "./lib/browser/index.js",
@@ -42,7 +42,7 @@
42
42
  "@coral-xyz/anchor": "0.29.0",
43
43
  "@coral-xyz/anchor-30": "npm:@coral-xyz/anchor@0.30.1",
44
44
  "@ellipsis-labs/phoenix-sdk": "1.4.5",
45
- "@grpc/grpc-js": "1.12.6",
45
+ "@grpc/grpc-js": "1.14.0",
46
46
  "@openbook-dex/openbook-v2": "0.2.10",
47
47
  "@project-serum/serum": "0.13.65",
48
48
  "@pythnetwork/client": "2.5.3",
@@ -52,7 +52,7 @@
52
52
  "@solana/web3.js": "1.98.0",
53
53
  "@switchboard-xyz/common": "3.0.14",
54
54
  "@switchboard-xyz/on-demand": "2.4.1",
55
- "@triton-one/yellowstone-grpc": "1.3.0",
55
+ "@triton-one/yellowstone-grpc": "1.4.1",
56
56
  "anchor-bankrun": "0.3.0",
57
57
  "gill": "^0.10.2",
58
58
  "helius-laserstream": "0.1.8",
@@ -0,0 +1,133 @@
1
+ import { DriftClient } from '../src/driftClient';
2
+ import { grpcDriftClientAccountSubscriberV2 } from '../src/accounts/grpcDriftClientAccountSubscriberV2';
3
+ import { Connection, Keypair, PublicKey } from '@solana/web3.js';
4
+ import { DriftClientConfig } from '../src/driftClientConfig';
5
+ import { decodeName, DRIFT_PROGRAM_ID, Wallet } from '../src';
6
+ import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
7
+ import dotenv from 'dotenv';
8
+
9
+ const GRPC_ENDPOINT = process.env.GRPC_ENDPOINT;
10
+ const TOKEN = process.env.TOKEN;
11
+
12
+ async function initializeGrpcDriftClientV2() {
13
+ const connection = new Connection('https://api.mainnet-beta.solana.com');
14
+ const wallet = new Wallet(new Keypair());
15
+ dotenv.config({ path: '../' });
16
+ const config: DriftClientConfig = {
17
+ connection,
18
+ wallet,
19
+ programID: new PublicKey(DRIFT_PROGRAM_ID),
20
+ accountSubscription: {
21
+ type: 'grpc',
22
+ grpcConfigs: {
23
+ endpoint: GRPC_ENDPOINT,
24
+ token: TOKEN,
25
+ commitmentLevel: 'confirmed' as unknown as CommitmentLevel,
26
+ channelOptions: {
27
+ 'grpc.keepalive_time_ms': 10_000,
28
+ 'grpc.keepalive_timeout_ms': 1_000,
29
+ 'grpc.keepalive_permit_without_calls': 1,
30
+ },
31
+ },
32
+ driftClientAccountSubscriber: grpcDriftClientAccountSubscriberV2,
33
+ },
34
+ perpMarketIndexes: [0, 1, 2], // Example market indexes
35
+ spotMarketIndexes: [0, 1, 2], // Example market indexes
36
+ oracleInfos: [], // Add oracle information if needed
37
+ };
38
+
39
+ const driftClient = new DriftClient(config);
40
+
41
+ let perpMarketUpdateCount = 0;
42
+ let spotMarketUpdateCount = 0;
43
+ let oraclePriceUpdateCount = 0;
44
+ let userAccountUpdateCount = 0;
45
+
46
+ const updatePromise = new Promise<void>((resolve) => {
47
+ driftClient.accountSubscriber.eventEmitter.on(
48
+ 'perpMarketAccountUpdate',
49
+ (data) => {
50
+ console.log('Perp market account update:', decodeName(data.name));
51
+ const perpMarketData = driftClient.getPerpMarketAccount(
52
+ data.marketIndex
53
+ );
54
+ console.log(
55
+ 'Perp market data market index:',
56
+ perpMarketData?.marketIndex
57
+ );
58
+ perpMarketUpdateCount++;
59
+ if (
60
+ perpMarketUpdateCount >= 10 &&
61
+ spotMarketUpdateCount >= 10 &&
62
+ oraclePriceUpdateCount >= 10 &&
63
+ userAccountUpdateCount >= 2
64
+ ) {
65
+ resolve();
66
+ }
67
+ }
68
+ );
69
+
70
+ driftClient.accountSubscriber.eventEmitter.on(
71
+ 'spotMarketAccountUpdate',
72
+ (data) => {
73
+ console.log('Spot market account update:', decodeName(data.name));
74
+ const spotMarketData = driftClient.getSpotMarketAccount(
75
+ data.marketIndex
76
+ );
77
+ console.log(
78
+ 'Spot market data market index:',
79
+ spotMarketData?.marketIndex
80
+ );
81
+ spotMarketUpdateCount++;
82
+ if (
83
+ perpMarketUpdateCount >= 10 &&
84
+ spotMarketUpdateCount >= 10 &&
85
+ oraclePriceUpdateCount >= 10 &&
86
+ userAccountUpdateCount >= 2
87
+ ) {
88
+ resolve();
89
+ }
90
+ }
91
+ );
92
+
93
+ driftClient.accountSubscriber.eventEmitter.on(
94
+ 'oraclePriceUpdate',
95
+ (data) => {
96
+ console.log('Oracle price update:', data.toBase58());
97
+ oraclePriceUpdateCount++;
98
+ if (
99
+ perpMarketUpdateCount >= 10 &&
100
+ spotMarketUpdateCount >= 10 &&
101
+ oraclePriceUpdateCount >= 10 &&
102
+ userAccountUpdateCount >= 2
103
+ ) {
104
+ resolve();
105
+ }
106
+ }
107
+ );
108
+
109
+ driftClient.accountSubscriber.eventEmitter.on(
110
+ 'userAccountUpdate',
111
+ (data) => {
112
+ console.log('User account update:', decodeName(data.name));
113
+ userAccountUpdateCount++;
114
+ if (
115
+ perpMarketUpdateCount >= 10 &&
116
+ spotMarketUpdateCount >= 10 &&
117
+ oraclePriceUpdateCount >= 10 &&
118
+ userAccountUpdateCount >= 2
119
+ ) {
120
+ resolve();
121
+ }
122
+ }
123
+ );
124
+ });
125
+
126
+ await driftClient.subscribe();
127
+ console.log('DriftClient initialized and listening for updates.');
128
+
129
+ await updatePromise;
130
+ console.log('Received required number of updates.');
131
+ }
132
+
133
+ initializeGrpcDriftClientV2().catch(console.error);
@@ -39,13 +39,16 @@ export class grpcAccountSubscriber<T> extends WebSocketAccountSubscriber<T> {
39
39
  program: Program,
40
40
  accountPublicKey: PublicKey,
41
41
  decodeBuffer?: (buffer: Buffer) => U,
42
- resubOpts?: ResubOpts
42
+ resubOpts?: ResubOpts,
43
+ clientProp?: Client
43
44
  ): Promise<grpcAccountSubscriber<U>> {
44
- const client = await createClient(
45
- grpcConfigs.endpoint,
46
- grpcConfigs.token,
47
- grpcConfigs.channelOptions ?? {}
48
- );
45
+ const client = clientProp
46
+ ? clientProp
47
+ : await createClient(
48
+ grpcConfigs.endpoint,
49
+ grpcConfigs.token,
50
+ grpcConfigs.channelOptions ?? {}
51
+ );
49
52
  const commitmentLevel =
50
53
  // @ts-ignore :: isomorphic exported enum fails typescript but will work at runtime
51
54
  grpcConfigs.commitmentLevel ?? CommitmentLevel.CONFIRMED;
@@ -12,7 +12,7 @@ import { grpcAccountSubscriber } from './grpcAccountSubscriber';
12
12
  import { PerpMarketAccount, SpotMarketAccount, StateAccount } from '../types';
13
13
  import { getOracleId } from '../oracles/oracleId';
14
14
 
15
- export class gprcDriftClientAccountSubscriber extends WebSocketDriftClientAccountSubscriber {
15
+ export class grpcDriftClientAccountSubscriber extends WebSocketDriftClientAccountSubscriber {
16
16
  private grpcConfigs: GrpcConfigs;
17
17
 
18
18
  constructor(
@@ -0,0 +1,358 @@
1
+ import { WebSocketDriftClientAccountSubscriber } from './webSocketDriftClientAccountSubscriber';
2
+ import { OracleInfo, OraclePriceData } from '../oracles/types';
3
+ import { Program } from '@coral-xyz/anchor';
4
+ import { PublicKey } from '@solana/web3.js';
5
+ import { findAllMarketAndOracles } from '../config';
6
+ import {
7
+ getDriftStateAccountPublicKey,
8
+ getPerpMarketPublicKey,
9
+ getSpotMarketPublicKey,
10
+ } from '../addresses/pda';
11
+ import {
12
+ DataAndSlot,
13
+ DelistedMarketSetting,
14
+ GrpcConfigs,
15
+ ResubOpts,
16
+ } from './types';
17
+ import { grpcAccountSubscriber } from './grpcAccountSubscriber';
18
+ import { grpcMultiAccountSubscriber } from './grpcMultiAccountSubscriber';
19
+ import { PerpMarketAccount, SpotMarketAccount, StateAccount } from '../types';
20
+ import { getOracleId } from '../oracles/oracleId';
21
+
22
+ export class grpcDriftClientAccountSubscriberV2 extends WebSocketDriftClientAccountSubscriber {
23
+ private grpcConfigs: GrpcConfigs;
24
+ private perpMarketsSubscriber?: grpcMultiAccountSubscriber<PerpMarketAccount>;
25
+ private spotMarketsSubscriber?: grpcMultiAccountSubscriber<SpotMarketAccount>;
26
+ private oracleMultiSubscriber?: grpcMultiAccountSubscriber<OraclePriceData>;
27
+ private perpMarketIndexToAccountPubkeyMap = new Map<number, PublicKey>();
28
+ private spotMarketIndexToAccountPubkeyMap = new Map<number, PublicKey>();
29
+
30
+ constructor(
31
+ grpcConfigs: GrpcConfigs,
32
+ program: Program,
33
+ perpMarketIndexes: number[],
34
+ spotMarketIndexes: number[],
35
+ oracleInfos: OracleInfo[],
36
+ shouldFindAllMarketsAndOracles: boolean,
37
+ delistedMarketSetting: DelistedMarketSetting,
38
+ resubOpts?: ResubOpts
39
+ ) {
40
+ super(
41
+ program,
42
+ perpMarketIndexes,
43
+ spotMarketIndexes,
44
+ oracleInfos,
45
+ shouldFindAllMarketsAndOracles,
46
+ delistedMarketSetting,
47
+ resubOpts
48
+ );
49
+ this.grpcConfigs = grpcConfigs;
50
+ }
51
+
52
+ public async subscribe(): Promise<boolean> {
53
+ if (this.isSubscribed) {
54
+ return true;
55
+ }
56
+
57
+ if (this.isSubscribing) {
58
+ return await this.subscriptionPromise;
59
+ }
60
+
61
+ this.isSubscribing = true;
62
+
63
+ this.subscriptionPromise = new Promise((res) => {
64
+ this.subscriptionPromiseResolver = res;
65
+ });
66
+
67
+ if (this.shouldFindAllMarketsAndOracles) {
68
+ const {
69
+ perpMarketIndexes,
70
+ perpMarketAccounts,
71
+ spotMarketIndexes,
72
+ spotMarketAccounts,
73
+ oracleInfos,
74
+ } = await findAllMarketAndOracles(this.program);
75
+ this.perpMarketIndexes = perpMarketIndexes;
76
+ this.spotMarketIndexes = spotMarketIndexes;
77
+ this.oracleInfos = oracleInfos;
78
+ // front run and set the initial data here to save extra gma call in set initial data
79
+ this.initialPerpMarketAccountData = new Map(
80
+ perpMarketAccounts.map((market) => [market.marketIndex, market])
81
+ );
82
+ this.initialSpotMarketAccountData = new Map(
83
+ spotMarketAccounts.map((market) => [market.marketIndex, market])
84
+ );
85
+ }
86
+
87
+ const statePublicKey = await getDriftStateAccountPublicKey(
88
+ this.program.programId
89
+ );
90
+
91
+ // create and activate main state account subscription
92
+ this.stateAccountSubscriber =
93
+ await grpcAccountSubscriber.create<StateAccount>(
94
+ this.grpcConfigs,
95
+ 'state',
96
+ this.program,
97
+ statePublicKey,
98
+ undefined,
99
+ undefined
100
+ );
101
+ await this.stateAccountSubscriber.subscribe((data: StateAccount) => {
102
+ this.eventEmitter.emit('stateAccountUpdate', data);
103
+ this.eventEmitter.emit('update');
104
+ });
105
+
106
+ // set initial data to avoid spamming getAccountInfo calls in webSocketAccountSubscriber
107
+ await this.setInitialData();
108
+
109
+ // subscribe to perp + spot markets (separate) and oracles
110
+ await Promise.all([
111
+ this.subscribeToPerpMarketAccounts(),
112
+ this.subscribeToSpotMarketAccounts(),
113
+ this.subscribeToOracles(),
114
+ ]);
115
+
116
+ this.eventEmitter.emit('update');
117
+
118
+ await this.handleDelistedMarkets();
119
+
120
+ await Promise.all([this.setPerpOracleMap(), this.setSpotOracleMap()]);
121
+
122
+ this.subscriptionPromiseResolver(true);
123
+
124
+ this.isSubscribing = false;
125
+ this.isSubscribed = true;
126
+
127
+ // delete initial data
128
+ this.removeInitialData();
129
+
130
+ return true;
131
+ }
132
+
133
+ override getMarketAccountAndSlot(
134
+ marketIndex: number
135
+ ): DataAndSlot<PerpMarketAccount> | undefined {
136
+ return this.perpMarketsSubscriber?.getAccountData(
137
+ this.perpMarketIndexToAccountPubkeyMap.get(marketIndex)
138
+ );
139
+ }
140
+
141
+ override getSpotMarketAccountAndSlot(
142
+ marketIndex: number
143
+ ): DataAndSlot<SpotMarketAccount> | undefined {
144
+ return this.spotMarketsSubscriber?.getAccountData(
145
+ this.spotMarketIndexToAccountPubkeyMap.get(marketIndex)
146
+ );
147
+ }
148
+
149
+ override async subscribeToPerpMarketAccounts(): Promise<boolean> {
150
+ const perpMarketIndexToAccountPubkeys: Array<[number, PublicKey]> =
151
+ await Promise.all(
152
+ this.perpMarketIndexes.map(async (marketIndex) => [
153
+ marketIndex,
154
+ await getPerpMarketPublicKey(this.program.programId, marketIndex),
155
+ ])
156
+ );
157
+ for (const [
158
+ marketIndex,
159
+ accountPubkey,
160
+ ] of perpMarketIndexToAccountPubkeys) {
161
+ this.perpMarketIndexToAccountPubkeyMap.set(marketIndex, accountPubkey);
162
+ }
163
+
164
+ const perpMarketPubkeys = perpMarketIndexToAccountPubkeys.map(
165
+ ([_, accountPubkey]) => accountPubkey
166
+ );
167
+
168
+ this.perpMarketsSubscriber =
169
+ await grpcMultiAccountSubscriber.create<PerpMarketAccount>(
170
+ this.grpcConfigs,
171
+ 'perpMarket',
172
+ this.program,
173
+ undefined,
174
+ this.resubOpts,
175
+ undefined,
176
+ async () => {
177
+ try {
178
+ if (this.resubOpts?.logResubMessages) {
179
+ console.log(
180
+ '[grpcDriftClientAccountSubscriberV2] perp markets subscriber unsubscribed; resubscribing'
181
+ );
182
+ }
183
+ await this.subscribeToPerpMarketAccounts();
184
+ } catch (e) {
185
+ console.error('Perp markets resubscribe failed:', e);
186
+ }
187
+ }
188
+ );
189
+
190
+ for (const data of this.initialPerpMarketAccountData.values()) {
191
+ this.perpMarketsSubscriber.setAccountData(data.pubkey, data);
192
+ }
193
+
194
+ await this.perpMarketsSubscriber.subscribe(
195
+ perpMarketPubkeys,
196
+ (_accountId, data) => {
197
+ this.eventEmitter.emit(
198
+ 'perpMarketAccountUpdate',
199
+ data as PerpMarketAccount
200
+ );
201
+ this.eventEmitter.emit('update');
202
+ }
203
+ );
204
+
205
+ return true;
206
+ }
207
+
208
+ override async subscribeToSpotMarketAccounts(): Promise<boolean> {
209
+ const spotMarketIndexToAccountPubkeys: Array<[number, PublicKey]> =
210
+ await Promise.all(
211
+ this.spotMarketIndexes.map(async (marketIndex) => [
212
+ marketIndex,
213
+ await getSpotMarketPublicKey(this.program.programId, marketIndex),
214
+ ])
215
+ );
216
+ for (const [
217
+ marketIndex,
218
+ accountPubkey,
219
+ ] of spotMarketIndexToAccountPubkeys) {
220
+ this.spotMarketIndexToAccountPubkeyMap.set(marketIndex, accountPubkey);
221
+ }
222
+
223
+ const spotMarketPubkeys = spotMarketIndexToAccountPubkeys.map(
224
+ ([_, accountPubkey]) => accountPubkey
225
+ );
226
+
227
+ this.spotMarketsSubscriber =
228
+ await grpcMultiAccountSubscriber.create<SpotMarketAccount>(
229
+ this.grpcConfigs,
230
+ 'spotMarket',
231
+ this.program,
232
+ undefined,
233
+ this.resubOpts,
234
+ undefined,
235
+ async () => {
236
+ try {
237
+ if (this.resubOpts?.logResubMessages) {
238
+ console.log(
239
+ '[grpcDriftClientAccountSubscriberV2] spot markets subscriber unsubscribed; resubscribing'
240
+ );
241
+ }
242
+ await this.subscribeToSpotMarketAccounts();
243
+ } catch (e) {
244
+ console.error('Spot markets resubscribe failed:', e);
245
+ }
246
+ }
247
+ );
248
+
249
+ for (const data of this.initialSpotMarketAccountData.values()) {
250
+ this.spotMarketsSubscriber.setAccountData(data.pubkey, data);
251
+ }
252
+
253
+ await this.spotMarketsSubscriber.subscribe(
254
+ spotMarketPubkeys,
255
+ (_accountId, data) => {
256
+ this.eventEmitter.emit(
257
+ 'spotMarketAccountUpdate',
258
+ data as SpotMarketAccount
259
+ );
260
+ this.eventEmitter.emit('update');
261
+ }
262
+ );
263
+
264
+ return true;
265
+ }
266
+
267
+ override async subscribeToOracles(): Promise<boolean> {
268
+ // Build list of unique oracle pubkeys and a lookup for sources
269
+ const uniqueOraclePubkeys = new Map<string, OracleInfo>();
270
+ for (const info of this.oracleInfos) {
271
+ const id = getOracleId(info.publicKey, info.source);
272
+ if (
273
+ !uniqueOraclePubkeys.has(id) &&
274
+ !info.publicKey.equals((PublicKey as any).default)
275
+ ) {
276
+ uniqueOraclePubkeys.set(id, info);
277
+ }
278
+ }
279
+
280
+ const oraclePubkeys = Array.from(uniqueOraclePubkeys.values()).map(
281
+ (i) => i.publicKey
282
+ );
283
+ const pubkeyToSource = new Map<string, OracleInfo['source']>(
284
+ Array.from(uniqueOraclePubkeys.values()).map((i) => [
285
+ i.publicKey.toBase58(),
286
+ i.source,
287
+ ])
288
+ );
289
+
290
+ this.oracleMultiSubscriber =
291
+ await grpcMultiAccountSubscriber.create<OraclePriceData>(
292
+ this.grpcConfigs,
293
+ 'oracle',
294
+ this.program,
295
+ (buffer: Buffer, pubkey?: string) => {
296
+ if (!pubkey) {
297
+ throw new Error('Oracle pubkey missing in decode');
298
+ }
299
+ const source = pubkeyToSource.get(pubkey);
300
+ const client = this.oracleClientCache.get(
301
+ source,
302
+ this.program.provider.connection,
303
+ this.program
304
+ );
305
+ return client.getOraclePriceDataFromBuffer(buffer);
306
+ },
307
+ this.resubOpts,
308
+ undefined,
309
+ async () => {
310
+ try {
311
+ if (this.resubOpts?.logResubMessages) {
312
+ console.log(
313
+ '[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing'
314
+ );
315
+ }
316
+ await this.subscribeToOracles();
317
+ } catch (e) {
318
+ console.error('Oracle resubscribe failed:', e);
319
+ }
320
+ }
321
+ );
322
+
323
+ for (const data of this.initialOraclePriceData.entries()) {
324
+ this.oracleMultiSubscriber.setAccountData(
325
+ new PublicKey(data[0]),
326
+ data[1]
327
+ );
328
+ }
329
+
330
+ await this.oracleMultiSubscriber.subscribe(
331
+ oraclePubkeys,
332
+ (accountId, data) => {
333
+ const source = pubkeyToSource.get(accountId.toBase58());
334
+ this.eventEmitter.emit('oraclePriceUpdate', accountId, source, data);
335
+ this.eventEmitter.emit('update');
336
+ }
337
+ );
338
+
339
+ return true;
340
+ }
341
+
342
+ async unsubscribeFromOracles(): Promise<void> {
343
+ if (this.oracleMultiSubscriber) {
344
+ await this.oracleMultiSubscriber.unsubscribe();
345
+ this.oracleMultiSubscriber = undefined;
346
+ return;
347
+ }
348
+ await super.unsubscribeFromOracles();
349
+ }
350
+
351
+ override async unsubscribe(): Promise<void> {
352
+ if (this.isSubscribed) {
353
+ return;
354
+ }
355
+
356
+ await this.stateAccountSubscriber.unsubscribe();
357
+ }
358
+ }