@drift-labs/sdk-browser 2.142.0-beta.9 → 2.143.0-beta.1
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/grpcDriftClientAccountSubscriberV2.d.ts +46 -5
- package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.js +276 -43
- package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +6 -3
- package/lib/browser/accounts/grpcMultiAccountSubscriber.js +112 -19
- package/lib/browser/adminClient.d.ts +4 -0
- package/lib/browser/adminClient.js +34 -0
- package/lib/browser/constants/perpMarkets.js +35 -0
- package/lib/browser/constants/spotMarkets.js +4 -4
- package/lib/browser/driftClient.d.ts +35 -5
- package/lib/browser/driftClient.js +41 -14
- package/lib/browser/events/parse.d.ts +2 -0
- package/lib/browser/events/parse.js +94 -1
- package/lib/browser/events/types.d.ts +22 -3
- package/lib/browser/idl/drift.json +105 -6
- package/lib/browser/math/amm.d.ts +1 -0
- package/lib/browser/math/amm.js +28 -4
- package/lib/browser/types.d.ts +20 -0
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts +46 -5
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts.map +1 -1
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.js +276 -43
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +6 -3
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -1
- package/lib/node/accounts/grpcMultiAccountSubscriber.js +112 -19
- package/lib/node/adminClient.d.ts +4 -0
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +34 -0
- package/lib/node/constants/perpMarkets.d.ts.map +1 -1
- package/lib/node/constants/perpMarkets.js +35 -0
- package/lib/node/constants/spotMarkets.js +4 -4
- package/lib/node/driftClient.d.ts +35 -5
- package/lib/node/driftClient.d.ts.map +1 -1
- package/lib/node/driftClient.js +41 -14
- package/lib/node/events/parse.d.ts +2 -0
- package/lib/node/events/parse.d.ts.map +1 -1
- package/lib/node/events/parse.js +94 -1
- package/lib/node/events/types.d.ts +22 -3
- package/lib/node/events/types.d.ts.map +1 -1
- package/lib/node/idl/drift.json +105 -6
- package/lib/node/math/amm.d.ts +1 -0
- package/lib/node/math/amm.d.ts.map +1 -1
- package/lib/node/math/amm.js +28 -4
- package/lib/node/types.d.ts +20 -0
- package/lib/node/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/scripts/grpc-client-test-comparison.ts +373 -0
- package/scripts/single-grpc-client-test.ts +226 -0
- package/src/accounts/grpcDriftClientAccountSubscriberV2.ts +439 -74
- package/src/accounts/grpcMultiAccountSubscriber.ts +163 -31
- package/src/adminClient.ts +74 -0
- package/src/constants/perpMarkets.ts +37 -0
- package/src/constants/spotMarkets.ts +4 -4
- package/src/driftClient.ts +65 -14
- package/src/events/parse.ts +115 -0
- package/src/events/types.ts +26 -2
- package/src/idl/drift.json +105 -6
- package/src/math/amm.ts +52 -8
- package/src/types.ts +22 -0
- package/tests/events/parseLogsForCuUsage.ts +139 -0
- package/scripts/client-test.ts +0 -214
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.143.0-beta.1
|
|
@@ -1,24 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
import { OracleInfo, OraclePriceData } from '../oracles/types';
|
|
3
5
|
import { Program } from '@coral-xyz/anchor';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
6
|
+
import { PublicKey } from '@solana/web3.js';
|
|
7
|
+
import { AccountSubscriber, DataAndSlot, DelistedMarketSetting, DriftClientAccountEvents, DriftClientAccountSubscriber, GrpcConfigs, ResubOpts } from './types';
|
|
8
|
+
import { PerpMarketAccount, SpotMarketAccount, StateAccount } from '../types';
|
|
9
|
+
import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
10
|
+
export declare class grpcDriftClientAccountSubscriberV2 implements DriftClientAccountSubscriber {
|
|
7
11
|
private grpcConfigs;
|
|
8
12
|
private perpMarketsSubscriber?;
|
|
9
13
|
private spotMarketsSubscriber?;
|
|
10
14
|
private oracleMultiSubscriber?;
|
|
11
15
|
private perpMarketIndexToAccountPubkeyMap;
|
|
12
16
|
private spotMarketIndexToAccountPubkeyMap;
|
|
17
|
+
private delistedMarketSetting;
|
|
18
|
+
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
19
|
+
isSubscribed: boolean;
|
|
20
|
+
isSubscribing: boolean;
|
|
21
|
+
program: Program;
|
|
22
|
+
perpMarketIndexes: number[];
|
|
23
|
+
spotMarketIndexes: number[];
|
|
24
|
+
shouldFindAllMarketsAndOracles: boolean;
|
|
25
|
+
oracleInfos: OracleInfo[];
|
|
26
|
+
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
27
|
+
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
28
|
+
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
29
|
+
perpOracleMap: Map<number, PublicKey>;
|
|
30
|
+
perpOracleStringMap: Map<number, string>;
|
|
31
|
+
spotOracleMap: Map<number, PublicKey>;
|
|
32
|
+
spotOracleStringMap: Map<number, string>;
|
|
33
|
+
private oracleIdToOracleDataMap;
|
|
34
|
+
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
35
|
+
oracleClientCache: OracleClientCache;
|
|
36
|
+
private resubOpts?;
|
|
37
|
+
private subscriptionPromise;
|
|
38
|
+
protected subscriptionPromiseResolver: (val: boolean) => void;
|
|
13
39
|
constructor(grpcConfigs: GrpcConfigs, program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean, delistedMarketSetting: DelistedMarketSetting, resubOpts?: ResubOpts);
|
|
40
|
+
chunks: <T>(array: readonly T[], size: number) => T[][];
|
|
41
|
+
setInitialData(): Promise<void>;
|
|
42
|
+
addPerpMarket(_marketIndex: number): Promise<boolean>;
|
|
43
|
+
addSpotMarket(_marketIndex: number): Promise<boolean>;
|
|
44
|
+
addOracle(oracleInfo: OracleInfo): Promise<boolean>;
|
|
14
45
|
subscribe(): Promise<boolean>;
|
|
46
|
+
fetch(): Promise<void>;
|
|
47
|
+
private assertIsSubscribed;
|
|
48
|
+
getStateAccountAndSlot(): DataAndSlot<StateAccount>;
|
|
49
|
+
getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
|
|
50
|
+
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
15
51
|
getMarketAccountAndSlot(marketIndex: number): DataAndSlot<PerpMarketAccount> | undefined;
|
|
16
52
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
53
|
+
getOraclePriceDataAndSlot(oracleId: string): DataAndSlot<OraclePriceData> | undefined;
|
|
54
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
55
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
17
56
|
setPerpOracleMap(): Promise<void>;
|
|
18
57
|
setSpotOracleMap(): Promise<void>;
|
|
19
58
|
subscribeToPerpMarketAccounts(): Promise<boolean>;
|
|
20
59
|
subscribeToSpotMarketAccounts(): Promise<boolean>;
|
|
21
60
|
subscribeToOracles(): Promise<boolean>;
|
|
61
|
+
handleDelistedMarkets(): Promise<void>;
|
|
62
|
+
removeInitialData(): void;
|
|
22
63
|
unsubscribeFromOracles(): Promise<void>;
|
|
23
64
|
unsubscribe(): Promise<void>;
|
|
24
65
|
}
|
|
@@ -1,19 +1,117 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.grpcDriftClientAccountSubscriberV2 = void 0;
|
|
4
|
-
const
|
|
4
|
+
const events_1 = require("events");
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
const config_1 = require("../config");
|
|
7
7
|
const pda_1 = require("../addresses/pda");
|
|
8
|
+
const types_1 = require("./types");
|
|
8
9
|
const grpcAccountSubscriber_1 = require("./grpcAccountSubscriber");
|
|
9
10
|
const grpcMultiAccountSubscriber_1 = require("./grpcMultiAccountSubscriber");
|
|
10
11
|
const oracleId_1 = require("../oracles/oracleId");
|
|
11
|
-
|
|
12
|
+
const oracleClientCache_1 = require("../oracles/oracleClientCache");
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
class grpcDriftClientAccountSubscriberV2 {
|
|
12
15
|
constructor(grpcConfigs, program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts) {
|
|
13
|
-
super(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, delistedMarketSetting, resubOpts);
|
|
14
16
|
this.perpMarketIndexToAccountPubkeyMap = new Map();
|
|
15
17
|
this.spotMarketIndexToAccountPubkeyMap = new Map();
|
|
18
|
+
this.perpOracleMap = new Map();
|
|
19
|
+
this.perpOracleStringMap = new Map();
|
|
20
|
+
this.spotOracleMap = new Map();
|
|
21
|
+
this.spotOracleStringMap = new Map();
|
|
22
|
+
this.oracleIdToOracleDataMap = new Map();
|
|
23
|
+
this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
|
|
24
|
+
this.chunks = (array, size) => {
|
|
25
|
+
return new Array(Math.ceil(array.length / size))
|
|
26
|
+
.fill(null)
|
|
27
|
+
.map((_, index) => index * size)
|
|
28
|
+
.map((begin) => array.slice(begin, begin + size));
|
|
29
|
+
};
|
|
30
|
+
this.eventEmitter = new events_1.EventEmitter();
|
|
31
|
+
this.isSubscribed = false;
|
|
32
|
+
this.isSubscribing = false;
|
|
33
|
+
this.program = program;
|
|
34
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
35
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
36
|
+
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
37
|
+
this.oracleInfos = oracleInfos;
|
|
38
|
+
this.initialPerpMarketAccountData = new Map();
|
|
39
|
+
this.initialSpotMarketAccountData = new Map();
|
|
40
|
+
this.initialOraclePriceData = new Map();
|
|
41
|
+
this.perpOracleMap = new Map();
|
|
42
|
+
this.perpOracleStringMap = new Map();
|
|
43
|
+
this.spotOracleMap = new Map();
|
|
44
|
+
this.spotOracleStringMap = new Map();
|
|
16
45
|
this.grpcConfigs = grpcConfigs;
|
|
46
|
+
this.resubOpts = resubOpts;
|
|
47
|
+
this.delistedMarketSetting = delistedMarketSetting;
|
|
48
|
+
}
|
|
49
|
+
async setInitialData() {
|
|
50
|
+
const connection = this.program.provider.connection;
|
|
51
|
+
if (!this.initialPerpMarketAccountData ||
|
|
52
|
+
this.initialPerpMarketAccountData.size === 0) {
|
|
53
|
+
const perpMarketPublicKeys = this.perpMarketIndexes.map((marketIndex) => (0, pda_1.getPerpMarketPublicKeySync)(this.program.programId, marketIndex));
|
|
54
|
+
const perpMarketPublicKeysChunks = this.chunks(perpMarketPublicKeys, 75);
|
|
55
|
+
const perpMarketAccountInfos = (await Promise.all(perpMarketPublicKeysChunks.map((perpMarketPublicKeysChunk) => connection.getMultipleAccountsInfo(perpMarketPublicKeysChunk)))).flat();
|
|
56
|
+
this.initialPerpMarketAccountData = new Map(perpMarketAccountInfos
|
|
57
|
+
.filter((accountInfo) => !!accountInfo)
|
|
58
|
+
.map((accountInfo) => {
|
|
59
|
+
const perpMarket = this.program.coder.accounts.decode('PerpMarket', accountInfo.data);
|
|
60
|
+
return [perpMarket.marketIndex, perpMarket];
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
if (!this.initialSpotMarketAccountData ||
|
|
64
|
+
this.initialSpotMarketAccountData.size === 0) {
|
|
65
|
+
const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) => (0, pda_1.getSpotMarketPublicKeySync)(this.program.programId, marketIndex));
|
|
66
|
+
const spotMarketPublicKeysChunks = this.chunks(spotMarketPublicKeys, 75);
|
|
67
|
+
const spotMarketAccountInfos = (await Promise.all(spotMarketPublicKeysChunks.map((spotMarketPublicKeysChunk) => connection.getMultipleAccountsInfo(spotMarketPublicKeysChunk)))).flat();
|
|
68
|
+
this.initialSpotMarketAccountData = new Map(spotMarketAccountInfos
|
|
69
|
+
.filter((accountInfo) => !!accountInfo)
|
|
70
|
+
.map((accountInfo) => {
|
|
71
|
+
const spotMarket = this.program.coder.accounts.decode('SpotMarket', accountInfo.data);
|
|
72
|
+
return [spotMarket.marketIndex, spotMarket];
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
const oracleAccountPubkeyChunks = this.chunks(this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey), 75);
|
|
76
|
+
const oracleAccountInfos = (await Promise.all(oracleAccountPubkeyChunks.map((oracleAccountPublicKeysChunk) => connection.getMultipleAccountsInfo(oracleAccountPublicKeysChunk)))).flat();
|
|
77
|
+
this.initialOraclePriceData = new Map(this.oracleInfos.reduce((result, oracleInfo, i) => {
|
|
78
|
+
if (!oracleAccountInfos[i]) {
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
const oracleClient = this.oracleClientCache.get(oracleInfo.source, connection, this.program);
|
|
82
|
+
const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(oracleAccountInfos[i].data);
|
|
83
|
+
result.push([
|
|
84
|
+
(0, oracleId_1.getOracleId)(oracleInfo.publicKey, oracleInfo.source),
|
|
85
|
+
oraclePriceData,
|
|
86
|
+
]);
|
|
87
|
+
return result;
|
|
88
|
+
}, []));
|
|
89
|
+
}
|
|
90
|
+
async addPerpMarket(_marketIndex) {
|
|
91
|
+
if (!this.perpMarketIndexes.includes(_marketIndex)) {
|
|
92
|
+
this.perpMarketIndexes = this.perpMarketIndexes.concat(_marketIndex);
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
async addSpotMarket(_marketIndex) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
async addOracle(oracleInfo) {
|
|
100
|
+
var _a, _c;
|
|
101
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
102
|
+
console.log('[grpcDriftClientAccountSubscriberV2] addOracle');
|
|
103
|
+
}
|
|
104
|
+
if (oracleInfo.publicKey.equals(web3_js_1.PublicKey.default)) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
const exists = this.oracleInfos.some((o) => o.source === oracleInfo.source &&
|
|
108
|
+
o.publicKey.equals(oracleInfo.publicKey));
|
|
109
|
+
if (exists) {
|
|
110
|
+
return true; // Already exists, don't add duplicate
|
|
111
|
+
}
|
|
112
|
+
this.oracleInfos = this.oracleInfos.concat(oracleInfo);
|
|
113
|
+
(_c = this.oracleMultiSubscriber) === null || _c === void 0 ? void 0 : _c.addAccounts([oracleInfo.publicKey]);
|
|
114
|
+
return true;
|
|
17
115
|
}
|
|
18
116
|
async subscribe() {
|
|
19
117
|
if (this.isSubscribed) {
|
|
@@ -61,6 +159,32 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
61
159
|
this.removeInitialData();
|
|
62
160
|
return true;
|
|
63
161
|
}
|
|
162
|
+
async fetch() {
|
|
163
|
+
var _a, _c, _d, _e;
|
|
164
|
+
await ((_a = this.stateAccountSubscriber) === null || _a === void 0 ? void 0 : _a.fetch());
|
|
165
|
+
await ((_c = this.perpMarketsSubscriber) === null || _c === void 0 ? void 0 : _c.fetch());
|
|
166
|
+
await ((_d = this.spotMarketsSubscriber) === null || _d === void 0 ? void 0 : _d.fetch());
|
|
167
|
+
await ((_e = this.oracleMultiSubscriber) === null || _e === void 0 ? void 0 : _e.fetch());
|
|
168
|
+
}
|
|
169
|
+
assertIsSubscribed() {
|
|
170
|
+
if (!this.isSubscribed) {
|
|
171
|
+
throw new types_1.NotSubscribedError('You must call `subscribe` before using this function');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
getStateAccountAndSlot() {
|
|
175
|
+
this.assertIsSubscribed();
|
|
176
|
+
return this.stateAccountSubscriber.dataAndSlot;
|
|
177
|
+
}
|
|
178
|
+
getMarketAccountsAndSlots() {
|
|
179
|
+
var _a, _c;
|
|
180
|
+
const map = (_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
|
|
181
|
+
return Array.from((_c = map === null || map === void 0 ? void 0 : map.values()) !== null && _c !== void 0 ? _c : []);
|
|
182
|
+
}
|
|
183
|
+
getSpotMarketAccountsAndSlots() {
|
|
184
|
+
var _a, _c;
|
|
185
|
+
const map = (_a = this.spotMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
|
|
186
|
+
return Array.from((_c = map === null || map === void 0 ? void 0 : map.values()) !== null && _c !== void 0 ? _c : []);
|
|
187
|
+
}
|
|
64
188
|
getMarketAccountAndSlot(marketIndex) {
|
|
65
189
|
var _a;
|
|
66
190
|
return (_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountData(this.perpMarketIndexToAccountPubkeyMap.get(marketIndex));
|
|
@@ -69,8 +193,40 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
69
193
|
var _a;
|
|
70
194
|
return (_a = this.spotMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountData(this.spotMarketIndexToAccountPubkeyMap.get(marketIndex));
|
|
71
195
|
}
|
|
196
|
+
getOraclePriceDataAndSlot(oracleId) {
|
|
197
|
+
this.assertIsSubscribed();
|
|
198
|
+
// we need to rely on a map we store in this class because the grpcMultiAccountSubscriber does not track a mapping or oracle ID.
|
|
199
|
+
// DO NOT call getAccountData on the oracleMultiSubscriber, it will not return the correct data in certain cases(BONK spot and perp market subscribed too at once).
|
|
200
|
+
return this.oracleIdToOracleDataMap.get(oracleId);
|
|
201
|
+
}
|
|
202
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
|
|
203
|
+
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
204
|
+
const oracle = this.perpOracleMap.get(marketIndex);
|
|
205
|
+
const oracleId = this.perpOracleStringMap.get(marketIndex);
|
|
206
|
+
if (!perpMarketAccount || !oracleId) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
210
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
211
|
+
this.setPerpOracleMap();
|
|
212
|
+
}
|
|
213
|
+
return this.getOraclePriceDataAndSlot(oracleId);
|
|
214
|
+
}
|
|
215
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
|
|
216
|
+
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
217
|
+
const oracle = this.spotOracleMap.get(marketIndex);
|
|
218
|
+
const oracleId = this.spotOracleStringMap.get(marketIndex);
|
|
219
|
+
if (!spotMarketAccount || !oracleId) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
223
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
224
|
+
this.setSpotOracleMap();
|
|
225
|
+
}
|
|
226
|
+
return this.getOraclePriceDataAndSlot(oracleId);
|
|
227
|
+
}
|
|
72
228
|
async setPerpOracleMap() {
|
|
73
|
-
var _a;
|
|
229
|
+
var _a, _c;
|
|
74
230
|
const perpMarketsMap = (_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
|
|
75
231
|
const perpMarkets = Array.from(perpMarketsMap.values());
|
|
76
232
|
const addOraclePromises = [];
|
|
@@ -82,7 +238,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
82
238
|
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
83
239
|
const oracle = perpMarketAccount.amm.oracle;
|
|
84
240
|
const oracleId = (0, oracleId_1.getOracleId)(oracle, perpMarket.data.amm.oracleSource);
|
|
85
|
-
if (!this.
|
|
241
|
+
if (!((_c = this.oracleMultiSubscriber) === null || _c === void 0 ? void 0 : _c.getAccountDataMap().has(oracleId))) {
|
|
86
242
|
addOraclePromises.push(this.addOracle({
|
|
87
243
|
publicKey: oracle,
|
|
88
244
|
source: perpMarket.data.amm.oracleSource,
|
|
@@ -94,7 +250,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
94
250
|
await Promise.all(addOraclePromises);
|
|
95
251
|
}
|
|
96
252
|
async setSpotOracleMap() {
|
|
97
|
-
var _a;
|
|
253
|
+
var _a, _c;
|
|
98
254
|
const spotMarketsMap = (_a = this.spotMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap();
|
|
99
255
|
const spotMarkets = Array.from(spotMarketsMap.values());
|
|
100
256
|
const addOraclePromises = [];
|
|
@@ -106,7 +262,7 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
106
262
|
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
107
263
|
const oracle = spotMarketAccount.oracle;
|
|
108
264
|
const oracleId = (0, oracleId_1.getOracleId)(oracle, spotMarketAccount.oracleSource);
|
|
109
|
-
if (!this.
|
|
265
|
+
if (!((_c = this.oracleMultiSubscriber) === null || _c === void 0 ? void 0 : _c.getAccountDataMap().has(oracleId))) {
|
|
110
266
|
addOraclePromises.push(this.addOracle({
|
|
111
267
|
publicKey: oracle,
|
|
112
268
|
source: spotMarketAccount.oracleSource,
|
|
@@ -118,6 +274,10 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
118
274
|
await Promise.all(addOraclePromises);
|
|
119
275
|
}
|
|
120
276
|
async subscribeToPerpMarketAccounts() {
|
|
277
|
+
var _a;
|
|
278
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
279
|
+
console.log('[grpcDriftClientAccountSubscriberV2] subscribeToPerpMarketAccounts');
|
|
280
|
+
}
|
|
121
281
|
const perpMarketIndexToAccountPubkeys = await Promise.all(this.perpMarketIndexes.map(async (marketIndex) => [
|
|
122
282
|
marketIndex,
|
|
123
283
|
await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, marketIndex),
|
|
@@ -149,6 +309,10 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
149
309
|
return true;
|
|
150
310
|
}
|
|
151
311
|
async subscribeToSpotMarketAccounts() {
|
|
312
|
+
var _a;
|
|
313
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
314
|
+
console.log('[grpcDriftClientAccountSubscriberV2] subscribeToSpotMarketAccounts');
|
|
315
|
+
}
|
|
152
316
|
const spotMarketIndexToAccountPubkeys = await Promise.all(this.spotMarketIndexes.map(async (marketIndex) => [
|
|
153
317
|
marketIndex,
|
|
154
318
|
await (0, pda_1.getSpotMarketPublicKey)(this.program.programId, marketIndex),
|
|
@@ -180,64 +344,133 @@ class grpcDriftClientAccountSubscriberV2 extends webSocketDriftClientAccountSubs
|
|
|
180
344
|
return true;
|
|
181
345
|
}
|
|
182
346
|
async subscribeToOracles() {
|
|
183
|
-
|
|
184
|
-
|
|
347
|
+
var _a;
|
|
348
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
349
|
+
console.log('grpcDriftClientAccountSubscriberV2 subscribeToOracles');
|
|
350
|
+
}
|
|
351
|
+
const oraclePubkeyToInfosMap = new Map();
|
|
185
352
|
for (const info of this.oracleInfos) {
|
|
186
|
-
const
|
|
187
|
-
if (!
|
|
188
|
-
|
|
189
|
-
uniqueOraclePubkeys.set(id, info);
|
|
353
|
+
const pubkey = info.publicKey.toBase58();
|
|
354
|
+
if (!oraclePubkeyToInfosMap.has(pubkey)) {
|
|
355
|
+
oraclePubkeyToInfosMap.set(pubkey, []);
|
|
190
356
|
}
|
|
357
|
+
oraclePubkeyToInfosMap.get(pubkey).push(info);
|
|
191
358
|
}
|
|
192
|
-
const oraclePubkeys = Array.from(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}, this.resubOpts, undefined, async () => {
|
|
206
|
-
var _a;
|
|
207
|
-
try {
|
|
208
|
-
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
209
|
-
console.log('[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing');
|
|
210
|
-
}
|
|
211
|
-
await this.subscribeToOracles();
|
|
212
|
-
}
|
|
213
|
-
catch (e) {
|
|
214
|
-
console.error('Oracle resubscribe failed:', e);
|
|
359
|
+
const oraclePubkeys = Array.from(new Set(this.oracleInfos.map((info) => info.publicKey)));
|
|
360
|
+
this.oracleMultiSubscriber = await grpcMultiAccountSubscriber_1.grpcMultiAccountSubscriber.create(this.grpcConfigs, 'oracle', this.program, (buffer, pubkey, accountProps) => {
|
|
361
|
+
if (!pubkey) {
|
|
362
|
+
throw new Error('Oracle pubkey missing in decode');
|
|
363
|
+
}
|
|
364
|
+
const client = this.oracleClientCache.get(accountProps.source, this.program.provider.connection, this.program);
|
|
365
|
+
const price = client.getOraclePriceDataFromBuffer(buffer);
|
|
366
|
+
return price;
|
|
367
|
+
}, this.resubOpts, undefined, async () => {
|
|
368
|
+
var _a;
|
|
369
|
+
try {
|
|
370
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.logResubMessages) {
|
|
371
|
+
console.log('[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing');
|
|
215
372
|
}
|
|
216
|
-
|
|
373
|
+
await this.subscribeToOracles();
|
|
374
|
+
}
|
|
375
|
+
catch (e) {
|
|
376
|
+
console.error('Oracle resubscribe failed:', e);
|
|
377
|
+
}
|
|
378
|
+
}, oraclePubkeyToInfosMap);
|
|
217
379
|
for (const data of this.initialOraclePriceData.entries()) {
|
|
218
380
|
const { publicKey } = (0, oracleId_1.getPublicKeyAndSourceFromOracleId)(data[0]);
|
|
219
381
|
this.oracleMultiSubscriber.setAccountData(publicKey.toBase58(), data[1]);
|
|
382
|
+
this.oracleIdToOracleDataMap.set(data[0], {
|
|
383
|
+
data: data[1],
|
|
384
|
+
slot: 0,
|
|
385
|
+
});
|
|
220
386
|
}
|
|
221
|
-
await this.oracleMultiSubscriber.subscribe(oraclePubkeys, (accountId, data) => {
|
|
222
|
-
const
|
|
223
|
-
this.
|
|
387
|
+
await this.oracleMultiSubscriber.subscribe(oraclePubkeys, (accountId, data, context, _b, accountProps) => {
|
|
388
|
+
const oracleId = (0, oracleId_1.getOracleId)(accountId, accountProps.source);
|
|
389
|
+
this.oracleIdToOracleDataMap.set(oracleId, {
|
|
390
|
+
data,
|
|
391
|
+
slot: context.slot,
|
|
392
|
+
});
|
|
393
|
+
this.eventEmitter.emit('oraclePriceUpdate', accountId, accountProps.source, data);
|
|
224
394
|
this.eventEmitter.emit('update');
|
|
225
395
|
});
|
|
226
396
|
return true;
|
|
227
397
|
}
|
|
398
|
+
async handleDelistedMarkets() {
|
|
399
|
+
var _a, _c;
|
|
400
|
+
if (this.delistedMarketSetting === types_1.DelistedMarketSetting.Subscribe) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const { perpMarketIndexes, oracles } = (0, utils_1.findDelistedPerpMarketsAndOracles)(Array.from(((_a = this.perpMarketsSubscriber) === null || _a === void 0 ? void 0 : _a.getAccountDataMap().values()) || []), Array.from(((_c = this.spotMarketsSubscriber) === null || _c === void 0 ? void 0 : _c.getAccountDataMap().values()) || []));
|
|
404
|
+
// Build array of perp market pubkeys to remove
|
|
405
|
+
const perpMarketPubkeysToRemove = perpMarketIndexes
|
|
406
|
+
.map((marketIndex) => {
|
|
407
|
+
const pubkeyString = this.perpMarketIndexToAccountPubkeyMap.get(marketIndex);
|
|
408
|
+
return pubkeyString ? new web3_js_1.PublicKey(pubkeyString) : null;
|
|
409
|
+
})
|
|
410
|
+
.filter((pubkey) => pubkey !== null);
|
|
411
|
+
// Build array of oracle pubkeys to remove
|
|
412
|
+
const oraclePubkeysToRemove = oracles.map((oracle) => oracle.publicKey);
|
|
413
|
+
// Remove accounts in batches - perp markets
|
|
414
|
+
if (perpMarketPubkeysToRemove.length > 0) {
|
|
415
|
+
await this.perpMarketsSubscriber.removeAccounts(perpMarketPubkeysToRemove);
|
|
416
|
+
// Clean up the mapping for removed perp markets
|
|
417
|
+
for (const pubkey of perpMarketPubkeysToRemove) {
|
|
418
|
+
const pubkeyString = pubkey.toBase58();
|
|
419
|
+
for (const [marketIndex, accountPubkey,] of this.perpMarketIndexToAccountPubkeyMap.entries()) {
|
|
420
|
+
if (accountPubkey === pubkeyString) {
|
|
421
|
+
this.perpMarketIndexToAccountPubkeyMap.delete(marketIndex);
|
|
422
|
+
this.perpOracleMap.delete(marketIndex);
|
|
423
|
+
this.perpOracleStringMap.delete(marketIndex);
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// Remove accounts in batches - oracles
|
|
430
|
+
if (oraclePubkeysToRemove.length > 0) {
|
|
431
|
+
await this.oracleMultiSubscriber.removeAccounts(oraclePubkeysToRemove);
|
|
432
|
+
// Clean up oracle data for removed oracles by finding their sources
|
|
433
|
+
for (const pubkey of oraclePubkeysToRemove) {
|
|
434
|
+
// Find the oracle source by checking oracleInfos
|
|
435
|
+
const oracleInfo = this.oracleInfos.find((info) => info.publicKey.equals(pubkey));
|
|
436
|
+
if (oracleInfo) {
|
|
437
|
+
const oracleId = (0, oracleId_1.getOracleId)(pubkey, oracleInfo.source);
|
|
438
|
+
this.oracleIdToOracleDataMap.delete(oracleId);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
removeInitialData() {
|
|
444
|
+
this.initialPerpMarketAccountData = new Map();
|
|
445
|
+
this.initialSpotMarketAccountData = new Map();
|
|
446
|
+
this.initialOraclePriceData = new Map();
|
|
447
|
+
}
|
|
228
448
|
async unsubscribeFromOracles() {
|
|
229
449
|
if (this.oracleMultiSubscriber) {
|
|
230
450
|
await this.oracleMultiSubscriber.unsubscribe();
|
|
231
451
|
this.oracleMultiSubscriber = undefined;
|
|
232
452
|
return;
|
|
233
453
|
}
|
|
234
|
-
await super.unsubscribeFromOracles();
|
|
235
454
|
}
|
|
236
455
|
async unsubscribe() {
|
|
237
|
-
|
|
456
|
+
var _a, _c, _d;
|
|
457
|
+
if (!this.isSubscribed) {
|
|
238
458
|
return;
|
|
239
459
|
}
|
|
240
|
-
|
|
460
|
+
this.isSubscribed = false;
|
|
461
|
+
this.isSubscribing = false;
|
|
462
|
+
await ((_a = this.stateAccountSubscriber) === null || _a === void 0 ? void 0 : _a.unsubscribe());
|
|
463
|
+
await this.unsubscribeFromOracles();
|
|
464
|
+
await ((_c = this.perpMarketsSubscriber) === null || _c === void 0 ? void 0 : _c.unsubscribe());
|
|
465
|
+
await ((_d = this.spotMarketsSubscriber) === null || _d === void 0 ? void 0 : _d.unsubscribe());
|
|
466
|
+
// Clean up all maps to prevent memory leaks
|
|
467
|
+
this.perpMarketIndexToAccountPubkeyMap.clear();
|
|
468
|
+
this.spotMarketIndexToAccountPubkeyMap.clear();
|
|
469
|
+
this.oracleIdToOracleDataMap.clear();
|
|
470
|
+
this.perpOracleMap.clear();
|
|
471
|
+
this.perpOracleStringMap.clear();
|
|
472
|
+
this.spotOracleMap.clear();
|
|
473
|
+
this.spotOracleStringMap.clear();
|
|
241
474
|
}
|
|
242
475
|
}
|
|
243
476
|
exports.grpcDriftClientAccountSubscriberV2 = grpcDriftClientAccountSubscriberV2;
|
|
@@ -4,7 +4,7 @@ import { Program } from '@coral-xyz/anchor';
|
|
|
4
4
|
import { Context, PublicKey } from '@solana/web3.js';
|
|
5
5
|
import { Client } from '../isomorphic/grpc';
|
|
6
6
|
import { DataAndSlot, GrpcConfigs, ResubOpts } from './types';
|
|
7
|
-
export declare class grpcMultiAccountSubscriber<T> {
|
|
7
|
+
export declare class grpcMultiAccountSubscriber<T, U = undefined> {
|
|
8
8
|
private client;
|
|
9
9
|
private stream;
|
|
10
10
|
private commitmentLevel;
|
|
@@ -20,12 +20,15 @@ export declare class grpcMultiAccountSubscriber<T> {
|
|
|
20
20
|
private subscribedAccounts;
|
|
21
21
|
private onChangeMap;
|
|
22
22
|
private dataMap;
|
|
23
|
+
private accountPropsMap;
|
|
24
|
+
private bufferMap;
|
|
23
25
|
private constructor();
|
|
24
|
-
static create<U>(grpcConfigs: GrpcConfigs, accountName: string, program: Program, decodeBuffer?: (buffer: Buffer, pubkey?: string) =>
|
|
26
|
+
static create<T, U = undefined>(grpcConfigs: GrpcConfigs, accountName: string, program: Program, decodeBuffer?: (buffer: Buffer, pubkey?: string, accountProps?: U) => T, resubOpts?: ResubOpts, clientProp?: Client, onUnsubscribe?: () => Promise<void>, accountPropsMap?: Map<string, U | Array<U>>): Promise<grpcMultiAccountSubscriber<T, U>>;
|
|
25
27
|
setAccountData(accountPubkey: string, data: T, slot?: number): void;
|
|
26
28
|
getAccountData(accountPubkey: string): DataAndSlot<T> | undefined;
|
|
27
29
|
getAccountDataMap(): Map<string, DataAndSlot<T>>;
|
|
28
|
-
|
|
30
|
+
fetch(): Promise<void>;
|
|
31
|
+
subscribe(accounts: PublicKey[], onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer, accountProps: U) => void): Promise<void>;
|
|
29
32
|
addAccounts(accounts: PublicKey[]): Promise<void>;
|
|
30
33
|
removeAccounts(accounts: PublicKey[]): Promise<void>;
|
|
31
34
|
unsubscribe(): Promise<void>;
|