@drift-labs/sdk 2.48.0-beta.2 → 2.48.0-beta.20

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 (50) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/bulkAccountLoader.js +1 -1
  3. package/lib/accounts/pollingUserAccountSubscriber.js +14 -7
  4. package/lib/accounts/pollingUserStatsAccountSubscriber.js +14 -7
  5. package/lib/accounts/webSocketAccountSubscriber.js +1 -1
  6. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +3 -2
  7. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +6 -5
  8. package/lib/accounts/webSocketProgramAccountSubscriber.js +1 -1
  9. package/lib/accounts/webSocketUserAccountSubscriber.js +1 -1
  10. package/lib/constants/spotMarkets.js +10 -0
  11. package/lib/dlob/orderBookLevels.js +1 -1
  12. package/lib/driftClient.js +4 -4
  13. package/lib/events/eventSubscriber.js +1 -1
  14. package/lib/events/types.d.ts +1 -0
  15. package/lib/events/webSocketLogProvider.d.ts +7 -1
  16. package/lib/events/webSocketLogProvider.js +45 -4
  17. package/lib/orderSubscriber/OrderSubscriber.d.ts +5 -1
  18. package/lib/orderSubscriber/OrderSubscriber.js +24 -7
  19. package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -1
  20. package/lib/orderSubscriber/WebsocketSubscription.js +4 -3
  21. package/lib/orderSubscriber/types.d.ts +3 -1
  22. package/lib/slot/SlotSubscriber.js +4 -2
  23. package/lib/user.js +3 -3
  24. package/lib/userMap/userMap.d.ts +16 -4
  25. package/lib/userMap/userMap.js +83 -41
  26. package/lib/userMap/userStatsMap.d.ts +29 -8
  27. package/lib/userMap/userStatsMap.js +46 -41
  28. package/package.json +1 -1
  29. package/src/accounts/bulkAccountLoader.ts +1 -1
  30. package/src/accounts/pollingUserAccountSubscriber.ts +19 -11
  31. package/src/accounts/pollingUserStatsAccountSubscriber.ts +20 -12
  32. package/src/accounts/webSocketAccountSubscriber.ts +1 -1
  33. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +13 -6
  34. package/src/accounts/webSocketProgramAccountSubscriber.ts +1 -1
  35. package/src/accounts/webSocketUserAccountSubscriber.ts +1 -1
  36. package/src/constants/spotMarkets.ts +10 -0
  37. package/src/dlob/orderBookLevels.ts +1 -1
  38. package/src/driftClient.ts +3 -2
  39. package/src/events/eventSubscriber.ts +2 -1
  40. package/src/events/types.ts +1 -0
  41. package/src/events/webSocketLogProvider.ts +51 -4
  42. package/src/orderSubscriber/OrderSubscriber.ts +39 -15
  43. package/src/orderSubscriber/WebsocketSubscription.ts +7 -2
  44. package/src/orderSubscriber/types.ts +3 -1
  45. package/src/slot/SlotSubscriber.ts +4 -2
  46. package/src/user.ts +3 -3
  47. package/src/userMap/userMap.ts +139 -66
  48. package/src/userMap/userStatsMap.ts +64 -69
  49. package/tests/amm/test.ts +3 -2
  50. package/tests/dlob/test.ts +8 -5
@@ -4,7 +4,6 @@ import {
4
4
  OrderRecord,
5
5
  UserStatsAccount,
6
6
  UserStats,
7
- UserStatsSubscriptionConfig,
8
7
  WrappedEvent,
9
8
  DepositRecord,
10
9
  FundingPaymentRecord,
@@ -14,12 +13,12 @@ import {
14
13
  NewUserRecord,
15
14
  LPRecord,
16
15
  InsuranceFundStakeRecord,
17
- StateAccount,
16
+ BulkAccountLoader,
17
+ PollingUserStatsAccountSubscriber,
18
18
  } from '..';
19
- import { AccountInfo, PublicKey } from '@solana/web3.js';
19
+ import { PublicKey } from '@solana/web3.js';
20
20
 
21
21
  import { UserMap } from './userMap';
22
- import { Buffer } from 'buffer';
23
22
 
24
23
  export class UserStatsMap {
25
24
  /**
@@ -27,39 +26,45 @@ export class UserStatsMap {
27
26
  */
28
27
  private userStatsMap = new Map<string, UserStats>();
29
28
  private driftClient: DriftClient;
30
- private accountSubscription: UserStatsSubscriptionConfig;
31
- private lastNumberOfAuthorities;
32
- private syncCallback = async (state: StateAccount) => {
33
- if (state.numberOfAuthorities !== this.lastNumberOfAuthorities) {
34
- await this.sync();
35
- this.lastNumberOfAuthorities = state.numberOfAuthorities;
36
- }
37
- };
29
+ private bulkAccountLoader: BulkAccountLoader;
38
30
 
39
- constructor(
40
- driftClient: DriftClient,
41
- accountSubscription: UserStatsSubscriptionConfig
42
- ) {
31
+ /**
32
+ * Creates a new UserStatsMap instance.
33
+ *
34
+ * @param {DriftClient} driftClient - The DriftClient instance.
35
+ * @param {BulkAccountLoader} [bulkAccountLoader] - If not provided, a new BulkAccountLoader with polling disabled will be created.
36
+ */
37
+ constructor(driftClient: DriftClient, bulkAccountLoader?: BulkAccountLoader) {
43
38
  this.driftClient = driftClient;
44
- this.accountSubscription = accountSubscription;
39
+ if (!bulkAccountLoader) {
40
+ bulkAccountLoader = new BulkAccountLoader(
41
+ driftClient.connection,
42
+ driftClient.opts.commitment,
43
+ 0
44
+ );
45
+ }
46
+ this.bulkAccountLoader = bulkAccountLoader;
45
47
  }
46
48
 
47
- public async subscribe() {
49
+ public async subscribe(authorities: PublicKey[]) {
48
50
  if (this.size() > 0) {
49
51
  return;
50
52
  }
51
53
 
52
54
  await this.driftClient.subscribe();
53
- this.lastNumberOfAuthorities =
54
- this.driftClient.getStateAccount().numberOfAuthorities;
55
- this.driftClient.eventEmitter.on('stateAccountUpdate', this.syncCallback);
56
-
57
- await this.sync();
55
+ await this.sync(authorities);
58
56
  }
59
57
 
58
+ /**
59
+ *
60
+ * @param authority that owns the UserStatsAccount
61
+ * @param userStatsAccount optional UserStatsAccount to subscribe to, if undefined will be fetched later
62
+ * @param skipFetch if true, will not immediately fetch the UserStatsAccount
63
+ */
60
64
  public async addUserStat(
61
65
  authority: PublicKey,
62
- userStatsAccount?: UserStatsAccount
66
+ userStatsAccount?: UserStatsAccount,
67
+ skipFetch?: boolean
63
68
  ) {
64
69
  const userStat = new UserStats({
65
70
  driftClient: this.driftClient,
@@ -67,9 +72,18 @@ export class UserStatsMap {
67
72
  this.driftClient.program.programId,
68
73
  authority
69
74
  ),
70
- accountSubscription: this.accountSubscription,
75
+ accountSubscription: {
76
+ type: 'polling',
77
+ accountLoader: this.bulkAccountLoader,
78
+ },
71
79
  });
72
- await userStat.subscribe(userStatsAccount);
80
+ if (skipFetch) {
81
+ await (
82
+ userStat.accountSubscriber as PollingUserStatsAccountSubscriber
83
+ ).addToAccountLoader();
84
+ } else {
85
+ await userStat.subscribe(userStatsAccount);
86
+ }
73
87
 
74
88
  this.userStatsMap.set(authority.toString(), userStat);
75
89
  }
@@ -77,7 +91,7 @@ export class UserStatsMap {
77
91
  public async updateWithOrderRecord(record: OrderRecord, userMap: UserMap) {
78
92
  const user = await userMap.mustGet(record.user.toString());
79
93
  if (!this.has(user.getUserAccount().authority.toString())) {
80
- await this.addUserStat(user.getUserAccount().authority);
94
+ await this.addUserStat(user.getUserAccount().authority, undefined, false);
81
95
  }
82
96
  }
83
97
 
@@ -156,9 +170,19 @@ export class UserStatsMap {
156
170
  return this.userStatsMap.get(authorityPublicKey);
157
171
  }
158
172
 
173
+ /**
174
+ * Enforce that a UserStats will exist for the given authorityPublicKey,
175
+ * reading one from the blockchain if necessary.
176
+ * @param authorityPublicKey
177
+ * @returns
178
+ */
159
179
  public async mustGet(authorityPublicKey: string): Promise<UserStats> {
160
180
  if (!this.has(authorityPublicKey)) {
161
- await this.addUserStat(new PublicKey(authorityPublicKey));
181
+ await this.addUserStat(
182
+ new PublicKey(authorityPublicKey),
183
+ undefined,
184
+ false
185
+ );
162
186
  }
163
187
  return this.get(authorityPublicKey);
164
188
  }
@@ -171,39 +195,18 @@ export class UserStatsMap {
171
195
  return this.userStatsMap.size;
172
196
  }
173
197
 
174
- public async sync() {
175
- const programAccounts =
176
- await this.driftClient.connection.getProgramAccounts(
177
- this.driftClient.program.programId,
178
- {
179
- commitment: this.driftClient.connection.commitment,
180
- filters: [
181
- {
182
- memcmp:
183
- this.driftClient.program.coder.accounts.memcmp('UserStats'),
184
- },
185
- ],
186
- }
187
- );
188
-
189
- const programAccountMap = new Map<string, AccountInfo<Buffer>>();
190
- for (const programAccount of programAccounts) {
191
- programAccountMap.set(
192
- new PublicKey(programAccount.account.data.slice(8, 40)).toString(),
193
- programAccount.account
194
- );
195
- }
196
-
197
- for (const key of programAccountMap.keys()) {
198
- if (!this.has(key)) {
199
- const userStatsAccount =
200
- this.driftClient.program.account.userStats.coder.accounts.decode(
201
- 'UserStats',
202
- programAccountMap.get(key).data
203
- );
204
- await this.addUserStat(new PublicKey(key), userStatsAccount);
205
- }
206
- }
198
+ /**
199
+ * Sync the UserStatsMap
200
+ * @param authorities list of authorities to derive UserStatsAccount public keys from.
201
+ * You may want to get this list from UserMap in order to filter out idle users
202
+ */
203
+ public async sync(authorities: PublicKey[]) {
204
+ await Promise.all(
205
+ authorities.map((authority) =>
206
+ this.addUserStat(authority, undefined, true)
207
+ )
208
+ );
209
+ await this.bulkAccountLoader.load();
207
210
  }
208
211
 
209
212
  public async unsubscribe() {
@@ -211,13 +214,5 @@ export class UserStatsMap {
211
214
  await userStats.unsubscribe();
212
215
  this.userStatsMap.delete(key);
213
216
  }
214
-
215
- if (this.lastNumberOfAuthorities) {
216
- this.driftClient.eventEmitter.removeListener(
217
- 'stateAccountUpdate',
218
- this.syncCallback
219
- );
220
- this.lastNumberOfAuthorities = undefined;
221
- }
222
217
  }
223
218
  }
package/tests/amm/test.ts CHANGED
@@ -967,8 +967,9 @@ describe('AMM Tests', () => {
967
967
  mockMarket1.amm.maxBaseAssetReserve = mockMarket1.amm.baseAssetReserve.add(
968
968
  new BN(9)
969
969
  );
970
- mockMarket1.amm.minBaseAssetReserve =
971
- mockMarket1.amm.baseAssetReserve.sub(new BN(9));
970
+ mockMarket1.amm.minBaseAssetReserve = mockMarket1.amm.baseAssetReserve.sub(
971
+ new BN(9)
972
+ );
972
973
  mockMarket1.amm.quoteAssetReserve = new BN(cc).mul(BASE_PRECISION);
973
974
  mockMarket1.amm.pegMultiplier = new BN(18.32 * PEG_PRECISION.toNumber());
974
975
  mockMarket1.amm.sqrtK = new BN(cc).mul(BASE_PRECISION);
@@ -27,7 +27,7 @@ import {
27
27
 
28
28
  import { mockPerpMarkets, mockSpotMarkets, mockStateAccount } from './helpers';
29
29
  import { DLOBOrdersCoder } from '../../src/dlob/DLOBOrders';
30
- import {isAuctionComplete, isRestingLimitOrder} from "../../lib";
30
+ import { isAuctionComplete, isRestingLimitOrder } from '../../lib';
31
31
 
32
32
  function insertOrderToDLOB(
33
33
  dlob: DLOB,
@@ -2537,18 +2537,21 @@ describe('DLOB Perp Tests', () => {
2537
2537
  OrderTriggerCondition.TRIGGERED_ABOVE, // triggerCondition: OrderTriggerCondition,
2538
2538
  vBid,
2539
2539
  vAsk,
2540
- new BN(1), // slot
2540
+ new BN(1) // slot
2541
2541
  );
2542
2542
 
2543
- const restingLimitBids = Array.from(dlob.getRestingLimitBids(marketIndex, slot, MarketType.PERP, oracle));
2543
+ const restingLimitBids = Array.from(
2544
+ dlob.getRestingLimitBids(marketIndex, slot, MarketType.PERP, oracle)
2545
+ );
2544
2546
  expect(restingLimitBids.length).to.equal(0);
2545
2547
 
2546
- const takingBids = Array.from(dlob.getTakingBids(marketIndex, MarketType.PERP, slot, oracle));
2548
+ const takingBids = Array.from(
2549
+ dlob.getTakingBids(marketIndex, MarketType.PERP, slot, oracle)
2550
+ );
2547
2551
  expect(takingBids.length).to.equal(1);
2548
2552
  const triggerLimitBid = takingBids[0];
2549
2553
  expect(isAuctionComplete(triggerLimitBid.order, slot)).to.equal(true);
2550
2554
  expect(isRestingLimitOrder(triggerLimitBid.order, slot)).to.equal(false);
2551
-
2552
2555
  });
2553
2556
 
2554
2557
  it('Test will return expired market orders to fill', () => {