@drift-labs/sdk 2.145.0-beta.2 → 2.145.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/browser/accounts/types.d.ts +13 -1
- package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.d.ts +53 -0
- package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.js +453 -0
- package/lib/browser/addresses/pda.d.ts +9 -0
- package/lib/browser/addresses/pda.js +60 -1
- package/lib/browser/adminClient.d.ts +160 -8
- package/lib/browser/adminClient.js +754 -18
- package/lib/browser/constituentMap/constituentMap.d.ts +64 -0
- package/lib/browser/constituentMap/constituentMap.js +170 -0
- package/lib/browser/constituentMap/pollingConstituentAccountSubscriber.d.ts +24 -0
- package/lib/browser/constituentMap/pollingConstituentAccountSubscriber.js +60 -0
- package/lib/browser/constituentMap/webSocketConstituentAccountSubscriber.d.ts +24 -0
- package/lib/browser/constituentMap/webSocketConstituentAccountSubscriber.js +58 -0
- package/lib/browser/driftClient.d.ts +89 -2
- package/lib/browser/driftClient.js +486 -27
- package/lib/browser/driftClientConfig.d.ts +2 -7
- package/lib/browser/idl/drift.json +4303 -1379
- package/lib/browser/index.d.ts +1 -4
- package/lib/browser/index.js +2 -9
- package/lib/browser/memcmp.d.ts +3 -1
- package/lib/browser/memcmp.js +19 -1
- package/lib/browser/types.d.ts +147 -0
- package/lib/browser/types.js +13 -1
- package/lib/node/accounts/types.d.ts +13 -1
- package/lib/node/accounts/types.d.ts.map +1 -1
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts +54 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts.map +1 -0
- package/lib/node/accounts/webSocketProgramAccountSubscriberV2.js +453 -0
- package/lib/node/addresses/pda.d.ts +9 -0
- package/lib/node/addresses/pda.d.ts.map +1 -1
- package/lib/node/addresses/pda.js +60 -1
- package/lib/node/adminClient.d.ts +160 -8
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +754 -18
- package/lib/node/constituentMap/constituentMap.d.ts +65 -0
- package/lib/node/constituentMap/constituentMap.d.ts.map +1 -0
- package/lib/node/constituentMap/constituentMap.js +170 -0
- package/lib/node/constituentMap/pollingConstituentAccountSubscriber.d.ts +25 -0
- package/lib/node/constituentMap/pollingConstituentAccountSubscriber.d.ts.map +1 -0
- package/lib/node/constituentMap/pollingConstituentAccountSubscriber.js +60 -0
- package/lib/node/constituentMap/webSocketConstituentAccountSubscriber.d.ts +25 -0
- package/lib/node/constituentMap/webSocketConstituentAccountSubscriber.d.ts.map +1 -0
- package/lib/node/constituentMap/webSocketConstituentAccountSubscriber.js +58 -0
- package/lib/node/driftClient.d.ts +89 -2
- package/lib/node/driftClient.d.ts.map +1 -1
- package/lib/node/driftClient.js +486 -27
- package/lib/node/driftClientConfig.d.ts +2 -7
- package/lib/node/driftClientConfig.d.ts.map +1 -1
- package/lib/node/idl/drift.json +4303 -1379
- package/lib/node/index.d.ts +1 -4
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +2 -9
- package/lib/node/memcmp.d.ts +3 -1
- package/lib/node/memcmp.d.ts.map +1 -1
- package/lib/node/memcmp.js +19 -1
- package/lib/node/types.d.ts +147 -0
- package/lib/node/types.d.ts.map +1 -1
- package/lib/node/types.js +13 -1
- package/package.json +1 -1
- package/src/accounts/types.ts +20 -0
- package/src/accounts/webSocketProgramAccountSubscriberV2.ts +596 -0
- package/src/addresses/pda.ts +115 -1
- package/src/adminClient.ts +1612 -41
- package/src/constituentMap/constituentMap.ts +285 -0
- package/src/constituentMap/pollingConstituentAccountSubscriber.ts +97 -0
- package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +112 -0
- package/src/driftClient.ts +1097 -17
- package/src/driftClientConfig.ts +8 -15
- package/src/idl/drift.json +4303 -1379
- package/src/index.ts +1 -4
- package/src/memcmp.ts +23 -1
- package/src/types.ts +160 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.145.0-beta.
|
|
1
|
+
2.145.0-beta.3
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
/// <reference types="node" />
|
|
4
|
-
import { SpotMarketAccount, PerpMarketAccount, OracleSource, StateAccount, UserAccount, UserStatsAccount, InsuranceFundStake, HighLeverageModeConfig } from '../types';
|
|
4
|
+
import { SpotMarketAccount, PerpMarketAccount, OracleSource, StateAccount, UserAccount, UserStatsAccount, InsuranceFundStake, ConstituentAccount, HighLeverageModeConfig } from '../types';
|
|
5
5
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
6
6
|
import { EventEmitter } from 'events';
|
|
7
7
|
import { Context, PublicKey } from '@solana/web3.js';
|
|
@@ -180,3 +180,15 @@ export interface HighLeverageModeConfigAccountEvents {
|
|
|
180
180
|
update: void;
|
|
181
181
|
error: (e: Error) => void;
|
|
182
182
|
}
|
|
183
|
+
export interface ConstituentAccountSubscriber {
|
|
184
|
+
eventEmitter: StrictEventEmitter<EventEmitter, ConstituentAccountEvents>;
|
|
185
|
+
isSubscribed: boolean;
|
|
186
|
+
subscribe(constituentAccount?: ConstituentAccount): Promise<boolean>;
|
|
187
|
+
sync(): Promise<void>;
|
|
188
|
+
unsubscribe(): Promise<void>;
|
|
189
|
+
}
|
|
190
|
+
export interface ConstituentAccountEvents {
|
|
191
|
+
onAccountUpdate: (account: ConstituentAccount, pubkey: PublicKey, slot: number) => void;
|
|
192
|
+
update: void;
|
|
193
|
+
error: (e: Error) => void;
|
|
194
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { BufferAndSlot, ProgramAccountSubscriber, ResubOpts } from './types';
|
|
4
|
+
import { Program } from '@coral-xyz/anchor';
|
|
5
|
+
import { Commitment, Context, MemcmpFilter, PublicKey } from '@solana/web3.js';
|
|
6
|
+
import { AccountInfoBase, AccountInfoWithBase58EncodedData, AccountInfoWithBase64EncodedData } from 'gill';
|
|
7
|
+
export declare class WebSocketProgramAccountSubscriberV2<T> implements ProgramAccountSubscriber<T> {
|
|
8
|
+
subscriptionName: string;
|
|
9
|
+
accountDiscriminator: string;
|
|
10
|
+
bufferAndSlot?: BufferAndSlot;
|
|
11
|
+
bufferAndSlotMap: Map<string, BufferAndSlot>;
|
|
12
|
+
program: Program;
|
|
13
|
+
decodeBuffer: (accountName: string, ix: Buffer) => T;
|
|
14
|
+
onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void;
|
|
15
|
+
listenerId?: number;
|
|
16
|
+
resubOpts?: ResubOpts;
|
|
17
|
+
isUnsubscribing: boolean;
|
|
18
|
+
timeoutId?: ReturnType<typeof setTimeout>;
|
|
19
|
+
options: {
|
|
20
|
+
filters: MemcmpFilter[];
|
|
21
|
+
commitment?: Commitment;
|
|
22
|
+
};
|
|
23
|
+
receivingData: boolean;
|
|
24
|
+
private rpc;
|
|
25
|
+
private rpcSubscriptions;
|
|
26
|
+
private abortController?;
|
|
27
|
+
private accountsToMonitor;
|
|
28
|
+
private pollingIntervalMs;
|
|
29
|
+
private pollingTimeouts;
|
|
30
|
+
private lastWsNotificationTime;
|
|
31
|
+
private accountsCurrentlyPolling;
|
|
32
|
+
private batchPollingTimeout?;
|
|
33
|
+
constructor(subscriptionName: string, accountDiscriminator: string, program: Program, decodeBufferFn: (accountName: string, ix: Buffer) => T, options?: {
|
|
34
|
+
filters: MemcmpFilter[];
|
|
35
|
+
commitment?: Commitment;
|
|
36
|
+
}, resubOpts?: ResubOpts, accountsToMonitor?: PublicKey[]);
|
|
37
|
+
subscribe(onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void): Promise<void>;
|
|
38
|
+
protected setTimeout(): void;
|
|
39
|
+
handleRpcResponse(context: {
|
|
40
|
+
slot: bigint;
|
|
41
|
+
}, accountInfo?: AccountInfoBase & (AccountInfoWithBase58EncodedData | AccountInfoWithBase64EncodedData)): void;
|
|
42
|
+
private startMonitoringForAccounts;
|
|
43
|
+
private startMonitoringForAccount;
|
|
44
|
+
private startPollingForAccount;
|
|
45
|
+
private startBatchPolling;
|
|
46
|
+
private pollAllAccounts;
|
|
47
|
+
private pollAccount;
|
|
48
|
+
private clearPollingTimeouts;
|
|
49
|
+
unsubscribe(onResub?: boolean): Promise<void>;
|
|
50
|
+
addAccountToMonitor(accountId: PublicKey): void;
|
|
51
|
+
removeAccountFromMonitor(accountId: PublicKey): void;
|
|
52
|
+
setPollingInterval(intervalMs: number): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WebSocketProgramAccountSubscriberV2 = void 0;
|
|
7
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
const gill_1 = require("gill");
|
|
9
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
10
|
+
class WebSocketProgramAccountSubscriberV2 {
|
|
11
|
+
constructor(subscriptionName, accountDiscriminator, program, decodeBufferFn, options = {
|
|
12
|
+
filters: [],
|
|
13
|
+
}, resubOpts, accountsToMonitor // Optional list of accounts to poll
|
|
14
|
+
) {
|
|
15
|
+
var _a;
|
|
16
|
+
this.bufferAndSlotMap = new Map();
|
|
17
|
+
this.isUnsubscribing = false;
|
|
18
|
+
this.receivingData = false;
|
|
19
|
+
// Polling logic for specific accounts
|
|
20
|
+
this.accountsToMonitor = new Set();
|
|
21
|
+
this.pollingIntervalMs = 30000; // 30 seconds
|
|
22
|
+
this.pollingTimeouts = new Map();
|
|
23
|
+
this.lastWsNotificationTime = new Map(); // Track last WS notification time per account
|
|
24
|
+
this.accountsCurrentlyPolling = new Set(); // Track which accounts are being polled
|
|
25
|
+
this.subscriptionName = subscriptionName;
|
|
26
|
+
this.accountDiscriminator = accountDiscriminator;
|
|
27
|
+
this.program = program;
|
|
28
|
+
this.decodeBuffer = decodeBufferFn;
|
|
29
|
+
this.resubOpts = resubOpts;
|
|
30
|
+
if (((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) < 1000) {
|
|
31
|
+
console.log('resubTimeoutMs should be at least 1000ms to avoid spamming resub');
|
|
32
|
+
}
|
|
33
|
+
this.options = options;
|
|
34
|
+
this.receivingData = false;
|
|
35
|
+
// Initialize accounts to monitor
|
|
36
|
+
if (accountsToMonitor) {
|
|
37
|
+
accountsToMonitor.forEach((account) => {
|
|
38
|
+
this.accountsToMonitor.add(account.toBase58());
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Initialize gill client using the same RPC URL as the program provider
|
|
42
|
+
const rpcUrl = this.program.provider.connection
|
|
43
|
+
.rpcEndpoint;
|
|
44
|
+
const { rpc, rpcSubscriptions } = (0, gill_1.createSolanaClient)({
|
|
45
|
+
urlOrMoniker: rpcUrl,
|
|
46
|
+
});
|
|
47
|
+
this.rpc = rpc;
|
|
48
|
+
this.rpcSubscriptions = rpcSubscriptions;
|
|
49
|
+
}
|
|
50
|
+
async subscribe(onChange) {
|
|
51
|
+
var _a, _b;
|
|
52
|
+
if (this.listenerId != null || this.isUnsubscribing) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.onChange = onChange;
|
|
56
|
+
// Create abort controller for proper cleanup
|
|
57
|
+
const abortController = new AbortController();
|
|
58
|
+
this.abortController = abortController;
|
|
59
|
+
// Subscribe to program account changes using gill's rpcSubscriptions
|
|
60
|
+
const programId = this.program.programId.toBase58();
|
|
61
|
+
if ((0, gill_1.isAddress)(programId)) {
|
|
62
|
+
const subscription = await this.rpcSubscriptions
|
|
63
|
+
.programNotifications(programId, {
|
|
64
|
+
commitment: this.options.commitment,
|
|
65
|
+
encoding: 'base64',
|
|
66
|
+
filters: this.options.filters.map((filter) => ({
|
|
67
|
+
memcmp: {
|
|
68
|
+
offset: BigInt(filter.memcmp.offset),
|
|
69
|
+
bytes: filter.memcmp.bytes,
|
|
70
|
+
encoding: 'base64',
|
|
71
|
+
},
|
|
72
|
+
})),
|
|
73
|
+
})
|
|
74
|
+
.subscribe({
|
|
75
|
+
abortSignal: abortController.signal,
|
|
76
|
+
});
|
|
77
|
+
for await (const notification of subscription) {
|
|
78
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
|
|
79
|
+
this.receivingData = true;
|
|
80
|
+
clearTimeout(this.timeoutId);
|
|
81
|
+
this.handleRpcResponse(notification.context, notification.value.account);
|
|
82
|
+
this.setTimeout();
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
this.handleRpcResponse(notification.context, notification.value.account);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this.listenerId = Math.random(); // Unique ID for logging purposes
|
|
90
|
+
if ((_b = this.resubOpts) === null || _b === void 0 ? void 0 : _b.resubTimeoutMs) {
|
|
91
|
+
this.receivingData = true;
|
|
92
|
+
this.setTimeout();
|
|
93
|
+
}
|
|
94
|
+
// Start monitoring for accounts that may need polling if no WS event is received
|
|
95
|
+
this.startMonitoringForAccounts();
|
|
96
|
+
}
|
|
97
|
+
setTimeout() {
|
|
98
|
+
var _a;
|
|
99
|
+
if (!this.onChange) {
|
|
100
|
+
throw new Error('onChange callback function must be set');
|
|
101
|
+
}
|
|
102
|
+
this.timeoutId = setTimeout(async () => {
|
|
103
|
+
var _a, _b;
|
|
104
|
+
if (this.isUnsubscribing) {
|
|
105
|
+
// If we are in the process of unsubscribing, do not attempt to resubscribe
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (this.receivingData) {
|
|
109
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
110
|
+
console.log(`No ws data from ${this.subscriptionName} in ${(_b = this.resubOpts) === null || _b === void 0 ? void 0 : _b.resubTimeoutMs}ms, resubscribing`);
|
|
111
|
+
}
|
|
112
|
+
await this.unsubscribe(true);
|
|
113
|
+
this.receivingData = false;
|
|
114
|
+
await this.subscribe(this.onChange);
|
|
115
|
+
}
|
|
116
|
+
}, (_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs);
|
|
117
|
+
}
|
|
118
|
+
handleRpcResponse(context, accountInfo) {
|
|
119
|
+
const newSlot = Number(context.slot);
|
|
120
|
+
let newBuffer = undefined;
|
|
121
|
+
if (accountInfo) {
|
|
122
|
+
// Extract data from gill response
|
|
123
|
+
if (accountInfo.data) {
|
|
124
|
+
// Handle different data formats from gill
|
|
125
|
+
if (Array.isArray(accountInfo.data)) {
|
|
126
|
+
// If it's a tuple [data, encoding]
|
|
127
|
+
const [data, encoding] = accountInfo.data;
|
|
128
|
+
if (encoding === 'base58') {
|
|
129
|
+
// Convert base58 to buffer using bs58
|
|
130
|
+
newBuffer = Buffer.from(bs58_1.default.decode(data));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
newBuffer = Buffer.from(data, 'base64');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Convert gill's account key to PublicKey
|
|
139
|
+
// Note: accountInfo doesn't have a key property, we need to get it from the notification
|
|
140
|
+
// For now, we'll use a placeholder - this needs to be fixed based on the actual gill API
|
|
141
|
+
const accountId = new web3_js_1.PublicKey('11111111111111111111111111111111'); // Placeholder
|
|
142
|
+
const accountIdString = accountId.toBase58();
|
|
143
|
+
const existingBufferAndSlot = this.bufferAndSlotMap.get(accountIdString);
|
|
144
|
+
// Track WebSocket notification time for this account
|
|
145
|
+
this.lastWsNotificationTime.set(accountIdString, Date.now());
|
|
146
|
+
// If this account was being polled, stop polling it
|
|
147
|
+
if (this.accountsCurrentlyPolling.has(accountIdString)) {
|
|
148
|
+
this.accountsCurrentlyPolling.delete(accountIdString);
|
|
149
|
+
// If no more accounts are being polled, stop batch polling
|
|
150
|
+
if (this.accountsCurrentlyPolling.size === 0 &&
|
|
151
|
+
this.batchPollingTimeout) {
|
|
152
|
+
clearTimeout(this.batchPollingTimeout);
|
|
153
|
+
this.batchPollingTimeout = undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!existingBufferAndSlot) {
|
|
157
|
+
if (newBuffer) {
|
|
158
|
+
this.bufferAndSlotMap.set(accountIdString, {
|
|
159
|
+
buffer: newBuffer,
|
|
160
|
+
slot: newSlot,
|
|
161
|
+
});
|
|
162
|
+
const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
|
|
163
|
+
this.onChange(accountId, account, { slot: newSlot }, newBuffer);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (newSlot < existingBufferAndSlot.slot) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const oldBuffer = existingBufferAndSlot.buffer;
|
|
171
|
+
if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
|
|
172
|
+
this.bufferAndSlotMap.set(accountIdString, {
|
|
173
|
+
buffer: newBuffer,
|
|
174
|
+
slot: newSlot,
|
|
175
|
+
});
|
|
176
|
+
const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
|
|
177
|
+
this.onChange(accountId, account, { slot: newSlot }, newBuffer);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
startMonitoringForAccounts() {
|
|
181
|
+
// Clear any existing polling timeouts
|
|
182
|
+
this.clearPollingTimeouts();
|
|
183
|
+
// Start monitoring for each account in the accountsToMonitor set
|
|
184
|
+
this.accountsToMonitor.forEach((accountIdString) => {
|
|
185
|
+
this.startMonitoringForAccount(accountIdString);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
startMonitoringForAccount(accountIdString) {
|
|
189
|
+
// Clear existing timeout for this account
|
|
190
|
+
const existingTimeout = this.pollingTimeouts.get(accountIdString);
|
|
191
|
+
if (existingTimeout) {
|
|
192
|
+
clearTimeout(existingTimeout);
|
|
193
|
+
}
|
|
194
|
+
// Set up monitoring timeout - only start polling if no WS notification in 30s
|
|
195
|
+
const timeoutId = setTimeout(async () => {
|
|
196
|
+
// Check if we've received a WS notification for this account recently
|
|
197
|
+
const lastNotificationTime = this.lastWsNotificationTime.get(accountIdString);
|
|
198
|
+
const currentTime = Date.now();
|
|
199
|
+
if (!lastNotificationTime ||
|
|
200
|
+
currentTime - lastNotificationTime >= this.pollingIntervalMs) {
|
|
201
|
+
// No recent WS notification, start polling
|
|
202
|
+
await this.pollAccount(accountIdString);
|
|
203
|
+
// Schedule next poll
|
|
204
|
+
this.startPollingForAccount(accountIdString);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
// We received a WS notification recently, continue monitoring
|
|
208
|
+
this.startMonitoringForAccount(accountIdString);
|
|
209
|
+
}
|
|
210
|
+
}, this.pollingIntervalMs);
|
|
211
|
+
this.pollingTimeouts.set(accountIdString, timeoutId);
|
|
212
|
+
}
|
|
213
|
+
startPollingForAccount(accountIdString) {
|
|
214
|
+
// Add account to polling set
|
|
215
|
+
this.accountsCurrentlyPolling.add(accountIdString);
|
|
216
|
+
// If this is the first account being polled, start batch polling
|
|
217
|
+
if (this.accountsCurrentlyPolling.size === 1) {
|
|
218
|
+
this.startBatchPolling();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
startBatchPolling() {
|
|
222
|
+
// Clear existing batch polling timeout
|
|
223
|
+
if (this.batchPollingTimeout) {
|
|
224
|
+
clearTimeout(this.batchPollingTimeout);
|
|
225
|
+
}
|
|
226
|
+
// Set up batch polling interval
|
|
227
|
+
this.batchPollingTimeout = setTimeout(async () => {
|
|
228
|
+
await this.pollAllAccounts();
|
|
229
|
+
// Schedule next batch poll
|
|
230
|
+
this.startBatchPolling();
|
|
231
|
+
}, this.pollingIntervalMs);
|
|
232
|
+
}
|
|
233
|
+
async pollAllAccounts() {
|
|
234
|
+
var _a, _b;
|
|
235
|
+
try {
|
|
236
|
+
// Get all accounts currently being polled
|
|
237
|
+
const accountsToPoll = Array.from(this.accountsCurrentlyPolling);
|
|
238
|
+
if (accountsToPoll.length === 0) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
// Fetch all accounts in a single batch request
|
|
242
|
+
const accountAddresses = accountsToPoll.map((accountId) => accountId);
|
|
243
|
+
const rpcResponse = await this.rpc
|
|
244
|
+
.getMultipleAccounts(accountAddresses, {
|
|
245
|
+
commitment: this.options.commitment,
|
|
246
|
+
encoding: 'base64',
|
|
247
|
+
})
|
|
248
|
+
.send();
|
|
249
|
+
const currentSlot = Number(rpcResponse.context.slot);
|
|
250
|
+
// Process each account response
|
|
251
|
+
for (let i = 0; i < accountsToPoll.length; i++) {
|
|
252
|
+
const accountIdString = accountsToPoll[i];
|
|
253
|
+
const accountInfo = rpcResponse.value[i];
|
|
254
|
+
if (!accountInfo) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const existingBufferAndSlot = this.bufferAndSlotMap.get(accountIdString);
|
|
258
|
+
if (!existingBufferAndSlot) {
|
|
259
|
+
// Account not in our map yet, add it
|
|
260
|
+
let newBuffer = undefined;
|
|
261
|
+
if (accountInfo.data) {
|
|
262
|
+
if (Array.isArray(accountInfo.data)) {
|
|
263
|
+
const [data, encoding] = accountInfo.data;
|
|
264
|
+
newBuffer = Buffer.from(data, encoding);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (newBuffer) {
|
|
268
|
+
this.bufferAndSlotMap.set(accountIdString, {
|
|
269
|
+
buffer: newBuffer,
|
|
270
|
+
slot: currentSlot,
|
|
271
|
+
});
|
|
272
|
+
const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
|
|
273
|
+
const accountId = new web3_js_1.PublicKey(accountIdString);
|
|
274
|
+
this.onChange(accountId, account, { slot: currentSlot }, newBuffer);
|
|
275
|
+
}
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
// Check if we missed an update
|
|
279
|
+
if (currentSlot > existingBufferAndSlot.slot) {
|
|
280
|
+
let newBuffer = undefined;
|
|
281
|
+
if (accountInfo.data) {
|
|
282
|
+
if (Array.isArray(accountInfo.data)) {
|
|
283
|
+
const [data, encoding] = accountInfo.data;
|
|
284
|
+
if (encoding === 'base58') {
|
|
285
|
+
newBuffer = Buffer.from(bs58_1.default.decode(data));
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
newBuffer = Buffer.from(data, 'base64');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Check if buffer has changed
|
|
293
|
+
if (newBuffer &&
|
|
294
|
+
(!existingBufferAndSlot.buffer ||
|
|
295
|
+
!newBuffer.equals(existingBufferAndSlot.buffer))) {
|
|
296
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
297
|
+
console.log(`[${this.subscriptionName}] Batch polling detected missed update for account ${accountIdString}, resubscribing`);
|
|
298
|
+
}
|
|
299
|
+
// We missed an update, resubscribe
|
|
300
|
+
await this.unsubscribe(true);
|
|
301
|
+
this.receivingData = false;
|
|
302
|
+
await this.subscribe(this.onChange);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
if ((_b = this.resubOpts) === null || _b === void 0 ? void 0 : _b.logResubMessages) {
|
|
310
|
+
console.log(`[${this.subscriptionName}] Error batch polling accounts:`, error);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async pollAccount(accountIdString) {
|
|
315
|
+
var _a, _b;
|
|
316
|
+
try {
|
|
317
|
+
// Fetch current account data using gill's rpc
|
|
318
|
+
const accountAddress = accountIdString;
|
|
319
|
+
const rpcResponse = await this.rpc
|
|
320
|
+
.getAccountInfo(accountAddress, {
|
|
321
|
+
commitment: this.options.commitment,
|
|
322
|
+
encoding: 'base64',
|
|
323
|
+
})
|
|
324
|
+
.send();
|
|
325
|
+
const currentSlot = Number(rpcResponse.context.slot);
|
|
326
|
+
const existingBufferAndSlot = this.bufferAndSlotMap.get(accountIdString);
|
|
327
|
+
if (!existingBufferAndSlot) {
|
|
328
|
+
// Account not in our map yet, add it
|
|
329
|
+
if (rpcResponse.value) {
|
|
330
|
+
let newBuffer = undefined;
|
|
331
|
+
if (rpcResponse.value.data) {
|
|
332
|
+
if (Array.isArray(rpcResponse.value.data)) {
|
|
333
|
+
const [data, encoding] = rpcResponse.value.data;
|
|
334
|
+
newBuffer = Buffer.from(data, encoding);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (newBuffer) {
|
|
338
|
+
this.bufferAndSlotMap.set(accountIdString, {
|
|
339
|
+
buffer: newBuffer,
|
|
340
|
+
slot: currentSlot,
|
|
341
|
+
});
|
|
342
|
+
const account = this.decodeBuffer(this.accountDiscriminator, newBuffer);
|
|
343
|
+
const accountId = new web3_js_1.PublicKey(accountIdString);
|
|
344
|
+
this.onChange(accountId, account, { slot: currentSlot }, newBuffer);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// Check if we missed an update
|
|
350
|
+
if (currentSlot > existingBufferAndSlot.slot) {
|
|
351
|
+
let newBuffer = undefined;
|
|
352
|
+
if (rpcResponse.value) {
|
|
353
|
+
if (rpcResponse.value.data) {
|
|
354
|
+
if (Array.isArray(rpcResponse.value.data)) {
|
|
355
|
+
const [data, encoding] = rpcResponse.value.data;
|
|
356
|
+
if (encoding === 'base58') {
|
|
357
|
+
newBuffer = Buffer.from(bs58_1.default.decode(data));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
newBuffer = Buffer.from(data, 'base64');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// Check if buffer has changed
|
|
366
|
+
if (newBuffer &&
|
|
367
|
+
(!existingBufferAndSlot.buffer ||
|
|
368
|
+
!newBuffer.equals(existingBufferAndSlot.buffer))) {
|
|
369
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
370
|
+
console.log(`[${this.subscriptionName}] Polling detected missed update for account ${accountIdString}, resubscribing`);
|
|
371
|
+
}
|
|
372
|
+
// We missed an update, resubscribe
|
|
373
|
+
await this.unsubscribe(true);
|
|
374
|
+
this.receivingData = false;
|
|
375
|
+
await this.subscribe(this.onChange);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
if ((_b = this.resubOpts) === null || _b === void 0 ? void 0 : _b.logResubMessages) {
|
|
382
|
+
console.log(`[${this.subscriptionName}] Error polling account ${accountIdString}:`, error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
clearPollingTimeouts() {
|
|
387
|
+
this.pollingTimeouts.forEach((timeoutId) => {
|
|
388
|
+
clearTimeout(timeoutId);
|
|
389
|
+
});
|
|
390
|
+
this.pollingTimeouts.clear();
|
|
391
|
+
// Clear batch polling timeout
|
|
392
|
+
if (this.batchPollingTimeout) {
|
|
393
|
+
clearTimeout(this.batchPollingTimeout);
|
|
394
|
+
this.batchPollingTimeout = undefined;
|
|
395
|
+
}
|
|
396
|
+
// Clear accounts currently polling
|
|
397
|
+
this.accountsCurrentlyPolling.clear();
|
|
398
|
+
}
|
|
399
|
+
unsubscribe(onResub = false) {
|
|
400
|
+
if (!onResub) {
|
|
401
|
+
this.resubOpts.resubTimeoutMs = undefined;
|
|
402
|
+
}
|
|
403
|
+
this.isUnsubscribing = true;
|
|
404
|
+
clearTimeout(this.timeoutId);
|
|
405
|
+
this.timeoutId = undefined;
|
|
406
|
+
// Clear polling timeouts
|
|
407
|
+
this.clearPollingTimeouts();
|
|
408
|
+
// Abort the WebSocket subscription
|
|
409
|
+
if (this.abortController) {
|
|
410
|
+
this.abortController.abort('unsubscribing');
|
|
411
|
+
this.abortController = undefined;
|
|
412
|
+
}
|
|
413
|
+
this.listenerId = undefined;
|
|
414
|
+
this.isUnsubscribing = false;
|
|
415
|
+
return Promise.resolve();
|
|
416
|
+
}
|
|
417
|
+
// Method to add accounts to the polling list
|
|
418
|
+
addAccountToMonitor(accountId) {
|
|
419
|
+
const accountIdString = accountId.toBase58();
|
|
420
|
+
this.accountsToMonitor.add(accountIdString);
|
|
421
|
+
// If already subscribed, start monitoring for this account
|
|
422
|
+
if (this.listenerId != null && !this.isUnsubscribing) {
|
|
423
|
+
this.startMonitoringForAccount(accountIdString);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// Method to remove accounts from the polling list
|
|
427
|
+
removeAccountFromMonitor(accountId) {
|
|
428
|
+
const accountIdString = accountId.toBase58();
|
|
429
|
+
this.accountsToMonitor.delete(accountIdString);
|
|
430
|
+
// Clear monitoring timeout for this account
|
|
431
|
+
const timeoutId = this.pollingTimeouts.get(accountIdString);
|
|
432
|
+
if (timeoutId) {
|
|
433
|
+
clearTimeout(timeoutId);
|
|
434
|
+
this.pollingTimeouts.delete(accountIdString);
|
|
435
|
+
}
|
|
436
|
+
// Remove from currently polling set if it was being polled
|
|
437
|
+
this.accountsCurrentlyPolling.delete(accountIdString);
|
|
438
|
+
// If no more accounts are being polled, stop batch polling
|
|
439
|
+
if (this.accountsCurrentlyPolling.size === 0 && this.batchPollingTimeout) {
|
|
440
|
+
clearTimeout(this.batchPollingTimeout);
|
|
441
|
+
this.batchPollingTimeout = undefined;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// Method to set polling interval
|
|
445
|
+
setPollingInterval(intervalMs) {
|
|
446
|
+
this.pollingIntervalMs = intervalMs;
|
|
447
|
+
// Restart monitoring with new interval if already subscribed
|
|
448
|
+
if (this.listenerId != null && !this.isUnsubscribing) {
|
|
449
|
+
this.startMonitoringForAccounts();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
exports.WebSocketProgramAccountSubscriberV2 = WebSocketProgramAccountSubscriberV2;
|
|
@@ -35,3 +35,12 @@ export declare function getProtectedMakerModeConfigPublicKey(programId: PublicKe
|
|
|
35
35
|
export declare function getIfRebalanceConfigPublicKey(programId: PublicKey, inMarketIndex: number, outMarketIndex: number): PublicKey;
|
|
36
36
|
export declare function getRevenueShareAccountPublicKey(programId: PublicKey, authority: PublicKey): PublicKey;
|
|
37
37
|
export declare function getRevenueShareEscrowAccountPublicKey(programId: PublicKey, authority: PublicKey): PublicKey;
|
|
38
|
+
export declare function getLpPoolPublicKey(programId: PublicKey, lpPoolId: number): PublicKey;
|
|
39
|
+
export declare function getLpPoolTokenVaultPublicKey(programId: PublicKey, lpPool: PublicKey): PublicKey;
|
|
40
|
+
export declare function getAmmConstituentMappingPublicKey(programId: PublicKey, lpPoolPublicKey: PublicKey): PublicKey;
|
|
41
|
+
export declare function getConstituentTargetBasePublicKey(programId: PublicKey, lpPoolPublicKey: PublicKey): PublicKey;
|
|
42
|
+
export declare function getConstituentPublicKey(programId: PublicKey, lpPoolPublicKey: PublicKey, spotMarketIndex: number): PublicKey;
|
|
43
|
+
export declare function getConstituentVaultPublicKey(programId: PublicKey, lpPoolPublicKey: PublicKey, spotMarketIndex: number): PublicKey;
|
|
44
|
+
export declare function getAmmCachePublicKey(programId: PublicKey): PublicKey;
|
|
45
|
+
export declare function getConstituentCorrelationsPublicKey(programId: PublicKey, lpPoolPublicKey: PublicKey): PublicKey;
|
|
46
|
+
export declare function getLpPoolTokenTokenAccountPublicKey(lpPoolTokenMint: PublicKey, authority: PublicKey): Promise<PublicKey>;
|
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.getRevenueShareEscrowAccountPublicKey = exports.getRevenueShareAccountPublicKey = exports.getIfRebalanceConfigPublicKey = exports.getProtectedMakerModeConfigPublicKey = exports.getHighLeverageModeConfigPublicKey = exports.getTokenProgramForSpotMarket = exports.getPythLazerOraclePublicKey = exports.getPythPullOraclePublicKey = exports.getPrelaunchOraclePublicKey = exports.getProtocolIfSharesTransferConfigPublicKey = exports.getReferrerNamePublicKeySync = exports.getOpenbookV2FulfillmentConfigPublicKey = exports.getPhoenixFulfillmentConfigPublicKey = exports.getSerumFulfillmentConfigPublicKey = exports.getSerumSignerPublicKey = exports.getSerumOpenOrdersPublicKey = exports.getDriftSignerPublicKey = exports.getInsuranceFundStakeAccountPublicKey = exports.getInsuranceFundVaultPublicKey = exports.getSpotMarketVaultPublicKey = exports.getSpotMarketPublicKeySync = exports.getSpotMarketPublicKey = exports.getPerpMarketPublicKeySync = exports.getPerpMarketPublicKey = exports.getSignedMsgWsDelegatesAccountPublicKey = exports.getSignedMsgUserAccountPublicKey = exports.getFuelOverflowAccountPublicKey = exports.getUserStatsAccountPublicKey = exports.getUserAccountPublicKeySync = exports.getUserAccountPublicKey = exports.getUserAccountPublicKeyAndNonce = exports.getDriftStateAccountPublicKey = exports.getDriftStateAccountPublicKeyAndNonce = void 0;
|
|
26
|
+
exports.getLpPoolTokenTokenAccountPublicKey = exports.getConstituentCorrelationsPublicKey = exports.getAmmCachePublicKey = exports.getConstituentVaultPublicKey = exports.getConstituentPublicKey = exports.getConstituentTargetBasePublicKey = exports.getAmmConstituentMappingPublicKey = exports.getLpPoolTokenVaultPublicKey = exports.getLpPoolPublicKey = exports.getRevenueShareEscrowAccountPublicKey = exports.getRevenueShareAccountPublicKey = exports.getIfRebalanceConfigPublicKey = exports.getProtectedMakerModeConfigPublicKey = exports.getHighLeverageModeConfigPublicKey = exports.getTokenProgramForSpotMarket = exports.getPythLazerOraclePublicKey = exports.getPythPullOraclePublicKey = exports.getPrelaunchOraclePublicKey = exports.getProtocolIfSharesTransferConfigPublicKey = exports.getReferrerNamePublicKeySync = exports.getOpenbookV2FulfillmentConfigPublicKey = exports.getPhoenixFulfillmentConfigPublicKey = exports.getSerumFulfillmentConfigPublicKey = exports.getSerumSignerPublicKey = exports.getSerumOpenOrdersPublicKey = exports.getDriftSignerPublicKey = exports.getInsuranceFundStakeAccountPublicKey = exports.getInsuranceFundVaultPublicKey = exports.getSpotMarketVaultPublicKey = exports.getSpotMarketPublicKeySync = exports.getSpotMarketPublicKey = exports.getPerpMarketPublicKeySync = exports.getPerpMarketPublicKey = exports.getSignedMsgWsDelegatesAccountPublicKey = exports.getSignedMsgUserAccountPublicKey = exports.getFuelOverflowAccountPublicKey = exports.getUserStatsAccountPublicKey = exports.getUserAccountPublicKeySync = exports.getUserAccountPublicKey = exports.getUserAccountPublicKeyAndNonce = exports.getDriftStateAccountPublicKey = exports.getDriftStateAccountPublicKeyAndNonce = void 0;
|
|
27
27
|
const web3_js_1 = require("@solana/web3.js");
|
|
28
28
|
const anchor = __importStar(require("@coral-xyz/anchor"));
|
|
29
29
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
@@ -246,3 +246,62 @@ function getRevenueShareEscrowAccountPublicKey(programId, authority) {
|
|
|
246
246
|
], programId)[0];
|
|
247
247
|
}
|
|
248
248
|
exports.getRevenueShareEscrowAccountPublicKey = getRevenueShareEscrowAccountPublicKey;
|
|
249
|
+
function getLpPoolPublicKey(programId, lpPoolId) {
|
|
250
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
251
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('lp_pool')),
|
|
252
|
+
new anchor.BN(lpPoolId).toArrayLike(Buffer, 'le', 1),
|
|
253
|
+
], programId)[0];
|
|
254
|
+
}
|
|
255
|
+
exports.getLpPoolPublicKey = getLpPoolPublicKey;
|
|
256
|
+
function getLpPoolTokenVaultPublicKey(programId, lpPool) {
|
|
257
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
258
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('LP_POOL_TOKEN_VAULT')),
|
|
259
|
+
lpPool.toBuffer(),
|
|
260
|
+
], programId)[0];
|
|
261
|
+
}
|
|
262
|
+
exports.getLpPoolTokenVaultPublicKey = getLpPoolTokenVaultPublicKey;
|
|
263
|
+
function getAmmConstituentMappingPublicKey(programId, lpPoolPublicKey) {
|
|
264
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
265
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('AMM_MAP')),
|
|
266
|
+
lpPoolPublicKey.toBuffer(),
|
|
267
|
+
], programId)[0];
|
|
268
|
+
}
|
|
269
|
+
exports.getAmmConstituentMappingPublicKey = getAmmConstituentMappingPublicKey;
|
|
270
|
+
function getConstituentTargetBasePublicKey(programId, lpPoolPublicKey) {
|
|
271
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
272
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('constituent_target_base_seed')),
|
|
273
|
+
lpPoolPublicKey.toBuffer(),
|
|
274
|
+
], programId)[0];
|
|
275
|
+
}
|
|
276
|
+
exports.getConstituentTargetBasePublicKey = getConstituentTargetBasePublicKey;
|
|
277
|
+
function getConstituentPublicKey(programId, lpPoolPublicKey, spotMarketIndex) {
|
|
278
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
279
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('CONSTITUENT')),
|
|
280
|
+
lpPoolPublicKey.toBuffer(),
|
|
281
|
+
new anchor.BN(spotMarketIndex).toArrayLike(Buffer, 'le', 2),
|
|
282
|
+
], programId)[0];
|
|
283
|
+
}
|
|
284
|
+
exports.getConstituentPublicKey = getConstituentPublicKey;
|
|
285
|
+
function getConstituentVaultPublicKey(programId, lpPoolPublicKey, spotMarketIndex) {
|
|
286
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
287
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('CONSTITUENT_VAULT')),
|
|
288
|
+
lpPoolPublicKey.toBuffer(),
|
|
289
|
+
new anchor.BN(spotMarketIndex).toArrayLike(Buffer, 'le', 2),
|
|
290
|
+
], programId)[0];
|
|
291
|
+
}
|
|
292
|
+
exports.getConstituentVaultPublicKey = getConstituentVaultPublicKey;
|
|
293
|
+
function getAmmCachePublicKey(programId) {
|
|
294
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(anchor.utils.bytes.utf8.encode('amm_cache_seed'))], programId)[0];
|
|
295
|
+
}
|
|
296
|
+
exports.getAmmCachePublicKey = getAmmCachePublicKey;
|
|
297
|
+
function getConstituentCorrelationsPublicKey(programId, lpPoolPublicKey) {
|
|
298
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
299
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('constituent_correlations')),
|
|
300
|
+
lpPoolPublicKey.toBuffer(),
|
|
301
|
+
], programId)[0];
|
|
302
|
+
}
|
|
303
|
+
exports.getConstituentCorrelationsPublicKey = getConstituentCorrelationsPublicKey;
|
|
304
|
+
async function getLpPoolTokenTokenAccountPublicKey(lpPoolTokenMint, authority) {
|
|
305
|
+
return await (0, spl_token_1.getAssociatedTokenAddress)(lpPoolTokenMint, authority, true);
|
|
306
|
+
}
|
|
307
|
+
exports.getLpPoolTokenTokenAccountPublicKey = getLpPoolTokenTokenAccountPublicKey;
|