@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
|
@@ -47,7 +47,7 @@ export class EventSubscriber {
|
|
|
47
47
|
new EventList(
|
|
48
48
|
eventType,
|
|
49
49
|
this.options.maxEventsPerType,
|
|
50
|
-
getSortFn(this.options.orderBy, this.options.orderDir
|
|
50
|
+
getSortFn(this.options.orderBy, this.options.orderDir),
|
|
51
51
|
this.options.orderDir
|
|
52
52
|
)
|
|
53
53
|
);
|
|
@@ -159,6 +159,7 @@ export class EventSubscriber {
|
|
|
159
159
|
|
|
160
160
|
if (!this.lastSeenSlot || slot > this.lastSeenSlot) {
|
|
161
161
|
this.lastSeenTxSig = txSig;
|
|
162
|
+
this.lastSeenSlot = slot;
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
if (
|
package/src/events/sort.ts
CHANGED
|
@@ -4,10 +4,7 @@ import {
|
|
|
4
4
|
EventSubscriptionOrderDirection,
|
|
5
5
|
EventType,
|
|
6
6
|
SortFn,
|
|
7
|
-
Event,
|
|
8
7
|
} from './types';
|
|
9
|
-
import { OrderActionRecord } from '../types';
|
|
10
|
-
import { ZERO } from '../index';
|
|
11
8
|
|
|
12
9
|
function clientSortAscFn(): 'less than' {
|
|
13
10
|
return 'less than';
|
|
@@ -17,45 +14,26 @@ function clientSortDescFn(): 'greater than' {
|
|
|
17
14
|
return 'greater than';
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
function
|
|
17
|
+
function blockchainSortFn(
|
|
21
18
|
currentEvent: EventMap[EventType],
|
|
22
19
|
newEvent: EventMap[EventType]
|
|
23
20
|
): 'less than' | 'greater than' {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
function orderActionRecordSortFn(
|
|
28
|
-
currentEvent: Event<OrderActionRecord>,
|
|
29
|
-
newEvent: Event<OrderActionRecord>
|
|
30
|
-
): 'less than' | 'greater than' {
|
|
31
|
-
const currentEventMarketIndex = currentEvent.marketIndex;
|
|
32
|
-
const newEventMarketIndex = newEvent.marketIndex;
|
|
33
|
-
if (currentEventMarketIndex !== newEventMarketIndex) {
|
|
34
|
-
return currentEvent.ts.lte(newEvent.ts) ? 'less than' : 'greater than';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (currentEvent.fillRecordId?.gt(ZERO) && newEvent.fillRecordId?.gt(ZERO)) {
|
|
38
|
-
return currentEvent.fillRecordId.lte(newEvent.fillRecordId)
|
|
21
|
+
if (currentEvent.slot == newEvent.slot) {
|
|
22
|
+
return currentEvent.txSigIndex < newEvent.txSigIndex
|
|
39
23
|
? 'less than'
|
|
40
24
|
: 'greater than';
|
|
41
|
-
} else {
|
|
42
|
-
return currentEvent.ts.lte(newEvent.ts) ? 'less than' : 'greater than';
|
|
43
25
|
}
|
|
26
|
+
|
|
27
|
+
return currentEvent.slot < newEvent.slot ? 'less than' : 'greater than';
|
|
44
28
|
}
|
|
45
29
|
|
|
46
30
|
export function getSortFn(
|
|
47
31
|
orderBy: EventSubscriptionOrderBy,
|
|
48
|
-
orderDir: EventSubscriptionOrderDirection
|
|
49
|
-
eventType: EventType
|
|
32
|
+
orderDir: EventSubscriptionOrderDirection
|
|
50
33
|
): SortFn {
|
|
51
34
|
if (orderBy === 'client') {
|
|
52
35
|
return orderDir === 'asc' ? clientSortAscFn : clientSortDescFn;
|
|
53
36
|
}
|
|
54
37
|
|
|
55
|
-
|
|
56
|
-
case 'OrderActionRecord':
|
|
57
|
-
return orderActionRecordSortFn;
|
|
58
|
-
default:
|
|
59
|
-
return defaultBlockchainSortFn;
|
|
60
|
-
}
|
|
38
|
+
return blockchainSortFn;
|
|
61
39
|
}
|
package/src/examples/loadDlob.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnchorProvider } from '@coral-xyz/anchor';
|
|
2
|
-
import {
|
|
2
|
+
import { UserMap, Wallet } from '..';
|
|
3
3
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
4
4
|
import {
|
|
5
5
|
DriftClient,
|
|
@@ -55,17 +55,22 @@ const main = async () => {
|
|
|
55
55
|
await driftClient.subscribe();
|
|
56
56
|
|
|
57
57
|
console.log('Loading user map...');
|
|
58
|
-
const userMap = new UserMap(
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
const userMap = new UserMap({
|
|
59
|
+
driftClient,
|
|
60
|
+
subscriptionConfig: {
|
|
61
|
+
type: 'websocket',
|
|
62
|
+
commitment: 'processed',
|
|
63
|
+
},
|
|
64
|
+
skipInitialLoad: false,
|
|
65
|
+
includeIdle: false,
|
|
61
66
|
});
|
|
62
67
|
|
|
63
68
|
// fetches all users and subscribes for updates
|
|
64
69
|
await userMap.subscribe();
|
|
65
70
|
|
|
66
71
|
console.log('Loading dlob from user map...');
|
|
67
|
-
const
|
|
68
|
-
await
|
|
72
|
+
const slot = await driftClient.connection.getSlot();
|
|
73
|
+
const dlob = await userMap.getDLOB(slot);
|
|
69
74
|
|
|
70
75
|
console.log('number of orders', dlob.getDLOBOrders().length);
|
|
71
76
|
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './types';
|
|
|
10
10
|
export * from './constants/perpMarkets';
|
|
11
11
|
export * from './accounts/fetch';
|
|
12
12
|
export * from './accounts/webSocketDriftClientAccountSubscriber';
|
|
13
|
+
export * from './accounts/webSocketInsuranceFundStakeAccountSubscriber';
|
|
13
14
|
export * from './accounts/bulkAccountLoader';
|
|
14
15
|
export * from './accounts/bulkUserSubscription';
|
|
15
16
|
export * from './accounts/bulkUserStatsSubscription';
|
|
@@ -18,7 +19,8 @@ export * from './accounts/pollingOracleAccountSubscriber';
|
|
|
18
19
|
export * from './accounts/pollingTokenAccountSubscriber';
|
|
19
20
|
export * from './accounts/pollingUserAccountSubscriber';
|
|
20
21
|
export * from './accounts/pollingUserStatsAccountSubscriber';
|
|
21
|
-
export * from './accounts/
|
|
22
|
+
export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
|
|
23
|
+
export * from './accounts/basicUserAccountSubscriber';
|
|
22
24
|
export * from './accounts/types';
|
|
23
25
|
export * from './addresses/pda';
|
|
24
26
|
export * from './adminClient';
|
package/src/math/superStake.ts
CHANGED
|
@@ -14,6 +14,38 @@ import { LAMPORTS_PRECISION, ZERO } from '../constants/numericConstants';
|
|
|
14
14
|
import fetch from 'node-fetch';
|
|
15
15
|
import { checkSameDate } from './utils';
|
|
16
16
|
|
|
17
|
+
export type BSOL_STATS_API_RESPONSE = {
|
|
18
|
+
success: boolean;
|
|
19
|
+
stats?: {
|
|
20
|
+
conversion: {
|
|
21
|
+
bsol_to_sol: number;
|
|
22
|
+
sol_to_bsol: number;
|
|
23
|
+
};
|
|
24
|
+
apy: {
|
|
25
|
+
base: number;
|
|
26
|
+
blze: number;
|
|
27
|
+
total: number;
|
|
28
|
+
lending: number;
|
|
29
|
+
liquidity: number;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type BSOL_EMISSIONS_API_RESPONSE = {
|
|
35
|
+
success: boolean;
|
|
36
|
+
emissions?: {
|
|
37
|
+
lend: number;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export async function fetchBSolMetrics() {
|
|
42
|
+
return await fetch('https://stake.solblaze.org/api/v1/stats');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function fetchBSolDriftEmissions() {
|
|
46
|
+
return await fetch('https://stake.solblaze.org/api/v1/drift_emissions');
|
|
47
|
+
}
|
|
48
|
+
|
|
17
49
|
export async function findBestSuperStakeIxs({
|
|
18
50
|
marketIndex,
|
|
19
51
|
amount,
|
|
@@ -56,6 +88,16 @@ export async function findBestSuperStakeIxs({
|
|
|
56
88
|
userAccountPublicKey,
|
|
57
89
|
onlyDirectRoutes,
|
|
58
90
|
});
|
|
91
|
+
} else if (marketIndex === 8) {
|
|
92
|
+
return findBestLstSuperStakeIxs({
|
|
93
|
+
amount,
|
|
94
|
+
lstMint: driftClient.getSpotMarketAccount(8).mint,
|
|
95
|
+
lstMarketIndex: 8,
|
|
96
|
+
jupiterClient,
|
|
97
|
+
driftClient,
|
|
98
|
+
userAccountPublicKey,
|
|
99
|
+
onlyDirectRoutes,
|
|
100
|
+
});
|
|
59
101
|
} else {
|
|
60
102
|
throw new Error(`Unsupported superstake market index: ${marketIndex}`);
|
|
61
103
|
}
|
|
@@ -153,16 +195,53 @@ export async function findBestJitoSolSuperStakeIxs({
|
|
|
153
195
|
lookupTables: AddressLookupTableAccount[];
|
|
154
196
|
method: 'jupiter' | 'marinade';
|
|
155
197
|
price: number;
|
|
198
|
+
}> {
|
|
199
|
+
return await findBestLstSuperStakeIxs({
|
|
200
|
+
amount,
|
|
201
|
+
jupiterClient,
|
|
202
|
+
driftClient,
|
|
203
|
+
userAccountPublicKey,
|
|
204
|
+
onlyDirectRoutes,
|
|
205
|
+
lstMint: driftClient.getSpotMarketAccount(6).mint,
|
|
206
|
+
lstMarketIndex: 6,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Finds best Jupiter Swap instructions for a generic lstMint
|
|
212
|
+
*
|
|
213
|
+
* Without doing any extra steps like checking if you can get a better rate by staking directly with that LST platform
|
|
214
|
+
*/
|
|
215
|
+
export async function findBestLstSuperStakeIxs({
|
|
216
|
+
amount,
|
|
217
|
+
lstMint,
|
|
218
|
+
jupiterClient,
|
|
219
|
+
driftClient,
|
|
220
|
+
userAccountPublicKey,
|
|
221
|
+
onlyDirectRoutes,
|
|
222
|
+
lstMarketIndex,
|
|
223
|
+
}: {
|
|
224
|
+
amount: BN;
|
|
225
|
+
lstMint: PublicKey;
|
|
226
|
+
lstMarketIndex: number;
|
|
227
|
+
jupiterClient: JupiterClient;
|
|
228
|
+
driftClient: DriftClient;
|
|
229
|
+
userAccountPublicKey?: PublicKey;
|
|
230
|
+
onlyDirectRoutes?: boolean;
|
|
231
|
+
}): Promise<{
|
|
232
|
+
ixs: TransactionInstruction[];
|
|
233
|
+
lookupTables: AddressLookupTableAccount[];
|
|
234
|
+
method: 'jupiter' | 'marinade';
|
|
235
|
+
price: number;
|
|
156
236
|
}> {
|
|
157
237
|
const solMint = driftClient.getSpotMarketAccount(1).mint;
|
|
158
|
-
const JitoSolMint = driftClient.getSpotMarketAccount(6).mint;
|
|
159
238
|
|
|
160
239
|
let jupiterPrice;
|
|
161
240
|
let bestRoute;
|
|
162
241
|
try {
|
|
163
242
|
const jupiterRoutes = await jupiterClient.getRoutes({
|
|
164
243
|
inputMint: solMint,
|
|
165
|
-
outputMint:
|
|
244
|
+
outputMint: lstMint,
|
|
166
245
|
amount,
|
|
167
246
|
onlyDirectRoutes,
|
|
168
247
|
});
|
|
@@ -176,7 +255,7 @@ export async function findBestJitoSolSuperStakeIxs({
|
|
|
176
255
|
|
|
177
256
|
const { ixs, lookupTables } = await driftClient.getJupiterSwapIx({
|
|
178
257
|
inMarketIndex: 1,
|
|
179
|
-
outMarketIndex:
|
|
258
|
+
outMarketIndex: lstMarketIndex,
|
|
180
259
|
route: bestRoute,
|
|
181
260
|
jupiterClient,
|
|
182
261
|
amount,
|
|
@@ -322,10 +401,27 @@ export async function calculateSolEarned({
|
|
|
322
401
|
}
|
|
323
402
|
};
|
|
324
403
|
|
|
404
|
+
const getBSolPrice = async (timestamps: number[]) => {
|
|
405
|
+
// Currently there's only one bSOL price, no timestamped data
|
|
406
|
+
// So just use the same price for every timestamp for now
|
|
407
|
+
const response = await fetchBSolMetrics();
|
|
408
|
+
if (response.status === 200) {
|
|
409
|
+
const data = (await response.json()) as BSOL_STATS_API_RESPONSE;
|
|
410
|
+
const bSolRatio = data?.stats?.conversion?.bsol_to_sol;
|
|
411
|
+
if (bSolRatio) {
|
|
412
|
+
timestamps.forEach((timestamp) => lstRatios.set(timestamp, bSolRatio));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// This block kind of assumes the record are all from the same market
|
|
418
|
+
// Otherwise the following code that checks the record.marketIndex would break
|
|
325
419
|
if (marketIndex === 2) {
|
|
326
420
|
await Promise.all(timestamps.map(getMsolPrice));
|
|
327
421
|
} else if (marketIndex === 6) {
|
|
328
422
|
lstRatios = await getJitoSolHistoricalPriceMap(timestamps);
|
|
423
|
+
} else if (marketIndex === 8) {
|
|
424
|
+
await getBSolPrice(timestamps);
|
|
329
425
|
}
|
|
330
426
|
|
|
331
427
|
let solEarned = ZERO;
|
|
@@ -336,23 +432,15 @@ export async function calculateSolEarned({
|
|
|
336
432
|
} else {
|
|
337
433
|
solEarned = solEarned.add(record.amount);
|
|
338
434
|
}
|
|
339
|
-
} else if (
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
} else if (record.marketIndex === 6) {
|
|
350
|
-
const jitoSolRatio = lstRatios.get(record.ts.toNumber());
|
|
351
|
-
const jitoSolRatioBN = new BN(jitoSolRatio * LAMPORTS_PER_SOL);
|
|
352
|
-
|
|
353
|
-
const solAmount = record.amount
|
|
354
|
-
.mul(jitoSolRatioBN)
|
|
355
|
-
.div(LAMPORTS_PRECISION);
|
|
435
|
+
} else if (
|
|
436
|
+
record.marketIndex === 2 ||
|
|
437
|
+
record.marketIndex === 6 ||
|
|
438
|
+
record.marketIndex === 8
|
|
439
|
+
) {
|
|
440
|
+
const lstRatio = lstRatios.get(record.ts.toNumber());
|
|
441
|
+
const lstRatioBN = new BN(lstRatio * LAMPORTS_PER_SOL);
|
|
442
|
+
|
|
443
|
+
const solAmount = record.amount.mul(lstRatioBN).div(LAMPORTS_PRECISION);
|
|
356
444
|
if (isVariant(record.direction, 'deposit')) {
|
|
357
445
|
solEarned = solEarned.sub(solAmount);
|
|
358
446
|
} else {
|
|
@@ -94,12 +94,16 @@ export class OrderSubscriber {
|
|
|
94
94
|
programAccount.account.data,
|
|
95
95
|
slot
|
|
96
96
|
);
|
|
97
|
+
// give event loop a chance to breathe
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
for (const key of this.usersAccounts.keys()) {
|
|
100
102
|
if (!programAccountSet.has(key)) {
|
|
101
103
|
this.usersAccounts.delete(key);
|
|
102
104
|
}
|
|
105
|
+
// give event loop a chance to breathe
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
103
107
|
}
|
|
104
108
|
} catch (e) {
|
|
105
109
|
console.error(e);
|
|
@@ -10,7 +10,7 @@ export class WebsocketSubscription {
|
|
|
10
10
|
private skipInitialLoad: boolean;
|
|
11
11
|
private resubTimeoutMs?: number;
|
|
12
12
|
|
|
13
|
-
private subscriber
|
|
13
|
+
private subscriber?: WebSocketProgramAccountSubscriber<UserAccount>;
|
|
14
14
|
|
|
15
15
|
constructor({
|
|
16
16
|
orderSubscriber,
|
|
@@ -30,22 +30,24 @@ export class WebsocketSubscription {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
public async subscribe(): Promise<void> {
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
'OrderSubscriber',
|
|
36
|
-
'User',
|
|
37
|
-
this.orderSubscriber.driftClient.program,
|
|
38
|
-
this.orderSubscriber.driftClient.program.account.user.coder.accounts.decode.bind(
|
|
39
|
-
this.orderSubscriber.driftClient.program.account.user.coder.accounts
|
|
40
|
-
),
|
|
41
|
-
{
|
|
42
|
-
filters: [getUserFilter(), getNonIdleUserFilter()],
|
|
43
|
-
commitment: this.commitment,
|
|
44
|
-
},
|
|
45
|
-
this.resubTimeoutMs
|
|
46
|
-
);
|
|
33
|
+
if (this.subscriber) {
|
|
34
|
+
return;
|
|
47
35
|
}
|
|
48
36
|
|
|
37
|
+
this.subscriber = new WebSocketProgramAccountSubscriber<UserAccount>(
|
|
38
|
+
'OrderSubscriber',
|
|
39
|
+
'User',
|
|
40
|
+
this.orderSubscriber.driftClient.program,
|
|
41
|
+
this.orderSubscriber.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(
|
|
42
|
+
this.orderSubscriber.driftClient.program.account.user.coder.accounts
|
|
43
|
+
),
|
|
44
|
+
{
|
|
45
|
+
filters: [getUserFilter(), getNonIdleUserFilter()],
|
|
46
|
+
commitment: this.commitment,
|
|
47
|
+
},
|
|
48
|
+
this.resubTimeoutMs
|
|
49
|
+
);
|
|
50
|
+
|
|
49
51
|
await this.subscriber.subscribe(
|
|
50
52
|
(accountId: PublicKey, account: UserAccount, context: Context) => {
|
|
51
53
|
const userKey = accountId.toBase58();
|
|
@@ -65,6 +67,7 @@ export class WebsocketSubscription {
|
|
|
65
67
|
|
|
66
68
|
public async unsubscribe(): Promise<void> {
|
|
67
69
|
if (!this.subscriber) return;
|
|
68
|
-
this.subscriber.unsubscribe();
|
|
70
|
+
await this.subscriber.unsubscribe();
|
|
71
|
+
this.subscriber = undefined;
|
|
69
72
|
}
|
|
70
73
|
}
|
package/src/types.ts
CHANGED
|
@@ -1000,8 +1000,6 @@ export interface IVersionedWallet {
|
|
|
1000
1000
|
|
|
1001
1001
|
export type FeeStructure = {
|
|
1002
1002
|
feeTiers: FeeTier[];
|
|
1003
|
-
makerRebateNumerator: BN;
|
|
1004
|
-
makerRebateDenominator: BN;
|
|
1005
1003
|
fillerRewardStructure: OrderFillerRewardStructure;
|
|
1006
1004
|
flatFillerFee: BN;
|
|
1007
1005
|
referrerRewardEpochUpperBound: BN;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { UserMap } from './userMap';
|
|
2
|
+
|
|
3
|
+
export class PollingSubscription {
|
|
4
|
+
private userMap: UserMap;
|
|
5
|
+
private frequency: number;
|
|
6
|
+
private skipInitialLoad: boolean;
|
|
7
|
+
|
|
8
|
+
intervalId?: ReturnType<typeof setTimeout>;
|
|
9
|
+
|
|
10
|
+
constructor({
|
|
11
|
+
userMap,
|
|
12
|
+
frequency,
|
|
13
|
+
skipInitialLoad = false,
|
|
14
|
+
}: {
|
|
15
|
+
userMap: UserMap;
|
|
16
|
+
frequency: number;
|
|
17
|
+
skipInitialLoad?: boolean;
|
|
18
|
+
includeIdle?: boolean;
|
|
19
|
+
}) {
|
|
20
|
+
this.userMap = userMap;
|
|
21
|
+
this.frequency = frequency;
|
|
22
|
+
this.skipInitialLoad = skipInitialLoad;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public async subscribe(): Promise<void> {
|
|
26
|
+
if (this.intervalId) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.intervalId = setInterval(
|
|
31
|
+
this.userMap.sync.bind(this.userMap),
|
|
32
|
+
this.frequency
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (!this.skipInitialLoad) {
|
|
36
|
+
await this.userMap.sync();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async unsubscribe(): Promise<void> {
|
|
41
|
+
if (this.intervalId) {
|
|
42
|
+
clearInterval(this.intervalId);
|
|
43
|
+
this.intervalId = undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { UserMap } from './userMap';
|
|
2
|
+
import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
|
|
3
|
+
import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
|
|
4
|
+
import { UserAccount } from '../types';
|
|
5
|
+
import { Commitment, Context, PublicKey } from '@solana/web3.js';
|
|
6
|
+
|
|
7
|
+
export class WebsocketSubscription {
|
|
8
|
+
private userMap: UserMap;
|
|
9
|
+
private commitment: Commitment;
|
|
10
|
+
private skipInitialLoad: boolean;
|
|
11
|
+
private resubTimeoutMs?: number;
|
|
12
|
+
private includeIdle?: boolean;
|
|
13
|
+
|
|
14
|
+
private subscriber: WebSocketProgramAccountSubscriber<UserAccount>;
|
|
15
|
+
|
|
16
|
+
constructor({
|
|
17
|
+
userMap,
|
|
18
|
+
commitment,
|
|
19
|
+
skipInitialLoad = false,
|
|
20
|
+
resubTimeoutMs,
|
|
21
|
+
includeIdle = false,
|
|
22
|
+
}: {
|
|
23
|
+
userMap: UserMap;
|
|
24
|
+
commitment: Commitment;
|
|
25
|
+
skipInitialLoad?: boolean;
|
|
26
|
+
resubTimeoutMs?: number;
|
|
27
|
+
includeIdle?: boolean;
|
|
28
|
+
}) {
|
|
29
|
+
this.userMap = userMap;
|
|
30
|
+
this.commitment = commitment;
|
|
31
|
+
this.skipInitialLoad = skipInitialLoad;
|
|
32
|
+
this.resubTimeoutMs = resubTimeoutMs;
|
|
33
|
+
this.includeIdle = includeIdle || false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public async subscribe(): Promise<void> {
|
|
37
|
+
if (!this.subscriber) {
|
|
38
|
+
const filters = [getUserFilter()];
|
|
39
|
+
if (!this.includeIdle) {
|
|
40
|
+
filters.push(getNonIdleUserFilter());
|
|
41
|
+
}
|
|
42
|
+
this.subscriber = new WebSocketProgramAccountSubscriber<UserAccount>(
|
|
43
|
+
'UserMap',
|
|
44
|
+
'User',
|
|
45
|
+
this.userMap.driftClient.program,
|
|
46
|
+
this.userMap.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(
|
|
47
|
+
this.userMap.driftClient.program.account.user.coder.accounts
|
|
48
|
+
),
|
|
49
|
+
{
|
|
50
|
+
filters,
|
|
51
|
+
commitment: this.commitment,
|
|
52
|
+
},
|
|
53
|
+
this.resubTimeoutMs
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await this.subscriber.subscribe(
|
|
58
|
+
(accountId: PublicKey, account: UserAccount, context: Context) => {
|
|
59
|
+
const userKey = accountId.toBase58();
|
|
60
|
+
this.userMap.updateUserAccount(userKey, account, context.slot);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (!this.skipInitialLoad) {
|
|
65
|
+
await this.userMap.sync();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public async unsubscribe(): Promise<void> {
|
|
70
|
+
if (!this.subscriber) return;
|
|
71
|
+
await this.subscriber.unsubscribe();
|
|
72
|
+
this.subscriber = undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|