@drift-labs/sdk 2.37.1-beta.0 → 2.37.1-beta.10

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 (44) hide show
  1. package/VERSION +1 -1
  2. package/lib/adminClient.d.ts +1 -0
  3. package/lib/adminClient.js +10 -0
  4. package/lib/constants/perpMarkets.js +20 -0
  5. package/lib/events/eventSubscriber.js +3 -0
  6. package/lib/events/fetchLogs.js +3 -0
  7. package/lib/events/types.d.ts +1 -0
  8. package/lib/idl/drift.json +73 -8
  9. package/lib/index.d.ts +1 -0
  10. package/lib/index.js +1 -0
  11. package/lib/math/auction.js +1 -1
  12. package/lib/orderSubscriber/OrderSubscriber.d.ts +5 -1
  13. package/lib/orderSubscriber/OrderSubscriber.js +10 -0
  14. package/lib/orderSubscriber/types.d.ts +5 -0
  15. package/lib/tx/baseTxSender.d.ts +30 -0
  16. package/lib/tx/baseTxSender.js +176 -0
  17. package/lib/tx/fastSingleTxSender.d.ts +27 -0
  18. package/lib/tx/fastSingleTxSender.js +83 -0
  19. package/lib/tx/retryTxSender.d.ts +5 -14
  20. package/lib/tx/retryTxSender.js +7 -158
  21. package/lib/types.d.ts +18 -0
  22. package/lib/types.js +1 -0
  23. package/lib/user.d.ts +10 -1
  24. package/lib/user.js +259 -61
  25. package/package.json +2 -2
  26. package/src/adminClient.ts +18 -0
  27. package/src/constants/perpMarkets.ts +20 -0
  28. package/src/events/eventSubscriber.ts +3 -0
  29. package/src/events/fetchLogs.ts +3 -0
  30. package/src/events/types.ts +1 -0
  31. package/src/idl/drift.json +73 -8
  32. package/src/index.ts +1 -0
  33. package/src/marinade/types.ts +70 -70
  34. package/src/math/auction.ts +1 -1
  35. package/src/orderSubscriber/OrderSubscriber.ts +19 -2
  36. package/src/orderSubscriber/types.ts +11 -0
  37. package/src/tx/baseTxSender.ts +276 -0
  38. package/src/tx/fastSingleTxSender.ts +142 -0
  39. package/src/tx/retryTxSender.ts +9 -235
  40. package/src/types.ts +19 -0
  41. package/src/user.ts +441 -101
  42. package/tests/amm/test.ts +83 -39
  43. package/tests/dlob/helpers.ts +2 -0
  44. package/tests/dlob/test.ts +19 -17
@@ -0,0 +1,276 @@
1
+ import { TxSender, TxSigAndSlot } from './types';
2
+ import {
3
+ Commitment,
4
+ ConfirmOptions,
5
+ Context,
6
+ RpcResponseAndContext,
7
+ Signer,
8
+ SignatureResult,
9
+ Transaction,
10
+ TransactionSignature,
11
+ Connection,
12
+ VersionedTransaction,
13
+ TransactionMessage,
14
+ TransactionInstruction,
15
+ AddressLookupTableAccount,
16
+ } from '@solana/web3.js';
17
+ import { AnchorProvider } from '@coral-xyz/anchor';
18
+ import assert from 'assert';
19
+ import bs58 from 'bs58';
20
+ import { IWallet } from '../types';
21
+
22
+ const DEFAULT_TIMEOUT = 35000;
23
+
24
+ export abstract class BaseTxSender implements TxSender {
25
+ connection: Connection;
26
+ wallet: IWallet;
27
+ opts: ConfirmOptions;
28
+ timeout: number;
29
+ additionalConnections: Connection[];
30
+ timeoutCount = 0;
31
+
32
+ public constructor({
33
+ connection,
34
+ wallet,
35
+ opts = AnchorProvider.defaultOptions(),
36
+ timeout = DEFAULT_TIMEOUT,
37
+ additionalConnections = new Array<Connection>(),
38
+ }: {
39
+ connection: Connection;
40
+ wallet: IWallet;
41
+ opts?: ConfirmOptions;
42
+ timeout?: number;
43
+ additionalConnections?;
44
+ }) {
45
+ this.connection = connection;
46
+ this.wallet = wallet;
47
+ this.opts = opts;
48
+ this.timeout = timeout;
49
+ this.additionalConnections = additionalConnections;
50
+ }
51
+
52
+ async send(
53
+ tx: Transaction,
54
+ additionalSigners?: Array<Signer>,
55
+ opts?: ConfirmOptions,
56
+ preSigned?: boolean
57
+ ): Promise<TxSigAndSlot> {
58
+ if (additionalSigners === undefined) {
59
+ additionalSigners = [];
60
+ }
61
+ if (opts === undefined) {
62
+ opts = this.opts;
63
+ }
64
+
65
+ const signedTx = preSigned
66
+ ? tx
67
+ : await this.prepareTx(tx, additionalSigners, opts);
68
+
69
+ return this.sendRawTransaction(signedTx.serialize(), opts);
70
+ }
71
+
72
+ async prepareTx(
73
+ tx: Transaction,
74
+ additionalSigners: Array<Signer>,
75
+ opts: ConfirmOptions
76
+ ): Promise<Transaction> {
77
+ tx.feePayer = this.wallet.publicKey;
78
+ tx.recentBlockhash = (
79
+ await this.connection.getLatestBlockhash(opts.preflightCommitment)
80
+ ).blockhash;
81
+
82
+ additionalSigners
83
+ .filter((s): s is Signer => s !== undefined)
84
+ .forEach((kp) => {
85
+ tx.partialSign(kp);
86
+ });
87
+
88
+ const signedTx = await this.wallet.signTransaction(tx);
89
+
90
+ return signedTx;
91
+ }
92
+
93
+ async getVersionedTransaction(
94
+ ixs: TransactionInstruction[],
95
+ lookupTableAccounts: AddressLookupTableAccount[],
96
+ additionalSigners?: Array<Signer>,
97
+ opts?: ConfirmOptions
98
+ ): Promise<VersionedTransaction> {
99
+ if (additionalSigners === undefined) {
100
+ additionalSigners = [];
101
+ }
102
+ if (opts === undefined) {
103
+ opts = this.opts;
104
+ }
105
+
106
+ const message = new TransactionMessage({
107
+ payerKey: this.wallet.publicKey,
108
+ recentBlockhash: (
109
+ await this.connection.getLatestBlockhash(opts.preflightCommitment)
110
+ ).blockhash,
111
+ instructions: ixs,
112
+ }).compileToV0Message(lookupTableAccounts);
113
+
114
+ const tx = new VersionedTransaction(message);
115
+
116
+ return tx;
117
+ }
118
+
119
+ async sendVersionedTransaction(
120
+ tx: VersionedTransaction,
121
+ additionalSigners?: Array<Signer>,
122
+ opts?: ConfirmOptions,
123
+ preSigned?: boolean
124
+ ): Promise<TxSigAndSlot> {
125
+ let signedTx;
126
+ if (preSigned) {
127
+ signedTx = tx;
128
+ // @ts-ignore
129
+ } else if (this.wallet.payer) {
130
+ // @ts-ignore
131
+ tx.sign((additionalSigners ?? []).concat(this.wallet.payer));
132
+ signedTx = tx;
133
+ } else {
134
+ additionalSigners
135
+ ?.filter((s): s is Signer => s !== undefined)
136
+ .forEach((kp) => {
137
+ tx.sign([kp]);
138
+ });
139
+ // @ts-ignore
140
+ signedTx = await this.wallet.signTransaction(tx);
141
+ }
142
+
143
+ if (opts === undefined) {
144
+ opts = this.opts;
145
+ }
146
+
147
+ return this.sendRawTransaction(signedTx.serialize(), opts);
148
+ }
149
+
150
+ async sendRawTransaction(
151
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
152
+ rawTransaction: Buffer | Uint8Array,
153
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
154
+ opts: ConfirmOptions
155
+ ): Promise<TxSigAndSlot> {
156
+ throw new Error('Must be implemented by subclass');
157
+ }
158
+
159
+ async confirmTransaction(
160
+ signature: TransactionSignature,
161
+ commitment?: Commitment
162
+ ): Promise<RpcResponseAndContext<SignatureResult>> {
163
+ let decodedSignature;
164
+ try {
165
+ decodedSignature = bs58.decode(signature);
166
+ } catch (err) {
167
+ throw new Error('signature must be base58 encoded: ' + signature);
168
+ }
169
+
170
+ assert(decodedSignature.length === 64, 'signature has invalid length');
171
+
172
+ const start = Date.now();
173
+ const subscriptionCommitment = commitment || this.opts.commitment;
174
+
175
+ const subscriptionIds = new Array<number>();
176
+ const connections = [this.connection, ...this.additionalConnections];
177
+ let response: RpcResponseAndContext<SignatureResult> | null = null;
178
+ const promises = connections.map((connection, i) => {
179
+ let subscriptionId;
180
+ const confirmPromise = new Promise((resolve, reject) => {
181
+ try {
182
+ subscriptionId = connection.onSignature(
183
+ signature,
184
+ (result: SignatureResult, context: Context) => {
185
+ subscriptionIds[i] = undefined;
186
+ response = {
187
+ context,
188
+ value: result,
189
+ };
190
+ resolve(null);
191
+ },
192
+ subscriptionCommitment
193
+ );
194
+ } catch (err) {
195
+ reject(err);
196
+ }
197
+ });
198
+ subscriptionIds.push(subscriptionId);
199
+ return confirmPromise;
200
+ });
201
+
202
+ try {
203
+ await this.promiseTimeout(promises, this.timeout);
204
+ } finally {
205
+ for (const [i, subscriptionId] of subscriptionIds.entries()) {
206
+ if (subscriptionId) {
207
+ connections[i].removeSignatureListener(subscriptionId);
208
+ }
209
+ }
210
+ }
211
+
212
+ if (response === null) {
213
+ this.timeoutCount += 1;
214
+ const duration = (Date.now() - start) / 1000;
215
+ throw new Error(
216
+ `Transaction was not confirmed in ${duration.toFixed(
217
+ 2
218
+ )} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`
219
+ );
220
+ }
221
+
222
+ return response;
223
+ }
224
+
225
+ getTimestamp(): number {
226
+ return new Date().getTime();
227
+ }
228
+
229
+ promiseTimeout<T>(
230
+ promises: Promise<T>[],
231
+ timeoutMs: number
232
+ ): Promise<T | null> {
233
+ let timeoutId: ReturnType<typeof setTimeout>;
234
+ const timeoutPromise: Promise<null> = new Promise((resolve) => {
235
+ timeoutId = setTimeout(() => resolve(null), timeoutMs);
236
+ });
237
+
238
+ return Promise.race([...promises, timeoutPromise]).then(
239
+ (result: T | null) => {
240
+ clearTimeout(timeoutId);
241
+ return result;
242
+ }
243
+ );
244
+ }
245
+
246
+ sendToAdditionalConnections(
247
+ rawTx: Buffer | Uint8Array,
248
+ opts: ConfirmOptions
249
+ ): void {
250
+ this.additionalConnections.map((connection) => {
251
+ connection.sendRawTransaction(rawTx, opts).catch((e) => {
252
+ console.error(
253
+ // @ts-ignore
254
+ `error sending tx to additional connection ${connection._rpcEndpoint}`
255
+ );
256
+ console.error(e);
257
+ });
258
+ });
259
+ }
260
+
261
+ public addAdditionalConnection(newConnection: Connection): void {
262
+ const alreadyUsingConnection =
263
+ this.additionalConnections.filter((connection) => {
264
+ // @ts-ignore
265
+ return connection._rpcEndpoint === newConnection.rpcEndpoint;
266
+ }).length > 0;
267
+
268
+ if (!alreadyUsingConnection) {
269
+ this.additionalConnections.push(newConnection);
270
+ }
271
+ }
272
+
273
+ public getTimeoutCount(): number {
274
+ return this.timeoutCount;
275
+ }
276
+ }
@@ -0,0 +1,142 @@
1
+ import { TxSigAndSlot } from './types';
2
+ import {
3
+ ConfirmOptions,
4
+ Signer,
5
+ Transaction,
6
+ TransactionSignature,
7
+ Connection,
8
+ VersionedTransaction,
9
+ TransactionMessage,
10
+ TransactionInstruction,
11
+ AddressLookupTableAccount,
12
+ } from '@solana/web3.js';
13
+ import { AnchorProvider } from '@coral-xyz/anchor';
14
+ import { IWallet } from '../types';
15
+ import { BaseTxSender } from './baseTxSender';
16
+
17
+ const DEFAULT_TIMEOUT = 35000;
18
+ const DEFAULT_BLOCKHASH_REFRESH = 10000;
19
+
20
+ export class FastSingleTxSender extends BaseTxSender {
21
+ connection: Connection;
22
+ wallet: IWallet;
23
+ opts: ConfirmOptions;
24
+ timeout: number;
25
+ blockhashRefreshInterval: number;
26
+ additionalConnections: Connection[];
27
+ timoutCount = 0;
28
+ recentBlockhash: string;
29
+
30
+ public constructor({
31
+ connection,
32
+ wallet,
33
+ opts = AnchorProvider.defaultOptions(),
34
+ timeout = DEFAULT_TIMEOUT,
35
+ blockhashRefreshInterval = DEFAULT_BLOCKHASH_REFRESH,
36
+ additionalConnections = new Array<Connection>(),
37
+ }: {
38
+ connection: Connection;
39
+ wallet: IWallet;
40
+ opts?: ConfirmOptions;
41
+ timeout?: number;
42
+ blockhashRefreshInterval?: number;
43
+ additionalConnections?;
44
+ }) {
45
+ super({ connection, wallet, opts, timeout, additionalConnections });
46
+ this.connection = connection;
47
+ this.wallet = wallet;
48
+ this.opts = opts;
49
+ this.timeout = timeout;
50
+ this.blockhashRefreshInterval = blockhashRefreshInterval;
51
+ this.additionalConnections = additionalConnections;
52
+ this.startBlockhashRefreshLoop();
53
+ }
54
+
55
+ startBlockhashRefreshLoop(): void {
56
+ setInterval(async () => {
57
+ this.recentBlockhash = (
58
+ await this.connection.getLatestBlockhash(this.opts)
59
+ ).blockhash;
60
+ }, this.blockhashRefreshInterval);
61
+ }
62
+
63
+ async prepareTx(
64
+ tx: Transaction,
65
+ additionalSigners: Array<Signer>,
66
+ opts: ConfirmOptions
67
+ ): Promise<Transaction> {
68
+ tx.feePayer = this.wallet.publicKey;
69
+
70
+ tx.recentBlockhash =
71
+ this.recentBlockhash ??
72
+ (await this.connection.getLatestBlockhash(opts.preflightCommitment))
73
+ .blockhash;
74
+
75
+ additionalSigners
76
+ .filter((s): s is Signer => s !== undefined)
77
+ .forEach((kp) => {
78
+ tx.partialSign(kp);
79
+ });
80
+
81
+ const signedTx = await this.wallet.signTransaction(tx);
82
+
83
+ return signedTx;
84
+ }
85
+
86
+ async getVersionedTransaction(
87
+ ixs: TransactionInstruction[],
88
+ lookupTableAccounts: AddressLookupTableAccount[],
89
+ additionalSigners?: Array<Signer>,
90
+ opts?: ConfirmOptions
91
+ ): Promise<VersionedTransaction> {
92
+ if (additionalSigners === undefined) {
93
+ additionalSigners = [];
94
+ }
95
+ if (opts === undefined) {
96
+ opts = this.opts;
97
+ }
98
+
99
+ const message = new TransactionMessage({
100
+ payerKey: this.wallet.publicKey,
101
+ recentBlockhash:
102
+ this.recentBlockhash ??
103
+ (await this.connection.getLatestBlockhash(opts.preflightCommitment))
104
+ .blockhash,
105
+ instructions: ixs,
106
+ }).compileToV0Message(lookupTableAccounts);
107
+
108
+ const tx = new VersionedTransaction(message);
109
+
110
+ return tx;
111
+ }
112
+
113
+ async sendRawTransaction(
114
+ rawTransaction: Buffer | Uint8Array,
115
+ opts: ConfirmOptions
116
+ ): Promise<TxSigAndSlot> {
117
+ let txid: TransactionSignature;
118
+ try {
119
+ txid = await this.connection.sendRawTransaction(rawTransaction, opts);
120
+ this.sendToAdditionalConnections(rawTransaction, opts);
121
+ } catch (e) {
122
+ console.error(e);
123
+ throw e;
124
+ }
125
+
126
+ this.connection.sendRawTransaction(rawTransaction, opts).catch((e) => {
127
+ console.error(e);
128
+ });
129
+ this.sendToAdditionalConnections(rawTransaction, opts);
130
+
131
+ let slot: number;
132
+ try {
133
+ const result = await this.confirmTransaction(txid, opts.commitment);
134
+ slot = result.context.slot;
135
+ } catch (e) {
136
+ console.error(e);
137
+ throw e;
138
+ }
139
+
140
+ return { txSig: txid, slot };
141
+ }
142
+ }
@@ -1,23 +1,12 @@
1
- import { TxSender, TxSigAndSlot } from './types';
1
+ import { TxSigAndSlot } from './types';
2
2
  import {
3
- Commitment,
4
3
  ConfirmOptions,
5
- Context,
6
- RpcResponseAndContext,
7
- Signer,
8
- SignatureResult,
9
- Transaction,
10
4
  TransactionSignature,
11
5
  Connection,
12
- VersionedTransaction,
13
- TransactionMessage,
14
- TransactionInstruction,
15
- AddressLookupTableAccount,
16
6
  } from '@solana/web3.js';
17
7
  import { AnchorProvider } from '@coral-xyz/anchor';
18
- import assert from 'assert';
19
- import bs58 from 'bs58';
20
8
  import { IWallet } from '../types';
9
+ import { BaseTxSender } from './baseTxSender';
21
10
 
22
11
  const DEFAULT_TIMEOUT = 35000;
23
12
  const DEFAULT_RETRY = 8000;
@@ -26,7 +15,7 @@ type ResolveReference = {
26
15
  resolve?: () => void;
27
16
  };
28
17
 
29
- export class RetryTxSender implements TxSender {
18
+ export class RetryTxSender extends BaseTxSender {
30
19
  connection: Connection;
31
20
  wallet: IWallet;
32
21
  opts: ConfirmOptions;
@@ -50,6 +39,7 @@ export class RetryTxSender implements TxSender {
50
39
  retrySleep?: number;
51
40
  additionalConnections?;
52
41
  }) {
42
+ super({ connection, wallet, opts, timeout, additionalConnections });
53
43
  this.connection = connection;
54
44
  this.wallet = wallet;
55
45
  this.opts = opts;
@@ -58,102 +48,11 @@ export class RetryTxSender implements TxSender {
58
48
  this.additionalConnections = additionalConnections;
59
49
  }
60
50
 
61
- async send(
62
- tx: Transaction,
63
- additionalSigners?: Array<Signer>,
64
- opts?: ConfirmOptions,
65
- preSigned?: boolean
66
- ): Promise<TxSigAndSlot> {
67
- if (additionalSigners === undefined) {
68
- additionalSigners = [];
69
- }
70
- if (opts === undefined) {
71
- opts = this.opts;
72
- }
73
-
74
- const signedTx = preSigned
75
- ? tx
76
- : await this.prepareTx(tx, additionalSigners, opts);
77
-
78
- return this.sendRawTransaction(signedTx.serialize(), opts);
79
- }
80
-
81
- async prepareTx(
82
- tx: Transaction,
83
- additionalSigners: Array<Signer>,
84
- opts: ConfirmOptions
85
- ): Promise<Transaction> {
86
- tx.feePayer = this.wallet.publicKey;
87
- tx.recentBlockhash = (
88
- await this.connection.getRecentBlockhash(opts.preflightCommitment)
89
- ).blockhash;
90
-
91
- additionalSigners
92
- .filter((s): s is Signer => s !== undefined)
93
- .forEach((kp) => {
94
- tx.partialSign(kp);
95
- });
96
-
97
- const signedTx = await this.wallet.signTransaction(tx);
98
-
99
- return signedTx;
100
- }
101
-
102
- async getVersionedTransaction(
103
- ixs: TransactionInstruction[],
104
- lookupTableAccounts: AddressLookupTableAccount[],
105
- additionalSigners?: Array<Signer>,
106
- opts?: ConfirmOptions
107
- ): Promise<VersionedTransaction> {
108
- if (additionalSigners === undefined) {
109
- additionalSigners = [];
110
- }
111
- if (opts === undefined) {
112
- opts = this.opts;
113
- }
114
-
115
- const message = new TransactionMessage({
116
- payerKey: this.wallet.publicKey,
117
- recentBlockhash: (
118
- await this.connection.getRecentBlockhash(opts.preflightCommitment)
119
- ).blockhash,
120
- instructions: ixs,
121
- }).compileToV0Message(lookupTableAccounts);
122
-
123
- const tx = new VersionedTransaction(message);
124
-
125
- return tx;
126
- }
127
-
128
- async sendVersionedTransaction(
129
- tx: VersionedTransaction,
130
- additionalSigners?: Array<Signer>,
131
- opts?: ConfirmOptions,
132
- preSigned?: boolean
133
- ): Promise<TxSigAndSlot> {
134
- let signedTx;
135
- if (preSigned) {
136
- signedTx = tx;
137
- // @ts-ignore
138
- } else if (this.wallet.payer) {
139
- // @ts-ignore
140
- tx.sign((additionalSigners ?? []).concat(this.wallet.payer));
141
- signedTx = tx;
142
- } else {
143
- additionalSigners
144
- ?.filter((s): s is Signer => s !== undefined)
145
- .forEach((kp) => {
146
- tx.sign([kp]);
147
- });
148
- // @ts-ignore
149
- signedTx = await this.wallet.signTransaction(tx);
150
- }
151
-
152
- if (opts === undefined) {
153
- opts = this.opts;
154
- }
155
-
156
- return this.sendRawTransaction(signedTx.serialize(), opts);
51
+ async sleep(reference: ResolveReference): Promise<void> {
52
+ return new Promise((resolve) => {
53
+ reference.resolve = resolve;
54
+ setTimeout(resolve, this.retrySleep);
55
+ });
157
56
  }
158
57
 
159
58
  async sendRawTransaction(
@@ -210,129 +109,4 @@ export class RetryTxSender implements TxSender {
210
109
 
211
110
  return { txSig: txid, slot };
212
111
  }
213
-
214
- async confirmTransaction(
215
- signature: TransactionSignature,
216
- commitment?: Commitment
217
- ): Promise<RpcResponseAndContext<SignatureResult>> {
218
- let decodedSignature;
219
- try {
220
- decodedSignature = bs58.decode(signature);
221
- } catch (err) {
222
- throw new Error('signature must be base58 encoded: ' + signature);
223
- }
224
-
225
- assert(decodedSignature.length === 64, 'signature has invalid length');
226
-
227
- const start = Date.now();
228
- const subscriptionCommitment = commitment || this.opts.commitment;
229
-
230
- const subscriptionIds = new Array<number>();
231
- const connections = [this.connection, ...this.additionalConnections];
232
- let response: RpcResponseAndContext<SignatureResult> | null = null;
233
- const promises = connections.map((connection, i) => {
234
- let subscriptionId;
235
- const confirmPromise = new Promise((resolve, reject) => {
236
- try {
237
- subscriptionId = connection.onSignature(
238
- signature,
239
- (result: SignatureResult, context: Context) => {
240
- subscriptionIds[i] = undefined;
241
- response = {
242
- context,
243
- value: result,
244
- };
245
- resolve(null);
246
- },
247
- subscriptionCommitment
248
- );
249
- } catch (err) {
250
- reject(err);
251
- }
252
- });
253
- subscriptionIds.push(subscriptionId);
254
- return confirmPromise;
255
- });
256
-
257
- try {
258
- await this.promiseTimeout(promises, this.timeout);
259
- } finally {
260
- for (const [i, subscriptionId] of subscriptionIds.entries()) {
261
- if (subscriptionId) {
262
- connections[i].removeSignatureListener(subscriptionId);
263
- }
264
- }
265
- }
266
-
267
- if (response === null) {
268
- this.timoutCount += 1;
269
- const duration = (Date.now() - start) / 1000;
270
- throw new Error(
271
- `Transaction was not confirmed in ${duration.toFixed(
272
- 2
273
- )} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`
274
- );
275
- }
276
-
277
- return response;
278
- }
279
-
280
- getTimestamp(): number {
281
- return new Date().getTime();
282
- }
283
-
284
- async sleep(reference: ResolveReference): Promise<void> {
285
- return new Promise((resolve) => {
286
- reference.resolve = resolve;
287
- setTimeout(resolve, this.retrySleep);
288
- });
289
- }
290
-
291
- promiseTimeout<T>(
292
- promises: Promise<T>[],
293
- timeoutMs: number
294
- ): Promise<T | null> {
295
- let timeoutId: ReturnType<typeof setTimeout>;
296
- const timeoutPromise: Promise<null> = new Promise((resolve) => {
297
- timeoutId = setTimeout(() => resolve(null), timeoutMs);
298
- });
299
-
300
- return Promise.race([...promises, timeoutPromise]).then(
301
- (result: T | null) => {
302
- clearTimeout(timeoutId);
303
- return result;
304
- }
305
- );
306
- }
307
-
308
- sendToAdditionalConnections(
309
- rawTx: Buffer | Uint8Array,
310
- opts: ConfirmOptions
311
- ): void {
312
- this.additionalConnections.map((connection) => {
313
- connection.sendRawTransaction(rawTx, opts).catch((e) => {
314
- console.error(
315
- // @ts-ignore
316
- `error sending tx to additional connection ${connection._rpcEndpoint}`
317
- );
318
- console.error(e);
319
- });
320
- });
321
- }
322
-
323
- public addAdditionalConnection(newConnection: Connection): void {
324
- const alreadyUsingConnection =
325
- this.additionalConnections.filter((connection) => {
326
- // @ts-ignore
327
- return connection._rpcEndpoint === newConnection.rpcEndpoint;
328
- }).length > 0;
329
-
330
- if (!alreadyUsingConnection) {
331
- this.additionalConnections.push(newConnection);
332
- }
333
- }
334
-
335
- public getTimeoutCount(): number {
336
- return this.timoutCount;
337
- }
338
112
  }