@drift-labs/sdk 2.49.0-beta.1 → 2.49.0-beta.11

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 (54) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/{mockUserAccountSubscriber.d.ts → basicUserAccountSubscriber.d.ts} +2 -2
  3. package/lib/accounts/{mockUserAccountSubscriber.js → basicUserAccountSubscriber.js} +9 -6
  4. package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +29 -0
  5. package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +110 -0
  6. package/lib/accounts/types.d.ts +14 -1
  7. package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +23 -0
  8. package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +65 -0
  9. package/lib/dlob/DLOB.d.ts +6 -2
  10. package/lib/dlob/DLOB.js +37 -12
  11. package/lib/driftClient.d.ts +66 -66
  12. package/lib/driftClient.js +208 -194
  13. package/lib/events/eventSubscriber.js +2 -1
  14. package/lib/events/sort.d.ts +2 -2
  15. package/lib/events/sort.js +6 -23
  16. package/lib/examples/loadDlob.js +10 -5
  17. package/lib/index.d.ts +3 -1
  18. package/lib/index.js +3 -1
  19. package/lib/math/superStake.d.ts +43 -0
  20. package/lib/math/superStake.js +64 -22
  21. package/lib/orderSubscriber/OrderSubscriber.js +4 -0
  22. package/lib/orderSubscriber/WebsocketSubscription.d.ts +1 -1
  23. package/lib/orderSubscriber/WebsocketSubscription.js +8 -6
  24. package/lib/types.d.ts +0 -2
  25. package/lib/userMap/PollingSubscription.d.ts +15 -0
  26. package/lib/userMap/PollingSubscription.js +26 -0
  27. package/lib/userMap/WebsocketSubscription.d.ts +19 -0
  28. package/lib/userMap/WebsocketSubscription.js +40 -0
  29. package/lib/userMap/userMap.d.ts +15 -18
  30. package/lib/userMap/userMap.js +62 -31
  31. package/lib/userMap/userMapConfig.d.ts +20 -0
  32. package/lib/userMap/userMapConfig.js +2 -0
  33. package/package.json +1 -1
  34. package/src/accounts/{mockUserAccountSubscriber.ts → basicUserAccountSubscriber.ts} +8 -6
  35. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +185 -0
  36. package/src/accounts/types.ts +21 -0
  37. package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +127 -0
  38. package/src/dlob/DLOB.ts +55 -15
  39. package/src/driftClient.ts +429 -272
  40. package/src/events/eventSubscriber.ts +2 -1
  41. package/src/events/sort.ts +7 -29
  42. package/src/examples/loadDlob.ts +11 -6
  43. package/src/index.ts +3 -1
  44. package/src/math/superStake.ts +108 -20
  45. package/src/orderSubscriber/OrderSubscriber.ts +4 -0
  46. package/src/orderSubscriber/WebsocketSubscription.ts +19 -16
  47. package/src/types.ts +0 -2
  48. package/src/userMap/PollingSubscription.ts +46 -0
  49. package/src/userMap/WebsocketSubscription.ts +74 -0
  50. package/src/userMap/userMap.ts +88 -60
  51. package/src/userMap/userMapConfig.ts +31 -0
  52. package/tests/amm/test.ts +6 -3
  53. package/tests/dlob/helpers.ts +2 -6
  54. package/tests/dlob/test.ts +194 -0
@@ -23,7 +23,7 @@ class EventSubscriber {
23
23
  this.txEventCache = new txEventCache_1.TxEventCache(this.options.maxTx);
24
24
  this.eventListMap = new Map();
25
25
  for (const eventType of this.options.eventTypes) {
26
- this.eventListMap.set(eventType, new eventList_1.EventList(eventType, this.options.maxEventsPerType, (0, sort_1.getSortFn)(this.options.orderBy, this.options.orderDir, eventType), this.options.orderDir));
26
+ this.eventListMap.set(eventType, new eventList_1.EventList(eventType, this.options.maxEventsPerType, (0, sort_1.getSortFn)(this.options.orderBy, this.options.orderDir), this.options.orderDir));
27
27
  }
28
28
  this.eventEmitter = new events_1.EventEmitter();
29
29
  if (this.options.logProviderConfig.type === 'websocket') {
@@ -89,6 +89,7 @@ class EventSubscriber {
89
89
  }
90
90
  if (!this.lastSeenSlot || slot > this.lastSeenSlot) {
91
91
  this.lastSeenTxSig = txSig;
92
+ this.lastSeenSlot = slot;
92
93
  }
93
94
  if (this.lastSeenBlockTime === undefined ||
94
95
  mostRecentBlockTime > this.lastSeenBlockTime) {
@@ -1,2 +1,2 @@
1
- import { EventSubscriptionOrderBy, EventSubscriptionOrderDirection, EventType, SortFn } from './types';
2
- export declare function getSortFn(orderBy: EventSubscriptionOrderBy, orderDir: EventSubscriptionOrderDirection, eventType: EventType): SortFn;
1
+ import { EventSubscriptionOrderBy, EventSubscriptionOrderDirection, SortFn } from './types';
2
+ export declare function getSortFn(orderBy: EventSubscriptionOrderBy, orderDir: EventSubscriptionOrderDirection): SortFn;
@@ -1,41 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSortFn = void 0;
4
- const index_1 = require("../index");
5
4
  function clientSortAscFn() {
6
5
  return 'less than';
7
6
  }
8
7
  function clientSortDescFn() {
9
8
  return 'greater than';
10
9
  }
11
- function defaultBlockchainSortFn(currentEvent, newEvent) {
12
- return currentEvent.slot <= newEvent.slot ? 'less than' : 'greater than';
13
- }
14
- function orderActionRecordSortFn(currentEvent, newEvent) {
15
- var _a, _b;
16
- const currentEventMarketIndex = currentEvent.marketIndex;
17
- const newEventMarketIndex = newEvent.marketIndex;
18
- if (currentEventMarketIndex !== newEventMarketIndex) {
19
- return currentEvent.ts.lte(newEvent.ts) ? 'less than' : 'greater than';
20
- }
21
- if (((_a = currentEvent.fillRecordId) === null || _a === void 0 ? void 0 : _a.gt(index_1.ZERO)) && ((_b = newEvent.fillRecordId) === null || _b === void 0 ? void 0 : _b.gt(index_1.ZERO))) {
22
- return currentEvent.fillRecordId.lte(newEvent.fillRecordId)
10
+ function blockchainSortFn(currentEvent, newEvent) {
11
+ if (currentEvent.slot == newEvent.slot) {
12
+ return currentEvent.txSigIndex < newEvent.txSigIndex
23
13
  ? 'less than'
24
14
  : 'greater than';
25
15
  }
26
- else {
27
- return currentEvent.ts.lte(newEvent.ts) ? 'less than' : 'greater than';
28
- }
16
+ return currentEvent.slot < newEvent.slot ? 'less than' : 'greater than';
29
17
  }
30
- function getSortFn(orderBy, orderDir, eventType) {
18
+ function getSortFn(orderBy, orderDir) {
31
19
  if (orderBy === 'client') {
32
20
  return orderDir === 'asc' ? clientSortAscFn : clientSortDescFn;
33
21
  }
34
- switch (eventType) {
35
- case 'OrderActionRecord':
36
- return orderActionRecordSortFn;
37
- default:
38
- return defaultBlockchainSortFn;
39
- }
22
+ return blockchainSortFn;
40
23
  }
41
24
  exports.getSortFn = getSortFn;
@@ -35,15 +35,20 @@ const main = async () => {
35
35
  console.log('Subscribing drift client...');
36
36
  await driftClient.subscribe();
37
37
  console.log('Loading user map...');
38
- const userMap = new __1.UserMap(driftClient, {
39
- type: 'polling',
40
- accountLoader: bulkAccountLoader,
38
+ const userMap = new __1.UserMap({
39
+ driftClient,
40
+ subscriptionConfig: {
41
+ type: 'websocket',
42
+ commitment: 'processed',
43
+ },
44
+ skipInitialLoad: false,
45
+ includeIdle: false,
41
46
  });
42
47
  // fetches all users and subscribes for updates
43
48
  await userMap.subscribe();
44
49
  console.log('Loading dlob from user map...');
45
- const dlob = new __1.DLOB();
46
- await dlob.initFromUserMap(userMap, bulkAccountLoader.mostRecentSlot);
50
+ const slot = await driftClient.connection.getSlot();
51
+ const dlob = await userMap.getDLOB(slot);
47
52
  console.log('number of orders', dlob.getDLOBOrders().length);
48
53
  dlob.clear();
49
54
  console.log('Unsubscribing users...');
package/lib/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from './types';
9
9
  export * from './constants/perpMarkets';
10
10
  export * from './accounts/fetch';
11
11
  export * from './accounts/webSocketDriftClientAccountSubscriber';
12
+ export * from './accounts/webSocketInsuranceFundStakeAccountSubscriber';
12
13
  export * from './accounts/bulkAccountLoader';
13
14
  export * from './accounts/bulkUserSubscription';
14
15
  export * from './accounts/bulkUserStatsSubscription';
@@ -17,7 +18,8 @@ export * from './accounts/pollingOracleAccountSubscriber';
17
18
  export * from './accounts/pollingTokenAccountSubscriber';
18
19
  export * from './accounts/pollingUserAccountSubscriber';
19
20
  export * from './accounts/pollingUserStatsAccountSubscriber';
20
- export * from './accounts/mockUserAccountSubscriber';
21
+ export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
22
+ export * from './accounts/basicUserAccountSubscriber';
21
23
  export * from './accounts/types';
22
24
  export * from './addresses/pda';
23
25
  export * from './adminClient';
package/lib/index.js CHANGED
@@ -32,6 +32,7 @@ __exportStar(require("./types"), exports);
32
32
  __exportStar(require("./constants/perpMarkets"), exports);
33
33
  __exportStar(require("./accounts/fetch"), exports);
34
34
  __exportStar(require("./accounts/webSocketDriftClientAccountSubscriber"), exports);
35
+ __exportStar(require("./accounts/webSocketInsuranceFundStakeAccountSubscriber"), exports);
35
36
  __exportStar(require("./accounts/bulkAccountLoader"), exports);
36
37
  __exportStar(require("./accounts/bulkUserSubscription"), exports);
37
38
  __exportStar(require("./accounts/bulkUserStatsSubscription"), exports);
@@ -40,7 +41,8 @@ __exportStar(require("./accounts/pollingOracleAccountSubscriber"), exports);
40
41
  __exportStar(require("./accounts/pollingTokenAccountSubscriber"), exports);
41
42
  __exportStar(require("./accounts/pollingUserAccountSubscriber"), exports);
42
43
  __exportStar(require("./accounts/pollingUserStatsAccountSubscriber"), exports);
43
- __exportStar(require("./accounts/mockUserAccountSubscriber"), exports);
44
+ __exportStar(require("./accounts/pollingInsuranceFundStakeAccountSubscriber"), exports);
45
+ __exportStar(require("./accounts/basicUserAccountSubscriber"), exports);
44
46
  __exportStar(require("./accounts/types"), exports);
45
47
  __exportStar(require("./addresses/pda"), exports);
46
48
  __exportStar(require("./adminClient"), exports);
@@ -5,6 +5,30 @@ import { DriftClient } from '../driftClient';
5
5
  import { BN } from '@coral-xyz/anchor';
6
6
  import { User } from '../user';
7
7
  import { DepositRecord } from '../types';
8
+ export type BSOL_STATS_API_RESPONSE = {
9
+ success: boolean;
10
+ stats?: {
11
+ conversion: {
12
+ bsol_to_sol: number;
13
+ sol_to_bsol: number;
14
+ };
15
+ apy: {
16
+ base: number;
17
+ blze: number;
18
+ total: number;
19
+ lending: number;
20
+ liquidity: number;
21
+ };
22
+ };
23
+ };
24
+ export type BSOL_EMISSIONS_API_RESPONSE = {
25
+ success: boolean;
26
+ emissions?: {
27
+ lend: number;
28
+ };
29
+ };
30
+ export declare function fetchBSolMetrics(): Promise<any>;
31
+ export declare function fetchBSolDriftEmissions(): Promise<any>;
8
32
  export declare function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, }: {
9
33
  marketIndex: number;
10
34
  amount: BN;
@@ -46,6 +70,25 @@ export declare function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, dr
46
70
  method: 'jupiter' | 'marinade';
47
71
  price: number;
48
72
  }>;
73
+ /**
74
+ * Finds best Jupiter Swap instructions for a generic lstMint
75
+ *
76
+ * Without doing any extra steps like checking if you can get a better rate by staking directly with that LST platform
77
+ */
78
+ export declare function findBestLstSuperStakeIxs({ amount, lstMint, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, lstMarketIndex, }: {
79
+ amount: BN;
80
+ lstMint: PublicKey;
81
+ lstMarketIndex: number;
82
+ jupiterClient: JupiterClient;
83
+ driftClient: DriftClient;
84
+ userAccountPublicKey?: PublicKey;
85
+ onlyDirectRoutes?: boolean;
86
+ }): Promise<{
87
+ ixs: TransactionInstruction[];
88
+ lookupTables: AddressLookupTableAccount[];
89
+ method: 'jupiter' | 'marinade';
90
+ price: number;
91
+ }>;
49
92
  export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
50
93
  data: {
51
94
  getStakePoolStats: {
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchJitoSolMetrics = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = void 0;
6
+ exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchJitoSolMetrics = exports.findBestLstSuperStakeIxs = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = exports.fetchBSolDriftEmissions = exports.fetchBSolMetrics = void 0;
7
7
  const web3_js_1 = require("@solana/web3.js");
8
8
  const marinade_1 = require("../marinade");
9
9
  const anchor_1 = require("@coral-xyz/anchor");
@@ -11,6 +11,14 @@ const types_1 = require("../types");
11
11
  const numericConstants_1 = require("../constants/numericConstants");
12
12
  const node_fetch_1 = __importDefault(require("node-fetch"));
13
13
  const utils_1 = require("./utils");
14
+ async function fetchBSolMetrics() {
15
+ return await (0, node_fetch_1.default)('https://stake.solblaze.org/api/v1/stats');
16
+ }
17
+ exports.fetchBSolMetrics = fetchBSolMetrics;
18
+ async function fetchBSolDriftEmissions() {
19
+ return await (0, node_fetch_1.default)('https://stake.solblaze.org/api/v1/drift_emissions');
20
+ }
21
+ exports.fetchBSolDriftEmissions = fetchBSolDriftEmissions;
14
22
  async function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, }) {
15
23
  if (marketIndex === 2) {
16
24
  return findBestMSolSuperStakeIxs({
@@ -32,6 +40,17 @@ async function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, drift
32
40
  onlyDirectRoutes,
33
41
  });
34
42
  }
43
+ else if (marketIndex === 8) {
44
+ return findBestLstSuperStakeIxs({
45
+ amount,
46
+ lstMint: driftClient.getSpotMarketAccount(8).mint,
47
+ lstMarketIndex: 8,
48
+ jupiterClient,
49
+ driftClient,
50
+ userAccountPublicKey,
51
+ onlyDirectRoutes,
52
+ });
53
+ }
35
54
  else {
36
55
  throw new Error(`Unsupported superstake market index: ${marketIndex}`);
37
56
  }
@@ -90,14 +109,30 @@ async function findBestMSolSuperStakeIxs({ amount, jupiterClient, driftClient, u
90
109
  }
91
110
  exports.findBestMSolSuperStakeIxs = findBestMSolSuperStakeIxs;
92
111
  async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, }) {
112
+ return await findBestLstSuperStakeIxs({
113
+ amount,
114
+ jupiterClient,
115
+ driftClient,
116
+ userAccountPublicKey,
117
+ onlyDirectRoutes,
118
+ lstMint: driftClient.getSpotMarketAccount(6).mint,
119
+ lstMarketIndex: 6,
120
+ });
121
+ }
122
+ exports.findBestJitoSolSuperStakeIxs = findBestJitoSolSuperStakeIxs;
123
+ /**
124
+ * Finds best Jupiter Swap instructions for a generic lstMint
125
+ *
126
+ * Without doing any extra steps like checking if you can get a better rate by staking directly with that LST platform
127
+ */
128
+ async function findBestLstSuperStakeIxs({ amount, lstMint, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, lstMarketIndex, }) {
93
129
  const solMint = driftClient.getSpotMarketAccount(1).mint;
94
- const JitoSolMint = driftClient.getSpotMarketAccount(6).mint;
95
130
  let jupiterPrice;
96
131
  let bestRoute;
97
132
  try {
98
133
  const jupiterRoutes = await jupiterClient.getRoutes({
99
134
  inputMint: solMint,
100
- outputMint: JitoSolMint,
135
+ outputMint: lstMint,
101
136
  amount,
102
137
  onlyDirectRoutes,
103
138
  });
@@ -110,7 +145,7 @@ async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient
110
145
  }
111
146
  const { ixs, lookupTables } = await driftClient.getJupiterSwapIx({
112
147
  inMarketIndex: 1,
113
- outMarketIndex: 6,
148
+ outMarketIndex: lstMarketIndex,
114
149
  route: bestRoute,
115
150
  jupiterClient,
116
151
  amount,
@@ -123,7 +158,7 @@ async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient
123
158
  price: jupiterPrice,
124
159
  };
125
160
  }
126
- exports.findBestJitoSolSuperStakeIxs = findBestJitoSolSuperStakeIxs;
161
+ exports.findBestLstSuperStakeIxs = findBestLstSuperStakeIxs;
127
162
  const JITO_SOL_START_DATE = '2022-10-31T00:00:00Z';
128
163
  async function fetchJitoSolMetrics() {
129
164
  const res = await (0, node_fetch_1.default)('https://kobe.mainnet.jito.network/', {
@@ -213,12 +248,30 @@ async function calculateSolEarned({ marketIndex, user, depositRecords, }) {
213
248
  lstRatios.set(timestamp, data);
214
249
  }
215
250
  };
251
+ const getBSolPrice = async (timestamps) => {
252
+ var _a, _b;
253
+ // Currently there's only one bSOL price, no timestamped data
254
+ // So just use the same price for every timestamp for now
255
+ const response = await fetchBSolMetrics();
256
+ if (response.status === 200) {
257
+ const data = (await response.json());
258
+ const bSolRatio = (_b = (_a = data === null || data === void 0 ? void 0 : data.stats) === null || _a === void 0 ? void 0 : _a.conversion) === null || _b === void 0 ? void 0 : _b.bsol_to_sol;
259
+ if (bSolRatio) {
260
+ timestamps.forEach((timestamp) => lstRatios.set(timestamp, bSolRatio));
261
+ }
262
+ }
263
+ };
264
+ // This block kind of assumes the record are all from the same market
265
+ // Otherwise the following code that checks the record.marketIndex would break
216
266
  if (marketIndex === 2) {
217
267
  await Promise.all(timestamps.map(getMsolPrice));
218
268
  }
219
269
  else if (marketIndex === 6) {
220
270
  lstRatios = await getJitoSolHistoricalPriceMap(timestamps);
221
271
  }
272
+ else if (marketIndex === 8) {
273
+ await getBSolPrice(timestamps);
274
+ }
222
275
  let solEarned = numericConstants_1.ZERO;
223
276
  for (const record of depositRecords) {
224
277
  if (record.marketIndex === 1) {
@@ -229,23 +282,12 @@ async function calculateSolEarned({ marketIndex, user, depositRecords, }) {
229
282
  solEarned = solEarned.add(record.amount);
230
283
  }
231
284
  }
232
- else if (record.marketIndex === 2) {
233
- const msolRatio = lstRatios.get(record.ts.toNumber());
234
- const msolRatioBN = new anchor_1.BN(msolRatio * web3_js_1.LAMPORTS_PER_SOL);
235
- const solAmount = record.amount.mul(msolRatioBN).div(numericConstants_1.LAMPORTS_PRECISION);
236
- if ((0, types_1.isVariant)(record.direction, 'deposit')) {
237
- solEarned = solEarned.sub(solAmount);
238
- }
239
- else {
240
- solEarned = solEarned.add(solAmount);
241
- }
242
- }
243
- else if (record.marketIndex === 6) {
244
- const jitoSolRatio = lstRatios.get(record.ts.toNumber());
245
- const jitoSolRatioBN = new anchor_1.BN(jitoSolRatio * web3_js_1.LAMPORTS_PER_SOL);
246
- const solAmount = record.amount
247
- .mul(jitoSolRatioBN)
248
- .div(numericConstants_1.LAMPORTS_PRECISION);
285
+ else if (record.marketIndex === 2 ||
286
+ record.marketIndex === 6 ||
287
+ record.marketIndex === 8) {
288
+ const lstRatio = lstRatios.get(record.ts.toNumber());
289
+ const lstRatioBN = new anchor_1.BN(lstRatio * web3_js_1.LAMPORTS_PER_SOL);
290
+ const solAmount = record.amount.mul(lstRatioBN).div(numericConstants_1.LAMPORTS_PRECISION);
249
291
  if ((0, types_1.isVariant)(record.direction, 'deposit')) {
250
292
  solEarned = solEarned.sub(solAmount);
251
293
  }
@@ -60,11 +60,15 @@ class OrderSubscriber {
60
60
  const key = programAccount.pubkey.toString();
61
61
  programAccountSet.add(key);
62
62
  this.tryUpdateUserAccount(key, 'raw', programAccount.account.data, slot);
63
+ // give event loop a chance to breathe
64
+ await new Promise((resolve) => setTimeout(resolve, 0));
63
65
  }
64
66
  for (const key of this.usersAccounts.keys()) {
65
67
  if (!programAccountSet.has(key)) {
66
68
  this.usersAccounts.delete(key);
67
69
  }
70
+ // give event loop a chance to breathe
71
+ await new Promise((resolve) => setTimeout(resolve, 0));
68
72
  }
69
73
  }
70
74
  catch (e) {
@@ -5,7 +5,7 @@ export declare class WebsocketSubscription {
5
5
  private commitment;
6
6
  private skipInitialLoad;
7
7
  private resubTimeoutMs?;
8
- private subscriber;
8
+ private subscriber?;
9
9
  constructor({ orderSubscriber, commitment, skipInitialLoad, resubTimeoutMs, }: {
10
10
  orderSubscriber: OrderSubscriber;
11
11
  commitment: Commitment;
@@ -11,12 +11,13 @@ class WebsocketSubscription {
11
11
  this.resubTimeoutMs = resubTimeoutMs;
12
12
  }
13
13
  async subscribe() {
14
- if (!this.subscriber) {
15
- this.subscriber = new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('OrderSubscriber', 'User', this.orderSubscriber.driftClient.program, this.orderSubscriber.driftClient.program.account.user.coder.accounts.decode.bind(this.orderSubscriber.driftClient.program.account.user.coder.accounts), {
16
- filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()],
17
- commitment: this.commitment,
18
- }, this.resubTimeoutMs);
14
+ if (this.subscriber) {
15
+ return;
19
16
  }
17
+ this.subscriber = new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('OrderSubscriber', 'User', this.orderSubscriber.driftClient.program, this.orderSubscriber.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(this.orderSubscriber.driftClient.program.account.user.coder.accounts), {
18
+ filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()],
19
+ commitment: this.commitment,
20
+ }, this.resubTimeoutMs);
20
21
  await this.subscriber.subscribe((accountId, account, context) => {
21
22
  const userKey = accountId.toBase58();
22
23
  this.orderSubscriber.tryUpdateUserAccount(userKey, 'decoded', account, context.slot);
@@ -28,7 +29,8 @@ class WebsocketSubscription {
28
29
  async unsubscribe() {
29
30
  if (!this.subscriber)
30
31
  return;
31
- this.subscriber.unsubscribe();
32
+ await this.subscriber.unsubscribe();
33
+ this.subscriber = undefined;
32
34
  }
33
35
  }
34
36
  exports.WebsocketSubscription = WebsocketSubscription;
package/lib/types.d.ts CHANGED
@@ -1025,8 +1025,6 @@ export interface IVersionedWallet {
1025
1025
  }
1026
1026
  export type FeeStructure = {
1027
1027
  feeTiers: FeeTier[];
1028
- makerRebateNumerator: BN;
1029
- makerRebateDenominator: BN;
1030
1028
  fillerRewardStructure: OrderFillerRewardStructure;
1031
1029
  flatFillerFee: BN;
1032
1030
  referrerRewardEpochUpperBound: BN;
@@ -0,0 +1,15 @@
1
+ import { UserMap } from './userMap';
2
+ export declare class PollingSubscription {
3
+ private userMap;
4
+ private frequency;
5
+ private skipInitialLoad;
6
+ intervalId?: ReturnType<typeof setTimeout>;
7
+ constructor({ userMap, frequency, skipInitialLoad, }: {
8
+ userMap: UserMap;
9
+ frequency: number;
10
+ skipInitialLoad?: boolean;
11
+ includeIdle?: boolean;
12
+ });
13
+ subscribe(): Promise<void>;
14
+ unsubscribe(): Promise<void>;
15
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PollingSubscription = void 0;
4
+ class PollingSubscription {
5
+ constructor({ userMap, frequency, skipInitialLoad = false, }) {
6
+ this.userMap = userMap;
7
+ this.frequency = frequency;
8
+ this.skipInitialLoad = skipInitialLoad;
9
+ }
10
+ async subscribe() {
11
+ if (this.intervalId) {
12
+ return;
13
+ }
14
+ this.intervalId = setInterval(this.userMap.sync.bind(this.userMap), this.frequency);
15
+ if (!this.skipInitialLoad) {
16
+ await this.userMap.sync();
17
+ }
18
+ }
19
+ async unsubscribe() {
20
+ if (this.intervalId) {
21
+ clearInterval(this.intervalId);
22
+ this.intervalId = undefined;
23
+ }
24
+ }
25
+ }
26
+ exports.PollingSubscription = PollingSubscription;
@@ -0,0 +1,19 @@
1
+ import { UserMap } from './userMap';
2
+ import { Commitment } from '@solana/web3.js';
3
+ export declare class WebsocketSubscription {
4
+ private userMap;
5
+ private commitment;
6
+ private skipInitialLoad;
7
+ private resubTimeoutMs?;
8
+ private includeIdle?;
9
+ private subscriber;
10
+ constructor({ userMap, commitment, skipInitialLoad, resubTimeoutMs, includeIdle, }: {
11
+ userMap: UserMap;
12
+ commitment: Commitment;
13
+ skipInitialLoad?: boolean;
14
+ resubTimeoutMs?: number;
15
+ includeIdle?: boolean;
16
+ });
17
+ subscribe(): Promise<void>;
18
+ unsubscribe(): Promise<void>;
19
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebsocketSubscription = void 0;
4
+ const memcmp_1 = require("../memcmp");
5
+ const webSocketProgramAccountSubscriber_1 = require("../accounts/webSocketProgramAccountSubscriber");
6
+ class WebsocketSubscription {
7
+ constructor({ userMap, commitment, skipInitialLoad = false, resubTimeoutMs, includeIdle = false, }) {
8
+ this.userMap = userMap;
9
+ this.commitment = commitment;
10
+ this.skipInitialLoad = skipInitialLoad;
11
+ this.resubTimeoutMs = resubTimeoutMs;
12
+ this.includeIdle = includeIdle || false;
13
+ }
14
+ async subscribe() {
15
+ if (!this.subscriber) {
16
+ const filters = [(0, memcmp_1.getUserFilter)()];
17
+ if (!this.includeIdle) {
18
+ filters.push((0, memcmp_1.getNonIdleUserFilter)());
19
+ }
20
+ this.subscriber = new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('UserMap', 'User', this.userMap.driftClient.program, this.userMap.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(this.userMap.driftClient.program.account.user.coder.accounts), {
21
+ filters,
22
+ commitment: this.commitment,
23
+ }, this.resubTimeoutMs);
24
+ }
25
+ await this.subscriber.subscribe((accountId, account, context) => {
26
+ const userKey = accountId.toBase58();
27
+ this.userMap.updateUserAccount(userKey, account, context.slot);
28
+ });
29
+ if (!this.skipInitialLoad) {
30
+ await this.userMap.sync();
31
+ }
32
+ }
33
+ async unsubscribe() {
34
+ if (!this.subscriber)
35
+ return;
36
+ await this.subscriber.unsubscribe();
37
+ this.subscriber = undefined;
38
+ }
39
+ }
40
+ exports.WebsocketSubscription = WebsocketSubscription;
@@ -1,5 +1,6 @@
1
- import { User, DriftClient, UserAccount, OrderRecord, UserSubscriptionConfig, WrappedEvent, DLOB } from '..';
1
+ import { User, DriftClient, UserAccount, OrderRecord, WrappedEvent, DLOB } from '..';
2
2
  import { PublicKey } from '@solana/web3.js';
3
+ import { UserAccountFilterCriteria as UserFilterCriteria, UserMapConfig } from './userMapConfig';
3
4
  export interface UserMapInterface {
4
5
  subscribe(): Promise<void>;
5
6
  unsubscribe(): Promise<void>;
@@ -11,33 +12,23 @@ export interface UserMapInterface {
11
12
  updateWithOrderRecord(record: OrderRecord): Promise<void>;
12
13
  values(): IterableIterator<User>;
13
14
  }
14
- export type SyncCallbackCriteria = {
15
- hasOpenOrders: boolean;
16
- };
17
15
  export declare class UserMap implements UserMapInterface {
18
16
  private userMap;
19
- private driftClient;
20
- private accountSubscription;
17
+ driftClient: DriftClient;
18
+ private connection;
19
+ private commitment;
21
20
  private includeIdle;
22
21
  private lastNumberOfSubAccounts;
22
+ private subscription;
23
23
  private stateAccountUpdateCallback;
24
- private syncCallback;
25
- private syncCallbackCriteria;
26
24
  private syncPromise?;
27
25
  private syncPromiseResolver;
28
26
  /**
29
27
  * Constructs a new UserMap instance.
30
- *
31
- * @param {DriftClient} driftClient - The DriftClient instance.
32
- * @param {UserSubscriptionConfig} accountSubscription - The UserSubscriptionConfig instance.
33
- * @param {boolean} includeIdle - Whether idle users are subscribed to. Defaults to false to decrease # of user subscriptions.
34
- * @param {(authorities: PublicKey[]) => Promise<void>} syncCallback - Called after `sync` completes, will pas in unique list of authorities. Useful for using it to sync UserStatsMap.
35
- * @param {SyncCallbackCriteria} syncCallbackCriteria - The criteria for the sync callback. Defaults to having no filters
36
28
  */
37
- constructor(driftClient: DriftClient, accountSubscription: UserSubscriptionConfig, includeIdle?: boolean, syncCallback?: (authorities: PublicKey[]) => Promise<void>, syncCallbackCriteria?: SyncCallbackCriteria);
38
- addSyncCallback(syncCallback?: (authorities: PublicKey[]) => Promise<void>, syncCallbackCriteria?: SyncCallbackCriteria): void;
29
+ constructor(config: UserMapConfig);
39
30
  subscribe(): Promise<void>;
40
- addPubkey(userAccountPublicKey: PublicKey, userAccount?: UserAccount): Promise<void>;
31
+ addPubkey(userAccountPublicKey: PublicKey, userAccount?: UserAccount, slot?: number): Promise<void>;
41
32
  has(key: string): boolean;
42
33
  /**
43
34
  * gets the User for a particular userAccountPublicKey, if no User exists, undefined is returned
@@ -67,7 +58,13 @@ export declare class UserMap implements UserMapInterface {
67
58
  updateWithEventRecord(record: WrappedEvent<any>): Promise<void>;
68
59
  values(): IterableIterator<User>;
69
60
  size(): number;
70
- getUniqueAuthorities(useSyncCallbackCriteria?: boolean): PublicKey[];
61
+ /**
62
+ * Returns a unique list of authorities for all users in the UserMap that meet the filter criteria
63
+ * @param filterCriteria: Users must meet these criteria to be included
64
+ * @returns
65
+ */
66
+ getUniqueAuthorities(filterCriteria?: UserFilterCriteria): PublicKey[];
71
67
  sync(): Promise<void>;
72
68
  unsubscribe(): Promise<void>;
69
+ updateUserAccount(key: string, userAccount: UserAccount, slot: number): Promise<void>;
73
70
  }