@drift-labs/sdk 2.95.0-beta.12 → 2.95.0-beta.14
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/pollingDriftClientAccountSubscriber.d.ts +3 -1
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +14 -4
- package/lib/accounts/types.d.ts +1 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +8 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +57 -6
- package/lib/addresses/pda.d.ts +2 -0
- package/lib/addresses/pda.js +15 -1
- package/lib/config.d.ts +3 -0
- package/lib/config.js +2 -0
- package/lib/driftClient.js +1 -1
- package/package.json +1 -1
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +17 -5
- package/src/accounts/types.ts +1 -1
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +115 -12
- package/src/addresses/pda.ts +26 -0
- package/src/config.ts +8 -0
- package/src/driftClient.ts +3 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.95.0-beta.
|
|
1
|
+
2.95.0-beta.14
|
|
@@ -24,8 +24,10 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
24
24
|
state?: DataAndSlot<StateAccount>;
|
|
25
25
|
perpMarket: Map<number, DataAndSlot<PerpMarketAccount>>;
|
|
26
26
|
perpOracleMap: Map<number, PublicKey>;
|
|
27
|
+
perpOracleStringMap: Map<number, string>;
|
|
27
28
|
spotMarket: Map<number, DataAndSlot<SpotMarketAccount>>;
|
|
28
29
|
spotOracleMap: Map<number, PublicKey>;
|
|
30
|
+
spotOracleStringMap: Map<number, string>;
|
|
29
31
|
oracles: Map<string, DataAndSlot<OraclePriceData>>;
|
|
30
32
|
user?: DataAndSlot<UserAccount>;
|
|
31
33
|
private isSubscribing;
|
|
@@ -58,7 +60,7 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
58
60
|
getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
|
|
59
61
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
60
62
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
61
|
-
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
|
|
63
|
+
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey | string): DataAndSlot<OraclePriceData> | undefined;
|
|
62
64
|
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
63
65
|
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
64
66
|
updateAccountLoaderPollingFrequency(pollingFrequency: number): void;
|
|
@@ -9,6 +9,7 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
9
9
|
const oracleClientCache_1 = require("../oracles/oracleClientCache");
|
|
10
10
|
const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
|
|
11
11
|
const config_1 = require("../config");
|
|
12
|
+
const ORACLE_DEFAULT_KEY = web3_js_1.PublicKey.default.toBase58();
|
|
12
13
|
class PollingDriftClientAccountSubscriber {
|
|
13
14
|
constructor(program, accountLoader, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles) {
|
|
14
15
|
this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
|
|
@@ -16,8 +17,10 @@ class PollingDriftClientAccountSubscriber {
|
|
|
16
17
|
this.oraclesToPoll = new Map();
|
|
17
18
|
this.perpMarket = new Map();
|
|
18
19
|
this.perpOracleMap = new Map();
|
|
20
|
+
this.perpOracleStringMap = new Map();
|
|
19
21
|
this.spotMarket = new Map();
|
|
20
22
|
this.spotOracleMap = new Map();
|
|
23
|
+
this.spotOracleStringMap = new Map();
|
|
21
24
|
this.oracles = new Map();
|
|
22
25
|
this.isSubscribing = false;
|
|
23
26
|
this.isSubscribed = false;
|
|
@@ -300,6 +303,7 @@ class PollingDriftClientAccountSubscriber {
|
|
|
300
303
|
}));
|
|
301
304
|
}
|
|
302
305
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
306
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
303
307
|
}
|
|
304
308
|
await Promise.all(oraclePromises);
|
|
305
309
|
}
|
|
@@ -317,6 +321,7 @@ class PollingDriftClientAccountSubscriber {
|
|
|
317
321
|
}));
|
|
318
322
|
}
|
|
319
323
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
324
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
320
325
|
}
|
|
321
326
|
await Promise.all(oraclePromises);
|
|
322
327
|
}
|
|
@@ -343,17 +348,21 @@ class PollingDriftClientAccountSubscriber {
|
|
|
343
348
|
}
|
|
344
349
|
getOraclePriceDataAndSlot(oraclePublicKey) {
|
|
345
350
|
this.assertIsSubscribed();
|
|
346
|
-
|
|
351
|
+
const oracleString = typeof oraclePublicKey === 'string'
|
|
352
|
+
? oraclePublicKey
|
|
353
|
+
: oraclePublicKey.toBase58();
|
|
354
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
347
355
|
return {
|
|
348
356
|
data: quoteAssetOracleClient_1.QUOTE_ORACLE_PRICE_DATA,
|
|
349
357
|
slot: 0,
|
|
350
358
|
};
|
|
351
359
|
}
|
|
352
|
-
return this.oracles.get(
|
|
360
|
+
return this.oracles.get(oracleString);
|
|
353
361
|
}
|
|
354
362
|
getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
|
|
355
363
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
356
364
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
365
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
357
366
|
if (!perpMarketAccount || !oracle) {
|
|
358
367
|
return undefined;
|
|
359
368
|
}
|
|
@@ -361,11 +370,12 @@ class PollingDriftClientAccountSubscriber {
|
|
|
361
370
|
// If the oracle has changed, we need to update the oracle map in background
|
|
362
371
|
this.setPerpOracleMap();
|
|
363
372
|
}
|
|
364
|
-
return this.getOraclePriceDataAndSlot(
|
|
373
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
365
374
|
}
|
|
366
375
|
getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
|
|
367
376
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
368
377
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
378
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
369
379
|
if (!spotMarketAccount || !oracle) {
|
|
370
380
|
return undefined;
|
|
371
381
|
}
|
|
@@ -373,7 +383,7 @@ class PollingDriftClientAccountSubscriber {
|
|
|
373
383
|
// If the oracle has changed, we need to update the oracle map in background
|
|
374
384
|
this.setSpotOracleMap();
|
|
375
385
|
}
|
|
376
|
-
return this.getOraclePriceDataAndSlot(
|
|
386
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
377
387
|
}
|
|
378
388
|
updateAccountLoaderPollingFrequency(pollingFrequency) {
|
|
379
389
|
this.accountLoader.updatePollingFrequency(pollingFrequency);
|
package/lib/accounts/types.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export interface DriftClientAccountSubscriber {
|
|
|
45
45
|
getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
|
|
46
46
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
47
47
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
48
|
-
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
|
|
48
|
+
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey | string): DataAndSlot<OraclePriceData> | undefined;
|
|
49
49
|
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
50
50
|
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
51
51
|
updateAccountLoaderPollingFrequency?: (pollingFrequency: number) => void;
|
|
@@ -22,14 +22,21 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
22
22
|
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
23
23
|
perpMarketAccountSubscribers: Map<number, AccountSubscriber<PerpMarketAccount>>;
|
|
24
24
|
perpOracleMap: Map<number, PublicKey>;
|
|
25
|
+
perpOracleStringMap: Map<number, string>;
|
|
25
26
|
spotMarketAccountSubscribers: Map<number, AccountSubscriber<SpotMarketAccount>>;
|
|
26
27
|
spotOracleMap: Map<number, PublicKey>;
|
|
28
|
+
spotOracleStringMap: Map<number, string>;
|
|
27
29
|
oracleSubscribers: Map<string, AccountSubscriber<OraclePriceData>>;
|
|
30
|
+
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
31
|
+
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
32
|
+
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
28
33
|
private isSubscribing;
|
|
29
34
|
private subscriptionPromise;
|
|
30
35
|
private subscriptionPromiseResolver;
|
|
31
36
|
constructor(program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean, resubOpts?: ResubOpts, commitment?: Commitment);
|
|
32
37
|
subscribe(): Promise<boolean>;
|
|
38
|
+
setInitialData(): Promise<void>;
|
|
39
|
+
removeInitialData(): void;
|
|
33
40
|
subscribeToPerpMarketAccounts(): Promise<boolean>;
|
|
34
41
|
subscribeToPerpMarketAccount(marketIndex: number): Promise<boolean>;
|
|
35
42
|
subscribeToSpotMarketAccounts(): Promise<boolean>;
|
|
@@ -52,7 +59,7 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
52
59
|
getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[];
|
|
53
60
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
54
61
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
55
|
-
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
|
|
62
|
+
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey | string): DataAndSlot<OraclePriceData> | undefined;
|
|
56
63
|
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
57
64
|
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
58
65
|
}
|
|
@@ -9,13 +9,16 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
9
9
|
const oracleClientCache_1 = require("../oracles/oracleClientCache");
|
|
10
10
|
const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
|
|
11
11
|
const config_1 = require("../config");
|
|
12
|
+
const ORACLE_DEFAULT_KEY = web3_js_1.PublicKey.default.toBase58();
|
|
12
13
|
class WebSocketDriftClientAccountSubscriber {
|
|
13
14
|
constructor(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, resubOpts, commitment) {
|
|
14
15
|
this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
|
|
15
16
|
this.perpMarketAccountSubscribers = new Map();
|
|
16
17
|
this.perpOracleMap = new Map();
|
|
18
|
+
this.perpOracleStringMap = new Map();
|
|
17
19
|
this.spotMarketAccountSubscribers = new Map();
|
|
18
20
|
this.spotOracleMap = new Map();
|
|
21
|
+
this.spotOracleStringMap = new Map();
|
|
19
22
|
this.oracleSubscribers = new Map();
|
|
20
23
|
this.isSubscribing = false;
|
|
21
24
|
this.isSubscribed = false;
|
|
@@ -40,10 +43,13 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
40
43
|
this.subscriptionPromiseResolver = res;
|
|
41
44
|
});
|
|
42
45
|
if (this.shouldFindAllMarketsAndOracles) {
|
|
43
|
-
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } = await (0, config_1.findAllMarketAndOracles)(this.program);
|
|
46
|
+
const { perpMarketIndexes, perpMarketAccounts, spotMarketIndexes, spotMarketAccounts, oracleInfos, } = await (0, config_1.findAllMarketAndOracles)(this.program);
|
|
44
47
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
45
48
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
46
49
|
this.oracleInfos = oracleInfos;
|
|
50
|
+
// front run and set the initial data here to save extra gma call in set initial data
|
|
51
|
+
this.initialPerpMarketAccountData = new Map(perpMarketAccounts.map((market) => [market.marketIndex, market]));
|
|
52
|
+
this.initialSpotMarketAccountData = new Map(spotMarketAccounts.map((market) => [market.marketIndex, market]));
|
|
47
53
|
}
|
|
48
54
|
const statePublicKey = await (0, pda_1.getDriftStateAccountPublicKey)(this.program.programId);
|
|
49
55
|
// create and activate main state account subscription
|
|
@@ -52,6 +58,8 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
52
58
|
this.eventEmitter.emit('stateAccountUpdate', data);
|
|
53
59
|
this.eventEmitter.emit('update');
|
|
54
60
|
});
|
|
61
|
+
// set initial data to avoid spamming getAccountInfo calls in webSocketAccountSubscriber
|
|
62
|
+
await this.setInitialData();
|
|
55
63
|
await Promise.all([
|
|
56
64
|
// subscribe to market accounts
|
|
57
65
|
this.subscribeToPerpMarketAccounts(),
|
|
@@ -65,8 +73,40 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
65
73
|
this.isSubscribing = false;
|
|
66
74
|
this.isSubscribed = true;
|
|
67
75
|
this.subscriptionPromiseResolver(true);
|
|
76
|
+
// delete initial data
|
|
77
|
+
this.removeInitialData();
|
|
68
78
|
return true;
|
|
69
79
|
}
|
|
80
|
+
async setInitialData() {
|
|
81
|
+
const connection = this.program.provider.connection;
|
|
82
|
+
if (!this.initialPerpMarketAccountData) {
|
|
83
|
+
const perpMarketPublicKeys = this.perpMarketIndexes.map((marketIndex) => (0, pda_1.getPerpMarketPublicKeySync)(this.program.programId, marketIndex));
|
|
84
|
+
const perpMarketAccountInfos = await connection.getMultipleAccountsInfo(perpMarketPublicKeys);
|
|
85
|
+
this.initialPerpMarketAccountData = new Map(perpMarketAccountInfos.map((accountInfo) => {
|
|
86
|
+
const perpMarket = this.program.coder.accounts.decode('PerpMarket', accountInfo.data);
|
|
87
|
+
return [perpMarket.marketIndex, perpMarket];
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
if (!this.initialSpotMarketAccountData) {
|
|
91
|
+
const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) => (0, pda_1.getSpotMarketPublicKeySync)(this.program.programId, marketIndex));
|
|
92
|
+
const spotMarketAccountInfos = await connection.getMultipleAccountsInfo(spotMarketPublicKeys);
|
|
93
|
+
this.initialSpotMarketAccountData = new Map(spotMarketAccountInfos.map((accountInfo) => {
|
|
94
|
+
const spotMarket = this.program.coder.accounts.decode('SpotMarket', accountInfo.data);
|
|
95
|
+
return [spotMarket.marketIndex, spotMarket];
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
const oracleAccountInfos = await connection.getMultipleAccountsInfo(this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey));
|
|
99
|
+
this.initialOraclePriceData = new Map(this.oracleInfos.map((oracleInfo, i) => {
|
|
100
|
+
const oracleClient = this.oracleClientCache.get(oracleInfo.source, connection, this.program);
|
|
101
|
+
const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(oracleAccountInfos[i].data);
|
|
102
|
+
return [oracleInfo.publicKey.toString(), oraclePriceData];
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
removeInitialData() {
|
|
106
|
+
this.initialPerpMarketAccountData = new Map();
|
|
107
|
+
this.initialSpotMarketAccountData = new Map();
|
|
108
|
+
this.initialOraclePriceData = new Map();
|
|
109
|
+
}
|
|
70
110
|
async subscribeToPerpMarketAccounts() {
|
|
71
111
|
await Promise.all(this.perpMarketIndexes.map((marketIndex) => this.subscribeToPerpMarketAccount(marketIndex)));
|
|
72
112
|
return true;
|
|
@@ -74,6 +114,7 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
74
114
|
async subscribeToPerpMarketAccount(marketIndex) {
|
|
75
115
|
const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, marketIndex);
|
|
76
116
|
const accountSubscriber = new webSocketAccountSubscriber_1.WebSocketAccountSubscriber('perpMarket', this.program, perpMarketPublicKey, undefined, this.resubOpts, this.commitment);
|
|
117
|
+
accountSubscriber.setData(this.initialPerpMarketAccountData.get(marketIndex));
|
|
77
118
|
await accountSubscriber.subscribe((data) => {
|
|
78
119
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
79
120
|
this.eventEmitter.emit('update');
|
|
@@ -88,6 +129,7 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
88
129
|
async subscribeToSpotMarketAccount(marketIndex) {
|
|
89
130
|
const marketPublicKey = await (0, pda_1.getSpotMarketPublicKey)(this.program.programId, marketIndex);
|
|
90
131
|
const accountSubscriber = new webSocketAccountSubscriber_1.WebSocketAccountSubscriber('spotMarket', this.program, marketPublicKey, undefined, this.resubOpts, this.commitment);
|
|
132
|
+
accountSubscriber.setData(this.initialSpotMarketAccountData.get(marketIndex));
|
|
91
133
|
await accountSubscriber.subscribe((data) => {
|
|
92
134
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
93
135
|
this.eventEmitter.emit('update');
|
|
@@ -102,15 +144,17 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
102
144
|
return true;
|
|
103
145
|
}
|
|
104
146
|
async subscribeToOracle(oracleInfo) {
|
|
147
|
+
const oracleString = oracleInfo.publicKey.toString();
|
|
105
148
|
const client = this.oracleClientCache.get(oracleInfo.source, this.program.provider.connection, this.program);
|
|
106
149
|
const accountSubscriber = new webSocketAccountSubscriber_1.WebSocketAccountSubscriber('oracle', this.program, oracleInfo.publicKey, (buffer) => {
|
|
107
150
|
return client.getOraclePriceDataFromBuffer(buffer);
|
|
108
151
|
}, this.resubOpts, this.commitment);
|
|
152
|
+
accountSubscriber.setData(this.initialOraclePriceData.get(oracleString));
|
|
109
153
|
await accountSubscriber.subscribe((data) => {
|
|
110
154
|
this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
|
|
111
155
|
this.eventEmitter.emit('update');
|
|
112
156
|
});
|
|
113
|
-
this.oracleSubscribers.set(
|
|
157
|
+
this.oracleSubscribers.set(oracleString, accountSubscriber);
|
|
114
158
|
return true;
|
|
115
159
|
}
|
|
116
160
|
async unsubscribeFromMarketAccounts() {
|
|
@@ -183,6 +227,7 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
183
227
|
}));
|
|
184
228
|
}
|
|
185
229
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
230
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
186
231
|
}
|
|
187
232
|
await Promise.all(addOraclePromises);
|
|
188
233
|
}
|
|
@@ -203,6 +248,7 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
203
248
|
}));
|
|
204
249
|
}
|
|
205
250
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
251
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
206
252
|
}
|
|
207
253
|
await Promise.all(addOraclePromises);
|
|
208
254
|
}
|
|
@@ -231,17 +277,21 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
231
277
|
}
|
|
232
278
|
getOraclePriceDataAndSlot(oraclePublicKey) {
|
|
233
279
|
this.assertIsSubscribed();
|
|
234
|
-
|
|
280
|
+
const oracleString = typeof oraclePublicKey === 'string'
|
|
281
|
+
? oraclePublicKey
|
|
282
|
+
: oraclePublicKey.toBase58();
|
|
283
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
235
284
|
return {
|
|
236
285
|
data: quoteAssetOracleClient_1.QUOTE_ORACLE_PRICE_DATA,
|
|
237
286
|
slot: 0,
|
|
238
287
|
};
|
|
239
288
|
}
|
|
240
|
-
return this.oracleSubscribers.get(
|
|
289
|
+
return this.oracleSubscribers.get(oracleString).dataAndSlot;
|
|
241
290
|
}
|
|
242
291
|
getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
|
|
243
292
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
244
293
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
294
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
245
295
|
if (!perpMarketAccount || !oracle) {
|
|
246
296
|
return undefined;
|
|
247
297
|
}
|
|
@@ -249,11 +299,12 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
249
299
|
// If the oracle has changed, we need to update the oracle map in background
|
|
250
300
|
this.setPerpOracleMap();
|
|
251
301
|
}
|
|
252
|
-
return this.getOraclePriceDataAndSlot(
|
|
302
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
253
303
|
}
|
|
254
304
|
getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
|
|
255
305
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
256
306
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
307
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
257
308
|
if (!spotMarketAccount || !oracle) {
|
|
258
309
|
return undefined;
|
|
259
310
|
}
|
|
@@ -261,7 +312,7 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
261
312
|
// If the oracle has changed, we need to update the oracle map in background
|
|
262
313
|
this.setSpotOracleMap();
|
|
263
314
|
}
|
|
264
|
-
return this.getOraclePriceDataAndSlot(
|
|
315
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
265
316
|
}
|
|
266
317
|
}
|
|
267
318
|
exports.WebSocketDriftClientAccountSubscriber = WebSocketDriftClientAccountSubscriber;
|
package/lib/addresses/pda.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export declare function getUserAccountPublicKey(programId: PublicKey, authority:
|
|
|
9
9
|
export declare function getUserAccountPublicKeySync(programId: PublicKey, authority: PublicKey, subAccountId?: number): PublicKey;
|
|
10
10
|
export declare function getUserStatsAccountPublicKey(programId: PublicKey, authority: PublicKey): PublicKey;
|
|
11
11
|
export declare function getPerpMarketPublicKey(programId: PublicKey, marketIndex: number): Promise<PublicKey>;
|
|
12
|
+
export declare function getPerpMarketPublicKeySync(programId: PublicKey, marketIndex: number): PublicKey;
|
|
12
13
|
export declare function getSpotMarketPublicKey(programId: PublicKey, marketIndex: number): Promise<PublicKey>;
|
|
14
|
+
export declare function getSpotMarketPublicKeySync(programId: PublicKey, marketIndex: number): PublicKey;
|
|
13
15
|
export declare function getSpotMarketVaultPublicKey(programId: PublicKey, marketIndex: number): Promise<PublicKey>;
|
|
14
16
|
export declare function getInsuranceFundVaultPublicKey(programId: PublicKey, marketIndex: number): Promise<PublicKey>;
|
|
15
17
|
export declare function getInsuranceFundStakeAccountPublicKey(programId: PublicKey, authority: PublicKey, marketIndex: number): PublicKey;
|
package/lib/addresses/pda.js
CHANGED
|
@@ -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.getTokenProgramForSpotMarket = 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.getSpotMarketPublicKey = exports.getPerpMarketPublicKey = exports.getUserStatsAccountPublicKey = exports.getUserAccountPublicKeySync = exports.getUserAccountPublicKey = exports.getUserAccountPublicKeyAndNonce = exports.getDriftStateAccountPublicKey = exports.getDriftStateAccountPublicKeyAndNonce = void 0;
|
|
26
|
+
exports.getTokenProgramForSpotMarket = 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.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 spl_token_1 = require("@solana/spl-token");
|
|
@@ -69,6 +69,13 @@ async function getPerpMarketPublicKey(programId, marketIndex) {
|
|
|
69
69
|
], programId))[0];
|
|
70
70
|
}
|
|
71
71
|
exports.getPerpMarketPublicKey = getPerpMarketPublicKey;
|
|
72
|
+
function getPerpMarketPublicKeySync(programId, marketIndex) {
|
|
73
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
74
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('perp_market')),
|
|
75
|
+
new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2),
|
|
76
|
+
], programId)[0];
|
|
77
|
+
}
|
|
78
|
+
exports.getPerpMarketPublicKeySync = getPerpMarketPublicKeySync;
|
|
72
79
|
async function getSpotMarketPublicKey(programId, marketIndex) {
|
|
73
80
|
return (await web3_js_1.PublicKey.findProgramAddress([
|
|
74
81
|
Buffer.from(anchor.utils.bytes.utf8.encode('spot_market')),
|
|
@@ -76,6 +83,13 @@ async function getSpotMarketPublicKey(programId, marketIndex) {
|
|
|
76
83
|
], programId))[0];
|
|
77
84
|
}
|
|
78
85
|
exports.getSpotMarketPublicKey = getSpotMarketPublicKey;
|
|
86
|
+
function getSpotMarketPublicKeySync(programId, marketIndex) {
|
|
87
|
+
return web3_js_1.PublicKey.findProgramAddressSync([
|
|
88
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('spot_market')),
|
|
89
|
+
new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2),
|
|
90
|
+
], programId)[0];
|
|
91
|
+
}
|
|
92
|
+
exports.getSpotMarketPublicKeySync = getSpotMarketPublicKeySync;
|
|
79
93
|
async function getSpotMarketVaultPublicKey(programId, marketIndex) {
|
|
80
94
|
return (await web3_js_1.PublicKey.findProgramAddress([
|
|
81
95
|
Buffer.from(anchor.utils.bytes.utf8.encode('spot_market_vault')),
|
package/lib/config.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PerpMarketAccount, SpotMarketAccount } from '.';
|
|
1
2
|
import { PerpMarketConfig } from './constants/perpMarkets';
|
|
2
3
|
import { SpotMarketConfig } from './constants/spotMarkets';
|
|
3
4
|
import { OracleInfo } from './oracles/types';
|
|
@@ -44,7 +45,9 @@ export declare function getMarketsAndOraclesForSubscription(env: DriftEnv): {
|
|
|
44
45
|
};
|
|
45
46
|
export declare function findAllMarketAndOracles(program: Program): Promise<{
|
|
46
47
|
perpMarketIndexes: number[];
|
|
48
|
+
perpMarketAccounts: PerpMarketAccount[];
|
|
47
49
|
spotMarketIndexes: number[];
|
|
48
50
|
oracleInfos: OracleInfo[];
|
|
51
|
+
spotMarketAccounts: SpotMarketAccount[];
|
|
49
52
|
}>;
|
|
50
53
|
export {};
|
package/lib/config.js
CHANGED
|
@@ -106,7 +106,9 @@ async function findAllMarketAndOracles(program) {
|
|
|
106
106
|
}
|
|
107
107
|
return {
|
|
108
108
|
perpMarketIndexes,
|
|
109
|
+
perpMarketAccounts: perpMarketProgramAccounts.map((account) => account.account),
|
|
109
110
|
spotMarketIndexes,
|
|
111
|
+
spotMarketAccounts: spotMarketProgramAccounts.map((account) => account.account),
|
|
110
112
|
oracleInfos: Array.from(oracleInfos.values()),
|
|
111
113
|
};
|
|
112
114
|
}
|
package/lib/driftClient.js
CHANGED
|
@@ -309,7 +309,7 @@ class DriftClient {
|
|
|
309
309
|
return this.accountSubscriber.getSpotMarketAccountAndSlot(numericConstants_1.QUOTE_SPOT_MARKET_INDEX).data;
|
|
310
310
|
}
|
|
311
311
|
getOraclePriceDataAndSlot(oraclePublicKey) {
|
|
312
|
-
return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
|
|
312
|
+
return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey.toBase58());
|
|
313
313
|
}
|
|
314
314
|
async getSerumV3FulfillmentConfig(serumMarket) {
|
|
315
315
|
const address = await (0, pda_1.getSerumFulfillmentConfigPublicKey)(this.program.programId, serumMarket);
|
package/package.json
CHANGED
|
@@ -28,6 +28,8 @@ import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
|
28
28
|
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
29
29
|
import { findAllMarketAndOracles } from '../config';
|
|
30
30
|
|
|
31
|
+
const ORACLE_DEFAULT_KEY = PublicKey.default.toBase58();
|
|
32
|
+
|
|
31
33
|
export class PollingDriftClientAccountSubscriber
|
|
32
34
|
implements DriftClientAccountSubscriber
|
|
33
35
|
{
|
|
@@ -50,8 +52,10 @@ export class PollingDriftClientAccountSubscriber
|
|
|
50
52
|
state?: DataAndSlot<StateAccount>;
|
|
51
53
|
perpMarket = new Map<number, DataAndSlot<PerpMarketAccount>>();
|
|
52
54
|
perpOracleMap = new Map<number, PublicKey>();
|
|
55
|
+
perpOracleStringMap = new Map<number, string>();
|
|
53
56
|
spotMarket = new Map<number, DataAndSlot<SpotMarketAccount>>();
|
|
54
57
|
spotOracleMap = new Map<number, PublicKey>();
|
|
58
|
+
spotOracleStringMap = new Map<number, string>();
|
|
55
59
|
oracles = new Map<string, DataAndSlot<OraclePriceData>>();
|
|
56
60
|
user?: DataAndSlot<UserAccount>;
|
|
57
61
|
|
|
@@ -470,6 +474,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
470
474
|
);
|
|
471
475
|
}
|
|
472
476
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
477
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
473
478
|
}
|
|
474
479
|
await Promise.all(oraclePromises);
|
|
475
480
|
}
|
|
@@ -490,6 +495,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
490
495
|
);
|
|
491
496
|
}
|
|
492
497
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
498
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
493
499
|
}
|
|
494
500
|
await Promise.all(oraclePromises);
|
|
495
501
|
}
|
|
@@ -528,17 +534,21 @@ export class PollingDriftClientAccountSubscriber
|
|
|
528
534
|
}
|
|
529
535
|
|
|
530
536
|
public getOraclePriceDataAndSlot(
|
|
531
|
-
oraclePublicKey: PublicKey
|
|
537
|
+
oraclePublicKey: PublicKey | string
|
|
532
538
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
533
539
|
this.assertIsSubscribed();
|
|
534
|
-
|
|
540
|
+
const oracleString =
|
|
541
|
+
typeof oraclePublicKey === 'string'
|
|
542
|
+
? oraclePublicKey
|
|
543
|
+
: oraclePublicKey.toBase58();
|
|
544
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
535
545
|
return {
|
|
536
546
|
data: QUOTE_ORACLE_PRICE_DATA,
|
|
537
547
|
slot: 0,
|
|
538
548
|
};
|
|
539
549
|
}
|
|
540
550
|
|
|
541
|
-
return this.oracles.get(
|
|
551
|
+
return this.oracles.get(oracleString);
|
|
542
552
|
}
|
|
543
553
|
|
|
544
554
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -546,6 +556,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
546
556
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
547
557
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
548
558
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
559
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
549
560
|
|
|
550
561
|
if (!perpMarketAccount || !oracle) {
|
|
551
562
|
return undefined;
|
|
@@ -556,7 +567,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
556
567
|
this.setPerpOracleMap();
|
|
557
568
|
}
|
|
558
569
|
|
|
559
|
-
return this.getOraclePriceDataAndSlot(
|
|
570
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
560
571
|
}
|
|
561
572
|
|
|
562
573
|
public getOraclePriceDataAndSlotForSpotMarket(
|
|
@@ -564,6 +575,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
564
575
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
565
576
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
566
577
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
578
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
567
579
|
if (!spotMarketAccount || !oracle) {
|
|
568
580
|
return undefined;
|
|
569
581
|
}
|
|
@@ -573,7 +585,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
573
585
|
this.setSpotOracleMap();
|
|
574
586
|
}
|
|
575
587
|
|
|
576
|
-
return this.getOraclePriceDataAndSlot(
|
|
588
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
577
589
|
}
|
|
578
590
|
|
|
579
591
|
public updateAccountLoaderPollingFrequency(pollingFrequency: number): void {
|
package/src/accounts/types.ts
CHANGED
|
@@ -72,7 +72,7 @@ export interface DriftClientAccountSubscriber {
|
|
|
72
72
|
): DataAndSlot<SpotMarketAccount> | undefined;
|
|
73
73
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
74
74
|
getOraclePriceDataAndSlot(
|
|
75
|
-
oraclePublicKey: PublicKey
|
|
75
|
+
oraclePublicKey: PublicKey | string
|
|
76
76
|
): DataAndSlot<OraclePriceData> | undefined;
|
|
77
77
|
getOraclePriceDataAndSlotForPerpMarket(
|
|
78
78
|
marketIndex: number
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
getDriftStateAccountPublicKey,
|
|
14
14
|
getSpotMarketPublicKey,
|
|
15
15
|
getPerpMarketPublicKey,
|
|
16
|
+
getPerpMarketPublicKeySync,
|
|
17
|
+
getSpotMarketPublicKeySync,
|
|
16
18
|
} from '../addresses/pda';
|
|
17
19
|
import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
|
|
18
20
|
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
@@ -22,6 +24,8 @@ import * as Buffer from 'buffer';
|
|
|
22
24
|
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
23
25
|
import { findAllMarketAndOracles } from '../config';
|
|
24
26
|
|
|
27
|
+
const ORACLE_DEFAULT_KEY = PublicKey.default.toBase58();
|
|
28
|
+
|
|
25
29
|
export class WebSocketDriftClientAccountSubscriber
|
|
26
30
|
implements DriftClientAccountSubscriber
|
|
27
31
|
{
|
|
@@ -43,13 +47,19 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
43
47
|
AccountSubscriber<PerpMarketAccount>
|
|
44
48
|
>();
|
|
45
49
|
perpOracleMap = new Map<number, PublicKey>();
|
|
50
|
+
perpOracleStringMap = new Map<number, string>();
|
|
46
51
|
spotMarketAccountSubscribers = new Map<
|
|
47
52
|
number,
|
|
48
53
|
AccountSubscriber<SpotMarketAccount>
|
|
49
54
|
>();
|
|
50
55
|
spotOracleMap = new Map<number, PublicKey>();
|
|
56
|
+
spotOracleStringMap = new Map<number, string>();
|
|
51
57
|
oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
|
|
52
58
|
|
|
59
|
+
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
60
|
+
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
61
|
+
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
62
|
+
|
|
53
63
|
private isSubscribing = false;
|
|
54
64
|
private subscriptionPromise: Promise<boolean>;
|
|
55
65
|
private subscriptionPromiseResolver: (val: boolean) => void;
|
|
@@ -90,11 +100,23 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
90
100
|
});
|
|
91
101
|
|
|
92
102
|
if (this.shouldFindAllMarketsAndOracles) {
|
|
93
|
-
const {
|
|
94
|
-
|
|
103
|
+
const {
|
|
104
|
+
perpMarketIndexes,
|
|
105
|
+
perpMarketAccounts,
|
|
106
|
+
spotMarketIndexes,
|
|
107
|
+
spotMarketAccounts,
|
|
108
|
+
oracleInfos,
|
|
109
|
+
} = await findAllMarketAndOracles(this.program);
|
|
95
110
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
96
111
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
97
112
|
this.oracleInfos = oracleInfos;
|
|
113
|
+
// front run and set the initial data here to save extra gma call in set initial data
|
|
114
|
+
this.initialPerpMarketAccountData = new Map(
|
|
115
|
+
perpMarketAccounts.map((market) => [market.marketIndex, market])
|
|
116
|
+
);
|
|
117
|
+
this.initialSpotMarketAccountData = new Map(
|
|
118
|
+
spotMarketAccounts.map((market) => [market.marketIndex, market])
|
|
119
|
+
);
|
|
98
120
|
}
|
|
99
121
|
|
|
100
122
|
const statePublicKey = await getDriftStateAccountPublicKey(
|
|
@@ -115,6 +137,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
115
137
|
this.eventEmitter.emit('update');
|
|
116
138
|
});
|
|
117
139
|
|
|
140
|
+
// set initial data to avoid spamming getAccountInfo calls in webSocketAccountSubscriber
|
|
141
|
+
await this.setInitialData();
|
|
142
|
+
|
|
118
143
|
await Promise.all([
|
|
119
144
|
// subscribe to market accounts
|
|
120
145
|
this.subscribeToPerpMarketAccounts(),
|
|
@@ -132,9 +157,75 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
132
157
|
this.isSubscribed = true;
|
|
133
158
|
this.subscriptionPromiseResolver(true);
|
|
134
159
|
|
|
160
|
+
// delete initial data
|
|
161
|
+
this.removeInitialData();
|
|
162
|
+
|
|
135
163
|
return true;
|
|
136
164
|
}
|
|
137
165
|
|
|
166
|
+
async setInitialData(): Promise<void> {
|
|
167
|
+
const connection = this.program.provider.connection;
|
|
168
|
+
|
|
169
|
+
if (!this.initialPerpMarketAccountData) {
|
|
170
|
+
const perpMarketPublicKeys = this.perpMarketIndexes.map((marketIndex) =>
|
|
171
|
+
getPerpMarketPublicKeySync(this.program.programId, marketIndex)
|
|
172
|
+
);
|
|
173
|
+
const perpMarketAccountInfos = await connection.getMultipleAccountsInfo(
|
|
174
|
+
perpMarketPublicKeys
|
|
175
|
+
);
|
|
176
|
+
this.initialPerpMarketAccountData = new Map(
|
|
177
|
+
perpMarketAccountInfos.map((accountInfo) => {
|
|
178
|
+
const perpMarket = this.program.coder.accounts.decode(
|
|
179
|
+
'PerpMarket',
|
|
180
|
+
accountInfo.data
|
|
181
|
+
);
|
|
182
|
+
return [perpMarket.marketIndex, perpMarket];
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!this.initialSpotMarketAccountData) {
|
|
188
|
+
const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) =>
|
|
189
|
+
getSpotMarketPublicKeySync(this.program.programId, marketIndex)
|
|
190
|
+
);
|
|
191
|
+
const spotMarketAccountInfos = await connection.getMultipleAccountsInfo(
|
|
192
|
+
spotMarketPublicKeys
|
|
193
|
+
);
|
|
194
|
+
this.initialSpotMarketAccountData = new Map(
|
|
195
|
+
spotMarketAccountInfos.map((accountInfo) => {
|
|
196
|
+
const spotMarket = this.program.coder.accounts.decode(
|
|
197
|
+
'SpotMarket',
|
|
198
|
+
accountInfo.data
|
|
199
|
+
);
|
|
200
|
+
return [spotMarket.marketIndex, spotMarket];
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const oracleAccountInfos = await connection.getMultipleAccountsInfo(
|
|
206
|
+
this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey)
|
|
207
|
+
);
|
|
208
|
+
this.initialOraclePriceData = new Map(
|
|
209
|
+
this.oracleInfos.map((oracleInfo, i) => {
|
|
210
|
+
const oracleClient = this.oracleClientCache.get(
|
|
211
|
+
oracleInfo.source,
|
|
212
|
+
connection,
|
|
213
|
+
this.program
|
|
214
|
+
);
|
|
215
|
+
const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(
|
|
216
|
+
oracleAccountInfos[i].data
|
|
217
|
+
);
|
|
218
|
+
return [oracleInfo.publicKey.toString(), oraclePriceData];
|
|
219
|
+
})
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
removeInitialData() {
|
|
224
|
+
this.initialPerpMarketAccountData = new Map();
|
|
225
|
+
this.initialSpotMarketAccountData = new Map();
|
|
226
|
+
this.initialOraclePriceData = new Map();
|
|
227
|
+
}
|
|
228
|
+
|
|
138
229
|
async subscribeToPerpMarketAccounts(): Promise<boolean> {
|
|
139
230
|
await Promise.all(
|
|
140
231
|
this.perpMarketIndexes.map((marketIndex) =>
|
|
@@ -157,6 +248,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
157
248
|
this.resubOpts,
|
|
158
249
|
this.commitment
|
|
159
250
|
);
|
|
251
|
+
accountSubscriber.setData(
|
|
252
|
+
this.initialPerpMarketAccountData.get(marketIndex)
|
|
253
|
+
);
|
|
160
254
|
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
161
255
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
162
256
|
this.eventEmitter.emit('update');
|
|
@@ -187,6 +281,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
187
281
|
this.resubOpts,
|
|
188
282
|
this.commitment
|
|
189
283
|
);
|
|
284
|
+
accountSubscriber.setData(
|
|
285
|
+
this.initialSpotMarketAccountData.get(marketIndex)
|
|
286
|
+
);
|
|
190
287
|
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
191
288
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
192
289
|
this.eventEmitter.emit('update');
|
|
@@ -206,6 +303,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
206
303
|
}
|
|
207
304
|
|
|
208
305
|
async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
|
|
306
|
+
const oracleString = oracleInfo.publicKey.toString();
|
|
209
307
|
const client = this.oracleClientCache.get(
|
|
210
308
|
oracleInfo.source,
|
|
211
309
|
this.program.provider.connection,
|
|
@@ -221,16 +319,13 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
221
319
|
this.resubOpts,
|
|
222
320
|
this.commitment
|
|
223
321
|
);
|
|
224
|
-
|
|
322
|
+
accountSubscriber.setData(this.initialOraclePriceData.get(oracleString));
|
|
225
323
|
await accountSubscriber.subscribe((data: OraclePriceData) => {
|
|
226
324
|
this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
|
|
227
325
|
this.eventEmitter.emit('update');
|
|
228
326
|
});
|
|
229
327
|
|
|
230
|
-
this.oracleSubscribers.set(
|
|
231
|
-
oracleInfo.publicKey.toString(),
|
|
232
|
-
accountSubscriber
|
|
233
|
-
);
|
|
328
|
+
this.oracleSubscribers.set(oracleString, accountSubscriber);
|
|
234
329
|
return true;
|
|
235
330
|
}
|
|
236
331
|
|
|
@@ -341,6 +436,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
341
436
|
);
|
|
342
437
|
}
|
|
343
438
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
439
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
344
440
|
}
|
|
345
441
|
await Promise.all(addOraclePromises);
|
|
346
442
|
}
|
|
@@ -364,6 +460,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
364
460
|
);
|
|
365
461
|
}
|
|
366
462
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
463
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
367
464
|
}
|
|
368
465
|
await Promise.all(addOraclePromises);
|
|
369
466
|
}
|
|
@@ -408,16 +505,20 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
408
505
|
}
|
|
409
506
|
|
|
410
507
|
public getOraclePriceDataAndSlot(
|
|
411
|
-
oraclePublicKey: PublicKey
|
|
508
|
+
oraclePublicKey: PublicKey | string
|
|
412
509
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
413
510
|
this.assertIsSubscribed();
|
|
414
|
-
|
|
511
|
+
const oracleString =
|
|
512
|
+
typeof oraclePublicKey === 'string'
|
|
513
|
+
? oraclePublicKey
|
|
514
|
+
: oraclePublicKey.toBase58();
|
|
515
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
415
516
|
return {
|
|
416
517
|
data: QUOTE_ORACLE_PRICE_DATA,
|
|
417
518
|
slot: 0,
|
|
418
519
|
};
|
|
419
520
|
}
|
|
420
|
-
return this.oracleSubscribers.get(
|
|
521
|
+
return this.oracleSubscribers.get(oracleString).dataAndSlot;
|
|
421
522
|
}
|
|
422
523
|
|
|
423
524
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -425,6 +526,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
425
526
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
426
527
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
427
528
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
529
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
428
530
|
if (!perpMarketAccount || !oracle) {
|
|
429
531
|
return undefined;
|
|
430
532
|
}
|
|
@@ -434,7 +536,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
434
536
|
this.setPerpOracleMap();
|
|
435
537
|
}
|
|
436
538
|
|
|
437
|
-
return this.getOraclePriceDataAndSlot(
|
|
539
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
438
540
|
}
|
|
439
541
|
|
|
440
542
|
public getOraclePriceDataAndSlotForSpotMarket(
|
|
@@ -442,6 +544,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
442
544
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
443
545
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
444
546
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
547
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
445
548
|
if (!spotMarketAccount || !oracle) {
|
|
446
549
|
return undefined;
|
|
447
550
|
}
|
|
@@ -451,6 +554,6 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
451
554
|
this.setSpotOracleMap();
|
|
452
555
|
}
|
|
453
556
|
|
|
454
|
-
return this.getOraclePriceDataAndSlot(
|
|
557
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
455
558
|
}
|
|
456
559
|
}
|
package/src/addresses/pda.ts
CHANGED
|
@@ -87,6 +87,19 @@ export async function getPerpMarketPublicKey(
|
|
|
87
87
|
)[0];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
export function getPerpMarketPublicKeySync(
|
|
91
|
+
programId: PublicKey,
|
|
92
|
+
marketIndex: number
|
|
93
|
+
): PublicKey {
|
|
94
|
+
return PublicKey.findProgramAddressSync(
|
|
95
|
+
[
|
|
96
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('perp_market')),
|
|
97
|
+
new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2),
|
|
98
|
+
],
|
|
99
|
+
programId
|
|
100
|
+
)[0];
|
|
101
|
+
}
|
|
102
|
+
|
|
90
103
|
export async function getSpotMarketPublicKey(
|
|
91
104
|
programId: PublicKey,
|
|
92
105
|
marketIndex: number
|
|
@@ -102,6 +115,19 @@ export async function getSpotMarketPublicKey(
|
|
|
102
115
|
)[0];
|
|
103
116
|
}
|
|
104
117
|
|
|
118
|
+
export function getSpotMarketPublicKeySync(
|
|
119
|
+
programId: PublicKey,
|
|
120
|
+
marketIndex: number
|
|
121
|
+
): PublicKey {
|
|
122
|
+
return PublicKey.findProgramAddressSync(
|
|
123
|
+
[
|
|
124
|
+
Buffer.from(anchor.utils.bytes.utf8.encode('spot_market')),
|
|
125
|
+
new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2),
|
|
126
|
+
],
|
|
127
|
+
programId
|
|
128
|
+
)[0];
|
|
129
|
+
}
|
|
130
|
+
|
|
105
131
|
export async function getSpotMarketVaultPublicKey(
|
|
106
132
|
programId: PublicKey,
|
|
107
133
|
marketIndex: number
|
package/src/config.ts
CHANGED
|
@@ -132,8 +132,10 @@ export function getMarketsAndOraclesForSubscription(env: DriftEnv): {
|
|
|
132
132
|
|
|
133
133
|
export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
134
134
|
perpMarketIndexes: number[];
|
|
135
|
+
perpMarketAccounts: PerpMarketAccount[];
|
|
135
136
|
spotMarketIndexes: number[];
|
|
136
137
|
oracleInfos: OracleInfo[];
|
|
138
|
+
spotMarketAccounts: SpotMarketAccount[];
|
|
137
139
|
}> {
|
|
138
140
|
const perpMarketIndexes = [];
|
|
139
141
|
const spotMarketIndexes = [];
|
|
@@ -164,7 +166,13 @@ export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
|
164
166
|
|
|
165
167
|
return {
|
|
166
168
|
perpMarketIndexes,
|
|
169
|
+
perpMarketAccounts: perpMarketProgramAccounts.map(
|
|
170
|
+
(account) => account.account
|
|
171
|
+
),
|
|
167
172
|
spotMarketIndexes,
|
|
173
|
+
spotMarketAccounts: spotMarketProgramAccounts.map(
|
|
174
|
+
(account) => account.account
|
|
175
|
+
),
|
|
168
176
|
oracleInfos: Array.from(oracleInfos.values()),
|
|
169
177
|
};
|
|
170
178
|
}
|
package/src/driftClient.ts
CHANGED
|
@@ -538,7 +538,9 @@ export class DriftClient {
|
|
|
538
538
|
public getOraclePriceDataAndSlot(
|
|
539
539
|
oraclePublicKey: PublicKey
|
|
540
540
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
541
|
-
return this.accountSubscriber.getOraclePriceDataAndSlot(
|
|
541
|
+
return this.accountSubscriber.getOraclePriceDataAndSlot(
|
|
542
|
+
oraclePublicKey.toBase58()
|
|
543
|
+
);
|
|
542
544
|
}
|
|
543
545
|
|
|
544
546
|
public async getSerumV3FulfillmentConfig(
|