@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.
- package/VERSION +1 -1
- package/lib/accounts/bulkAccountLoader.js +1 -1
- package/lib/accounts/pollingUserAccountSubscriber.js +14 -7
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +14 -7
- package/lib/accounts/webSocketAccountSubscriber.js +1 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +3 -2
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +6 -5
- package/lib/accounts/webSocketProgramAccountSubscriber.js +1 -1
- package/lib/accounts/webSocketUserAccountSubscriber.js +1 -1
- package/lib/constants/spotMarkets.js +10 -0
- package/lib/dlob/orderBookLevels.js +1 -1
- package/lib/driftClient.js +4 -4
- package/lib/events/eventSubscriber.js +1 -1
- package/lib/events/types.d.ts +1 -0
- package/lib/events/webSocketLogProvider.d.ts +7 -1
- package/lib/events/webSocketLogProvider.js +45 -4
- package/lib/orderSubscriber/OrderSubscriber.d.ts +5 -1
- package/lib/orderSubscriber/OrderSubscriber.js +24 -7
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -1
- package/lib/orderSubscriber/WebsocketSubscription.js +4 -3
- package/lib/orderSubscriber/types.d.ts +3 -1
- package/lib/slot/SlotSubscriber.js +4 -2
- package/lib/user.js +3 -3
- package/lib/userMap/userMap.d.ts +16 -4
- package/lib/userMap/userMap.js +83 -41
- package/lib/userMap/userStatsMap.d.ts +29 -8
- package/lib/userMap/userStatsMap.js +46 -41
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +1 -1
- package/src/accounts/pollingUserAccountSubscriber.ts +19 -11
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +20 -12
- package/src/accounts/webSocketAccountSubscriber.ts +1 -1
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +13 -6
- package/src/accounts/webSocketProgramAccountSubscriber.ts +1 -1
- package/src/accounts/webSocketUserAccountSubscriber.ts +1 -1
- package/src/constants/spotMarkets.ts +10 -0
- package/src/dlob/orderBookLevels.ts +1 -1
- package/src/driftClient.ts +3 -2
- package/src/events/eventSubscriber.ts +2 -1
- package/src/events/types.ts +1 -0
- package/src/events/webSocketLogProvider.ts +51 -4
- package/src/orderSubscriber/OrderSubscriber.ts +39 -15
- package/src/orderSubscriber/WebsocketSubscription.ts +7 -2
- package/src/orderSubscriber/types.ts +3 -1
- package/src/slot/SlotSubscriber.ts +4 -2
- package/src/user.ts +3 -3
- package/src/userMap/userMap.ts +139 -66
- package/src/userMap/userStatsMap.ts +64 -69
- package/tests/amm/test.ts +3 -2
- package/tests/dlob/test.ts +8 -5
package/lib/userMap/userMap.js
CHANGED
|
@@ -7,14 +7,17 @@ const buffer_1 = require("buffer");
|
|
|
7
7
|
const memcmp_1 = require("../memcmp");
|
|
8
8
|
class UserMap {
|
|
9
9
|
/**
|
|
10
|
+
* Constructs a new UserMap instance.
|
|
10
11
|
*
|
|
11
|
-
* @param driftClient
|
|
12
|
-
* @param accountSubscription
|
|
13
|
-
* @param includeIdle
|
|
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
|
|
14
17
|
*/
|
|
15
|
-
constructor(driftClient, accountSubscription, includeIdle = false) {
|
|
18
|
+
constructor(driftClient, accountSubscription, includeIdle = false, syncCallback, syncCallbackCriteria = { hasOpenOrders: false }) {
|
|
16
19
|
this.userMap = new Map();
|
|
17
|
-
this.
|
|
20
|
+
this.stateAccountUpdateCallback = async (state) => {
|
|
18
21
|
if (state.numberOfSubAccounts !== this.lastNumberOfSubAccounts) {
|
|
19
22
|
await this.sync();
|
|
20
23
|
this.lastNumberOfSubAccounts = state.numberOfSubAccounts;
|
|
@@ -23,6 +26,12 @@ class UserMap {
|
|
|
23
26
|
this.driftClient = driftClient;
|
|
24
27
|
this.accountSubscription = accountSubscription;
|
|
25
28
|
this.includeIdle = includeIdle;
|
|
29
|
+
this.syncCallback = syncCallback;
|
|
30
|
+
this.syncCallbackCriteria = syncCallbackCriteria;
|
|
31
|
+
}
|
|
32
|
+
addSyncCallback(syncCallback, syncCallbackCriteria = { hasOpenOrders: false }) {
|
|
33
|
+
this.syncCallback = syncCallback;
|
|
34
|
+
this.syncCallbackCriteria = syncCallbackCriteria;
|
|
26
35
|
}
|
|
27
36
|
async subscribe() {
|
|
28
37
|
if (this.size() > 0) {
|
|
@@ -31,7 +40,7 @@ class UserMap {
|
|
|
31
40
|
await this.driftClient.subscribe();
|
|
32
41
|
this.lastNumberOfSubAccounts =
|
|
33
42
|
this.driftClient.getStateAccount().numberOfSubAccounts;
|
|
34
|
-
this.driftClient.eventEmitter.on('stateAccountUpdate', this.
|
|
43
|
+
this.driftClient.eventEmitter.on('stateAccountUpdate', this.stateAccountUpdateCallback);
|
|
35
44
|
await this.sync();
|
|
36
45
|
}
|
|
37
46
|
async addPubkey(userAccountPublicKey, userAccount) {
|
|
@@ -139,45 +148,78 @@ class UserMap {
|
|
|
139
148
|
size() {
|
|
140
149
|
return this.userMap.size;
|
|
141
150
|
}
|
|
151
|
+
getUniqueAuthorities(useSyncCallbackCriteria = true) {
|
|
152
|
+
const usersMeetingCriteria = Array.from(this.userMap.values()).filter((user) => {
|
|
153
|
+
let pass = true;
|
|
154
|
+
if (useSyncCallbackCriteria &&
|
|
155
|
+
this.syncCallbackCriteria.hasOpenOrders) {
|
|
156
|
+
pass = pass && user.getUserAccount().hasOpenOrder;
|
|
157
|
+
}
|
|
158
|
+
return pass;
|
|
159
|
+
});
|
|
160
|
+
const userAuths = new Set(usersMeetingCriteria.map((user) => user.getUserAccount().authority.toBase58()));
|
|
161
|
+
const userAuthKeys = Array.from(userAuths).map((userAuth) => new web3_js_1.PublicKey(userAuth));
|
|
162
|
+
return userAuthKeys;
|
|
163
|
+
}
|
|
142
164
|
async sync() {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
filters.push((0, memcmp_1.getNonIdleUserFilter)());
|
|
146
|
-
}
|
|
147
|
-
const rpcRequestArgs = [
|
|
148
|
-
this.driftClient.program.programId.toBase58(),
|
|
149
|
-
{
|
|
150
|
-
commitment: this.driftClient.connection.commitment,
|
|
151
|
-
filters,
|
|
152
|
-
encoding: 'base64',
|
|
153
|
-
withContext: true,
|
|
154
|
-
},
|
|
155
|
-
];
|
|
156
|
-
// @ts-ignore
|
|
157
|
-
const rpcJSONResponse = await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
|
|
158
|
-
const rpcResponseAndContext = rpcJSONResponse.result;
|
|
159
|
-
const slot = rpcResponseAndContext.context.slot;
|
|
160
|
-
const programAccountBufferMap = new Map();
|
|
161
|
-
for (const programAccount of rpcResponseAndContext.value) {
|
|
162
|
-
programAccountBufferMap.set(programAccount.pubkey.toString(),
|
|
163
|
-
// @ts-ignore
|
|
164
|
-
buffer_1.Buffer.from(programAccount.account.data[0], programAccount.account.data[1]));
|
|
165
|
+
if (this.syncPromise) {
|
|
166
|
+
return this.syncPromise;
|
|
165
167
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
this.syncPromise = new Promise((resolver) => {
|
|
169
|
+
this.syncPromiseResolver = resolver;
|
|
170
|
+
});
|
|
171
|
+
try {
|
|
172
|
+
const filters = [(0, memcmp_1.getUserFilter)()];
|
|
173
|
+
if (!this.includeIdle) {
|
|
174
|
+
filters.push((0, memcmp_1.getNonIdleUserFilter)());
|
|
170
175
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
const rpcRequestArgs = [
|
|
177
|
+
this.driftClient.program.programId.toBase58(),
|
|
178
|
+
{
|
|
179
|
+
commitment: this.driftClient.connection.commitment,
|
|
180
|
+
filters,
|
|
181
|
+
encoding: 'base64',
|
|
182
|
+
withContext: true,
|
|
183
|
+
},
|
|
184
|
+
];
|
|
185
|
+
const rpcJSONResponse =
|
|
186
|
+
// @ts-ignore
|
|
187
|
+
await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
|
|
188
|
+
const rpcResponseAndContext = rpcJSONResponse.result;
|
|
189
|
+
const slot = rpcResponseAndContext.context.slot;
|
|
190
|
+
const programAccountBufferMap = new Map();
|
|
191
|
+
for (const programAccount of rpcResponseAndContext.value) {
|
|
192
|
+
programAccountBufferMap.set(programAccount.pubkey.toString(),
|
|
193
|
+
// @ts-ignore
|
|
194
|
+
buffer_1.Buffer.from(programAccount.account.data[0], programAccount.account.data[1]));
|
|
195
|
+
}
|
|
196
|
+
for (const [key, buffer] of programAccountBufferMap.entries()) {
|
|
197
|
+
if (!this.has(key)) {
|
|
198
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', buffer);
|
|
199
|
+
await this.addPubkey(new web3_js_1.PublicKey(key), userAccount);
|
|
200
|
+
}
|
|
176
201
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
202
|
+
for (const [key, user] of this.userMap.entries()) {
|
|
203
|
+
if (!programAccountBufferMap.has(key)) {
|
|
204
|
+
await user.unsubscribe();
|
|
205
|
+
this.userMap.delete(key);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', programAccountBufferMap.get(key));
|
|
209
|
+
user.accountSubscriber.updateData(userAccount, slot);
|
|
210
|
+
}
|
|
180
211
|
}
|
|
212
|
+
if (this.syncCallback) {
|
|
213
|
+
await this.syncCallback(this.getUniqueAuthorities());
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
console.error(`Error in UserMap.sync()`);
|
|
218
|
+
console.error(e);
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
this.syncPromiseResolver();
|
|
222
|
+
this.syncPromise = undefined;
|
|
181
223
|
}
|
|
182
224
|
}
|
|
183
225
|
async unsubscribe() {
|
|
@@ -186,7 +228,7 @@ class UserMap {
|
|
|
186
228
|
this.userMap.delete(key);
|
|
187
229
|
}
|
|
188
230
|
if (this.lastNumberOfSubAccounts) {
|
|
189
|
-
this.driftClient.eventEmitter.removeListener('stateAccountUpdate', this.
|
|
231
|
+
this.driftClient.eventEmitter.removeListener('stateAccountUpdate', this.stateAccountUpdateCallback);
|
|
190
232
|
this.lastNumberOfSubAccounts = undefined;
|
|
191
233
|
}
|
|
192
234
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DriftClient, OrderRecord, UserStatsAccount, UserStats,
|
|
1
|
+
import { DriftClient, OrderRecord, UserStatsAccount, UserStats, WrappedEvent, BulkAccountLoader } from '..';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { UserMap } from './userMap';
|
|
4
4
|
export declare class UserStatsMap {
|
|
@@ -7,19 +7,40 @@ export declare class UserStatsMap {
|
|
|
7
7
|
*/
|
|
8
8
|
private userStatsMap;
|
|
9
9
|
private driftClient;
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
private bulkAccountLoader;
|
|
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: DriftClient, bulkAccountLoader?: BulkAccountLoader);
|
|
18
|
+
subscribe(authorities: PublicKey[]): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param authority that owns the UserStatsAccount
|
|
22
|
+
* @param userStatsAccount optional UserStatsAccount to subscribe to, if undefined will be fetched later
|
|
23
|
+
* @param skipFetch if true, will not immediately fetch the UserStatsAccount
|
|
24
|
+
*/
|
|
25
|
+
addUserStat(authority: PublicKey, userStatsAccount?: UserStatsAccount, skipFetch?: boolean): Promise<void>;
|
|
16
26
|
updateWithOrderRecord(record: OrderRecord, userMap: UserMap): Promise<void>;
|
|
17
27
|
updateWithEventRecord(record: WrappedEvent<any>, userMap?: UserMap): Promise<void>;
|
|
18
28
|
has(authorityPublicKey: string): boolean;
|
|
19
29
|
get(authorityPublicKey: string): UserStats;
|
|
30
|
+
/**
|
|
31
|
+
* Enforce that a UserStats will exist for the given authorityPublicKey,
|
|
32
|
+
* reading one from the blockchain if necessary.
|
|
33
|
+
* @param authorityPublicKey
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
20
36
|
mustGet(authorityPublicKey: string): Promise<UserStats>;
|
|
21
37
|
values(): IterableIterator<UserStats>;
|
|
22
38
|
size(): number;
|
|
23
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Sync the UserStatsMap
|
|
41
|
+
* @param authorities list of authorities to derive UserStatsAccount public keys from.
|
|
42
|
+
* You may want to get this list from UserMap in order to filter out idle users
|
|
43
|
+
*/
|
|
44
|
+
sync(authorities: PublicKey[]): Promise<void>;
|
|
24
45
|
unsubscribe(): Promise<void>;
|
|
25
46
|
}
|
|
@@ -4,43 +4,57 @@ exports.UserStatsMap = void 0;
|
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
class UserStatsMap {
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new UserStatsMap instance.
|
|
9
|
+
*
|
|
10
|
+
* @param {DriftClient} driftClient - The DriftClient instance.
|
|
11
|
+
* @param {BulkAccountLoader} [bulkAccountLoader] - If not provided, a new BulkAccountLoader with polling disabled will be created.
|
|
12
|
+
*/
|
|
13
|
+
constructor(driftClient, bulkAccountLoader) {
|
|
8
14
|
/**
|
|
9
15
|
* map from authority pubkey to UserStats
|
|
10
16
|
*/
|
|
11
17
|
this.userStatsMap = new Map();
|
|
12
|
-
this.syncCallback = async (state) => {
|
|
13
|
-
if (state.numberOfAuthorities !== this.lastNumberOfAuthorities) {
|
|
14
|
-
await this.sync();
|
|
15
|
-
this.lastNumberOfAuthorities = state.numberOfAuthorities;
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
18
|
this.driftClient = driftClient;
|
|
19
|
-
|
|
19
|
+
if (!bulkAccountLoader) {
|
|
20
|
+
bulkAccountLoader = new __1.BulkAccountLoader(driftClient.connection, driftClient.opts.commitment, 0);
|
|
21
|
+
}
|
|
22
|
+
this.bulkAccountLoader = bulkAccountLoader;
|
|
20
23
|
}
|
|
21
|
-
async subscribe() {
|
|
24
|
+
async subscribe(authorities) {
|
|
22
25
|
if (this.size() > 0) {
|
|
23
26
|
return;
|
|
24
27
|
}
|
|
25
28
|
await this.driftClient.subscribe();
|
|
26
|
-
this.
|
|
27
|
-
this.driftClient.getStateAccount().numberOfAuthorities;
|
|
28
|
-
this.driftClient.eventEmitter.on('stateAccountUpdate', this.syncCallback);
|
|
29
|
-
await this.sync();
|
|
29
|
+
await this.sync(authorities);
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @param authority that owns the UserStatsAccount
|
|
34
|
+
* @param userStatsAccount optional UserStatsAccount to subscribe to, if undefined will be fetched later
|
|
35
|
+
* @param skipFetch if true, will not immediately fetch the UserStatsAccount
|
|
36
|
+
*/
|
|
37
|
+
async addUserStat(authority, userStatsAccount, skipFetch) {
|
|
32
38
|
const userStat = new __1.UserStats({
|
|
33
39
|
driftClient: this.driftClient,
|
|
34
40
|
userStatsAccountPublicKey: (0, __1.getUserStatsAccountPublicKey)(this.driftClient.program.programId, authority),
|
|
35
|
-
accountSubscription:
|
|
41
|
+
accountSubscription: {
|
|
42
|
+
type: 'polling',
|
|
43
|
+
accountLoader: this.bulkAccountLoader,
|
|
44
|
+
},
|
|
36
45
|
});
|
|
37
|
-
|
|
46
|
+
if (skipFetch) {
|
|
47
|
+
await userStat.accountSubscriber.addToAccountLoader();
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await userStat.subscribe(userStatsAccount);
|
|
51
|
+
}
|
|
38
52
|
this.userStatsMap.set(authority.toString(), userStat);
|
|
39
53
|
}
|
|
40
54
|
async updateWithOrderRecord(record, userMap) {
|
|
41
55
|
const user = await userMap.mustGet(record.user.toString());
|
|
42
56
|
if (!this.has(user.getUserAccount().authority.toString())) {
|
|
43
|
-
await this.addUserStat(user.getUserAccount().authority);
|
|
57
|
+
await this.addUserStat(user.getUserAccount().authority, undefined, false);
|
|
44
58
|
}
|
|
45
59
|
}
|
|
46
60
|
async updateWithEventRecord(record, userMap) {
|
|
@@ -114,9 +128,15 @@ class UserStatsMap {
|
|
|
114
128
|
get(authorityPublicKey) {
|
|
115
129
|
return this.userStatsMap.get(authorityPublicKey);
|
|
116
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Enforce that a UserStats will exist for the given authorityPublicKey,
|
|
133
|
+
* reading one from the blockchain if necessary.
|
|
134
|
+
* @param authorityPublicKey
|
|
135
|
+
* @returns
|
|
136
|
+
*/
|
|
117
137
|
async mustGet(authorityPublicKey) {
|
|
118
138
|
if (!this.has(authorityPublicKey)) {
|
|
119
|
-
await this.addUserStat(new web3_js_1.PublicKey(authorityPublicKey));
|
|
139
|
+
await this.addUserStat(new web3_js_1.PublicKey(authorityPublicKey), undefined, false);
|
|
120
140
|
}
|
|
121
141
|
return this.get(authorityPublicKey);
|
|
122
142
|
}
|
|
@@ -126,35 +146,20 @@ class UserStatsMap {
|
|
|
126
146
|
size() {
|
|
127
147
|
return this.userStatsMap.size;
|
|
128
148
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
});
|
|
138
|
-
const programAccountMap = new Map();
|
|
139
|
-
for (const programAccount of programAccounts) {
|
|
140
|
-
programAccountMap.set(new web3_js_1.PublicKey(programAccount.account.data.slice(8, 40)).toString(), programAccount.account);
|
|
141
|
-
}
|
|
142
|
-
for (const key of programAccountMap.keys()) {
|
|
143
|
-
if (!this.has(key)) {
|
|
144
|
-
const userStatsAccount = this.driftClient.program.account.userStats.coder.accounts.decode('UserStats', programAccountMap.get(key).data);
|
|
145
|
-
await this.addUserStat(new web3_js_1.PublicKey(key), userStatsAccount);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
149
|
+
/**
|
|
150
|
+
* Sync the UserStatsMap
|
|
151
|
+
* @param authorities list of authorities to derive UserStatsAccount public keys from.
|
|
152
|
+
* You may want to get this list from UserMap in order to filter out idle users
|
|
153
|
+
*/
|
|
154
|
+
async sync(authorities) {
|
|
155
|
+
await Promise.all(authorities.map((authority) => this.addUserStat(authority, undefined, true)));
|
|
156
|
+
await this.bulkAccountLoader.load();
|
|
148
157
|
}
|
|
149
158
|
async unsubscribe() {
|
|
150
159
|
for (const [key, userStats] of this.userStatsMap.entries()) {
|
|
151
160
|
await userStats.unsubscribe();
|
|
152
161
|
this.userStatsMap.delete(key);
|
|
153
162
|
}
|
|
154
|
-
if (this.lastNumberOfAuthorities) {
|
|
155
|
-
this.driftClient.eventEmitter.removeListener('stateAccountUpdate', this.syncCallback);
|
|
156
|
-
this.lastNumberOfAuthorities = undefined;
|
|
157
|
-
}
|
|
158
163
|
}
|
|
159
164
|
}
|
|
160
165
|
exports.UserStatsMap = UserStatsMap;
|
package/package.json
CHANGED
|
@@ -193,7 +193,7 @@ export class BulkAccountLoader {
|
|
|
193
193
|
const key = accountToLoad.publicKey.toBase58();
|
|
194
194
|
const oldRPCResponse = this.bufferAndSlotMap.get(key);
|
|
195
195
|
|
|
196
|
-
if (oldRPCResponse && newSlot
|
|
196
|
+
if (oldRPCResponse && newSlot < oldRPCResponse.slot) {
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -93,17 +93,21 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
async fetch(): Promise<void> {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
try {
|
|
97
|
+
const dataAndContext = await this.program.account.user.fetchAndContext(
|
|
98
|
+
this.userAccountPublicKey,
|
|
99
|
+
this.accountLoader.commitment
|
|
100
|
+
);
|
|
101
|
+
if (dataAndContext.context.slot > (this.user?.slot ?? 0)) {
|
|
102
|
+
this.user = {
|
|
103
|
+
data: dataAndContext.data as UserAccount,
|
|
104
|
+
slot: dataAndContext.context.slot,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.log(
|
|
109
|
+
`PollingUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}`
|
|
105
110
|
);
|
|
106
|
-
this.user = { data: account, slot };
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
|
|
@@ -137,7 +141,11 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
public getUserAccountAndSlot(): DataAndSlot<UserAccount> {
|
|
140
|
-
this.
|
|
144
|
+
if (!this.doesAccountExist()) {
|
|
145
|
+
throw new NotSubscribedError(
|
|
146
|
+
'You must call `subscribe` or `fetch` before using this function'
|
|
147
|
+
);
|
|
148
|
+
}
|
|
141
149
|
return this.user;
|
|
142
150
|
}
|
|
143
151
|
|
|
@@ -97,18 +97,22 @@ export class PollingUserStatsAccountSubscriber
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
async fetch(): Promise<void> {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (buffer && slot > currentSlot) {
|
|
106
|
-
const account =
|
|
107
|
-
this.program.account.userStats.coder.accounts.decodeUnchecked(
|
|
108
|
-
'UserStats',
|
|
109
|
-
buffer
|
|
100
|
+
try {
|
|
101
|
+
const dataAndContext =
|
|
102
|
+
await this.program.account.userStats.fetchAndContext(
|
|
103
|
+
this.userStatsAccountPublicKey,
|
|
104
|
+
this.accountLoader.commitment
|
|
110
105
|
);
|
|
111
|
-
this.userStats
|
|
106
|
+
if (dataAndContext.context.slot > (this.userStats?.slot ?? 0)) {
|
|
107
|
+
this.userStats = {
|
|
108
|
+
data: dataAndContext.data as UserStatsAccount,
|
|
109
|
+
slot: dataAndContext.context.slot,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
console.log(
|
|
114
|
+
`PollingUserStatsAccountSubscriber.fetch() UserStatsAccount does not exist: ${e.message}`
|
|
115
|
+
);
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
|
|
@@ -142,7 +146,11 @@ export class PollingUserStatsAccountSubscriber
|
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
public getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount> {
|
|
145
|
-
this.
|
|
149
|
+
if (!this.doesAccountExist()) {
|
|
150
|
+
throw new NotSubscribedError(
|
|
151
|
+
'You must call `subscribe` or `fetch` before using this function'
|
|
152
|
+
);
|
|
153
|
+
}
|
|
146
154
|
return this.userStats;
|
|
147
155
|
}
|
|
148
156
|
}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getPerpMarketPublicKey,
|
|
15
15
|
} from '../addresses/pda';
|
|
16
16
|
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
17
|
-
import { PublicKey } from '@solana/web3.js';
|
|
17
|
+
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
18
18
|
import { OracleInfo, OraclePriceData } from '../oracles/types';
|
|
19
19
|
import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
20
20
|
import * as Buffer from 'buffer';
|
|
@@ -26,6 +26,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
26
26
|
{
|
|
27
27
|
isSubscribed: boolean;
|
|
28
28
|
program: Program;
|
|
29
|
+
commitment?: Commitment;
|
|
29
30
|
perpMarketIndexes: number[];
|
|
30
31
|
spotMarketIndexes: number[];
|
|
31
32
|
oracleInfos: OracleInfo[];
|
|
@@ -56,7 +57,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
56
57
|
spotMarketIndexes: number[],
|
|
57
58
|
oracleInfos: OracleInfo[],
|
|
58
59
|
shouldFindAllMarketsAndOracles: boolean,
|
|
59
|
-
resubTimeoutMs?: number
|
|
60
|
+
resubTimeoutMs?: number,
|
|
61
|
+
commitment?: Commitment
|
|
60
62
|
) {
|
|
61
63
|
this.isSubscribed = false;
|
|
62
64
|
this.program = program;
|
|
@@ -66,6 +68,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
66
68
|
this.oracleInfos = oracleInfos;
|
|
67
69
|
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
68
70
|
this.resubTimeoutMs = resubTimeoutMs;
|
|
71
|
+
this.commitment = commitment;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
public async subscribe(): Promise<boolean> {
|
|
@@ -101,7 +104,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
101
104
|
this.program,
|
|
102
105
|
statePublicKey,
|
|
103
106
|
undefined,
|
|
104
|
-
this.resubTimeoutMs
|
|
107
|
+
this.resubTimeoutMs,
|
|
108
|
+
this.commitment
|
|
105
109
|
);
|
|
106
110
|
await this.stateAccountSubscriber.subscribe((data: StateAccount) => {
|
|
107
111
|
this.eventEmitter.emit('stateAccountUpdate', data);
|
|
@@ -143,7 +147,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
143
147
|
this.program,
|
|
144
148
|
perpMarketPublicKey,
|
|
145
149
|
undefined,
|
|
146
|
-
this.resubTimeoutMs
|
|
150
|
+
this.resubTimeoutMs,
|
|
151
|
+
this.commitment
|
|
147
152
|
);
|
|
148
153
|
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
149
154
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
@@ -170,7 +175,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
170
175
|
this.program,
|
|
171
176
|
marketPublicKey,
|
|
172
177
|
undefined,
|
|
173
|
-
this.resubTimeoutMs
|
|
178
|
+
this.resubTimeoutMs,
|
|
179
|
+
this.commitment
|
|
174
180
|
);
|
|
175
181
|
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
176
182
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
@@ -202,7 +208,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
202
208
|
(buffer: Buffer) => {
|
|
203
209
|
return client.getOraclePriceDataFromBuffer(buffer);
|
|
204
210
|
},
|
|
205
|
-
this.resubTimeoutMs
|
|
211
|
+
this.resubTimeoutMs,
|
|
212
|
+
this.commitment
|
|
206
213
|
);
|
|
207
214
|
|
|
208
215
|
await accountSubscriber.subscribe((data: OraclePriceData) => {
|
|
@@ -94,7 +94,7 @@ export class WebSocketUserAccountSubscriber implements UserAccountSubscriber {
|
|
|
94
94
|
public updateData(userAccount: UserAccount, slot: number) {
|
|
95
95
|
const currentDataSlot =
|
|
96
96
|
this.userDataAccountSubscriber.dataAndSlot?.slot || 0;
|
|
97
|
-
if (currentDataSlot
|
|
97
|
+
if (currentDataSlot <= slot) {
|
|
98
98
|
this.userDataAccountSubscriber.setData(userAccount, slot);
|
|
99
99
|
this.eventEmitter.emit('userAccountUpdate', userAccount);
|
|
100
100
|
this.eventEmitter.emit('update');
|
|
@@ -150,6 +150,16 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
|
|
|
150
150
|
'2sTMN9A1D1qeZLF95XQgJCUPiKe5DiV52jLfZGqMP46m'
|
|
151
151
|
),
|
|
152
152
|
},
|
|
153
|
+
{
|
|
154
|
+
symbol: 'bSOL',
|
|
155
|
+
marketIndex: 8,
|
|
156
|
+
oracle: new PublicKey('AFrYBhb5wKQtxRS9UA9YRS4V3dwFm7SqmS6DHKq6YVgo'),
|
|
157
|
+
oracleSource: OracleSource.PYTH,
|
|
158
|
+
mint: new PublicKey('bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1'),
|
|
159
|
+
precision: new BN(10).pow(NINE),
|
|
160
|
+
precisionExp: NINE,
|
|
161
|
+
serumMarket: new PublicKey('ARjaHVxGCQfTvvKjLd7U7srvk6orthZSE6uqWchCczZc'),
|
|
162
|
+
},
|
|
153
163
|
];
|
|
154
164
|
|
|
155
165
|
export const SpotMarkets: { [key in DriftEnv]: SpotMarketConfig[] } = {
|
|
@@ -173,7 +173,7 @@ export function getVammL2Generator({
|
|
|
173
173
|
updatedAmm.orderStepSize
|
|
174
174
|
);
|
|
175
175
|
|
|
176
|
-
const minOrderSize = marketAccount.amm.
|
|
176
|
+
const minOrderSize = marketAccount.amm.minOrderSize;
|
|
177
177
|
if (openBids.lt(minOrderSize.muln(2))) {
|
|
178
178
|
openBids = ZERO;
|
|
179
179
|
}
|
package/src/driftClient.ts
CHANGED
|
@@ -283,7 +283,8 @@ export class DriftClient {
|
|
|
283
283
|
config.spotMarketIndexes ?? [],
|
|
284
284
|
config.oracleInfos ?? [],
|
|
285
285
|
noMarketsAndOraclesSpecified,
|
|
286
|
-
config.accountSubscription?.resubTimeoutMs
|
|
286
|
+
config.accountSubscription?.resubTimeoutMs,
|
|
287
|
+
config.accountSubscription?.commitment
|
|
287
288
|
);
|
|
288
289
|
}
|
|
289
290
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
@@ -2028,7 +2029,7 @@ export class DriftClient {
|
|
|
2028
2029
|
}
|
|
2029
2030
|
|
|
2030
2031
|
const tx = await this.buildTransaction(withdrawIxs, {
|
|
2031
|
-
computeUnits:
|
|
2032
|
+
computeUnits: 1_400_000,
|
|
2032
2033
|
});
|
|
2033
2034
|
const { txSig, slot } = await this.sendTransaction(
|
|
2034
2035
|
tx,
|
|
@@ -56,7 +56,8 @@ export class EventSubscriber {
|
|
|
56
56
|
this.logProvider = new WebSocketLogProvider(
|
|
57
57
|
this.connection,
|
|
58
58
|
this.address,
|
|
59
|
-
this.options.commitment
|
|
59
|
+
this.options.commitment,
|
|
60
|
+
this.options.resubTimeoutMs
|
|
60
61
|
);
|
|
61
62
|
} else {
|
|
62
63
|
this.logProvider = new PollingLogProvider(
|
package/src/events/types.ts
CHANGED
|
@@ -28,6 +28,7 @@ export type EventSubscriptionOptions = {
|
|
|
28
28
|
// when the subscription starts, client might want to backtrack and fetch old tx's
|
|
29
29
|
// this specifies how far to backtrack
|
|
30
30
|
untilTx?: TransactionSignature;
|
|
31
|
+
resubTimeoutMs?: number;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
export const DefaultEventSubscriptionOptions: EventSubscriptionOptions = {
|