@drift-labs/sdk 2.98.0-beta.9 → 2.99.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.
Files changed (69) hide show
  1. package/VERSION +1 -1
  2. package/lib/browser/accounts/pollingHighLeverageModeConfigAccountSubscriber.d.ts +29 -0
  3. package/lib/browser/accounts/pollingHighLeverageModeConfigAccountSubscriber.js +111 -0
  4. package/lib/browser/accounts/types.d.ts +14 -1
  5. package/lib/browser/accounts/webSocketHighLeverageModeConfigAccountSubscriber.d.ts +23 -0
  6. package/lib/browser/accounts/webSocketHighLeverageModeConfigAccountSubscriber.js +69 -0
  7. package/lib/browser/addresses/pda.d.ts +1 -0
  8. package/lib/browser/addresses/pda.js +8 -1
  9. package/lib/browser/constants/perpMarkets.js +11 -0
  10. package/lib/browser/constants/spotMarkets.js +2 -2
  11. package/lib/browser/driftClient.d.ts +14 -4
  12. package/lib/browser/driftClient.js +64 -19
  13. package/lib/browser/idl/drift.json +199 -8
  14. package/lib/browser/index.d.ts +4 -0
  15. package/lib/browser/index.js +4 -0
  16. package/lib/browser/jupiter/jupiterClient.d.ts +6 -0
  17. package/lib/browser/memcmp.d.ts +3 -0
  18. package/lib/browser/memcmp.js +28 -1
  19. package/lib/browser/slot/SlothashSubscriber.d.ts +26 -0
  20. package/lib/browser/slot/SlothashSubscriber.js +85 -0
  21. package/lib/browser/types.d.ts +4 -3
  22. package/lib/browser/user.js +3 -0
  23. package/lib/browser/userMap/referrerMap.d.ts +45 -0
  24. package/lib/browser/userMap/referrerMap.js +180 -0
  25. package/lib/browser/util/digest.d.ts +1 -0
  26. package/lib/browser/util/digest.js +5 -1
  27. package/lib/node/accounts/pollingHighLeverageModeConfigAccountSubscriber.d.ts +29 -0
  28. package/lib/node/accounts/pollingHighLeverageModeConfigAccountSubscriber.js +111 -0
  29. package/lib/node/accounts/types.d.ts +14 -1
  30. package/lib/node/accounts/webSocketHighLeverageModeConfigAccountSubscriber.d.ts +23 -0
  31. package/lib/node/accounts/webSocketHighLeverageModeConfigAccountSubscriber.js +69 -0
  32. package/lib/node/addresses/pda.d.ts +1 -0
  33. package/lib/node/addresses/pda.js +8 -1
  34. package/lib/node/constants/perpMarkets.js +11 -0
  35. package/lib/node/constants/spotMarkets.js +2 -2
  36. package/lib/node/driftClient.d.ts +14 -4
  37. package/lib/node/driftClient.js +64 -19
  38. package/lib/node/idl/drift.json +199 -8
  39. package/lib/node/index.d.ts +4 -0
  40. package/lib/node/index.js +4 -0
  41. package/lib/node/jupiter/jupiterClient.d.ts +6 -0
  42. package/lib/node/memcmp.d.ts +3 -0
  43. package/lib/node/memcmp.js +28 -1
  44. package/lib/node/slot/SlothashSubscriber.d.ts +26 -0
  45. package/lib/node/slot/SlothashSubscriber.js +85 -0
  46. package/lib/node/types.d.ts +4 -3
  47. package/lib/node/user.js +3 -0
  48. package/lib/node/userMap/referrerMap.d.ts +45 -0
  49. package/lib/node/userMap/referrerMap.js +180 -0
  50. package/lib/node/util/digest.d.ts +1 -0
  51. package/lib/node/util/digest.js +5 -1
  52. package/package.json +1 -1
  53. package/src/accounts/pollingHighLeverageModeConfigAccountSubscriber.ts +189 -0
  54. package/src/accounts/types.ts +25 -1
  55. package/src/accounts/webSocketHighLeverageModeConfigAccountSubscriber.ts +131 -0
  56. package/src/addresses/pda.ts +13 -0
  57. package/src/constants/perpMarkets.ts +12 -0
  58. package/src/constants/spotMarkets.ts +2 -2
  59. package/src/driftClient.ts +129 -36
  60. package/src/idl/drift.json +226 -9
  61. package/src/index.ts +4 -0
  62. package/src/jupiter/jupiterClient.ts +6 -0
  63. package/src/memcmp.ts +27 -0
  64. package/src/slot/SlothashSubscriber.ts +126 -0
  65. package/src/types.ts +4 -3
  66. package/src/user.ts +4 -0
  67. package/src/userMap/referrerMap.ts +283 -0
  68. package/src/util/digest.ts +4 -0
  69. package/tests/ci/verifyConstants.ts +16 -2
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SlothashSubscriber = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const bytes_1 = require("@coral-xyz/anchor/dist/cjs/utils/bytes");
6
+ const anchor_1 = require("@coral-xyz/anchor");
7
+ class SlothashSubscriber {
8
+ constructor(connection, config) {
9
+ var _a;
10
+ this.connection = connection;
11
+ this.isUnsubscribing = false;
12
+ this.receivingData = false;
13
+ this.resubTimeoutMs = config === null || config === void 0 ? void 0 : config.resubTimeoutMs;
14
+ this.commitment = (_a = config === null || config === void 0 ? void 0 : config.commitment) !== null && _a !== void 0 ? _a : 'processed';
15
+ if (this.resubTimeoutMs < 1000) {
16
+ console.log('resubTimeoutMs should be at least 1000ms to avoid spamming resub');
17
+ }
18
+ }
19
+ async subscribe() {
20
+ if (this.subscriptionId != null) {
21
+ return;
22
+ }
23
+ const currentAccountData = await this.connection.getAccountInfo(web3_js_1.SYSVAR_SLOT_HASHES_PUBKEY, this.commitment);
24
+ if (currentAccountData == null) {
25
+ throw new Error('Failed to retrieve current slot hash');
26
+ }
27
+ this.currentSlothash = deserializeSlothash(currentAccountData.data);
28
+ this.subscriptionId = this.connection.onAccountChange(web3_js_1.SYSVAR_SLOT_HASHES_PUBKEY, (slothashInfo, context) => {
29
+ if (!this.currentSlothash || this.currentSlothash.slot < context.slot) {
30
+ if (this.resubTimeoutMs && !this.isUnsubscribing) {
31
+ this.receivingData = true;
32
+ clearTimeout(this.timeoutId);
33
+ this.setTimeout();
34
+ }
35
+ this.currentSlothash = deserializeSlothash(slothashInfo.data);
36
+ }
37
+ }, this.commitment);
38
+ if (this.resubTimeoutMs) {
39
+ this.receivingData = true;
40
+ this.setTimeout();
41
+ }
42
+ }
43
+ setTimeout() {
44
+ this.timeoutId = setTimeout(async () => {
45
+ if (this.isUnsubscribing) {
46
+ // If we are in the process of unsubscribing, do not attempt to resubscribe
47
+ return;
48
+ }
49
+ if (this.receivingData) {
50
+ console.log(`No new slot in ${this.resubTimeoutMs}ms, slot subscriber resubscribing`);
51
+ await this.unsubscribe(true);
52
+ this.receivingData = false;
53
+ await this.subscribe();
54
+ }
55
+ }, this.resubTimeoutMs);
56
+ }
57
+ getSlothash() {
58
+ return this.currentSlothash;
59
+ }
60
+ async unsubscribe(onResub = false) {
61
+ if (!onResub) {
62
+ this.resubTimeoutMs = undefined;
63
+ }
64
+ this.isUnsubscribing = true;
65
+ clearTimeout(this.timeoutId);
66
+ this.timeoutId = undefined;
67
+ if (this.subscriptionId != null) {
68
+ await this.connection.removeSlotChangeListener(this.subscriptionId);
69
+ this.subscriptionId = undefined;
70
+ this.isUnsubscribing = false;
71
+ }
72
+ else {
73
+ this.isUnsubscribing = false;
74
+ }
75
+ }
76
+ }
77
+ exports.SlothashSubscriber = SlothashSubscriber;
78
+ function deserializeSlothash(data) {
79
+ const slotNumber = new anchor_1.BN(data.subarray(8, 16), 10, 'le');
80
+ const hash = bytes_1.bs58.encode(data.subarray(16, 48));
81
+ return {
82
+ slot: slotNumber.toNumber(),
83
+ hash,
84
+ };
85
+ }
@@ -647,8 +647,9 @@ export type SwiftOrderRecord = {
647
647
  user: PublicKey;
648
648
  hash: string;
649
649
  matchingOrderParams: OrderParams;
650
- swiftOrderSlot: BN;
651
- userNextOrderId: number;
650
+ swiftOrderMaxSlot: BN;
651
+ swiftOrderUuid: Uint8Array;
652
+ userOrderId: number;
652
653
  };
653
654
  export type OrderRecord = {
654
655
  ts: BN;
@@ -1118,10 +1119,10 @@ export declare const DefaultOrderParams: OrderParams;
1118
1119
  export type SwiftServerMessage = {
1119
1120
  slot: BN;
1120
1121
  swiftOrderSignature: Uint8Array;
1122
+ uuid: Uint8Array;
1121
1123
  };
1122
1124
  export type SwiftOrderParamsMessage = {
1123
1125
  swiftOrderParams: OptionalOrderParams;
1124
- expectedOrderId: number;
1125
1126
  subAccountId: number;
1126
1127
  takeProfitOrderParams: SwiftTriggerOrderParams | null;
1127
1128
  stopLossOrderParams: SwiftTriggerOrderParams | null;
package/lib/node/user.js CHANGED
@@ -1811,6 +1811,9 @@ class User {
1811
1811
  const state = this.driftClient.getStateAccount();
1812
1812
  let feeTierIndex = 0;
1813
1813
  if ((0, types_1.isVariant)(marketType, 'perp')) {
1814
+ if (this.isHighLeverageMode()) {
1815
+ return state.perpFeeStructure.feeTiers[0];
1816
+ }
1814
1817
  const userStatsAccount = this.driftClient
1815
1818
  .getUserStats()
1816
1819
  .getAccount();
@@ -0,0 +1,45 @@
1
+ import { MemcmpFilter } from '@solana/web3.js';
2
+ import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
+ import { DriftClient } from '../driftClient';
4
+ import { ReferrerInfo } from '../types';
5
+ export declare class ReferrerMap {
6
+ /**
7
+ * map from authority pubkey to ReferrerInfo.
8
+ * - if a user has not been entered into the map, the value is undefined
9
+ * - if a user has no referrer, the value is null
10
+ * - if a user has a referrer, the value is a ReferrerInfo object
11
+ */
12
+ private referrerMap;
13
+ private driftClient;
14
+ private bulkAccountLoader;
15
+ private parallelSync;
16
+ private fetchPromise?;
17
+ private fetchPromiseResolver;
18
+ /**
19
+ * Creates a new UserStatsMap instance.
20
+ *
21
+ * @param {DriftClient} driftClient - The DriftClient instance.
22
+ * @param {BulkAccountLoader} [bulkAccountLoader] - If not provided, a new BulkAccountLoader with polling disabled will be created.
23
+ */
24
+ constructor(driftClient: DriftClient, bulkAccountLoader?: BulkAccountLoader, parallelSync?: boolean);
25
+ /**
26
+ * Subscribe to all UserStats accounts.
27
+ */
28
+ subscribe(): Promise<void>;
29
+ has(authorityPublicKey: string): boolean;
30
+ get(authorityPublicKey: string): ReferrerInfo | undefined;
31
+ addReferrerInfo(authority: string, referrerInfo?: ReferrerInfo | null): Promise<void>;
32
+ /**
33
+ * Enforce that a UserStats will exist for the given authorityPublicKey,
34
+ * reading one from the blockchain if necessary.
35
+ * @param authorityPublicKey
36
+ * @returns
37
+ */
38
+ mustGet(authorityPublicKey: string): Promise<ReferrerInfo | undefined>;
39
+ values(): IterableIterator<ReferrerInfo | null>;
40
+ size(): number;
41
+ sync(): Promise<void>;
42
+ syncAll(): Promise<void>;
43
+ syncReferrer(referrerFilter: MemcmpFilter): Promise<void>;
44
+ unsubscribe(): Promise<void>;
45
+ }
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReferrerMap = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const bulkAccountLoader_1 = require("../accounts/bulkAccountLoader");
6
+ const pda_1 = require("../addresses/pda");
7
+ const memcmp_1 = require("../memcmp");
8
+ const bytes_1 = require("@coral-xyz/anchor/dist/cjs/utils/bytes");
9
+ const DEFAULT_PUBLIC_KEY = web3_js_1.PublicKey.default.toBase58();
10
+ class ReferrerMap {
11
+ /**
12
+ * Creates a new UserStatsMap instance.
13
+ *
14
+ * @param {DriftClient} driftClient - The DriftClient instance.
15
+ * @param {BulkAccountLoader} [bulkAccountLoader] - If not provided, a new BulkAccountLoader with polling disabled will be created.
16
+ */
17
+ constructor(driftClient, bulkAccountLoader, parallelSync) {
18
+ /**
19
+ * map from authority pubkey to ReferrerInfo.
20
+ * - if a user has not been entered into the map, the value is undefined
21
+ * - if a user has no referrer, the value is null
22
+ * - if a user has a referrer, the value is a ReferrerInfo object
23
+ */
24
+ this.referrerMap = new Map();
25
+ this.driftClient = driftClient;
26
+ if (!bulkAccountLoader) {
27
+ bulkAccountLoader = new bulkAccountLoader_1.BulkAccountLoader(driftClient.connection, driftClient.opts.commitment, 0);
28
+ }
29
+ this.bulkAccountLoader = bulkAccountLoader;
30
+ this.parallelSync = parallelSync !== undefined ? parallelSync : true;
31
+ }
32
+ /**
33
+ * Subscribe to all UserStats accounts.
34
+ */
35
+ async subscribe() {
36
+ if (this.size() > 0) {
37
+ return;
38
+ }
39
+ await this.driftClient.subscribe();
40
+ await this.sync();
41
+ }
42
+ has(authorityPublicKey) {
43
+ return this.referrerMap.has(authorityPublicKey);
44
+ }
45
+ get(authorityPublicKey) {
46
+ const info = this.referrerMap.get(authorityPublicKey);
47
+ return info === null ? undefined : info;
48
+ }
49
+ async addReferrerInfo(authority, referrerInfo) {
50
+ if (referrerInfo || referrerInfo === null) {
51
+ this.referrerMap.set(authority, referrerInfo);
52
+ }
53
+ else if (referrerInfo === undefined) {
54
+ const userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, new web3_js_1.PublicKey(authority));
55
+ const buffer = (await this.driftClient.connection.getAccountInfo(userStatsAccountPublicKey, 'processed')).data;
56
+ const referrer = bytes_1.bs58.encode(buffer.subarray(40, 72));
57
+ const referrerKey = new web3_js_1.PublicKey(referrer);
58
+ this.addReferrerInfo(authority, referrer === DEFAULT_PUBLIC_KEY
59
+ ? null
60
+ : {
61
+ referrer: (0, pda_1.getUserAccountPublicKeySync)(this.driftClient.program.programId, referrerKey, 0),
62
+ referrerStats: (0, pda_1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, referrerKey),
63
+ });
64
+ }
65
+ }
66
+ /**
67
+ * Enforce that a UserStats will exist for the given authorityPublicKey,
68
+ * reading one from the blockchain if necessary.
69
+ * @param authorityPublicKey
70
+ * @returns
71
+ */
72
+ async mustGet(authorityPublicKey) {
73
+ if (!this.has(authorityPublicKey)) {
74
+ await this.addReferrerInfo(authorityPublicKey);
75
+ }
76
+ return this.get(authorityPublicKey);
77
+ }
78
+ values() {
79
+ return this.referrerMap.values();
80
+ }
81
+ size() {
82
+ return this.referrerMap.size;
83
+ }
84
+ async sync() {
85
+ if (this.fetchPromise) {
86
+ return this.fetchPromise;
87
+ }
88
+ this.fetchPromise = new Promise((resolver) => {
89
+ this.fetchPromiseResolver = resolver;
90
+ });
91
+ try {
92
+ if (this.parallelSync) {
93
+ await Promise.all([
94
+ this.syncAll(),
95
+ this.syncReferrer((0, memcmp_1.getUserStatsIsReferredFilter)()),
96
+ this.syncReferrer((0, memcmp_1.getUserStatsIsReferredOrReferrerFilter)()),
97
+ ]);
98
+ }
99
+ else {
100
+ await this.syncAll();
101
+ await this.syncReferrer((0, memcmp_1.getUserStatsIsReferredFilter)());
102
+ await this.syncReferrer((0, memcmp_1.getUserStatsIsReferredOrReferrerFilter)());
103
+ }
104
+ }
105
+ catch (e) {
106
+ console.error('error in referrerMap.sync', e);
107
+ }
108
+ finally {
109
+ this.fetchPromiseResolver();
110
+ this.fetchPromise = undefined;
111
+ }
112
+ }
113
+ async syncAll() {
114
+ const rpcRequestArgs = [
115
+ this.driftClient.program.programId.toBase58(),
116
+ {
117
+ commitment: this.driftClient.opts.commitment,
118
+ filters: [(0, memcmp_1.getUserStatsFilter)()],
119
+ encoding: 'base64',
120
+ dataSlice: {
121
+ offset: 0,
122
+ length: 0,
123
+ },
124
+ withContext: true,
125
+ },
126
+ ];
127
+ const rpcJSONResponse =
128
+ // @ts-ignore
129
+ await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
130
+ const rpcResponseAndContext = rpcJSONResponse.result;
131
+ for (const account of rpcResponseAndContext.value) {
132
+ // only add if it isn't already in the map
133
+ // so that if syncReferrer already set it, we dont overwrite
134
+ if (!this.has(account.pubkey)) {
135
+ this.addReferrerInfo(account.pubkey, null);
136
+ }
137
+ }
138
+ }
139
+ async syncReferrer(referrerFilter) {
140
+ const rpcRequestArgs = [
141
+ this.driftClient.program.programId.toBase58(),
142
+ {
143
+ commitment: this.driftClient.opts.commitment,
144
+ filters: [(0, memcmp_1.getUserStatsFilter)(), referrerFilter],
145
+ encoding: 'base64',
146
+ dataSlice: {
147
+ offset: 0,
148
+ length: 72,
149
+ },
150
+ withContext: true,
151
+ },
152
+ ];
153
+ const rpcJSONResponse =
154
+ // @ts-ignore
155
+ await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
156
+ const rpcResponseAndContext = rpcJSONResponse.result;
157
+ const batchSize = 1000;
158
+ for (let i = 0; i < rpcResponseAndContext.value.length; i += batchSize) {
159
+ const batch = rpcResponseAndContext.value.slice(i, i + batchSize);
160
+ await Promise.all(batch.map(async (programAccount) => {
161
+ // @ts-ignore
162
+ const buffer = Buffer.from(programAccount.account.data[0], programAccount.account.data[1]);
163
+ const authority = bytes_1.bs58.encode(buffer.subarray(8, 40));
164
+ const referrer = bytes_1.bs58.encode(buffer.subarray(40, 72));
165
+ const referrerKey = new web3_js_1.PublicKey(referrer);
166
+ this.addReferrerInfo(authority, referrer === DEFAULT_PUBLIC_KEY
167
+ ? null
168
+ : {
169
+ referrer: (0, pda_1.getUserAccountPublicKeySync)(this.driftClient.program.programId, referrerKey, 0),
170
+ referrerStats: (0, pda_1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, referrerKey),
171
+ });
172
+ }));
173
+ await new Promise((resolve) => setTimeout(resolve, 0));
174
+ }
175
+ }
176
+ async unsubscribe() {
177
+ this.referrerMap.clear();
178
+ }
179
+ }
180
+ exports.ReferrerMap = ReferrerMap;
@@ -1,3 +1,4 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  export declare function digest(data: Buffer): Buffer;
4
+ export declare function digestSignature(signature: Uint8Array): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.digest = void 0;
3
+ exports.digestSignature = exports.digest = void 0;
4
4
  const crypto_1 = require("crypto");
5
5
  function digest(data) {
6
6
  const hash = (0, crypto_1.createHash)('sha256');
@@ -8,3 +8,7 @@ function digest(data) {
8
8
  return hash.digest();
9
9
  }
10
10
  exports.digest = digest;
11
+ function digestSignature(signature) {
12
+ return (0, crypto_1.createHash)('sha256').update(signature).digest('base64');
13
+ }
14
+ exports.digestSignature = digestSignature;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.98.0-beta.9",
3
+ "version": "2.99.0-beta.1",
4
4
  "main": "lib/node/index.js",
5
5
  "types": "lib/node/index.d.ts",
6
6
  "browser": "./lib/browser/index.js",
@@ -0,0 +1,189 @@
1
+ import {
2
+ DataAndSlot,
3
+ NotSubscribedError,
4
+ HighLeverageModeConfigAccountEvents,
5
+ HighLeverageModeConfigAccountSubscriber,
6
+ } from './types';
7
+ import { Program } from '@coral-xyz/anchor';
8
+ import StrictEventEmitter from 'strict-event-emitter-types';
9
+ import { EventEmitter } from 'events';
10
+ import { PublicKey } from '@solana/web3.js';
11
+ import { BulkAccountLoader } from './bulkAccountLoader';
12
+ import { HighLeverageModeConfig } from '../types';
13
+
14
+ export class PollingHighLeverageModeConfigAccountSubscriber
15
+ implements HighLeverageModeConfigAccountSubscriber
16
+ {
17
+ isSubscribed: boolean;
18
+ program: Program;
19
+ eventEmitter: StrictEventEmitter<
20
+ EventEmitter,
21
+ HighLeverageModeConfigAccountEvents
22
+ >;
23
+ highLeverageModeConfigAccountPublicKey: PublicKey;
24
+
25
+ accountLoader: BulkAccountLoader;
26
+ callbackId?: string;
27
+ errorCallbackId?: string;
28
+
29
+ highLeverageModeConfigAccountAndSlot?: DataAndSlot<HighLeverageModeConfig>;
30
+
31
+ public constructor(
32
+ program: Program,
33
+ publicKey: PublicKey,
34
+ accountLoader: BulkAccountLoader
35
+ ) {
36
+ this.isSubscribed = false;
37
+ this.program = program;
38
+ this.highLeverageModeConfigAccountPublicKey = publicKey;
39
+ this.accountLoader = accountLoader;
40
+ this.eventEmitter = new EventEmitter();
41
+ }
42
+
43
+ async subscribe(
44
+ highLeverageModeConfig?: HighLeverageModeConfig
45
+ ): Promise<boolean> {
46
+ if (this.isSubscribed) {
47
+ return true;
48
+ }
49
+
50
+ if (highLeverageModeConfig) {
51
+ this.highLeverageModeConfigAccountAndSlot = {
52
+ data: highLeverageModeConfig,
53
+ slot: undefined,
54
+ };
55
+ }
56
+
57
+ await this.addToAccountLoader();
58
+
59
+ await this.fetchIfUnloaded();
60
+
61
+ if (this.doesAccountExist()) {
62
+ this.eventEmitter.emit('update');
63
+ }
64
+
65
+ this.isSubscribed = true;
66
+ return true;
67
+ }
68
+
69
+ async addToAccountLoader(): Promise<void> {
70
+ if (this.callbackId) {
71
+ return;
72
+ }
73
+
74
+ this.callbackId = await this.accountLoader.addAccount(
75
+ this.highLeverageModeConfigAccountPublicKey,
76
+ (buffer, slot: number) => {
77
+ if (!buffer) {
78
+ return;
79
+ }
80
+
81
+ if (
82
+ this.highLeverageModeConfigAccountAndSlot &&
83
+ this.highLeverageModeConfigAccountAndSlot.slot > slot
84
+ ) {
85
+ return;
86
+ }
87
+
88
+ const account = this.program.account.user.coder.accounts.decode(
89
+ 'HighLeverageModeConfig',
90
+ buffer
91
+ );
92
+ this.highLeverageModeConfigAccountAndSlot = { data: account, slot };
93
+ this.eventEmitter.emit('highLeverageModeConfigAccountUpdate', account);
94
+ this.eventEmitter.emit('update');
95
+ }
96
+ );
97
+
98
+ this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
99
+ this.eventEmitter.emit('error', error);
100
+ });
101
+ }
102
+
103
+ async fetchIfUnloaded(): Promise<void> {
104
+ if (this.highLeverageModeConfigAccountAndSlot === undefined) {
105
+ await this.fetch();
106
+ }
107
+ }
108
+
109
+ async fetch(): Promise<void> {
110
+ try {
111
+ const dataAndContext =
112
+ await this.program.account.highLeverageModeConfig.fetchAndContext(
113
+ this.highLeverageModeConfigAccountPublicKey,
114
+ this.accountLoader.commitment
115
+ );
116
+ if (
117
+ dataAndContext.context.slot >
118
+ (this.highLeverageModeConfigAccountAndSlot?.slot ?? 0)
119
+ ) {
120
+ this.highLeverageModeConfigAccountAndSlot = {
121
+ data: dataAndContext.data as HighLeverageModeConfig,
122
+ slot: dataAndContext.context.slot,
123
+ };
124
+ }
125
+ } catch (e) {
126
+ console.log(
127
+ `PollingHighLeverageModeConfigAccountSubscriber.fetch() HighLeverageModeConfig does not exist: ${e.message}`
128
+ );
129
+ }
130
+ }
131
+
132
+ doesAccountExist(): boolean {
133
+ return this.highLeverageModeConfigAccountAndSlot !== undefined;
134
+ }
135
+
136
+ async unsubscribe(): Promise<void> {
137
+ if (!this.isSubscribed) {
138
+ return;
139
+ }
140
+
141
+ this.accountLoader.removeAccount(
142
+ this.highLeverageModeConfigAccountPublicKey,
143
+ this.callbackId
144
+ );
145
+ this.callbackId = undefined;
146
+
147
+ this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
148
+ this.errorCallbackId = undefined;
149
+
150
+ this.isSubscribed = false;
151
+ }
152
+
153
+ assertIsSubscribed(): void {
154
+ if (!this.isSubscribed) {
155
+ throw new NotSubscribedError(
156
+ 'You must call `subscribe` before using this function'
157
+ );
158
+ }
159
+ }
160
+
161
+ public getHighLeverageModeConfigAccountAndSlot(): DataAndSlot<HighLeverageModeConfig> {
162
+ this.assertIsSubscribed();
163
+ return this.highLeverageModeConfigAccountAndSlot;
164
+ }
165
+
166
+ didSubscriptionSucceed(): boolean {
167
+ return !!this.highLeverageModeConfigAccountAndSlot;
168
+ }
169
+
170
+ public updateData(
171
+ highLeverageModeConfig: HighLeverageModeConfig,
172
+ slot: number
173
+ ): void {
174
+ if (
175
+ !this.highLeverageModeConfigAccountAndSlot ||
176
+ this.highLeverageModeConfigAccountAndSlot.slot < slot
177
+ ) {
178
+ this.highLeverageModeConfigAccountAndSlot = {
179
+ data: highLeverageModeConfig,
180
+ slot,
181
+ };
182
+ this.eventEmitter.emit(
183
+ 'highLeverageModeConfigAccountUpdate',
184
+ highLeverageModeConfig
185
+ );
186
+ this.eventEmitter.emit('update');
187
+ }
188
+ }
189
+ }
@@ -11,7 +11,7 @@ import StrictEventEmitter from 'strict-event-emitter-types';
11
11
  import { EventEmitter } from 'events';
12
12
  import { Context, PublicKey } from '@solana/web3.js';
13
13
  import { Account } from '@solana/spl-token';
14
- import { OracleInfo, OraclePriceData } from '..';
14
+ import { HighLeverageModeConfig, OracleInfo, OraclePriceData } from '..';
15
15
  import { ChannelOptions, CommitmentLevel } from '../isomorphic/grpc';
16
16
 
17
17
  export interface AccountSubscriber<T> {
@@ -215,3 +215,27 @@ export type GrpcConfigs = {
215
215
  commitmentLevel?: CommitmentLevel;
216
216
  channelOptions?: ChannelOptions;
217
217
  };
218
+
219
+ export interface HighLeverageModeConfigAccountSubscriber {
220
+ eventEmitter: StrictEventEmitter<
221
+ EventEmitter,
222
+ HighLeverageModeConfigAccountEvents
223
+ >;
224
+ isSubscribed: boolean;
225
+
226
+ subscribe(
227
+ highLeverageModeConfigAccount?: HighLeverageModeConfig
228
+ ): Promise<boolean>;
229
+ fetch(): Promise<void>;
230
+ unsubscribe(): Promise<void>;
231
+
232
+ getHighLeverageModeConfigAccountAndSlot(): DataAndSlot<HighLeverageModeConfig>;
233
+ }
234
+
235
+ export interface HighLeverageModeConfigAccountEvents {
236
+ highLeverageModeConfigAccountUpdate: (
237
+ payload: HighLeverageModeConfig
238
+ ) => void;
239
+ update: void;
240
+ error: (e: Error) => void;
241
+ }