@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.
- package/VERSION +1 -1
- package/lib/accounts/{mockUserAccountSubscriber.d.ts → basicUserAccountSubscriber.d.ts} +2 -2
- package/lib/accounts/{mockUserAccountSubscriber.js → basicUserAccountSubscriber.js} +9 -6
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +29 -0
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +110 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +23 -0
- package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +65 -0
- package/lib/dlob/DLOB.d.ts +6 -2
- package/lib/dlob/DLOB.js +37 -12
- package/lib/driftClient.d.ts +66 -66
- package/lib/driftClient.js +208 -194
- package/lib/events/eventSubscriber.js +2 -1
- package/lib/events/sort.d.ts +2 -2
- package/lib/events/sort.js +6 -23
- package/lib/examples/loadDlob.js +10 -5
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/math/superStake.d.ts +43 -0
- package/lib/math/superStake.js +64 -22
- package/lib/orderSubscriber/OrderSubscriber.js +4 -0
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +1 -1
- package/lib/orderSubscriber/WebsocketSubscription.js +8 -6
- package/lib/types.d.ts +0 -2
- package/lib/userMap/PollingSubscription.d.ts +15 -0
- package/lib/userMap/PollingSubscription.js +26 -0
- package/lib/userMap/WebsocketSubscription.d.ts +19 -0
- package/lib/userMap/WebsocketSubscription.js +40 -0
- package/lib/userMap/userMap.d.ts +15 -18
- package/lib/userMap/userMap.js +62 -31
- package/lib/userMap/userMapConfig.d.ts +20 -0
- package/lib/userMap/userMapConfig.js +2 -0
- package/package.json +1 -1
- package/src/accounts/{mockUserAccountSubscriber.ts → basicUserAccountSubscriber.ts} +8 -6
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +185 -0
- package/src/accounts/types.ts +21 -0
- package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +127 -0
- package/src/dlob/DLOB.ts +55 -15
- package/src/driftClient.ts +429 -272
- package/src/events/eventSubscriber.ts +2 -1
- package/src/events/sort.ts +7 -29
- package/src/examples/loadDlob.ts +11 -6
- package/src/index.ts +3 -1
- package/src/math/superStake.ts +108 -20
- package/src/orderSubscriber/OrderSubscriber.ts +4 -0
- package/src/orderSubscriber/WebsocketSubscription.ts +19 -16
- package/src/types.ts +0 -2
- package/src/userMap/PollingSubscription.ts +46 -0
- package/src/userMap/WebsocketSubscription.ts +74 -0
- package/src/userMap/userMap.ts +88 -60
- package/src/userMap/userMapConfig.ts +31 -0
- package/tests/amm/test.ts +6 -3
- package/tests/dlob/helpers.ts +2 -6
- package/tests/dlob/test.ts +194 -0
package/lib/userMap/userMap.js
CHANGED
|
@@ -5,33 +5,46 @@ const __1 = require("..");
|
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
const buffer_1 = require("buffer");
|
|
7
7
|
const memcmp_1 = require("../memcmp");
|
|
8
|
+
const WebsocketSubscription_1 = require("./WebsocketSubscription");
|
|
9
|
+
const PollingSubscription_1 = require("./PollingSubscription");
|
|
8
10
|
class UserMap {
|
|
9
11
|
/**
|
|
10
12
|
* Constructs a new UserMap instance.
|
|
11
|
-
*
|
|
12
|
-
* @param {DriftClient} driftClient - The DriftClient instance.
|
|
13
|
-
* @param {UserSubscriptionConfig} accountSubscription - The UserSubscriptionConfig instance.
|
|
14
|
-
* @param {boolean} includeIdle - Whether idle users are subscribed to. Defaults to false to decrease # of user subscriptions.
|
|
15
|
-
* @param {(authorities: PublicKey[]) => Promise<void>} syncCallback - Called after `sync` completes, will pas in unique list of authorities. Useful for using it to sync UserStatsMap.
|
|
16
|
-
* @param {SyncCallbackCriteria} syncCallbackCriteria - The criteria for the sync callback. Defaults to having no filters
|
|
17
13
|
*/
|
|
18
|
-
constructor(
|
|
14
|
+
constructor(config) {
|
|
15
|
+
var _a, _b;
|
|
19
16
|
this.userMap = new Map();
|
|
20
17
|
this.stateAccountUpdateCallback = async (state) => {
|
|
21
|
-
if (state.numberOfSubAccounts
|
|
18
|
+
if (!state.numberOfSubAccounts.eq(this.lastNumberOfSubAccounts)) {
|
|
22
19
|
await this.sync();
|
|
23
20
|
this.lastNumberOfSubAccounts = state.numberOfSubAccounts;
|
|
24
21
|
}
|
|
25
22
|
};
|
|
26
|
-
this.driftClient = driftClient;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
|
|
23
|
+
this.driftClient = config.driftClient;
|
|
24
|
+
if (config.connection) {
|
|
25
|
+
this.connection = config.connection;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.connection = this.driftClient.connection;
|
|
29
|
+
}
|
|
30
|
+
this.commitment =
|
|
31
|
+
(_a = config.subscriptionConfig.commitment) !== null && _a !== void 0 ? _a : this.driftClient.opts.commitment;
|
|
32
|
+
this.includeIdle = (_b = config.includeIdle) !== null && _b !== void 0 ? _b : false;
|
|
33
|
+
if (config.subscriptionConfig.type === 'polling') {
|
|
34
|
+
this.subscription = new PollingSubscription_1.PollingSubscription({
|
|
35
|
+
userMap: this,
|
|
36
|
+
frequency: config.subscriptionConfig.frequency,
|
|
37
|
+
skipInitialLoad: config.skipInitialLoad,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.subscription = new WebsocketSubscription_1.WebsocketSubscription({
|
|
42
|
+
userMap: this,
|
|
43
|
+
commitment: this.commitment,
|
|
44
|
+
resubTimeoutMs: config.subscriptionConfig.resubTimeoutMs,
|
|
45
|
+
skipInitialLoad: config.skipInitialLoad,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
35
48
|
}
|
|
36
49
|
async subscribe() {
|
|
37
50
|
if (this.size() > 0) {
|
|
@@ -41,13 +54,16 @@ class UserMap {
|
|
|
41
54
|
this.lastNumberOfSubAccounts =
|
|
42
55
|
this.driftClient.getStateAccount().numberOfSubAccounts;
|
|
43
56
|
this.driftClient.eventEmitter.on('stateAccountUpdate', this.stateAccountUpdateCallback);
|
|
44
|
-
await this.
|
|
57
|
+
await this.subscription.subscribe();
|
|
45
58
|
}
|
|
46
|
-
async addPubkey(userAccountPublicKey, userAccount) {
|
|
59
|
+
async addPubkey(userAccountPublicKey, userAccount, slot) {
|
|
47
60
|
const user = new __1.User({
|
|
48
61
|
driftClient: this.driftClient,
|
|
49
62
|
userAccountPublicKey,
|
|
50
|
-
accountSubscription:
|
|
63
|
+
accountSubscription: {
|
|
64
|
+
type: 'custom',
|
|
65
|
+
userAccountSubscriber: new __1.BasicUserAccountSubscriber(userAccountPublicKey, userAccount, slot),
|
|
66
|
+
},
|
|
51
67
|
});
|
|
52
68
|
await user.subscribe(userAccount);
|
|
53
69
|
this.userMap.set(userAccountPublicKey.toString(), user);
|
|
@@ -148,11 +164,15 @@ class UserMap {
|
|
|
148
164
|
size() {
|
|
149
165
|
return this.userMap.size;
|
|
150
166
|
}
|
|
151
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Returns a unique list of authorities for all users in the UserMap that meet the filter criteria
|
|
169
|
+
* @param filterCriteria: Users must meet these criteria to be included
|
|
170
|
+
* @returns
|
|
171
|
+
*/
|
|
172
|
+
getUniqueAuthorities(filterCriteria) {
|
|
152
173
|
const usersMeetingCriteria = Array.from(this.userMap.values()).filter((user) => {
|
|
153
174
|
let pass = true;
|
|
154
|
-
if (
|
|
155
|
-
this.syncCallbackCriteria.hasOpenOrders) {
|
|
175
|
+
if (filterCriteria && filterCriteria.hasOpenOrders) {
|
|
156
176
|
pass = pass && user.getUserAccount().hasOpenOrder;
|
|
157
177
|
}
|
|
158
178
|
return pass;
|
|
@@ -176,7 +196,7 @@ class UserMap {
|
|
|
176
196
|
const rpcRequestArgs = [
|
|
177
197
|
this.driftClient.program.programId.toBase58(),
|
|
178
198
|
{
|
|
179
|
-
commitment: this.
|
|
199
|
+
commitment: this.commitment,
|
|
180
200
|
filters,
|
|
181
201
|
encoding: 'base64',
|
|
182
202
|
withContext: true,
|
|
@@ -184,7 +204,7 @@ class UserMap {
|
|
|
184
204
|
];
|
|
185
205
|
const rpcJSONResponse =
|
|
186
206
|
// @ts-ignore
|
|
187
|
-
await this.
|
|
207
|
+
await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
|
|
188
208
|
const rpcResponseAndContext = rpcJSONResponse.result;
|
|
189
209
|
const slot = rpcResponseAndContext.context.slot;
|
|
190
210
|
const programAccountBufferMap = new Map();
|
|
@@ -195,9 +215,11 @@ class UserMap {
|
|
|
195
215
|
}
|
|
196
216
|
for (const [key, buffer] of programAccountBufferMap.entries()) {
|
|
197
217
|
if (!this.has(key)) {
|
|
198
|
-
const userAccount = this.driftClient.program.account.user.coder.accounts.
|
|
218
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decodeUnchecked('User', buffer);
|
|
199
219
|
await this.addPubkey(new web3_js_1.PublicKey(key), userAccount);
|
|
200
220
|
}
|
|
221
|
+
// give event loop a chance to breathe
|
|
222
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
201
223
|
}
|
|
202
224
|
for (const [key, user] of this.userMap.entries()) {
|
|
203
225
|
if (!programAccountBufferMap.has(key)) {
|
|
@@ -205,16 +227,15 @@ class UserMap {
|
|
|
205
227
|
this.userMap.delete(key);
|
|
206
228
|
}
|
|
207
229
|
else {
|
|
208
|
-
const userAccount = this.driftClient.program.account.user.coder.accounts.
|
|
230
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decodeUnchecked('User', programAccountBufferMap.get(key));
|
|
209
231
|
user.accountSubscriber.updateData(userAccount, slot);
|
|
210
232
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
await this.syncCallback(this.getUniqueAuthorities());
|
|
233
|
+
// give event loop a chance to breathe
|
|
234
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
214
235
|
}
|
|
215
236
|
}
|
|
216
237
|
catch (e) {
|
|
217
|
-
console.error(`Error in UserMap.sync()
|
|
238
|
+
console.error(`Error in UserMap.sync():`);
|
|
218
239
|
console.error(e);
|
|
219
240
|
}
|
|
220
241
|
finally {
|
|
@@ -223,6 +244,7 @@ class UserMap {
|
|
|
223
244
|
}
|
|
224
245
|
}
|
|
225
246
|
async unsubscribe() {
|
|
247
|
+
await this.subscription.unsubscribe();
|
|
226
248
|
for (const [key, user] of this.userMap.entries()) {
|
|
227
249
|
await user.unsubscribe();
|
|
228
250
|
this.userMap.delete(key);
|
|
@@ -232,5 +254,14 @@ class UserMap {
|
|
|
232
254
|
this.lastNumberOfSubAccounts = undefined;
|
|
233
255
|
}
|
|
234
256
|
}
|
|
257
|
+
async updateUserAccount(key, userAccount, slot) {
|
|
258
|
+
if (!this.userMap.has(key)) {
|
|
259
|
+
this.addPubkey(new web3_js_1.PublicKey(key), userAccount, slot);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const user = this.userMap.get(key);
|
|
263
|
+
user.accountSubscriber.updateData(userAccount, slot);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
235
266
|
}
|
|
236
267
|
exports.UserMap = UserMap;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Commitment, Connection } from '@solana/web3.js';
|
|
2
|
+
import { DriftClient } from '../driftClient';
|
|
3
|
+
export type UserAccountFilterCriteria = {
|
|
4
|
+
hasOpenOrders: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type UserMapConfig = {
|
|
7
|
+
driftClient: DriftClient;
|
|
8
|
+
connection?: Connection;
|
|
9
|
+
subscriptionConfig: {
|
|
10
|
+
type: 'polling';
|
|
11
|
+
frequency: number;
|
|
12
|
+
commitment?: Commitment;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'websocket';
|
|
15
|
+
resubTimeoutMs?: number;
|
|
16
|
+
commitment?: Commitment;
|
|
17
|
+
};
|
|
18
|
+
skipInitialLoad?: boolean;
|
|
19
|
+
includeIdle?: boolean;
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import StrictEventEmitter from 'strict-event-emitter-types';
|
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
import { UserAccount } from '../types';
|
|
6
6
|
|
|
7
|
-
export class
|
|
7
|
+
export class BasicUserAccountSubscriber implements UserAccountSubscriber {
|
|
8
8
|
isSubscribed: boolean;
|
|
9
9
|
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
10
10
|
userAccountPublicKey: PublicKey;
|
|
@@ -16,8 +16,8 @@ export class MockUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
16
16
|
|
|
17
17
|
public constructor(
|
|
18
18
|
userAccountPublicKey: PublicKey,
|
|
19
|
-
data
|
|
20
|
-
slot
|
|
19
|
+
data?: UserAccount,
|
|
20
|
+
slot?: number
|
|
21
21
|
) {
|
|
22
22
|
this.isSubscribed = true;
|
|
23
23
|
this.eventEmitter = new EventEmitter();
|
|
@@ -46,8 +46,10 @@ export class MockUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
public updateData(userAccount: UserAccount, slot: number): void {
|
|
49
|
-
this.user
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (!this.user || slot >= (this.user.slot ?? 0)) {
|
|
50
|
+
this.user = { data: userAccount, slot };
|
|
51
|
+
this.eventEmitter.emit('userAccountUpdate', userAccount);
|
|
52
|
+
this.eventEmitter.emit('update');
|
|
53
|
+
}
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataAndSlot,
|
|
3
|
+
NotSubscribedError,
|
|
4
|
+
InsuranceFundStakeAccountEvents,
|
|
5
|
+
InsuranceFundStakeAccountSubscriber,
|
|
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 { InsuranceFundStake } from '../types';
|
|
13
|
+
|
|
14
|
+
export class PollingInsuranceFundStakeAccountSubscriber
|
|
15
|
+
implements InsuranceFundStakeAccountSubscriber
|
|
16
|
+
{
|
|
17
|
+
isSubscribed: boolean;
|
|
18
|
+
program: Program;
|
|
19
|
+
eventEmitter: StrictEventEmitter<
|
|
20
|
+
EventEmitter,
|
|
21
|
+
InsuranceFundStakeAccountEvents
|
|
22
|
+
>;
|
|
23
|
+
insuranceFundStakeAccountPublicKey: PublicKey;
|
|
24
|
+
|
|
25
|
+
accountLoader: BulkAccountLoader;
|
|
26
|
+
callbackId?: string;
|
|
27
|
+
errorCallbackId?: string;
|
|
28
|
+
|
|
29
|
+
insuranceFundStakeAccountAndSlot?: DataAndSlot<InsuranceFundStake>;
|
|
30
|
+
|
|
31
|
+
public constructor(
|
|
32
|
+
program: Program,
|
|
33
|
+
publicKey: PublicKey,
|
|
34
|
+
accountLoader: BulkAccountLoader
|
|
35
|
+
) {
|
|
36
|
+
this.isSubscribed = false;
|
|
37
|
+
this.program = program;
|
|
38
|
+
this.insuranceFundStakeAccountPublicKey = publicKey;
|
|
39
|
+
this.accountLoader = accountLoader;
|
|
40
|
+
this.eventEmitter = new EventEmitter();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async subscribe(insuranceFundStake?: InsuranceFundStake): Promise<boolean> {
|
|
44
|
+
if (this.isSubscribed) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (insuranceFundStake) {
|
|
49
|
+
this.insuranceFundStakeAccountAndSlot = {
|
|
50
|
+
data: insuranceFundStake,
|
|
51
|
+
slot: undefined,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await this.addToAccountLoader();
|
|
56
|
+
|
|
57
|
+
if (this.doesAccountExist()) {
|
|
58
|
+
this.eventEmitter.emit('update');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.isSubscribed = true;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async addToAccountLoader(): Promise<void> {
|
|
66
|
+
if (this.callbackId) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.callbackId = await this.accountLoader.addAccount(
|
|
71
|
+
this.insuranceFundStakeAccountPublicKey,
|
|
72
|
+
(buffer, slot: number) => {
|
|
73
|
+
if (!buffer) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
this.insuranceFundStakeAccountAndSlot &&
|
|
79
|
+
this.insuranceFundStakeAccountAndSlot.slot > slot
|
|
80
|
+
) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const account = this.program.account.user.coder.accounts.decode(
|
|
85
|
+
'InsuranceFundStake',
|
|
86
|
+
buffer
|
|
87
|
+
);
|
|
88
|
+
this.insuranceFundStakeAccountAndSlot = { data: account, slot };
|
|
89
|
+
this.eventEmitter.emit('insuranceFundStakeAccountUpdate', account);
|
|
90
|
+
this.eventEmitter.emit('update');
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
this.errorCallbackId = this.accountLoader.addErrorCallbacks((error) => {
|
|
95
|
+
this.eventEmitter.emit('error', error);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async fetchIfUnloaded(): Promise<void> {
|
|
100
|
+
if (this.insuranceFundStakeAccountAndSlot === undefined) {
|
|
101
|
+
await this.fetch();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async fetch(): Promise<void> {
|
|
106
|
+
try {
|
|
107
|
+
const dataAndContext =
|
|
108
|
+
await this.program.account.insuranceFundStake.fetchAndContext(
|
|
109
|
+
this.insuranceFundStakeAccountPublicKey,
|
|
110
|
+
this.accountLoader.commitment
|
|
111
|
+
);
|
|
112
|
+
if (
|
|
113
|
+
dataAndContext.context.slot >
|
|
114
|
+
(this.insuranceFundStakeAccountAndSlot?.slot ?? 0)
|
|
115
|
+
) {
|
|
116
|
+
this.insuranceFundStakeAccountAndSlot = {
|
|
117
|
+
data: dataAndContext.data as InsuranceFundStake,
|
|
118
|
+
slot: dataAndContext.context.slot,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.log(
|
|
123
|
+
`PollingInsuranceFundStakeAccountSubscriber.fetch() InsuranceFundStake does not exist: ${e.message}`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
doesAccountExist(): boolean {
|
|
129
|
+
return this.insuranceFundStakeAccountAndSlot !== undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async unsubscribe(): Promise<void> {
|
|
133
|
+
if (!this.isSubscribed) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.accountLoader.removeAccount(
|
|
138
|
+
this.insuranceFundStakeAccountPublicKey,
|
|
139
|
+
this.callbackId
|
|
140
|
+
);
|
|
141
|
+
this.callbackId = undefined;
|
|
142
|
+
|
|
143
|
+
this.accountLoader.removeErrorCallbacks(this.errorCallbackId);
|
|
144
|
+
this.errorCallbackId = undefined;
|
|
145
|
+
|
|
146
|
+
this.isSubscribed = false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
assertIsSubscribed(): void {
|
|
150
|
+
if (!this.isSubscribed) {
|
|
151
|
+
throw new NotSubscribedError(
|
|
152
|
+
'You must call `subscribe` before using this function'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public getInsuranceFundStakeAccountAndSlot(): DataAndSlot<InsuranceFundStake> {
|
|
158
|
+
this.assertIsSubscribed();
|
|
159
|
+
return this.insuranceFundStakeAccountAndSlot;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
didSubscriptionSucceed(): boolean {
|
|
163
|
+
return !!this.insuranceFundStakeAccountAndSlot;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public updateData(
|
|
167
|
+
insuranceFundStake: InsuranceFundStake,
|
|
168
|
+
slot: number
|
|
169
|
+
): void {
|
|
170
|
+
if (
|
|
171
|
+
!this.insuranceFundStakeAccountAndSlot ||
|
|
172
|
+
this.insuranceFundStakeAccountAndSlot.slot < slot
|
|
173
|
+
) {
|
|
174
|
+
this.insuranceFundStakeAccountAndSlot = {
|
|
175
|
+
data: insuranceFundStake,
|
|
176
|
+
slot,
|
|
177
|
+
};
|
|
178
|
+
this.eventEmitter.emit(
|
|
179
|
+
'insuranceFundStakeAccountUpdate',
|
|
180
|
+
insuranceFundStake
|
|
181
|
+
);
|
|
182
|
+
this.eventEmitter.emit('update');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
StateAccount,
|
|
6
6
|
UserAccount,
|
|
7
7
|
UserStatsAccount,
|
|
8
|
+
InsuranceFundStake,
|
|
8
9
|
} from '../types';
|
|
9
10
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
11
|
import { EventEmitter } from 'events';
|
|
@@ -105,6 +106,26 @@ export interface TokenAccountSubscriber {
|
|
|
105
106
|
getTokenAccountAndSlot(): DataAndSlot<Account>;
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
export interface InsuranceFundStakeAccountSubscriber {
|
|
110
|
+
eventEmitter: StrictEventEmitter<
|
|
111
|
+
EventEmitter,
|
|
112
|
+
InsuranceFundStakeAccountEvents
|
|
113
|
+
>;
|
|
114
|
+
isSubscribed: boolean;
|
|
115
|
+
|
|
116
|
+
subscribe(): Promise<boolean>;
|
|
117
|
+
fetch(): Promise<void>;
|
|
118
|
+
unsubscribe(): Promise<void>;
|
|
119
|
+
|
|
120
|
+
getInsuranceFundStakeAccountAndSlot(): DataAndSlot<InsuranceFundStake>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface InsuranceFundStakeAccountEvents {
|
|
124
|
+
insuranceFundStakeAccountUpdate: (payload: InsuranceFundStake) => void;
|
|
125
|
+
update: void;
|
|
126
|
+
error: (e: Error) => void;
|
|
127
|
+
}
|
|
128
|
+
|
|
108
129
|
export interface OracleEvents {
|
|
109
130
|
oracleUpdate: (payload: OraclePriceData) => void;
|
|
110
131
|
update: void;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataAndSlot,
|
|
3
|
+
AccountSubscriber,
|
|
4
|
+
NotSubscribedError,
|
|
5
|
+
InsuranceFundStakeAccountEvents,
|
|
6
|
+
InsuranceFundStakeAccountSubscriber,
|
|
7
|
+
} from './types';
|
|
8
|
+
import { Program } from '@coral-xyz/anchor';
|
|
9
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
12
|
+
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
13
|
+
import { InsuranceFundStake } from '../types';
|
|
14
|
+
|
|
15
|
+
export class WebSocketInsuranceFundStakeAccountSubscriber
|
|
16
|
+
implements InsuranceFundStakeAccountSubscriber
|
|
17
|
+
{
|
|
18
|
+
isSubscribed: boolean;
|
|
19
|
+
reconnectTimeoutMs?: number;
|
|
20
|
+
commitment?: Commitment;
|
|
21
|
+
program: Program;
|
|
22
|
+
eventEmitter: StrictEventEmitter<
|
|
23
|
+
EventEmitter,
|
|
24
|
+
InsuranceFundStakeAccountEvents
|
|
25
|
+
>;
|
|
26
|
+
insuranceFundStakeAccountPublicKey: PublicKey;
|
|
27
|
+
|
|
28
|
+
insuranceFundStakeDataAccountSubscriber: AccountSubscriber<InsuranceFundStake>;
|
|
29
|
+
|
|
30
|
+
public constructor(
|
|
31
|
+
program: Program,
|
|
32
|
+
insuranceFundStakeAccountPublicKey: PublicKey,
|
|
33
|
+
reconnectTimeoutMs?: number,
|
|
34
|
+
commitment?: Commitment
|
|
35
|
+
) {
|
|
36
|
+
this.isSubscribed = false;
|
|
37
|
+
this.program = program;
|
|
38
|
+
this.insuranceFundStakeAccountPublicKey =
|
|
39
|
+
insuranceFundStakeAccountPublicKey;
|
|
40
|
+
this.eventEmitter = new EventEmitter();
|
|
41
|
+
this.reconnectTimeoutMs = reconnectTimeoutMs;
|
|
42
|
+
this.commitment = commitment;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async subscribe(
|
|
46
|
+
insuranceFundStakeAccount?: InsuranceFundStake
|
|
47
|
+
): Promise<boolean> {
|
|
48
|
+
if (this.isSubscribed) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.insuranceFundStakeDataAccountSubscriber =
|
|
53
|
+
new WebSocketAccountSubscriber(
|
|
54
|
+
'insuranceFundStake',
|
|
55
|
+
this.program,
|
|
56
|
+
this.insuranceFundStakeAccountPublicKey,
|
|
57
|
+
undefined,
|
|
58
|
+
this.reconnectTimeoutMs,
|
|
59
|
+
this.commitment
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (insuranceFundStakeAccount) {
|
|
63
|
+
this.insuranceFundStakeDataAccountSubscriber.setData(
|
|
64
|
+
insuranceFundStakeAccount
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await this.insuranceFundStakeDataAccountSubscriber.subscribe(
|
|
69
|
+
(data: InsuranceFundStake) => {
|
|
70
|
+
this.eventEmitter.emit('insuranceFundStakeAccountUpdate', data);
|
|
71
|
+
this.eventEmitter.emit('update');
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
this.eventEmitter.emit('update');
|
|
76
|
+
this.isSubscribed = true;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async fetch(): Promise<void> {
|
|
81
|
+
await Promise.all([this.insuranceFundStakeDataAccountSubscriber.fetch()]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async unsubscribe(): Promise<void> {
|
|
85
|
+
if (!this.isSubscribed) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
await Promise.all([
|
|
90
|
+
this.insuranceFundStakeDataAccountSubscriber.unsubscribe(),
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
this.isSubscribed = false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
assertIsSubscribed(): void {
|
|
97
|
+
if (!this.isSubscribed) {
|
|
98
|
+
throw new NotSubscribedError(
|
|
99
|
+
'You must call `subscribe` before using this function'
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public getInsuranceFundStakeAccountAndSlot(): DataAndSlot<InsuranceFundStake> {
|
|
105
|
+
this.assertIsSubscribed();
|
|
106
|
+
return this.insuranceFundStakeDataAccountSubscriber.dataAndSlot;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public updateData(
|
|
110
|
+
insuranceFundStake: InsuranceFundStake,
|
|
111
|
+
slot: number
|
|
112
|
+
): void {
|
|
113
|
+
const currentDataSlot =
|
|
114
|
+
this.insuranceFundStakeDataAccountSubscriber.dataAndSlot?.slot || 0;
|
|
115
|
+
if (currentDataSlot <= slot) {
|
|
116
|
+
this.insuranceFundStakeDataAccountSubscriber.setData(
|
|
117
|
+
insuranceFundStake,
|
|
118
|
+
slot
|
|
119
|
+
);
|
|
120
|
+
this.eventEmitter.emit(
|
|
121
|
+
'insuranceFundStakeAccountUpdate',
|
|
122
|
+
insuranceFundStake
|
|
123
|
+
);
|
|
124
|
+
this.eventEmitter.emit('update');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|