@drift-labs/sdk 2.83.0-beta.9 → 2.84.0-beta.1
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.
- package/VERSION +1 -1
- package/bun.lockb +0 -0
- package/lib/adminClient.d.ts +2 -2
- package/lib/adminClient.js +7 -9
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/dlob/DLOB.d.ts +5 -5
- package/lib/dlob/DLOB.js +8 -8
- package/lib/driftClient.d.ts +2 -2
- package/lib/driftClient.js +4 -4
- package/lib/idl/drift.json +1 -1
- package/lib/math/auction.js +2 -2
- package/lib/math/orders.js +1 -1
- package/lib/tx/txHandler.d.ts +4 -4
- package/lib/tx/txHandler.js +67 -29
- package/lib/tx/whileValidTxSender.js +15 -2
- package/lib/userMap/userMap.d.ts +3 -0
- package/lib/userMap/userMap.js +103 -1
- package/lib/userMap/userMapConfig.d.ts +8 -0
- package/package.json +1 -1
- package/src/adminClient.ts +12 -10
- package/src/constants/perpMarkets.ts +20 -0
- package/src/dlob/DLOB.ts +17 -9
- package/src/driftClient.ts +10 -6
- package/src/idl/drift.json +1 -1
- package/src/math/auction.ts +2 -2
- package/src/math/orders.ts +5 -2
- package/src/tx/txHandler.ts +92 -44
- package/src/tx/whileValidTxSender.ts +20 -2
- package/src/userMap/userMap.ts +131 -0
- package/src/userMap/userMapConfig.ts +12 -0
package/src/tx/txHandler.ts
CHANGED
|
@@ -25,6 +25,14 @@ import {
|
|
|
25
25
|
} from '../types';
|
|
26
26
|
import { containsComputeUnitIxs } from '../util/computeUnits';
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Explanation for SIGNATURE_BLOCK_AND_EXPIRY:
|
|
30
|
+
*
|
|
31
|
+
* When the whileValidTxSender waits for confirmation of a given transaction, it needs the last available blockheight and blockhash used in the signature to do so. For pre-signed transactions, these values aren't attached to the transaction object by default. For a "scrappy" workaround which doesn't break backwards compatibility, the SIGNATURE_BLOCK_AND_EXPIRY property is simply attached to the transaction objects as they are created or signed in this handler despite a mismatch in the typescript types. If the values are attached to the transaction when they reach the whileValidTxSender, it can opt-in to use these values.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const DEV_TRY_FORCE_TX_TIMEOUTS = false;
|
|
35
|
+
|
|
28
36
|
export const COMPUTE_UNITS_DEFAULT = 200_000;
|
|
29
37
|
|
|
30
38
|
export type TxBuildingProps = {
|
|
@@ -36,7 +44,7 @@ export type TxBuildingProps = {
|
|
|
36
44
|
lookupTables?: AddressLookupTableAccount[];
|
|
37
45
|
forceVersionedTransaction?: boolean;
|
|
38
46
|
txParams?: TxParams;
|
|
39
|
-
|
|
47
|
+
recentBlockhash?: BlockhashWithExpiryBlockHeight;
|
|
40
48
|
wallet?: IWallet;
|
|
41
49
|
};
|
|
42
50
|
|
|
@@ -139,6 +147,9 @@ export class TxHandler {
|
|
|
139
147
|
|
|
140
148
|
const signedTx = await this.signTx(tx, additionalSigners);
|
|
141
149
|
|
|
150
|
+
// @ts-ignore
|
|
151
|
+
signedTx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
152
|
+
|
|
142
153
|
return signedTx;
|
|
143
154
|
}
|
|
144
155
|
|
|
@@ -202,15 +213,18 @@ export class TxHandler {
|
|
|
202
213
|
public async signVersionedTx(
|
|
203
214
|
tx: VersionedTransaction,
|
|
204
215
|
additionalSigners: Array<Signer>,
|
|
205
|
-
|
|
216
|
+
recentBlockhash?: BlockhashWithExpiryBlockHeight,
|
|
206
217
|
wallet?: IWallet
|
|
207
218
|
): Promise<VersionedTransaction> {
|
|
208
219
|
[wallet] = this.getProps(wallet);
|
|
209
220
|
|
|
210
|
-
if (
|
|
211
|
-
tx.message.recentBlockhash =
|
|
221
|
+
if (recentBlockhash) {
|
|
222
|
+
tx.message.recentBlockhash = recentBlockhash.blockhash;
|
|
212
223
|
|
|
213
|
-
this.addHashAndExpiryToLookup(
|
|
224
|
+
this.addHashAndExpiryToLookup(recentBlockhash);
|
|
225
|
+
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
214
228
|
}
|
|
215
229
|
|
|
216
230
|
additionalSigners
|
|
@@ -305,10 +319,10 @@ export class TxHandler {
|
|
|
305
319
|
}
|
|
306
320
|
|
|
307
321
|
private _generateVersionedTransaction(
|
|
308
|
-
|
|
322
|
+
recentBlockhash: BlockhashWithExpiryBlockHeight,
|
|
309
323
|
message: Message | MessageV0
|
|
310
324
|
) {
|
|
311
|
-
this.addHashAndExpiryToLookup(
|
|
325
|
+
this.addHashAndExpiryToLookup(recentBlockhash);
|
|
312
326
|
|
|
313
327
|
return new VersionedTransaction(message);
|
|
314
328
|
}
|
|
@@ -326,7 +340,12 @@ export class TxHandler {
|
|
|
326
340
|
instructions: ixs,
|
|
327
341
|
}).compileToLegacyMessage();
|
|
328
342
|
|
|
329
|
-
|
|
343
|
+
const tx = this._generateVersionedTransaction(recentBlockhash, message);
|
|
344
|
+
|
|
345
|
+
// @ts-ignore
|
|
346
|
+
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
347
|
+
|
|
348
|
+
return tx;
|
|
330
349
|
}
|
|
331
350
|
|
|
332
351
|
public generateVersionedTransaction(
|
|
@@ -343,7 +362,12 @@ export class TxHandler {
|
|
|
343
362
|
instructions: ixs,
|
|
344
363
|
}).compileToV0Message(lookupTableAccounts);
|
|
345
364
|
|
|
346
|
-
|
|
365
|
+
const tx = this._generateVersionedTransaction(recentBlockhash, message);
|
|
366
|
+
|
|
367
|
+
// @ts-ignore
|
|
368
|
+
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
369
|
+
|
|
370
|
+
return tx;
|
|
347
371
|
}
|
|
348
372
|
|
|
349
373
|
public generateLegacyTransaction(ixs: TransactionInstruction[]) {
|
|
@@ -360,8 +384,8 @@ export class TxHandler {
|
|
|
360
384
|
instructions: (TransactionInstruction | TransactionInstruction[])[];
|
|
361
385
|
}
|
|
362
386
|
) {
|
|
363
|
-
const
|
|
364
|
-
props?.
|
|
387
|
+
const recentBlockhash =
|
|
388
|
+
props?.recentBlockhash ?? (await this.getLatestBlockhashForTransaction());
|
|
365
389
|
|
|
366
390
|
return await Promise.all(
|
|
367
391
|
props.instructions.map((ix) => {
|
|
@@ -369,7 +393,7 @@ export class TxHandler {
|
|
|
369
393
|
return this.buildTransaction({
|
|
370
394
|
...props,
|
|
371
395
|
instructions: ix,
|
|
372
|
-
|
|
396
|
+
recentBlockhash,
|
|
373
397
|
});
|
|
374
398
|
})
|
|
375
399
|
);
|
|
@@ -433,7 +457,13 @@ export class TxHandler {
|
|
|
433
457
|
|
|
434
458
|
const computeUnitsPrice = baseTxParams?.computeUnitsPrice;
|
|
435
459
|
|
|
436
|
-
if (
|
|
460
|
+
if (process.env.DEV_TRY_FORCE_TX_TIMEOUTS || DEV_TRY_FORCE_TX_TIMEOUTS) {
|
|
461
|
+
allIx.push(
|
|
462
|
+
ComputeBudgetProgram.setComputeUnitPrice({
|
|
463
|
+
microLamports: 0,
|
|
464
|
+
})
|
|
465
|
+
);
|
|
466
|
+
} else if (computeUnitsPrice > 0 && !hasSetComputeUnitPriceIx) {
|
|
437
467
|
allIx.push(
|
|
438
468
|
ComputeBudgetProgram.setComputeUnitPrice({
|
|
439
469
|
microLamports: computeUnitsPrice,
|
|
@@ -443,13 +473,13 @@ export class TxHandler {
|
|
|
443
473
|
|
|
444
474
|
allIx.push(...instructionsArray);
|
|
445
475
|
|
|
446
|
-
const
|
|
447
|
-
props?.
|
|
476
|
+
const recentBlockhash =
|
|
477
|
+
props?.recentBlockhash ?? (await this.getLatestBlockhashForTransaction());
|
|
448
478
|
|
|
449
479
|
// # Create and return Transaction
|
|
450
480
|
if (txVersion === 'legacy') {
|
|
451
481
|
if (forceVersionedTransaction) {
|
|
452
|
-
return this.generateLegacyVersionedTransaction(
|
|
482
|
+
return this.generateLegacyVersionedTransaction(recentBlockhash, allIx);
|
|
453
483
|
} else {
|
|
454
484
|
return this.generateLegacyTransaction(allIx);
|
|
455
485
|
}
|
|
@@ -461,7 +491,7 @@ export class TxHandler {
|
|
|
461
491
|
: [marketLookupTable];
|
|
462
492
|
|
|
463
493
|
return this.generateVersionedTransaction(
|
|
464
|
-
|
|
494
|
+
recentBlockhash,
|
|
465
495
|
allIx,
|
|
466
496
|
lookupTables
|
|
467
497
|
);
|
|
@@ -482,7 +512,13 @@ export class TxHandler {
|
|
|
482
512
|
);
|
|
483
513
|
}
|
|
484
514
|
|
|
485
|
-
if (
|
|
515
|
+
if (process.env.DEV_TRY_FORCE_TX_TIMEOUTS || DEV_TRY_FORCE_TX_TIMEOUTS) {
|
|
516
|
+
tx.add(
|
|
517
|
+
ComputeBudgetProgram.setComputeUnitPrice({
|
|
518
|
+
microLamports: 0,
|
|
519
|
+
})
|
|
520
|
+
);
|
|
521
|
+
} else if (computeUnitsPrice != 0) {
|
|
486
522
|
tx.add(
|
|
487
523
|
ComputeBudgetProgram.setComputeUnitPrice({
|
|
488
524
|
microLamports: computeUnitsPrice,
|
|
@@ -506,18 +542,21 @@ export class TxHandler {
|
|
|
506
542
|
keys: string[],
|
|
507
543
|
wallet?: IWallet,
|
|
508
544
|
commitment?: Commitment,
|
|
509
|
-
|
|
545
|
+
recentBlockhash?: BlockhashWithExpiryBlockHeight
|
|
510
546
|
) {
|
|
511
|
-
|
|
512
|
-
?
|
|
547
|
+
recentBlockhash = recentBlockhash
|
|
548
|
+
? recentBlockhash
|
|
513
549
|
: await this.getLatestBlockhashForTransaction();
|
|
514
550
|
|
|
515
|
-
this.addHashAndExpiryToLookup(
|
|
551
|
+
this.addHashAndExpiryToLookup(recentBlockhash);
|
|
516
552
|
|
|
517
553
|
for (const tx of txsToSign) {
|
|
518
554
|
if (!tx) continue;
|
|
519
|
-
tx.recentBlockhash =
|
|
555
|
+
tx.recentBlockhash = recentBlockhash.blockhash;
|
|
520
556
|
tx.feePayer = wallet?.publicKey ?? this.wallet?.publicKey;
|
|
557
|
+
|
|
558
|
+
// @ts-ignore
|
|
559
|
+
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
521
560
|
}
|
|
522
561
|
|
|
523
562
|
return this.getSignedTransactionMap(txsToSign, keys, wallet);
|
|
@@ -536,18 +575,21 @@ export class TxHandler {
|
|
|
536
575
|
keys: string[],
|
|
537
576
|
wallet?: IWallet,
|
|
538
577
|
commitment?: Commitment,
|
|
539
|
-
|
|
578
|
+
recentBlockhash?: BlockhashWithExpiryBlockHeight
|
|
540
579
|
) {
|
|
541
|
-
|
|
542
|
-
?
|
|
580
|
+
recentBlockhash = recentBlockhash
|
|
581
|
+
? recentBlockhash
|
|
543
582
|
: await this.getLatestBlockhashForTransaction();
|
|
544
583
|
|
|
545
|
-
this.addHashAndExpiryToLookup(
|
|
584
|
+
this.addHashAndExpiryToLookup(recentBlockhash);
|
|
546
585
|
|
|
547
586
|
for (const tx of txsToSign) {
|
|
548
587
|
if (!tx) continue;
|
|
549
|
-
tx.recentBlockhash =
|
|
588
|
+
tx.recentBlockhash = recentBlockhash.blockhash;
|
|
550
589
|
tx.feePayer = wallet?.publicKey ?? this.wallet?.publicKey;
|
|
590
|
+
|
|
591
|
+
// @ts-ignore
|
|
592
|
+
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
551
593
|
}
|
|
552
594
|
|
|
553
595
|
return this.getSignedTransactionMap(txsToSign, keys, wallet);
|
|
@@ -584,13 +626,20 @@ export class TxHandler {
|
|
|
584
626
|
|
|
585
627
|
this.preSignedCb?.();
|
|
586
628
|
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
);
|
|
629
|
+
const filteredTxs = txsToSign
|
|
630
|
+
.map((tx) => {
|
|
631
|
+
return tx as Transaction;
|
|
632
|
+
})
|
|
633
|
+
.filter((tx) => tx !== undefined);
|
|
634
|
+
|
|
635
|
+
const signedTxs = await wallet.signAllTransactions(filteredTxs);
|
|
636
|
+
|
|
637
|
+
signedTxs.forEach((signedTx, index) => {
|
|
638
|
+
// @ts-ignore
|
|
639
|
+
signedTx.SIGNATURE_BLOCK_AND_EXPIRY =
|
|
640
|
+
// @ts-ignore
|
|
641
|
+
txsToSign[index]?.SIGNATURE_BLOCK_AND_EXPIRY;
|
|
642
|
+
});
|
|
594
643
|
|
|
595
644
|
this.handleSignedTxData(
|
|
596
645
|
signedTxs.map((signedTx) => {
|
|
@@ -622,15 +671,14 @@ export class TxHandler {
|
|
|
622
671
|
) {
|
|
623
672
|
const transactions = await this.buildBulkTransactions(props);
|
|
624
673
|
|
|
625
|
-
const preppedTransactions =
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
: this.getSignedTransactionMap(transactions, props.keys, props.wallet);
|
|
674
|
+
const preppedTransactions = await (props.txVersion === 'legacy'
|
|
675
|
+
? this.getPreparedAndSignedLegacyTransactionMap(
|
|
676
|
+
transactions as Transaction[],
|
|
677
|
+
props.keys,
|
|
678
|
+
props.wallet,
|
|
679
|
+
props.preFlightCommitment
|
|
680
|
+
)
|
|
681
|
+
: this.getSignedTransactionMap(transactions, props.keys, props.wallet));
|
|
634
682
|
|
|
635
683
|
return preppedTransactions;
|
|
636
684
|
}
|
|
@@ -15,6 +15,8 @@ import { IWallet } from '../types';
|
|
|
15
15
|
|
|
16
16
|
const DEFAULT_RETRY = 2000;
|
|
17
17
|
|
|
18
|
+
const VALID_BLOCK_HEIGHT_OFFSET = -150; // This is a bit of weirdness but the lastValidBlockHeight value returned from connection.getLatestBlockhash is always 300 blocks ahead of the current block, even though the transaction actually expires after 150 blocks. This accounts for that so that we can at least accuractely estimate the transaction expiry.
|
|
19
|
+
|
|
18
20
|
type ResolveReference = {
|
|
19
21
|
resolve?: () => void;
|
|
20
22
|
};
|
|
@@ -93,6 +95,13 @@ export class WhileValidTxSender extends BaseTxSender {
|
|
|
93
95
|
);
|
|
94
96
|
}
|
|
95
97
|
|
|
98
|
+
// See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
if (preSigned && tx.SIGNATURE_BLOCK_AND_EXPIRY) {
|
|
101
|
+
// @ts-ignore
|
|
102
|
+
latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
|
|
103
|
+
}
|
|
104
|
+
|
|
96
105
|
// handle subclass-specific side effects
|
|
97
106
|
const txSig = bs58.encode(
|
|
98
107
|
signedTx.signatures[0]?.signature || signedTx.signatures[0]
|
|
@@ -108,12 +117,20 @@ export class WhileValidTxSender extends BaseTxSender {
|
|
|
108
117
|
opts?: ConfirmOptions,
|
|
109
118
|
preSigned?: boolean
|
|
110
119
|
): Promise<TxSigAndSlot> {
|
|
111
|
-
|
|
120
|
+
let latestBlockhash =
|
|
112
121
|
await this.txHandler.getLatestBlockhashForTransaction();
|
|
113
122
|
|
|
114
123
|
let signedTx;
|
|
115
124
|
if (preSigned) {
|
|
116
125
|
signedTx = tx;
|
|
126
|
+
|
|
127
|
+
// See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
if (tx.SIGNATURE_BLOCK_AND_EXPIRY) {
|
|
130
|
+
// @ts-ignore
|
|
131
|
+
latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
|
|
132
|
+
}
|
|
133
|
+
|
|
117
134
|
// @ts-ignore
|
|
118
135
|
} else if (this.wallet.payer) {
|
|
119
136
|
tx.message.recentBlockhash = latestBlockhash.blockhash;
|
|
@@ -185,7 +202,8 @@ export class WhileValidTxSender extends BaseTxSender {
|
|
|
185
202
|
const result = await this.connection.confirmTransaction(
|
|
186
203
|
{
|
|
187
204
|
signature: txid,
|
|
188
|
-
lastValidBlockHeight
|
|
205
|
+
lastValidBlockHeight:
|
|
206
|
+
lastValidBlockHeight + VALID_BLOCK_HEIGHT_OFFSET,
|
|
189
207
|
blockhash,
|
|
190
208
|
},
|
|
191
209
|
opts.commitment
|
package/src/userMap/userMap.ts
CHANGED
|
@@ -29,6 +29,7 @@ import { Buffer } from 'buffer';
|
|
|
29
29
|
import { ZSTDDecoder } from 'zstddec';
|
|
30
30
|
import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
|
|
31
31
|
import {
|
|
32
|
+
SyncConfig,
|
|
32
33
|
UserAccountFilterCriteria as UserFilterCriteria,
|
|
33
34
|
UserMapConfig,
|
|
34
35
|
} from './userMapConfig';
|
|
@@ -83,6 +84,7 @@ export class UserMap implements UserMapInterface {
|
|
|
83
84
|
};
|
|
84
85
|
private decode;
|
|
85
86
|
private mostRecentSlot = 0;
|
|
87
|
+
private syncConfig: SyncConfig;
|
|
86
88
|
|
|
87
89
|
private syncPromise?: Promise<void>;
|
|
88
90
|
private syncPromiseResolver: () => void;
|
|
@@ -132,6 +134,10 @@ export class UserMap implements UserMapInterface {
|
|
|
132
134
|
decodeFn,
|
|
133
135
|
});
|
|
134
136
|
}
|
|
137
|
+
|
|
138
|
+
this.syncConfig = config.syncConfig ?? {
|
|
139
|
+
type: 'default',
|
|
140
|
+
};
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
public async subscribe() {
|
|
@@ -345,6 +351,14 @@ export class UserMap implements UserMapInterface {
|
|
|
345
351
|
}
|
|
346
352
|
|
|
347
353
|
public async sync() {
|
|
354
|
+
if (this.syncConfig.type === 'default') {
|
|
355
|
+
return this.defaultSync();
|
|
356
|
+
} else {
|
|
357
|
+
return this.paginatedSync();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
private async defaultSync() {
|
|
348
362
|
if (this.syncPromise) {
|
|
349
363
|
return this.syncPromise;
|
|
350
364
|
}
|
|
@@ -438,6 +452,123 @@ export class UserMap implements UserMapInterface {
|
|
|
438
452
|
}
|
|
439
453
|
}
|
|
440
454
|
|
|
455
|
+
private async paginatedSync() {
|
|
456
|
+
if (this.syncPromise) {
|
|
457
|
+
return this.syncPromise;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
this.syncPromise = new Promise<void>((resolve) => {
|
|
461
|
+
this.syncPromiseResolver = resolve;
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
const accountsPrefetch = await this.connection.getProgramAccounts(
|
|
466
|
+
this.driftClient.program.programId,
|
|
467
|
+
{
|
|
468
|
+
dataSlice: { offset: 0, length: 0 },
|
|
469
|
+
filters: [
|
|
470
|
+
getUserFilter(),
|
|
471
|
+
...(!this.includeIdle ? [getNonIdleUserFilter()] : []),
|
|
472
|
+
],
|
|
473
|
+
}
|
|
474
|
+
);
|
|
475
|
+
const accountPublicKeys = accountsPrefetch.map(
|
|
476
|
+
(account) => account.pubkey
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
const limitConcurrency = async (tasks, limit) => {
|
|
480
|
+
const executing = [];
|
|
481
|
+
const results = [];
|
|
482
|
+
|
|
483
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
484
|
+
const executor = Promise.resolve().then(tasks[i]);
|
|
485
|
+
results.push(executor);
|
|
486
|
+
|
|
487
|
+
if (executing.length < limit) {
|
|
488
|
+
executing.push(executor);
|
|
489
|
+
executor.finally(() => {
|
|
490
|
+
const index = executing.indexOf(executor);
|
|
491
|
+
if (index > -1) {
|
|
492
|
+
executing.splice(index, 1);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
} else {
|
|
496
|
+
await Promise.race(executing);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return Promise.all(results);
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
const programAccountBufferMap = new Map<string, Buffer>();
|
|
504
|
+
|
|
505
|
+
// @ts-ignore
|
|
506
|
+
const chunkSize = this.syncConfig.chunkSize ?? 100;
|
|
507
|
+
const tasks = [];
|
|
508
|
+
for (let i = 0; i < accountPublicKeys.length; i += chunkSize) {
|
|
509
|
+
const chunk = accountPublicKeys.slice(i, i + chunkSize);
|
|
510
|
+
tasks.push(async () => {
|
|
511
|
+
const accountInfos =
|
|
512
|
+
await this.connection.getMultipleAccountsInfoAndContext(chunk, {
|
|
513
|
+
commitment: this.commitment,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
const accountInfosSlot = accountInfos.context.slot;
|
|
517
|
+
|
|
518
|
+
for (let j = 0; j < accountInfos.value.length; j += 1) {
|
|
519
|
+
const accountInfo = accountInfos.value[j];
|
|
520
|
+
if (accountInfo === null) continue;
|
|
521
|
+
|
|
522
|
+
const publicKeyString = chunk[j].toString();
|
|
523
|
+
const buffer = Buffer.from(accountInfo.data);
|
|
524
|
+
programAccountBufferMap.set(publicKeyString, buffer);
|
|
525
|
+
|
|
526
|
+
const decodedUser = this.decode('User', buffer);
|
|
527
|
+
|
|
528
|
+
const currAccountWithSlot = this.getWithSlot(publicKeyString);
|
|
529
|
+
if (
|
|
530
|
+
currAccountWithSlot &&
|
|
531
|
+
currAccountWithSlot.slot <= accountInfosSlot
|
|
532
|
+
) {
|
|
533
|
+
this.updateUserAccount(
|
|
534
|
+
publicKeyString,
|
|
535
|
+
decodedUser,
|
|
536
|
+
accountInfosSlot
|
|
537
|
+
);
|
|
538
|
+
} else {
|
|
539
|
+
await this.addPubkey(
|
|
540
|
+
new PublicKey(publicKeyString),
|
|
541
|
+
decodedUser,
|
|
542
|
+
accountInfosSlot
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// @ts-ignore
|
|
550
|
+
const concurrencyLimit = this.syncConfig.concurrencyLimit ?? 10;
|
|
551
|
+
await limitConcurrency(tasks, concurrencyLimit);
|
|
552
|
+
|
|
553
|
+
for (const [key] of this.entries()) {
|
|
554
|
+
if (!programAccountBufferMap.has(key)) {
|
|
555
|
+
const user = this.get(key);
|
|
556
|
+
if (user) {
|
|
557
|
+
await user.unsubscribe();
|
|
558
|
+
this.userMap.delete(key);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
} catch (err) {
|
|
563
|
+
console.error(`Error in UserMap.sync():`, err);
|
|
564
|
+
} finally {
|
|
565
|
+
if (this.syncPromiseResolver) {
|
|
566
|
+
this.syncPromiseResolver();
|
|
567
|
+
}
|
|
568
|
+
this.syncPromise = undefined;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
441
572
|
public async unsubscribe() {
|
|
442
573
|
await this.subscription.unsubscribe();
|
|
443
574
|
|
|
@@ -7,6 +7,16 @@ export type UserAccountFilterCriteria = {
|
|
|
7
7
|
hasOpenOrders: boolean;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
export type SyncConfig =
|
|
11
|
+
| {
|
|
12
|
+
type: 'default';
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
type: 'paginated';
|
|
16
|
+
chunkSize?: number;
|
|
17
|
+
concurrencyLimit?: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
10
20
|
export type UserMapConfig = {
|
|
11
21
|
driftClient: DriftClient;
|
|
12
22
|
// connection object to use specifically for the UserMap. If undefined, will use the driftClient's connection
|
|
@@ -36,4 +46,6 @@ export type UserMapConfig = {
|
|
|
36
46
|
// If true, will not do a full sync whenever StateAccount.numberOfSubAccounts changes.
|
|
37
47
|
// default behavior is to do a full sync on changes.
|
|
38
48
|
disableSyncOnTotalAccountsChange?: boolean;
|
|
49
|
+
|
|
50
|
+
syncConfig?: SyncConfig;
|
|
39
51
|
};
|