@drift-labs/sdk 2.21.0-beta.1 → 2.21.0-beta.2

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.
@@ -14,9 +14,8 @@ export declare class PollingUserAccountSubscriber implements UserAccountSubscrib
14
14
  accountLoader: BulkAccountLoader;
15
15
  accountsToPoll: Map<string, AccountToPoll>;
16
16
  errorCallbackId?: string;
17
- lazyDecode: boolean;
18
17
  user?: DataAndSlot<UserAccount>;
19
- constructor(program: Program, userAccountPublicKey: PublicKey, accountLoader: BulkAccountLoader, lazyDecode?: boolean);
18
+ constructor(program: Program, userAccountPublicKey: PublicKey, accountLoader: BulkAccountLoader);
20
19
  subscribe(): Promise<boolean>;
21
20
  addToAccountLoader(): Promise<void>;
22
21
  fetchIfUnloaded(): Promise<void>;
@@ -5,14 +5,13 @@ const types_1 = require("./types");
5
5
  const events_1 = require("events");
6
6
  const utils_1 = require("./utils");
7
7
  class PollingUserAccountSubscriber {
8
- constructor(program, userAccountPublicKey, accountLoader, lazyDecode = false) {
8
+ constructor(program, userAccountPublicKey, accountLoader) {
9
9
  this.accountsToPoll = new Map();
10
10
  this.isSubscribed = false;
11
11
  this.program = program;
12
12
  this.accountLoader = accountLoader;
13
13
  this.eventEmitter = new events_1.EventEmitter();
14
14
  this.userAccountPublicKey = userAccountPublicKey;
15
- this.lazyDecode = lazyDecode;
16
15
  }
17
16
  async subscribe() {
18
17
  if (this.isSubscribed) {
@@ -41,9 +40,7 @@ class PollingUserAccountSubscriber {
41
40
  return;
42
41
  }
43
42
  const account = this.program.account[accountToPoll.key].coder.accounts.decode((0, utils_1.capitalize)(accountToPoll.key), buffer);
44
- if (!this.lazyDecode) {
45
- this[accountToPoll.key] = { data: account, slot };
46
- }
43
+ this[accountToPoll.key] = { data: account, slot };
47
44
  // @ts-ignore
48
45
  this.eventEmitter.emit(accountToPoll.eventType, account);
49
46
  this.eventEmitter.emit('update');
@@ -56,12 +53,7 @@ class PollingUserAccountSubscriber {
56
53
  async fetchIfUnloaded() {
57
54
  let shouldFetch = false;
58
55
  for (const [_, accountToPoll] of this.accountsToPoll) {
59
- if (!this.lazyDecode && this[accountToPoll.key] === undefined) {
60
- shouldFetch = true;
61
- break;
62
- }
63
- else if (this.lazyDecode &&
64
- this.accountLoader.bufferAndSlotMap.has(accountToPoll.publicKey.toString())) {
56
+ if (this[accountToPoll.key] === undefined) {
65
57
  shouldFetch = true;
66
58
  break;
67
59
  }
@@ -74,7 +66,7 @@ class PollingUserAccountSubscriber {
74
66
  await this.accountLoader.load();
75
67
  for (const [_, accountToPoll] of this.accountsToPoll) {
76
68
  const { buffer, slot } = this.accountLoader.getBufferAndSlot(accountToPoll.publicKey);
77
- if (buffer && !this.lazyDecode) {
69
+ if (buffer) {
78
70
  const account = this.program.account[accountToPoll.key].coder.accounts.decode((0, utils_1.capitalize)(accountToPoll.key), buffer);
79
71
  this[accountToPoll.key] = { data: account, slot };
80
72
  }
@@ -83,7 +75,7 @@ class PollingUserAccountSubscriber {
83
75
  doAccountsExist() {
84
76
  let success = true;
85
77
  for (const [_, accountToPoll] of this.accountsToPoll) {
86
- if (!this.accountLoader.bufferAndSlotMap.has(accountToPoll.publicKey.toString())) {
78
+ if (!this[accountToPoll.key]) {
87
79
  success = false;
88
80
  break;
89
81
  }
@@ -109,14 +101,7 @@ class PollingUserAccountSubscriber {
109
101
  }
110
102
  getUserAccountAndSlot() {
111
103
  this.assertIsSubscribed();
112
- if (!this.lazyDecode) {
113
- return this.user;
114
- }
115
- else {
116
- const { buffer, slot } = this.accountLoader.getBufferAndSlot(this.userAccountPublicKey);
117
- const account = this.program.account.user.coder.accounts.decode('User', buffer);
118
- return { data: account, slot };
119
- }
104
+ return this.user;
120
105
  }
121
106
  }
122
107
  exports.PollingUserAccountSubscriber = PollingUserAccountSubscriber;
package/lib/dlob/DLOB.js CHANGED
@@ -633,8 +633,10 @@ class DLOB {
633
633
  * @returns
634
634
  */
635
635
  *getMakerLimitAsks(marketIndex, slot, marketType, oraclePriceData, fallbackBid) {
636
+ const isPerpMarket = (0, __1.isVariant)(marketType, 'perp');
636
637
  for (const node of this.getRestingLimitAsks(marketIndex, slot, marketType, oraclePriceData)) {
637
- if (fallbackBid &&
638
+ if (isPerpMarket &&
639
+ fallbackBid &&
638
640
  node.getPrice(oraclePriceData, slot).lte(fallbackBid)) {
639
641
  continue;
640
642
  }
@@ -668,8 +670,10 @@ class DLOB {
668
670
  * @returns
669
671
  */
670
672
  *getMakerLimitBids(marketIndex, slot, marketType, oraclePriceData, fallbackAsk) {
673
+ const isPerpMarket = (0, __1.isVariant)(marketType, 'perp');
671
674
  for (const node of this.getRestingLimitBids(marketIndex, slot, marketType, oraclePriceData)) {
672
- if (fallbackAsk &&
675
+ if (isPerpMarket &&
676
+ fallbackAsk &&
673
677
  node.getPrice(oraclePriceData, slot).gte(fallbackAsk)) {
674
678
  continue;
675
679
  }
@@ -145,7 +145,7 @@ export declare class DriftClient {
145
145
  * @param fromSubAccountId
146
146
  * @returns
147
147
  */
148
- initializeUserAccountAndDepositCollateral(amount: BN, userTokenAccount: PublicKey, marketIndex?: number, subAccountId?: number, name?: string, fromSubAccountId?: number, referrerInfo?: ReferrerInfo): Promise<[TransactionSignature, PublicKey]>;
148
+ initializeUserAccountAndDepositCollateral(amount: BN, userTokenAccount: PublicKey, marketIndex?: number, subAccountId?: number, name?: string, fromSubAccountId?: number, referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<[TransactionSignature, PublicKey]>;
149
149
  initializeUserAccountForDevnet(subAccountId: number, name: string, marketIndex: number, tokenFaucet: TokenFaucet, amount: BN, referrerInfo?: ReferrerInfo): Promise<[TransactionSignature, PublicKey]>;
150
150
  withdraw(amount: BN, marketIndex: number, userTokenAccount: PublicKey, reduceOnly?: boolean): Promise<TransactionSignature>;
151
151
  getWithdrawIx(amount: BN, marketIndex: number, userTokenAccount: PublicKey, reduceOnly?: boolean): Promise<TransactionInstruction>;
@@ -79,7 +79,6 @@ class DriftClient {
79
79
  ? {
80
80
  type: 'polling',
81
81
  accountLoader: config.accountSubscription.accountLoader,
82
- lazyDecode: config.accountSubscription.lazyDecode,
83
82
  }
84
83
  : {
85
84
  type: 'websocket',
@@ -821,12 +820,21 @@ class DriftClient {
821
820
  * @param fromSubAccountId
822
821
  * @returns
823
822
  */
824
- async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, marketIndex = 0, subAccountId = 0, name = userName_1.DEFAULT_USER_NAME, fromSubAccountId, referrerInfo) {
823
+ async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, marketIndex = 0, subAccountId = 0, name = userName_1.DEFAULT_USER_NAME, fromSubAccountId, referrerInfo, txParams) {
824
+ var _a;
825
825
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(subAccountId, name, referrerInfo);
826
826
  const additionalSigners = [];
827
827
  const spotMarket = this.getSpotMarketAccount(marketIndex);
828
828
  const isSolMarket = spotMarket.mint.equals(spotMarkets_1.WRAPPED_SOL_MINT);
829
829
  const tx = new web3_js_1.Transaction();
830
+ tx.add(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
831
+ units: (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a : 600000,
832
+ }));
833
+ if (txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice) {
834
+ tx.add(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
835
+ microLamports: txParams.computeUnitsPrice,
836
+ }));
837
+ }
830
838
  const authority = this.wallet.publicKey;
831
839
  const createWSOLTokenAccount = isSolMarket && userTokenAccount.equals(authority);
832
840
  if (createWSOLTokenAccount) {
@@ -25,7 +25,6 @@ export type DriftClientSubscriptionConfig = {
25
25
  } | {
26
26
  type: 'polling';
27
27
  accountLoader: BulkAccountLoader;
28
- lazyDecode?: boolean;
29
28
  };
30
29
  type TxSenderConfig = {
31
30
  type: 'retry';
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.21.0-beta.1",
2
+ "version": "2.21.0-beta.2",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/lib/user.js CHANGED
@@ -25,7 +25,7 @@ class User {
25
25
  this.driftClient = config.driftClient;
26
26
  this.userAccountPublicKey = config.userAccountPublicKey;
27
27
  if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
28
- this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey, config.accountSubscription.accountLoader, config.accountSubscription.lazyDecode);
28
+ this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
29
29
  }
30
30
  else {
31
31
  this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey);
@@ -11,5 +11,4 @@ export type UserSubscriptionConfig = {
11
11
  } | {
12
12
  type: 'polling';
13
13
  accountLoader: BulkAccountLoader;
14
- lazyDecode?: boolean;
15
14
  };
@@ -40,4 +40,5 @@ export declare class UserMap implements UserMapInterface {
40
40
  updateWithEventRecord(record: WrappedEvent<any>): Promise<void>;
41
41
  values(): IterableIterator<User>;
42
42
  size(): number;
43
+ sync(includeIdle?: boolean): Promise<void>;
43
44
  }
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.UserMap = void 0;
4
7
  const __1 = require("..");
5
8
  const web3_js_1 = require("@solana/web3.js");
9
+ const bs58_1 = __importDefault(require("bs58"));
6
10
  class UserMap {
7
11
  constructor(driftClient, accountSubscription) {
8
12
  this.userMap = new Map();
@@ -131,5 +135,42 @@ class UserMap {
131
135
  size() {
132
136
  return this.userMap.size;
133
137
  }
138
+ async sync(includeIdle = true) {
139
+ let filters = undefined;
140
+ if (!includeIdle) {
141
+ filters = [
142
+ {
143
+ memcmp: {
144
+ offset: 4350,
145
+ bytes: bs58_1.default.encode(Uint8Array.from([0])),
146
+ },
147
+ },
148
+ ];
149
+ }
150
+ const programAccounts = await this.driftClient.connection.getProgramAccounts(this.driftClient.program.programId, {
151
+ commitment: this.driftClient.connection.commitment,
152
+ filters: [
153
+ {
154
+ memcmp: this.driftClient.program.coder.accounts.memcmp('User'),
155
+ },
156
+ ...(Array.isArray(filters) ? filters : []),
157
+ ],
158
+ });
159
+ const programAccountMap = new Map();
160
+ for (const programAccount of programAccounts) {
161
+ programAccountMap.set(programAccount.pubkey.toString(), programAccount.account);
162
+ }
163
+ for (const key of programAccountMap.keys()) {
164
+ if (!this.has(key)) {
165
+ await this.addPubkey(new web3_js_1.PublicKey(key));
166
+ }
167
+ }
168
+ for (const [key, user] of this.userMap.entries()) {
169
+ if (!programAccountMap.has(key)) {
170
+ await user.unsubscribe();
171
+ this.userMap.delete(key);
172
+ }
173
+ }
174
+ }
134
175
  }
135
176
  exports.UserMap = UserMap;
@@ -18,4 +18,5 @@ export declare class UserStatsMap {
18
18
  mustGet(authorityPublicKey: string): Promise<UserStats>;
19
19
  values(): IterableIterator<UserStats>;
20
20
  size(): number;
21
+ sync(): Promise<void>;
21
22
  }
@@ -137,5 +137,24 @@ class UserStatsMap {
137
137
  size() {
138
138
  return this.userStatsMap.size;
139
139
  }
140
+ async sync() {
141
+ const programAccounts = await this.driftClient.connection.getProgramAccounts(this.driftClient.program.programId, {
142
+ commitment: this.driftClient.connection.commitment,
143
+ filters: [
144
+ {
145
+ memcmp: this.driftClient.program.coder.accounts.memcmp('UserStats'),
146
+ },
147
+ ],
148
+ });
149
+ const programAccountMap = new Map();
150
+ for (const programAccount of programAccounts) {
151
+ programAccountMap.set(new web3_js_1.PublicKey(programAccount.account.data.slice(8, 40)).toString(), programAccount.account);
152
+ }
153
+ for (const key of programAccountMap.keys()) {
154
+ if (!this.has(key)) {
155
+ await this.addUserStat(new web3_js_1.PublicKey(key));
156
+ }
157
+ }
158
+ }
140
159
  }
141
160
  exports.UserStatsMap = UserStatsMap;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.21.0-beta.1",
3
+ "version": "2.21.0-beta.2",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -23,22 +23,18 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
23
23
  accountsToPoll = new Map<string, AccountToPoll>();
24
24
  errorCallbackId?: string;
25
25
 
26
- lazyDecode: boolean;
27
-
28
26
  user?: DataAndSlot<UserAccount>;
29
27
 
30
28
  public constructor(
31
29
  program: Program,
32
30
  userAccountPublicKey: PublicKey,
33
- accountLoader: BulkAccountLoader,
34
- lazyDecode = false
31
+ accountLoader: BulkAccountLoader
35
32
  ) {
36
33
  this.isSubscribed = false;
37
34
  this.program = program;
38
35
  this.accountLoader = accountLoader;
39
36
  this.eventEmitter = new EventEmitter();
40
37
  this.userAccountPublicKey = userAccountPublicKey;
41
- this.lazyDecode = lazyDecode;
42
38
  }
43
39
 
44
40
  async subscribe(): Promise<boolean> {
@@ -79,9 +75,7 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
79
75
  const account = this.program.account[
80
76
  accountToPoll.key
81
77
  ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
82
- if (!this.lazyDecode) {
83
- this[accountToPoll.key] = { data: account, slot };
84
- }
78
+ this[accountToPoll.key] = { data: account, slot };
85
79
  // @ts-ignore
86
80
  this.eventEmitter.emit(accountToPoll.eventType, account);
87
81
  this.eventEmitter.emit('update');
@@ -97,15 +91,7 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
97
91
  async fetchIfUnloaded(): Promise<void> {
98
92
  let shouldFetch = false;
99
93
  for (const [_, accountToPoll] of this.accountsToPoll) {
100
- if (!this.lazyDecode && this[accountToPoll.key] === undefined) {
101
- shouldFetch = true;
102
- break;
103
- } else if (
104
- this.lazyDecode &&
105
- this.accountLoader.bufferAndSlotMap.has(
106
- accountToPoll.publicKey.toString()
107
- )
108
- ) {
94
+ if (this[accountToPoll.key] === undefined) {
109
95
  shouldFetch = true;
110
96
  break;
111
97
  }
@@ -122,7 +108,7 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
122
108
  const { buffer, slot } = this.accountLoader.getBufferAndSlot(
123
109
  accountToPoll.publicKey
124
110
  );
125
- if (buffer && !this.lazyDecode) {
111
+ if (buffer) {
126
112
  const account = this.program.account[
127
113
  accountToPoll.key
128
114
  ].coder.accounts.decode(capitalize(accountToPoll.key), buffer);
@@ -134,11 +120,7 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
134
120
  doAccountsExist(): boolean {
135
121
  let success = true;
136
122
  for (const [_, accountToPoll] of this.accountsToPoll) {
137
- if (
138
- !this.accountLoader.bufferAndSlotMap.has(
139
- accountToPoll.publicKey.toString()
140
- )
141
- ) {
123
+ if (!this[accountToPoll.key]) {
142
124
  success = false;
143
125
  break;
144
126
  }
@@ -176,17 +158,6 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
176
158
 
177
159
  public getUserAccountAndSlot(): DataAndSlot<UserAccount> {
178
160
  this.assertIsSubscribed();
179
- if (!this.lazyDecode) {
180
- return this.user;
181
- } else {
182
- const { buffer, slot } = this.accountLoader.getBufferAndSlot(
183
- this.userAccountPublicKey
184
- );
185
- const account = this.program.account.user.coder.accounts.decode(
186
- 'User',
187
- buffer
188
- );
189
- return { data: account, slot };
190
- }
161
+ return this.user;
191
162
  }
192
163
  }
package/src/dlob/DLOB.ts CHANGED
@@ -1148,6 +1148,7 @@ export class DLOB {
1148
1148
  oraclePriceData: OraclePriceData,
1149
1149
  fallbackBid?: BN
1150
1150
  ): Generator<DLOBNode> {
1151
+ const isPerpMarket = isVariant(marketType, 'perp');
1151
1152
  for (const node of this.getRestingLimitAsks(
1152
1153
  marketIndex,
1153
1154
  slot,
@@ -1155,6 +1156,7 @@ export class DLOB {
1155
1156
  oraclePriceData
1156
1157
  )) {
1157
1158
  if (
1159
+ isPerpMarket &&
1158
1160
  fallbackBid &&
1159
1161
  node.getPrice(oraclePriceData, slot).lte(fallbackBid)
1160
1162
  ) {
@@ -1213,6 +1215,7 @@ export class DLOB {
1213
1215
  oraclePriceData: OraclePriceData,
1214
1216
  fallbackAsk?: BN
1215
1217
  ): Generator<DLOBNode> {
1218
+ const isPerpMarket = isVariant(marketType, 'perp');
1216
1219
  for (const node of this.getRestingLimitBids(
1217
1220
  marketIndex,
1218
1221
  slot,
@@ -1220,6 +1223,7 @@ export class DLOB {
1220
1223
  oraclePriceData
1221
1224
  )) {
1222
1225
  if (
1226
+ isPerpMarket &&
1223
1227
  fallbackAsk &&
1224
1228
  node.getPrice(oraclePriceData, slot).gte(fallbackAsk)
1225
1229
  ) {
@@ -160,7 +160,6 @@ export class DriftClient {
160
160
  ? {
161
161
  type: 'polling',
162
162
  accountLoader: config.accountSubscription.accountLoader,
163
- lazyDecode: config.accountSubscription.lazyDecode,
164
163
  }
165
164
  : {
166
165
  type: 'websocket',
@@ -1330,7 +1329,8 @@ export class DriftClient {
1330
1329
  subAccountId = 0,
1331
1330
  name = DEFAULT_USER_NAME,
1332
1331
  fromSubAccountId?: number,
1333
- referrerInfo?: ReferrerInfo
1332
+ referrerInfo?: ReferrerInfo,
1333
+ txParams?: TxParams
1334
1334
  ): Promise<[TransactionSignature, PublicKey]> {
1335
1335
  const [userAccountPublicKey, initializeUserAccountIx] =
1336
1336
  await this.getInitializeUserInstructions(
@@ -1347,6 +1347,20 @@ export class DriftClient {
1347
1347
 
1348
1348
  const tx = new Transaction();
1349
1349
 
1350
+ tx.add(
1351
+ ComputeBudgetProgram.setComputeUnitLimit({
1352
+ units: txParams?.computeUnits ?? 600_000,
1353
+ })
1354
+ );
1355
+
1356
+ if (txParams?.computeUnitsPrice) {
1357
+ tx.add(
1358
+ ComputeBudgetProgram.setComputeUnitPrice({
1359
+ microLamports: txParams.computeUnitsPrice,
1360
+ })
1361
+ );
1362
+ }
1363
+
1350
1364
  const authority = this.wallet.publicKey;
1351
1365
 
1352
1366
  const createWSOLTokenAccount =
@@ -29,7 +29,6 @@ export type DriftClientSubscriptionConfig =
29
29
  | {
30
30
  type: 'polling';
31
31
  accountLoader: BulkAccountLoader;
32
- lazyDecode?: boolean;
33
32
  };
34
33
 
35
34
  type TxSenderConfig = {
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.21.0-beta.1",
2
+ "version": "2.21.0-beta.2",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/src/user.ts CHANGED
@@ -95,8 +95,7 @@ export class User {
95
95
  this.accountSubscriber = new PollingUserAccountSubscriber(
96
96
  config.driftClient.program,
97
97
  config.userAccountPublicKey,
98
- config.accountSubscription.accountLoader,
99
- config.accountSubscription.lazyDecode
98
+ config.accountSubscription.accountLoader
100
99
  );
101
100
  } else {
102
101
  this.accountSubscriber = new WebSocketUserAccountSubscriber(
package/src/userConfig.ts CHANGED
@@ -15,5 +15,4 @@ export type UserSubscriptionConfig =
15
15
  | {
16
16
  type: 'polling';
17
17
  accountLoader: BulkAccountLoader;
18
- lazyDecode?: boolean;
19
18
  };
@@ -15,7 +15,9 @@ import {
15
15
  LPRecord,
16
16
  } from '..';
17
17
 
18
- import { PublicKey } from '@solana/web3.js';
18
+ import { AccountInfo, PublicKey } from '@solana/web3.js';
19
+ import { Buffer } from 'buffer';
20
+ import bs58 from 'bs58';
19
21
 
20
22
  export interface UserMapInterface {
21
23
  fetchAllUsers(): Promise<void>;
@@ -177,4 +179,53 @@ export class UserMap implements UserMapInterface {
177
179
  public size(): number {
178
180
  return this.userMap.size;
179
181
  }
182
+
183
+ public async sync(includeIdle = true) {
184
+ let filters = undefined;
185
+ if (!includeIdle) {
186
+ filters = [
187
+ {
188
+ memcmp: {
189
+ offset: 4350,
190
+ bytes: bs58.encode(Uint8Array.from([0])),
191
+ },
192
+ },
193
+ ];
194
+ }
195
+
196
+ const programAccounts =
197
+ await this.driftClient.connection.getProgramAccounts(
198
+ this.driftClient.program.programId,
199
+ {
200
+ commitment: this.driftClient.connection.commitment,
201
+ filters: [
202
+ {
203
+ memcmp: this.driftClient.program.coder.accounts.memcmp('User'),
204
+ },
205
+ ...(Array.isArray(filters) ? filters : []),
206
+ ],
207
+ }
208
+ );
209
+
210
+ const programAccountMap = new Map<string, AccountInfo<Buffer>>();
211
+ for (const programAccount of programAccounts) {
212
+ programAccountMap.set(
213
+ programAccount.pubkey.toString(),
214
+ programAccount.account
215
+ );
216
+ }
217
+
218
+ for (const key of programAccountMap.keys()) {
219
+ if (!this.has(key)) {
220
+ await this.addPubkey(new PublicKey(key));
221
+ }
222
+ }
223
+
224
+ for (const [key, user] of this.userMap.entries()) {
225
+ if (!programAccountMap.has(key)) {
226
+ await user.unsubscribe();
227
+ this.userMap.delete(key);
228
+ }
229
+ }
230
+ }
180
231
  }
@@ -17,9 +17,10 @@ import {
17
17
  InsuranceFundStakeRecord,
18
18
  } from '..';
19
19
  import { ProgramAccount } from '@project-serum/anchor';
20
- import { PublicKey } from '@solana/web3.js';
20
+ import { AccountInfo, PublicKey } from '@solana/web3.js';
21
21
 
22
22
  import { UserMap } from './userMap';
23
+ import { Buffer } from 'buffer';
23
24
 
24
25
  export class UserStatsMap {
25
26
  /**
@@ -190,4 +191,34 @@ export class UserStatsMap {
190
191
  public size(): number {
191
192
  return this.userStatsMap.size;
192
193
  }
194
+
195
+ public async sync() {
196
+ const programAccounts =
197
+ await this.driftClient.connection.getProgramAccounts(
198
+ this.driftClient.program.programId,
199
+ {
200
+ commitment: this.driftClient.connection.commitment,
201
+ filters: [
202
+ {
203
+ memcmp:
204
+ this.driftClient.program.coder.accounts.memcmp('UserStats'),
205
+ },
206
+ ],
207
+ }
208
+ );
209
+
210
+ const programAccountMap = new Map<string, AccountInfo<Buffer>>();
211
+ for (const programAccount of programAccounts) {
212
+ programAccountMap.set(
213
+ new PublicKey(programAccount.account.data.slice(8, 40)).toString(),
214
+ programAccount.account
215
+ );
216
+ }
217
+
218
+ for (const key of programAccountMap.keys()) {
219
+ if (!this.has(key)) {
220
+ await this.addUserStat(new PublicKey(key));
221
+ }
222
+ }
223
+ }
193
224
  }