@drift-labs/sdk 2.96.0-beta.1 → 2.96.0-beta.3
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/types.d.ts +0 -8
- package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +3 -3
- package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +1 -1
- package/lib/driftClient.js +14 -35
- package/lib/driftClientConfig.d.ts +0 -6
- package/lib/events/eventSubscriber.d.ts +7 -0
- package/lib/events/eventSubscriber.js +69 -32
- package/lib/events/eventsServerLogProvider.d.ts +21 -0
- package/lib/events/eventsServerLogProvider.js +121 -0
- package/lib/events/pollingLogProvider.js +1 -1
- package/lib/events/types.d.ts +12 -5
- package/lib/events/types.js +5 -1
- package/lib/events/webSocketLogProvider.js +2 -2
- package/lib/orderSubscriber/OrderSubscriber.d.ts +1 -2
- package/lib/orderSubscriber/OrderSubscriber.js +4 -19
- package/lib/orderSubscriber/types.d.ts +0 -9
- package/lib/user.js +4 -11
- package/lib/userConfig.d.ts +1 -6
- package/lib/userMap/userMap.js +0 -14
- package/lib/userMap/userMapConfig.d.ts +0 -7
- package/lib/userStatsConfig.d.ts +0 -6
- package/package.json +1 -3
- package/src/accounts/types.ts +0 -9
- package/src/accounts/webSocketAccountSubscriber.ts +1 -1
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +3 -3
- package/src/accounts/webSocketProgramAccountSubscriber.ts +1 -1
- package/src/driftClient.ts +0 -28
- package/src/driftClientConfig.ts +0 -7
- package/src/events/eventSubscriber.ts +125 -54
- package/src/events/eventsServerLogProvider.ts +152 -0
- package/src/events/pollingLogProvider.ts +1 -1
- package/src/events/types.ts +29 -6
- package/src/events/webSocketLogProvider.ts +4 -4
- package/src/orderSubscriber/OrderSubscriber.ts +1 -15
- package/src/orderSubscriber/types.ts +0 -10
- package/src/user.ts +0 -11
- package/src/userConfig.ts +1 -7
- package/src/userMap/userMap.ts +1 -17
- package/src/userMap/userMapConfig.ts +0 -8
- package/src/userStatsConfig.ts +0 -7
- package/lib/accounts/grpcAccountSubscriber.d.ts +0 -16
- package/lib/accounts/grpcAccountSubscriber.js +0 -155
- package/lib/accounts/grpcDriftClientAccountSubscriber.d.ts +0 -13
- package/lib/accounts/grpcDriftClientAccountSubscriber.js +0 -96
- package/lib/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts +0 -10
- package/lib/accounts/grpcInsuranceFundStakeAccountSubscriber.js +0 -30
- package/lib/accounts/grpcProgramAccountSubscriber.d.ts +0 -19
- package/lib/accounts/grpcProgramAccountSubscriber.js +0 -161
- package/lib/accounts/grpcUserAccountSubscriber.d.ts +0 -10
- package/lib/accounts/grpcUserAccountSubscriber.js +0 -28
- package/lib/accounts/grpcUserStatsAccountSubscriber.d.ts +0 -10
- package/lib/accounts/grpcUserStatsAccountSubscriber.js +0 -28
- package/lib/orderSubscriber/grpcSubscription.d.ts +0 -25
- package/lib/orderSubscriber/grpcSubscription.js +0 -68
- package/lib/userMap/grpcSubscription.d.ts +0 -26
- package/lib/userMap/grpcSubscription.js +0 -42
- package/src/accounts/grpcAccountSubscriber.ts +0 -158
- package/src/accounts/grpcDriftClientAccountSubscriber.ts +0 -196
- package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -62
- package/src/accounts/grpcProgramAccountSubscriber.ts +0 -181
- package/src/accounts/grpcUserAccountSubscriber.ts +0 -48
- package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -51
- package/src/orderSubscriber/grpcSubscription.ts +0 -126
- package/src/userMap/grpcSubscription.ts +0 -83
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.96.0-beta.
|
|
1
|
+
2.96.0-beta.3
|
package/lib/accounts/types.d.ts
CHANGED
|
@@ -6,8 +6,6 @@ import { EventEmitter } from 'events';
|
|
|
6
6
|
import { Context, PublicKey } from '@solana/web3.js';
|
|
7
7
|
import { Account } from '@solana/spl-token';
|
|
8
8
|
import { OracleInfo, OraclePriceData } from '..';
|
|
9
|
-
import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
|
|
10
|
-
import { ChannelOptions } from '@grpc/grpc-js';
|
|
11
9
|
export interface AccountSubscriber<T> {
|
|
12
10
|
dataAndSlot?: DataAndSlot<T>;
|
|
13
11
|
subscribe(onChange: (data: T) => void): Promise<void>;
|
|
@@ -142,9 +140,3 @@ export interface UserStatsAccountSubscriber {
|
|
|
142
140
|
unsubscribe(): Promise<void>;
|
|
143
141
|
getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
|
|
144
142
|
}
|
|
145
|
-
export type GrpcConfigs = {
|
|
146
|
-
endpoint: string;
|
|
147
|
-
token: string;
|
|
148
|
-
commitmentLevel?: CommitmentLevel;
|
|
149
|
-
channelOptions?: ChannelOptions;
|
|
150
|
-
};
|
|
@@ -20,7 +20,7 @@ export declare class WebSocketAccountSubscriber<T> implements AccountSubscriber<
|
|
|
20
20
|
constructor(accountName: string, program: Program, accountPublicKey: PublicKey, decodeBuffer?: (buffer: Buffer) => T, resubOpts?: ResubOpts, commitment?: Commitment);
|
|
21
21
|
subscribe(onChange: (data: T) => void): Promise<void>;
|
|
22
22
|
setData(data: T, slot?: number): void;
|
|
23
|
-
|
|
23
|
+
private setTimeout;
|
|
24
24
|
fetch(): Promise<void>;
|
|
25
25
|
handleRpcResponse(context: Context, accountInfo?: AccountInfo<Buffer>): void;
|
|
26
26
|
decodeBuffer(buffer: Buffer): T;
|
|
@@ -30,9 +30,9 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
30
30
|
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
31
31
|
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
32
32
|
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
private isSubscribing;
|
|
34
|
+
private subscriptionPromise;
|
|
35
|
+
private subscriptionPromiseResolver;
|
|
36
36
|
constructor(program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean, resubOpts?: ResubOpts, commitment?: Commitment);
|
|
37
37
|
subscribe(): Promise<boolean>;
|
|
38
38
|
setInitialData(): Promise<void>;
|
|
@@ -27,7 +27,7 @@ export declare class WebSocketProgramAccountSubscriber<T> implements ProgramAcco
|
|
|
27
27
|
commitment?: Commitment;
|
|
28
28
|
}, resubOpts?: ResubOpts);
|
|
29
29
|
subscribe(onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void): Promise<void>;
|
|
30
|
-
|
|
30
|
+
private setTimeout;
|
|
31
31
|
handleRpcResponse(context: Context, keyedAccountInfo: KeyedAccountInfo): void;
|
|
32
32
|
unsubscribe(onResub?: boolean): Promise<void>;
|
|
33
33
|
}
|
package/lib/driftClient.js
CHANGED
|
@@ -68,7 +68,6 @@ const utils_2 = require("./tx/utils");
|
|
|
68
68
|
const pyth_solana_receiver_json_1 = __importDefault(require("./idl/pyth_solana_receiver.json"));
|
|
69
69
|
const on_demand_1 = require("@switchboard-xyz/on-demand");
|
|
70
70
|
const switchboard_on_demand_30_json_1 = __importDefault(require("./idl/switchboard_on_demand_30.json"));
|
|
71
|
-
const grpcDriftClientAccountSubscriber_1 = require("./accounts/grpcDriftClientAccountSubscriber");
|
|
72
71
|
/**
|
|
73
72
|
* # DriftClient
|
|
74
73
|
* This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
|
|
@@ -81,7 +80,7 @@ class DriftClient {
|
|
|
81
80
|
this._isSubscribed = val;
|
|
82
81
|
}
|
|
83
82
|
constructor(config) {
|
|
84
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6
|
|
83
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
|
|
85
84
|
this.users = new Map();
|
|
86
85
|
this._isSubscribed = false;
|
|
87
86
|
this.perpMarketLastSlotCache = new Map();
|
|
@@ -144,32 +143,18 @@ class DriftClient {
|
|
|
144
143
|
accountLoader: config.accountSubscription.accountLoader,
|
|
145
144
|
};
|
|
146
145
|
}
|
|
147
|
-
else if (((_q = config.accountSubscription) === null || _q === void 0 ? void 0 : _q.type) === 'grpc') {
|
|
148
|
-
this.userAccountSubscriptionConfig = {
|
|
149
|
-
type: 'grpc',
|
|
150
|
-
resubTimeoutMs: (_r = config.accountSubscription) === null || _r === void 0 ? void 0 : _r.resubTimeoutMs,
|
|
151
|
-
logResubMessages: (_s = config.accountSubscription) === null || _s === void 0 ? void 0 : _s.logResubMessages,
|
|
152
|
-
configs: (_t = config.accountSubscription) === null || _t === void 0 ? void 0 : _t.configs,
|
|
153
|
-
};
|
|
154
|
-
this.userStatsAccountSubscriptionConfig = {
|
|
155
|
-
type: 'grpc',
|
|
156
|
-
resubTimeoutMs: (_u = config.accountSubscription) === null || _u === void 0 ? void 0 : _u.resubTimeoutMs,
|
|
157
|
-
logResubMessages: (_v = config.accountSubscription) === null || _v === void 0 ? void 0 : _v.logResubMessages,
|
|
158
|
-
configs: (_w = config.accountSubscription) === null || _w === void 0 ? void 0 : _w.configs,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
146
|
else {
|
|
162
147
|
this.userAccountSubscriptionConfig = {
|
|
163
148
|
type: 'websocket',
|
|
164
|
-
resubTimeoutMs: (
|
|
165
|
-
logResubMessages: (
|
|
166
|
-
commitment: (
|
|
149
|
+
resubTimeoutMs: (_q = config.accountSubscription) === null || _q === void 0 ? void 0 : _q.resubTimeoutMs,
|
|
150
|
+
logResubMessages: (_r = config.accountSubscription) === null || _r === void 0 ? void 0 : _r.logResubMessages,
|
|
151
|
+
commitment: (_s = config.accountSubscription) === null || _s === void 0 ? void 0 : _s.commitment,
|
|
167
152
|
};
|
|
168
153
|
this.userStatsAccountSubscriptionConfig = {
|
|
169
154
|
type: 'websocket',
|
|
170
|
-
resubTimeoutMs: (
|
|
171
|
-
logResubMessages: (
|
|
172
|
-
commitment: (
|
|
155
|
+
resubTimeoutMs: (_t = config.accountSubscription) === null || _t === void 0 ? void 0 : _t.resubTimeoutMs,
|
|
156
|
+
logResubMessages: (_u = config.accountSubscription) === null || _u === void 0 ? void 0 : _u.logResubMessages,
|
|
157
|
+
commitment: (_v = config.accountSubscription) === null || _v === void 0 ? void 0 : _v.commitment,
|
|
173
158
|
};
|
|
174
159
|
}
|
|
175
160
|
if (config.userStats) {
|
|
@@ -186,20 +171,14 @@ class DriftClient {
|
|
|
186
171
|
const noMarketsAndOraclesSpecified = config.perpMarketIndexes === undefined &&
|
|
187
172
|
config.spotMarketIndexes === undefined &&
|
|
188
173
|
config.oracleInfos === undefined;
|
|
189
|
-
if (((
|
|
190
|
-
this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (
|
|
191
|
-
}
|
|
192
|
-
else if (((_7 = config.accountSubscription) === null || _7 === void 0 ? void 0 : _7.type) === 'grpc') {
|
|
193
|
-
this.accountSubscriber = new grpcDriftClientAccountSubscriber_1.gprcDriftClientAccountSubscriber(config.accountSubscription.configs, this.program, (_8 = config.perpMarketIndexes) !== null && _8 !== void 0 ? _8 : [], (_9 = config.spotMarketIndexes) !== null && _9 !== void 0 ? _9 : [], (_10 = config.oracleInfos) !== null && _10 !== void 0 ? _10 : [], noMarketsAndOraclesSpecified, {
|
|
194
|
-
resubTimeoutMs: (_11 = config.accountSubscription) === null || _11 === void 0 ? void 0 : _11.resubTimeoutMs,
|
|
195
|
-
logResubMessages: (_12 = config.accountSubscription) === null || _12 === void 0 ? void 0 : _12.logResubMessages,
|
|
196
|
-
});
|
|
174
|
+
if (((_w = config.accountSubscription) === null || _w === void 0 ? void 0 : _w.type) === 'polling') {
|
|
175
|
+
this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (_x = config.perpMarketIndexes) !== null && _x !== void 0 ? _x : [], (_y = config.spotMarketIndexes) !== null && _y !== void 0 ? _y : [], (_z = config.oracleInfos) !== null && _z !== void 0 ? _z : [], noMarketsAndOraclesSpecified);
|
|
197
176
|
}
|
|
198
177
|
else {
|
|
199
|
-
this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (
|
|
200
|
-
resubTimeoutMs: (
|
|
201
|
-
logResubMessages: (
|
|
202
|
-
}, (
|
|
178
|
+
this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (_0 = config.perpMarketIndexes) !== null && _0 !== void 0 ? _0 : [], (_1 = config.spotMarketIndexes) !== null && _1 !== void 0 ? _1 : [], (_2 = config.oracleInfos) !== null && _2 !== void 0 ? _2 : [], noMarketsAndOraclesSpecified, {
|
|
179
|
+
resubTimeoutMs: (_3 = config.accountSubscription) === null || _3 === void 0 ? void 0 : _3.resubTimeoutMs,
|
|
180
|
+
logResubMessages: (_4 = config.accountSubscription) === null || _4 === void 0 ? void 0 : _4.logResubMessages,
|
|
181
|
+
}, (_5 = config.accountSubscription) === null || _5 === void 0 ? void 0 : _5.commitment);
|
|
203
182
|
}
|
|
204
183
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
205
184
|
this.metricsEventEmitter = new events_1.EventEmitter();
|
|
@@ -207,7 +186,7 @@ class DriftClient {
|
|
|
207
186
|
this.enableMetricsEvents = true;
|
|
208
187
|
}
|
|
209
188
|
this.txSender =
|
|
210
|
-
(
|
|
189
|
+
(_6 = config.txSender) !== null && _6 !== void 0 ? _6 : new retryTxSender_1.RetryTxSender({
|
|
211
190
|
connection: this.connection,
|
|
212
191
|
wallet: this.wallet,
|
|
213
192
|
opts: this.opts,
|
|
@@ -5,7 +5,6 @@ import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
|
5
5
|
import { DriftEnv } from './config';
|
|
6
6
|
import { TxSender } from './tx/types';
|
|
7
7
|
import { TxHandler, TxHandlerConfig } from './tx/txHandler';
|
|
8
|
-
import { GrpcConfigs } from './accounts/types';
|
|
9
8
|
export type DriftClientConfig = {
|
|
10
9
|
connection: Connection;
|
|
11
10
|
wallet: IWallet;
|
|
@@ -39,9 +38,4 @@ export type DriftClientSubscriptionConfig = {
|
|
|
39
38
|
} | {
|
|
40
39
|
type: 'polling';
|
|
41
40
|
accountLoader: BulkAccountLoader;
|
|
42
|
-
} | {
|
|
43
|
-
type: 'grpc';
|
|
44
|
-
configs: GrpcConfigs;
|
|
45
|
-
resubTimeoutMs?: number;
|
|
46
|
-
logResubMessages?: boolean;
|
|
47
41
|
};
|
|
@@ -15,12 +15,19 @@ export declare class EventSubscriber {
|
|
|
15
15
|
private awaitTxPromises;
|
|
16
16
|
private awaitTxResolver;
|
|
17
17
|
private logProvider;
|
|
18
|
+
private currentProviderType;
|
|
18
19
|
eventEmitter: StrictEventEmitter<EventEmitter, EventSubscriberEvents>;
|
|
19
20
|
private lastSeenSlot;
|
|
20
21
|
private lastSeenBlockTime;
|
|
21
22
|
lastSeenTxSig: string;
|
|
22
23
|
constructor(connection: Connection, program: Program, options?: EventSubscriptionOptions);
|
|
24
|
+
private initializeLogProvider;
|
|
23
25
|
private populateInitialEventListMap;
|
|
26
|
+
/**
|
|
27
|
+
* Implements fallback logic for reconnecting to LogProvider. Currently terminates at polling,
|
|
28
|
+
* could be improved to try the original type again after some cooldown.
|
|
29
|
+
*/
|
|
30
|
+
private updateFallbackProviderType;
|
|
24
31
|
subscribe(): Promise<boolean>;
|
|
25
32
|
private handleTxLogs;
|
|
26
33
|
fetchPreviousTx(fetchMax?: boolean): Promise<void>;
|
|
@@ -10,6 +10,7 @@ const webSocketLogProvider_1 = require("./webSocketLogProvider");
|
|
|
10
10
|
const events_1 = require("events");
|
|
11
11
|
const sort_1 = require("./sort");
|
|
12
12
|
const parse_1 = require("./parse");
|
|
13
|
+
const eventsServerLogProvider_1 = require("./eventsServerLogProvider");
|
|
13
14
|
class EventSubscriber {
|
|
14
15
|
constructor(connection, program, options = types_1.DefaultEventSubscriptionOptions) {
|
|
15
16
|
var _a;
|
|
@@ -23,15 +24,36 @@ class EventSubscriber {
|
|
|
23
24
|
this.txEventCache = new txEventCache_1.TxEventCache(this.options.maxTx);
|
|
24
25
|
this.eventListMap = new Map();
|
|
25
26
|
this.eventEmitter = new events_1.EventEmitter();
|
|
26
|
-
|
|
27
|
+
this.currentProviderType = this.options.logProviderConfig.type;
|
|
28
|
+
this.initializeLogProvider();
|
|
29
|
+
}
|
|
30
|
+
initializeLogProvider(subscribe = false) {
|
|
31
|
+
if (this.currentProviderType === 'websocket') {
|
|
32
|
+
const logProviderConfig = this.options
|
|
33
|
+
.logProviderConfig;
|
|
27
34
|
this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(
|
|
28
35
|
// @ts-ignore
|
|
29
|
-
this.connection, this.address, this.options.commitment,
|
|
36
|
+
this.connection, this.address, this.options.commitment, logProviderConfig.resubTimeoutMs);
|
|
30
37
|
}
|
|
31
|
-
else {
|
|
38
|
+
else if (this.currentProviderType === 'polling') {
|
|
39
|
+
const logProviderConfig = this.options
|
|
40
|
+
.logProviderConfig;
|
|
32
41
|
this.logProvider = new pollingLogProvider_1.PollingLogProvider(
|
|
33
42
|
// @ts-ignore
|
|
34
|
-
this.connection, this.address, options.commitment,
|
|
43
|
+
this.connection, this.address, this.options.commitment, logProviderConfig.frequency, logProviderConfig.batchSize);
|
|
44
|
+
}
|
|
45
|
+
else if (this.currentProviderType === 'events-server') {
|
|
46
|
+
const logProviderConfig = this.options
|
|
47
|
+
.logProviderConfig;
|
|
48
|
+
this.logProvider = new eventsServerLogProvider_1.EventsServerLogProvider(logProviderConfig.url, this.options.eventTypes, this.options.address ? this.options.address.toString() : undefined);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new Error(`Invalid log provider type: ${this.currentProviderType}`);
|
|
52
|
+
}
|
|
53
|
+
if (subscribe) {
|
|
54
|
+
this.logProvider.subscribe((txSig, slot, logs, mostRecentBlockTime, txSigIndex) => {
|
|
55
|
+
this.handleTxLogs(txSig, slot, logs, mostRecentBlockTime, this.currentProviderType === 'events-server', txSigIndex);
|
|
56
|
+
}, true);
|
|
35
57
|
}
|
|
36
58
|
}
|
|
37
59
|
populateInitialEventListMap() {
|
|
@@ -39,37 +61,51 @@ class EventSubscriber {
|
|
|
39
61
|
this.eventListMap.set(eventType, new eventList_1.EventList(eventType, this.options.maxEventsPerType, (0, sort_1.getSortFn)(this.options.orderBy, this.options.orderDir), this.options.orderDir));
|
|
40
62
|
}
|
|
41
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Implements fallback logic for reconnecting to LogProvider. Currently terminates at polling,
|
|
66
|
+
* could be improved to try the original type again after some cooldown.
|
|
67
|
+
*/
|
|
68
|
+
updateFallbackProviderType(reconnectAttempts, maxReconnectAttempts) {
|
|
69
|
+
if (reconnectAttempts < maxReconnectAttempts) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let nextProviderType = this.currentProviderType;
|
|
73
|
+
if (this.currentProviderType === 'events-server') {
|
|
74
|
+
nextProviderType = 'websocket';
|
|
75
|
+
}
|
|
76
|
+
else if (this.currentProviderType === 'websocket') {
|
|
77
|
+
nextProviderType = 'polling';
|
|
78
|
+
}
|
|
79
|
+
else if (this.currentProviderType === 'polling') {
|
|
80
|
+
nextProviderType = 'polling';
|
|
81
|
+
}
|
|
82
|
+
console.log(`EventSubscriber: Failing over providerType ${this.currentProviderType} to ${nextProviderType}`);
|
|
83
|
+
this.currentProviderType = nextProviderType;
|
|
84
|
+
}
|
|
42
85
|
async subscribe() {
|
|
43
86
|
try {
|
|
44
87
|
if (this.logProvider.isSubscribed()) {
|
|
45
88
|
return true;
|
|
46
89
|
}
|
|
47
90
|
this.populateInitialEventListMap();
|
|
48
|
-
if (this.options.logProviderConfig.type === 'websocket'
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.logProvider.subscribe((txSig, slot, logs, mostRecentBlockTime) => {
|
|
63
|
-
this.handleTxLogs(txSig, slot, logs, mostRecentBlockTime);
|
|
64
|
-
}, true);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
91
|
+
if (this.options.logProviderConfig.type === 'websocket' ||
|
|
92
|
+
this.options.logProviderConfig.type === 'events-server') {
|
|
93
|
+
const logProviderConfig = this.options
|
|
94
|
+
.logProviderConfig;
|
|
95
|
+
if (this.logProvider.eventEmitter) {
|
|
96
|
+
this.logProvider.eventEmitter.on('reconnect', async (reconnectAttempts) => {
|
|
97
|
+
if (reconnectAttempts > logProviderConfig.maxReconnectAttempts) {
|
|
98
|
+
console.log(`EventSubscriber: Reconnect attempts ${reconnectAttempts}/${logProviderConfig.maxReconnectAttempts}, reconnecting...`);
|
|
99
|
+
this.logProvider.eventEmitter.removeAllListeners('reconnect');
|
|
100
|
+
await this.unsubscribe();
|
|
101
|
+
this.updateFallbackProviderType(reconnectAttempts, logProviderConfig.maxReconnectAttempts);
|
|
102
|
+
this.initializeLogProvider(true);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
69
105
|
}
|
|
70
106
|
}
|
|
71
|
-
this.logProvider.subscribe((txSig, slot, logs, mostRecentBlockTime) => {
|
|
72
|
-
this.handleTxLogs(txSig, slot, logs, mostRecentBlockTime);
|
|
107
|
+
this.logProvider.subscribe((txSig, slot, logs, mostRecentBlockTime, txSigIndex) => {
|
|
108
|
+
this.handleTxLogs(txSig, slot, logs, mostRecentBlockTime, this.currentProviderType === 'events-server', txSigIndex);
|
|
73
109
|
}, true);
|
|
74
110
|
return true;
|
|
75
111
|
}
|
|
@@ -79,11 +115,11 @@ class EventSubscriber {
|
|
|
79
115
|
return false;
|
|
80
116
|
}
|
|
81
117
|
}
|
|
82
|
-
handleTxLogs(txSig, slot, logs, mostRecentBlockTime) {
|
|
83
|
-
if (this.txEventCache.has(txSig)) {
|
|
118
|
+
handleTxLogs(txSig, slot, logs, mostRecentBlockTime, fromEventsServer = false, txSigIndex = undefined) {
|
|
119
|
+
if (!fromEventsServer && this.txEventCache.has(txSig)) {
|
|
84
120
|
return;
|
|
85
121
|
}
|
|
86
|
-
const wrappedEvents = this.parseEventsFromLogs(txSig, slot, logs);
|
|
122
|
+
const wrappedEvents = this.parseEventsFromLogs(txSig, slot, logs, txSigIndex);
|
|
87
123
|
for (const wrappedEvent of wrappedEvents) {
|
|
88
124
|
this.eventListMap.get(wrappedEvent.eventType).insert(wrappedEvent);
|
|
89
125
|
}
|
|
@@ -134,7 +170,7 @@ class EventSubscriber {
|
|
|
134
170
|
this.awaitTxResolver.clear();
|
|
135
171
|
return await this.logProvider.unsubscribe(true);
|
|
136
172
|
}
|
|
137
|
-
parseEventsFromLogs(txSig, slot, logs) {
|
|
173
|
+
parseEventsFromLogs(txSig, slot, logs, txSigIndex) {
|
|
138
174
|
const records = [];
|
|
139
175
|
// @ts-ignore
|
|
140
176
|
const events = (0, parse_1.parseLogs)(this.program, logs);
|
|
@@ -146,7 +182,8 @@ class EventSubscriber {
|
|
|
146
182
|
event.data.txSig = txSig;
|
|
147
183
|
event.data.slot = slot;
|
|
148
184
|
event.data.eventType = event.name;
|
|
149
|
-
event.data.txSigIndex =
|
|
185
|
+
event.data.txSigIndex =
|
|
186
|
+
txSigIndex !== undefined ? txSigIndex : runningEventIndex;
|
|
150
187
|
records.push(event.data);
|
|
151
188
|
}
|
|
152
189
|
runningEventIndex++;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { logProviderCallback, EventType, LogProvider } from './types';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
export declare class EventsServerLogProvider implements LogProvider {
|
|
5
|
+
private readonly url;
|
|
6
|
+
private readonly eventTypes;
|
|
7
|
+
private readonly userAccount?;
|
|
8
|
+
private ws?;
|
|
9
|
+
private callback?;
|
|
10
|
+
private isUnsubscribing;
|
|
11
|
+
private externalUnsubscribe;
|
|
12
|
+
private lastHeartbeat;
|
|
13
|
+
private timeoutId?;
|
|
14
|
+
private reconnectAttempts;
|
|
15
|
+
eventEmitter?: EventEmitter;
|
|
16
|
+
constructor(url: string, eventTypes: EventType[], userAccount?: string);
|
|
17
|
+
isSubscribed(): boolean;
|
|
18
|
+
subscribe(callback: logProviderCallback): Promise<boolean>;
|
|
19
|
+
unsubscribe(external?: boolean): Promise<boolean>;
|
|
20
|
+
private setTimeout;
|
|
21
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventsServerLogProvider = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
// browser support
|
|
6
|
+
let WebSocketImpl;
|
|
7
|
+
if (typeof window !== 'undefined' && window.WebSocket) {
|
|
8
|
+
WebSocketImpl = window.WebSocket;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
WebSocketImpl = require('ws');
|
|
12
|
+
}
|
|
13
|
+
const EVENT_SERVER_HEARTBEAT_INTERVAL_MS = 5000;
|
|
14
|
+
const ALLOWED_MISSED_HEARTBEATS = 3;
|
|
15
|
+
class EventsServerLogProvider {
|
|
16
|
+
constructor(url, eventTypes, userAccount) {
|
|
17
|
+
this.url = url;
|
|
18
|
+
this.eventTypes = eventTypes;
|
|
19
|
+
this.userAccount = userAccount;
|
|
20
|
+
this.isUnsubscribing = false;
|
|
21
|
+
this.externalUnsubscribe = false;
|
|
22
|
+
this.lastHeartbeat = 0;
|
|
23
|
+
this.reconnectAttempts = 0;
|
|
24
|
+
this.eventEmitter = new events_1.EventEmitter();
|
|
25
|
+
}
|
|
26
|
+
isSubscribed() {
|
|
27
|
+
return this.ws !== undefined;
|
|
28
|
+
}
|
|
29
|
+
async subscribe(callback) {
|
|
30
|
+
if (this.ws !== undefined) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
this.ws = new WebSocketImpl(this.url);
|
|
34
|
+
this.callback = callback;
|
|
35
|
+
this.ws.addEventListener('open', () => {
|
|
36
|
+
for (const channel of this.eventTypes) {
|
|
37
|
+
const subscribeMessage = {
|
|
38
|
+
type: 'subscribe',
|
|
39
|
+
channel: channel,
|
|
40
|
+
};
|
|
41
|
+
if (this.userAccount) {
|
|
42
|
+
subscribeMessage['user'] = this.userAccount;
|
|
43
|
+
}
|
|
44
|
+
this.ws.send(JSON.stringify(subscribeMessage));
|
|
45
|
+
}
|
|
46
|
+
this.reconnectAttempts = 0;
|
|
47
|
+
});
|
|
48
|
+
this.ws.addEventListener('message', (data) => {
|
|
49
|
+
try {
|
|
50
|
+
if (!this.isUnsubscribing) {
|
|
51
|
+
clearTimeout(this.timeoutId);
|
|
52
|
+
this.setTimeout();
|
|
53
|
+
if (this.reconnectAttempts > 0) {
|
|
54
|
+
console.log('eventsServerLogProvider: Resetting reconnect attempts to 0');
|
|
55
|
+
}
|
|
56
|
+
this.reconnectAttempts = 0;
|
|
57
|
+
}
|
|
58
|
+
const parsedData = JSON.parse(data.data.toString());
|
|
59
|
+
if (parsedData.channel === 'heartbeat') {
|
|
60
|
+
this.lastHeartbeat = Date.now();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (parsedData.message !== undefined) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const event = JSON.parse(parsedData.data);
|
|
67
|
+
this.callback(event.txSig, event.slot, [
|
|
68
|
+
'Program dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH invoke [1]',
|
|
69
|
+
event.rawLog,
|
|
70
|
+
'Program dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH success',
|
|
71
|
+
], undefined, event.txSigIndex);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Error parsing message:', error);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
this.ws.addEventListener('close', () => {
|
|
78
|
+
console.log('eventsServerLogProvider: WebSocket closed');
|
|
79
|
+
});
|
|
80
|
+
this.ws.addEventListener('error', (error) => {
|
|
81
|
+
console.error('eventsServerLogProvider: WebSocket error:', error);
|
|
82
|
+
});
|
|
83
|
+
this.setTimeout();
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
async unsubscribe(external = false) {
|
|
87
|
+
this.isUnsubscribing = true;
|
|
88
|
+
this.externalUnsubscribe = external;
|
|
89
|
+
if (this.timeoutId) {
|
|
90
|
+
clearInterval(this.timeoutId);
|
|
91
|
+
this.timeoutId = undefined;
|
|
92
|
+
}
|
|
93
|
+
if (this.ws !== undefined) {
|
|
94
|
+
this.ws.close();
|
|
95
|
+
this.ws = undefined;
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
this.isUnsubscribing = false;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
setTimeout() {
|
|
104
|
+
this.timeoutId = setTimeout(async () => {
|
|
105
|
+
if (this.isUnsubscribing || this.externalUnsubscribe) {
|
|
106
|
+
// If we are in the process of unsubscribing, do not attempt to resubscribe
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const timeSinceLastHeartbeat = Date.now() - this.lastHeartbeat;
|
|
110
|
+
if (timeSinceLastHeartbeat >
|
|
111
|
+
EVENT_SERVER_HEARTBEAT_INTERVAL_MS * ALLOWED_MISSED_HEARTBEATS) {
|
|
112
|
+
console.log(`eventServerLogProvider: No heartbeat in ${timeSinceLastHeartbeat}ms, resubscribing on attempt ${this.reconnectAttempts + 1}`);
|
|
113
|
+
await this.unsubscribe();
|
|
114
|
+
this.reconnectAttempts++;
|
|
115
|
+
this.eventEmitter.emit('reconnect', this.reconnectAttempts);
|
|
116
|
+
this.subscribe(this.callback);
|
|
117
|
+
}
|
|
118
|
+
}, EVENT_SERVER_HEARTBEAT_INTERVAL_MS * 2);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.EventsServerLogProvider = EventsServerLogProvider;
|
|
@@ -30,7 +30,7 @@ class PollingLogProvider {
|
|
|
30
30
|
this.firstFetch = false;
|
|
31
31
|
const { mostRecentTx, transactionLogs } = response;
|
|
32
32
|
for (const { txSig, slot, logs } of transactionLogs) {
|
|
33
|
-
callback(txSig, slot, logs, response.mostRecentBlockTime);
|
|
33
|
+
callback(txSig, slot, logs, response.mostRecentBlockTime, undefined);
|
|
34
34
|
}
|
|
35
35
|
this.mostRecentSeenTx = mostRecentTx;
|
|
36
36
|
}
|
package/lib/events/types.d.ts
CHANGED
|
@@ -48,23 +48,30 @@ export interface EventSubscriberEvents {
|
|
|
48
48
|
newEvent: (event: WrappedEvent<EventType>) => void;
|
|
49
49
|
}
|
|
50
50
|
export type SortFn = (currentRecord: EventMap[EventType], newRecord: EventMap[EventType]) => 'less than' | 'greater than';
|
|
51
|
-
export type logProviderCallback = (txSig: TransactionSignature, slot: number, logs: string[], mostRecentBlockTime: number | undefined) => void;
|
|
51
|
+
export type logProviderCallback = (txSig: TransactionSignature, slot: number, logs: string[], mostRecentBlockTime: number | undefined, txSigIndex: number | undefined) => void;
|
|
52
52
|
export interface LogProvider {
|
|
53
53
|
isSubscribed(): boolean;
|
|
54
54
|
subscribe(callback: logProviderCallback, skipHistory?: boolean): Promise<boolean>;
|
|
55
55
|
unsubscribe(external?: boolean): Promise<boolean>;
|
|
56
56
|
eventEmitter?: EventEmitter;
|
|
57
57
|
}
|
|
58
|
-
export type
|
|
59
|
-
|
|
60
|
-
resubTimeoutMs?: number;
|
|
58
|
+
export type LogProviderType = 'websocket' | 'polling' | 'events-server';
|
|
59
|
+
export type StreamingLogProviderConfig = {
|
|
61
60
|
maxReconnectAttempts?: number;
|
|
62
61
|
fallbackFrequency?: number;
|
|
63
62
|
fallbackBatchSize?: number;
|
|
64
63
|
};
|
|
64
|
+
export type WebSocketLogProviderConfig = StreamingLogProviderConfig & {
|
|
65
|
+
type: 'websocket';
|
|
66
|
+
resubTimeoutMs?: number;
|
|
67
|
+
};
|
|
65
68
|
export type PollingLogProviderConfig = {
|
|
66
69
|
type: 'polling';
|
|
67
70
|
frequency: number;
|
|
68
71
|
batchSize?: number;
|
|
69
72
|
};
|
|
70
|
-
export type
|
|
73
|
+
export type EventsServerLogProviderConfig = StreamingLogProviderConfig & {
|
|
74
|
+
type: 'events-server';
|
|
75
|
+
url: string;
|
|
76
|
+
};
|
|
77
|
+
export type LogProviderConfig = WebSocketLogProviderConfig | PollingLogProviderConfig | EventsServerLogProviderConfig;
|
package/lib/events/types.js
CHANGED
|
@@ -25,6 +25,10 @@ exports.DefaultEventSubscriptionOptions = {
|
|
|
25
25
|
commitment: 'confirmed',
|
|
26
26
|
maxTx: 4096,
|
|
27
27
|
logProviderConfig: {
|
|
28
|
-
type: '
|
|
28
|
+
type: 'events-server',
|
|
29
|
+
url: 'wss://events.drift.trade/ws',
|
|
30
|
+
maxReconnectAttempts: 5,
|
|
31
|
+
fallbackFrequency: 1000,
|
|
32
|
+
fallbackBatchSize: 100,
|
|
29
33
|
},
|
|
30
34
|
};
|
|
@@ -47,7 +47,7 @@ class WebSocketLogProvider {
|
|
|
47
47
|
if (logs.err !== null) {
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
callback(logs.signature, ctx.slot, logs.logs, undefined);
|
|
50
|
+
callback(logs.signature, ctx.slot, logs.logs, undefined, undefined);
|
|
51
51
|
}, this.commitment);
|
|
52
52
|
}
|
|
53
53
|
isSubscribed() {
|
|
@@ -83,7 +83,7 @@ class WebSocketLogProvider {
|
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
if (this.receivingData) {
|
|
86
|
-
console.log(`No log data in ${this.resubTimeoutMs}ms, resubscribing on attempt ${this.reconnectAttempts + 1}`);
|
|
86
|
+
console.log(`webSocketLogProvider: No log data in ${this.resubTimeoutMs}ms, resubscribing on attempt ${this.reconnectAttempts + 1}`);
|
|
87
87
|
await this.unsubscribe();
|
|
88
88
|
this.receivingData = false;
|
|
89
89
|
this.reconnectAttempts++;
|
|
@@ -10,14 +10,13 @@ import { PollingSubscription } from './PollingSubscription';
|
|
|
10
10
|
import { WebsocketSubscription } from './WebsocketSubscription';
|
|
11
11
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
12
12
|
import { EventEmitter } from 'events';
|
|
13
|
-
import { grpcSubscription } from './grpcSubscription';
|
|
14
13
|
export declare class OrderSubscriber {
|
|
15
14
|
driftClient: DriftClient;
|
|
16
15
|
usersAccounts: Map<string, {
|
|
17
16
|
slot: number;
|
|
18
17
|
userAccount: UserAccount;
|
|
19
18
|
}>;
|
|
20
|
-
subscription: PollingSubscription | WebsocketSubscription
|
|
19
|
+
subscription: PollingSubscription | WebsocketSubscription;
|
|
21
20
|
commitment: Commitment;
|
|
22
21
|
eventEmitter: StrictEventEmitter<EventEmitter, OrderSubscriberEvents>;
|
|
23
22
|
fetchPromise?: Promise<void>;
|
|
@@ -10,10 +10,9 @@ const WebsocketSubscription_1 = require("./WebsocketSubscription");
|
|
|
10
10
|
const events_1 = require("events");
|
|
11
11
|
const index_1 = require("../index");
|
|
12
12
|
const user_1 = require("../decode/user");
|
|
13
|
-
const grpcSubscription_1 = require("./grpcSubscription");
|
|
14
13
|
class OrderSubscriber {
|
|
15
14
|
constructor(config) {
|
|
16
|
-
var _a, _b, _c
|
|
15
|
+
var _a, _b, _c;
|
|
17
16
|
this.usersAccounts = new Map();
|
|
18
17
|
this.driftClient = config.driftClient;
|
|
19
18
|
this.commitment = config.subscriptionConfig.commitment || 'processed';
|
|
@@ -23,34 +22,20 @@ class OrderSubscriber {
|
|
|
23
22
|
frequency: config.subscriptionConfig.frequency,
|
|
24
23
|
});
|
|
25
24
|
}
|
|
26
|
-
else if (config.subscriptionConfig.type === 'grpc') {
|
|
27
|
-
this.subscription = new grpcSubscription_1.grpcSubscription({
|
|
28
|
-
grpcConfigs: config.subscriptionConfig.configs,
|
|
29
|
-
orderSubscriber: this,
|
|
30
|
-
commitment: this.commitment,
|
|
31
|
-
skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
|
|
32
|
-
resubOpts: {
|
|
33
|
-
resubTimeoutMs: (_a = config.subscriptionConfig) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs,
|
|
34
|
-
logResubMessages: (_b = config.subscriptionConfig) === null || _b === void 0 ? void 0 : _b.logResubMessages,
|
|
35
|
-
},
|
|
36
|
-
resyncIntervalMs: config.subscriptionConfig.resyncIntervalMs,
|
|
37
|
-
decoded: config.decodeData,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
25
|
else {
|
|
41
26
|
this.subscription = new WebsocketSubscription_1.WebsocketSubscription({
|
|
42
27
|
orderSubscriber: this,
|
|
43
28
|
commitment: this.commitment,
|
|
44
29
|
skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
|
|
45
30
|
resubOpts: {
|
|
46
|
-
resubTimeoutMs: (
|
|
47
|
-
logResubMessages: (
|
|
31
|
+
resubTimeoutMs: (_a = config.subscriptionConfig) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs,
|
|
32
|
+
logResubMessages: (_b = config.subscriptionConfig) === null || _b === void 0 ? void 0 : _b.logResubMessages,
|
|
48
33
|
},
|
|
49
34
|
resyncIntervalMs: config.subscriptionConfig.resyncIntervalMs,
|
|
50
35
|
decoded: config.decodeData,
|
|
51
36
|
});
|
|
52
37
|
}
|
|
53
|
-
if ((
|
|
38
|
+
if ((_c = config.fastDecode) !== null && _c !== void 0 ? _c : true) {
|
|
54
39
|
this.decodeFn = (name, data) => (0, user_1.decodeUser)(data);
|
|
55
40
|
}
|
|
56
41
|
else {
|