@drift-labs/sdk 2.142.0-beta.13 → 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.
@@ -1,5 +1,5 @@
1
1
  import { Program } from '@coral-xyz/anchor';
2
- import { Context, PublicKey } from '@solana/web3.js';
2
+ import { Commitment, Context, PublicKey } from '@solana/web3.js';
3
3
  import * as Buffer from 'buffer';
4
4
  import bs58 from 'bs58';
5
5
 
@@ -21,13 +21,32 @@ interface AccountInfoLike {
21
21
  rentEpoch: number;
22
22
  }
23
23
 
24
- export class grpcMultiAccountSubscriber<T> {
24
+ function commitmentLevelToCommitment(
25
+ commitmentLevel: CommitmentLevel
26
+ ): Commitment {
27
+ switch (commitmentLevel) {
28
+ case CommitmentLevel.PROCESSED:
29
+ return 'processed';
30
+ case CommitmentLevel.CONFIRMED:
31
+ return 'confirmed';
32
+ case CommitmentLevel.FINALIZED:
33
+ return 'finalized';
34
+ default:
35
+ return 'confirmed';
36
+ }
37
+ }
38
+
39
+ export class grpcMultiAccountSubscriber<T, U = undefined> {
25
40
  private client: Client;
26
41
  private stream: ClientDuplexStream<SubscribeRequest, SubscribeUpdate>;
27
42
  private commitmentLevel: CommitmentLevel;
28
43
  private program: Program;
29
44
  private accountName: string;
30
- private decodeBufferFn?: (buffer: Buffer, pubkey?: string) => T;
45
+ private decodeBufferFn?: (
46
+ buffer: Buffer,
47
+ pubkey?: string,
48
+ accountProps?: U
49
+ ) => T;
31
50
  private resubOpts?: ResubOpts;
32
51
  private onUnsubscribe?: () => Promise<void>;
33
52
 
@@ -39,10 +58,11 @@ export class grpcMultiAccountSubscriber<T> {
39
58
  private subscribedAccounts = new Set<string>();
40
59
  private onChangeMap = new Map<
41
60
  string,
42
- (data: T, context: Context, buffer: Buffer) => void
61
+ (data: T, context: Context, buffer: Buffer, accountProps: U) => void
43
62
  >();
44
63
 
45
64
  private dataMap = new Map<string, DataAndSlot<T>>();
65
+ private accountPropsMap = new Map<string, U | Array<U>>();
46
66
 
47
67
  private constructor(
48
68
  client: Client,
@@ -51,7 +71,8 @@ export class grpcMultiAccountSubscriber<T> {
51
71
  program: Program,
52
72
  decodeBuffer?: (buffer: Buffer, pubkey?: string) => T,
53
73
  resubOpts?: ResubOpts,
54
- onUnsubscribe?: () => Promise<void>
74
+ onUnsubscribe?: () => Promise<void>,
75
+ accountPropsMap?: Map<string, U | Array<U>>
55
76
  ) {
56
77
  this.client = client;
57
78
  this.commitmentLevel = commitmentLevel;
@@ -60,17 +81,19 @@ export class grpcMultiAccountSubscriber<T> {
60
81
  this.decodeBufferFn = decodeBuffer;
61
82
  this.resubOpts = resubOpts;
62
83
  this.onUnsubscribe = onUnsubscribe;
84
+ this.accountPropsMap = accountPropsMap;
63
85
  }
64
86
 
65
- public static async create<U>(
87
+ public static async create<T, U = undefined>(
66
88
  grpcConfigs: GrpcConfigs,
67
89
  accountName: string,
68
90
  program: Program,
69
- decodeBuffer?: (buffer: Buffer, pubkey?: string) => U,
91
+ decodeBuffer?: (buffer: Buffer, pubkey?: string, accountProps?: U) => T,
70
92
  resubOpts?: ResubOpts,
71
93
  clientProp?: Client,
72
- onUnsubscribe?: () => Promise<void>
73
- ): Promise<grpcMultiAccountSubscriber<U>> {
94
+ onUnsubscribe?: () => Promise<void>,
95
+ accountPropsMap?: Map<string, U | Array<U>>
96
+ ): Promise<grpcMultiAccountSubscriber<T, U>> {
74
97
  const client = clientProp
75
98
  ? clientProp
76
99
  : await createClient(
@@ -89,7 +112,8 @@ export class grpcMultiAccountSubscriber<T> {
89
112
  program,
90
113
  decodeBuffer,
91
114
  resubOpts,
92
- onUnsubscribe
115
+ onUnsubscribe,
116
+ accountPropsMap
93
117
  );
94
118
  }
95
119
 
@@ -105,13 +129,64 @@ export class grpcMultiAccountSubscriber<T> {
105
129
  return this.dataMap;
106
130
  }
107
131
 
132
+ async fetch(): Promise<void> {
133
+ try {
134
+ // Chunk account IDs into groups of 100 (getMultipleAccounts limit)
135
+ const chunkSize = 100;
136
+ const chunks: string[][] = [];
137
+ const accountIds = Array.from(this.subscribedAccounts.values());
138
+ for (let i = 0; i < accountIds.length; i += chunkSize) {
139
+ chunks.push(accountIds.slice(i, i + chunkSize));
140
+ }
141
+
142
+ // Process all chunks concurrently
143
+ await Promise.all(
144
+ chunks.map(async (chunk) => {
145
+ const accountAddresses = chunk.map(
146
+ (accountId) => new PublicKey(accountId)
147
+ );
148
+ const rpcResponseAndContext =
149
+ await this.program.provider.connection.getMultipleAccountsInfoAndContext(
150
+ accountAddresses,
151
+ {
152
+ commitment: commitmentLevelToCommitment(this.commitmentLevel),
153
+ }
154
+ );
155
+
156
+ const rpcResponse = rpcResponseAndContext.value;
157
+ const currentSlot = rpcResponseAndContext.context.slot;
158
+
159
+ for (let i = 0; i < chunk.length; i++) {
160
+ const accountId = chunk[i];
161
+ const accountInfo = rpcResponse[i];
162
+ if (accountInfo) {
163
+ const perpMarket = this.program.coder.accounts.decode(
164
+ 'PerpMarket',
165
+ accountInfo.data
166
+ );
167
+ this.setAccountData(accountId, perpMarket, currentSlot);
168
+ }
169
+ }
170
+ })
171
+ );
172
+ } catch (error) {
173
+ if (this.resubOpts?.logResubMessages) {
174
+ console.log(
175
+ `[${this.accountName}] grpcMultiAccountSubscriber error fetching accounts:`,
176
+ error
177
+ );
178
+ }
179
+ }
180
+ }
181
+
108
182
  async subscribe(
109
183
  accounts: PublicKey[],
110
184
  onChange: (
111
185
  accountId: PublicKey,
112
186
  data: T,
113
187
  context: Context,
114
- buffer: Buffer
188
+ buffer: Buffer,
189
+ accountProps: U
115
190
  ) => void
116
191
  ): Promise<void> {
117
192
  if (this.listenerId != null || this.isUnsubscribing) {
@@ -122,9 +197,9 @@ export class grpcMultiAccountSubscriber<T> {
122
197
  for (const pk of accounts) {
123
198
  const key = pk.toBase58();
124
199
  this.subscribedAccounts.add(key);
125
- this.onChangeMap.set(key, (data, ctx, buffer) => {
200
+ this.onChangeMap.set(key, (data, ctx, buffer, accountProps) => {
126
201
  this.setAccountData(key, data, ctx.slot);
127
- onChange(new PublicKey(key), data, ctx, buffer);
202
+ onChange(new PublicKey(key), data, ctx, buffer, accountProps);
128
203
  });
129
204
  }
130
205
 
@@ -170,23 +245,38 @@ export class grpcMultiAccountSubscriber<T> {
170
245
 
171
246
  const context = { slot } as Context;
172
247
  const buffer = accountInfo.data;
173
- const data = this.decodeBufferFn
174
- ? this.decodeBufferFn(buffer, accountPubkey)
175
- : this.program.account[this.accountName].coder.accounts.decode(
176
- this.capitalize(this.accountName),
177
- buffer
178
- );
179
-
180
- const handler = this.onChangeMap.get(accountPubkey);
181
- if (handler) {
182
- if (this.resubOpts?.resubTimeoutMs) {
183
- this.receivingData = true;
184
- clearTimeout(this.timeoutId);
185
- handler(data, context, buffer);
186
- this.setTimeout();
187
- } else {
188
- handler(data, context, buffer);
248
+ const accountProps = this.accountPropsMap?.get(accountPubkey);
249
+
250
+ const handleDataBuffer = (
251
+ context: Context,
252
+ buffer: Buffer,
253
+ accountProps: U
254
+ ) => {
255
+ const data = this.decodeBufferFn
256
+ ? this.decodeBufferFn(buffer, accountPubkey, accountProps)
257
+ : this.program.account[this.accountName].coder.accounts.decode(
258
+ this.capitalize(this.accountName),
259
+ buffer
260
+ );
261
+ const handler = this.onChangeMap.get(accountPubkey);
262
+ if (handler) {
263
+ if (this.resubOpts?.resubTimeoutMs) {
264
+ this.receivingData = true;
265
+ clearTimeout(this.timeoutId);
266
+ handler(data, context, buffer, accountProps);
267
+ this.setTimeout();
268
+ } else {
269
+ handler(data, context, buffer, accountProps);
270
+ }
271
+ }
272
+ };
273
+
274
+ if (Array.isArray(accountProps)) {
275
+ for (const props of accountProps) {
276
+ handleDataBuffer(context, buffer, props);
189
277
  }
278
+ } else {
279
+ handleDataBuffer(context, buffer, accountProps);
190
280
  }
191
281
  });
192
282