@drift-labs/sdk 2.142.0-beta.14 → 2.142.0-beta.15
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 +1 -0
- package/lib/browser/accounts/grpcDriftClientAccountSubscriberV2.js +55 -60
- package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +4 -3
- package/lib/browser/accounts/grpcMultiAccountSubscriber.js +31 -17
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts +1 -0
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.d.ts.map +1 -1
- package/lib/node/accounts/grpcDriftClientAccountSubscriberV2.js +55 -60
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +4 -3
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -1
- package/lib/node/accounts/grpcMultiAccountSubscriber.js +31 -17
- package/package.json +1 -1
- package/scripts/client-test.ts +123 -162
- package/src/accounts/grpcDriftClientAccountSubscriberV2.ts +69 -61
- package/src/accounts/grpcMultiAccountSubscriber.ts +53 -28
|
@@ -44,12 +44,13 @@ function commitmentLevelToCommitment(commitmentLevel) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
class grpcMultiAccountSubscriber {
|
|
47
|
-
constructor(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe) {
|
|
47
|
+
constructor(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe, accountPropsMap) {
|
|
48
48
|
this.isUnsubscribing = false;
|
|
49
49
|
this.receivingData = false;
|
|
50
50
|
this.subscribedAccounts = new Set();
|
|
51
51
|
this.onChangeMap = new Map();
|
|
52
52
|
this.dataMap = new Map();
|
|
53
|
+
this.accountPropsMap = new Map();
|
|
53
54
|
this.client = client;
|
|
54
55
|
this.commitmentLevel = commitmentLevel;
|
|
55
56
|
this.accountName = accountName;
|
|
@@ -57,8 +58,9 @@ class grpcMultiAccountSubscriber {
|
|
|
57
58
|
this.decodeBufferFn = decodeBuffer;
|
|
58
59
|
this.resubOpts = resubOpts;
|
|
59
60
|
this.onUnsubscribe = onUnsubscribe;
|
|
61
|
+
this.accountPropsMap = accountPropsMap;
|
|
60
62
|
}
|
|
61
|
-
static async create(grpcConfigs, accountName, program, decodeBuffer, resubOpts, clientProp, onUnsubscribe) {
|
|
63
|
+
static async create(grpcConfigs, accountName, program, decodeBuffer, resubOpts, clientProp, onUnsubscribe, accountPropsMap) {
|
|
62
64
|
var _a, _b;
|
|
63
65
|
const client = clientProp
|
|
64
66
|
? clientProp
|
|
@@ -66,7 +68,7 @@ class grpcMultiAccountSubscriber {
|
|
|
66
68
|
const commitmentLevel =
|
|
67
69
|
// @ts-ignore :: isomorphic exported enum fails typescript but will work at runtime
|
|
68
70
|
(_b = grpcConfigs.commitmentLevel) !== null && _b !== void 0 ? _b : grpc_1.CommitmentLevel.CONFIRMED;
|
|
69
|
-
return new grpcMultiAccountSubscriber(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe);
|
|
71
|
+
return new grpcMultiAccountSubscriber(client, commitmentLevel, accountName, program, decodeBuffer, resubOpts, onUnsubscribe, accountPropsMap);
|
|
70
72
|
}
|
|
71
73
|
setAccountData(accountPubkey, data, slot) {
|
|
72
74
|
this.dataMap.set(accountPubkey, { data, slot });
|
|
@@ -119,9 +121,9 @@ class grpcMultiAccountSubscriber {
|
|
|
119
121
|
for (const pk of accounts) {
|
|
120
122
|
const key = pk.toBase58();
|
|
121
123
|
this.subscribedAccounts.add(key);
|
|
122
|
-
this.onChangeMap.set(key, (data, ctx, buffer) => {
|
|
124
|
+
this.onChangeMap.set(key, (data, ctx, buffer, accountProps) => {
|
|
123
125
|
this.setAccountData(key, data, ctx.slot);
|
|
124
|
-
onChange(new web3_js_1.PublicKey(key), data, ctx, buffer);
|
|
126
|
+
onChange(new web3_js_1.PublicKey(key), data, ctx, buffer, accountProps);
|
|
125
127
|
});
|
|
126
128
|
}
|
|
127
129
|
this.stream =
|
|
@@ -163,21 +165,33 @@ class grpcMultiAccountSubscriber {
|
|
|
163
165
|
};
|
|
164
166
|
const context = { slot };
|
|
165
167
|
const buffer = accountInfo.data;
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
168
|
+
const accountProps = (_a = this.accountPropsMap) === null || _a === void 0 ? void 0 : _a.get(accountPubkey);
|
|
169
|
+
const handleDataBuffer = (context, buffer, accountProps) => {
|
|
170
|
+
var _a;
|
|
171
|
+
const data = this.decodeBufferFn
|
|
172
|
+
? this.decodeBufferFn(buffer, accountPubkey, accountProps)
|
|
173
|
+
: this.program.account[this.accountName].coder.accounts.decode(this.capitalize(this.accountName), buffer);
|
|
174
|
+
const handler = this.onChangeMap.get(accountPubkey);
|
|
175
|
+
if (handler) {
|
|
176
|
+
if ((_a = this.resubOpts) === null || _a === void 0 ? void 0 : _a.resubTimeoutMs) {
|
|
177
|
+
this.receivingData = true;
|
|
178
|
+
clearTimeout(this.timeoutId);
|
|
179
|
+
handler(data, context, buffer, accountProps);
|
|
180
|
+
this.setTimeout();
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
handler(data, context, buffer, accountProps);
|
|
184
|
+
}
|
|
176
185
|
}
|
|
177
|
-
|
|
178
|
-
|
|
186
|
+
};
|
|
187
|
+
if (Array.isArray(accountProps)) {
|
|
188
|
+
for (const props of accountProps) {
|
|
189
|
+
handleDataBuffer(context, buffer, props);
|
|
179
190
|
}
|
|
180
191
|
}
|
|
192
|
+
else {
|
|
193
|
+
handleDataBuffer(context, buffer, accountProps);
|
|
194
|
+
}
|
|
181
195
|
});
|
|
182
196
|
return new Promise((resolve, reject) => {
|
|
183
197
|
this.stream.write(request, (err) => {
|
package/package.json
CHANGED
package/scripts/client-test.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { DriftClient } from '../src/driftClient';
|
|
2
2
|
import { grpcDriftClientAccountSubscriberV2 } from '../src/accounts/grpcDriftClientAccountSubscriberV2';
|
|
3
|
+
import { grpcDriftClientAccountSubscriber } from '../src/accounts/grpcDriftClientAccountSubscriber';
|
|
3
4
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
4
5
|
import { DriftClientConfig } from '../src/driftClientConfig';
|
|
5
6
|
import {
|
|
6
|
-
decodeName,
|
|
7
7
|
DRIFT_PROGRAM_ID,
|
|
8
8
|
PerpMarketAccount,
|
|
9
|
+
SpotMarketAccount,
|
|
9
10
|
Wallet,
|
|
11
|
+
OracleInfo,
|
|
10
12
|
} from '../src';
|
|
11
13
|
import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
|
|
12
14
|
import dotenv from 'dotenv';
|
|
@@ -21,8 +23,8 @@ import driftIDL from '../src/idl/drift.json';
|
|
|
21
23
|
const GRPC_ENDPOINT = process.env.GRPC_ENDPOINT;
|
|
22
24
|
const TOKEN = process.env.TOKEN;
|
|
23
25
|
|
|
24
|
-
async function
|
|
25
|
-
const connection = new Connection('
|
|
26
|
+
async function initializeGrpcDriftClientV2VersusV1() {
|
|
27
|
+
const connection = new Connection('');
|
|
26
28
|
const wallet = new Wallet(new Keypair());
|
|
27
29
|
dotenv.config({ path: '../' });
|
|
28
30
|
|
|
@@ -38,177 +40,136 @@ async function initializeGrpcDriftClientV2() {
|
|
|
38
40
|
|
|
39
41
|
const program = new Program(driftIDL as Idl, programId, provider);
|
|
40
42
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
const perpMarketIndexes = [4];
|
|
44
|
+
const spotMarketIndexes = [32];
|
|
45
|
+
|
|
46
|
+
const perpMarketProgramAccounts = (
|
|
47
|
+
await program.account.perpMarket.all()
|
|
48
|
+
).filter((a) =>
|
|
49
|
+
perpMarketIndexes.includes(a.account.marketIndex as number)
|
|
50
|
+
) as ProgramAccount<PerpMarketAccount>[];
|
|
51
|
+
const spotMarketProgramAccounts = (
|
|
52
|
+
await program.account.spotMarket.all()
|
|
53
|
+
).filter((a) =>
|
|
54
|
+
spotMarketIndexes.includes(a.account.marketIndex as number)
|
|
55
|
+
) as ProgramAccount<SpotMarketAccount>[];
|
|
56
|
+
|
|
57
|
+
// const perpMarketIndexes = perpMarketProgramAccounts.map(
|
|
58
|
+
// (a) => a.account.marketIndex
|
|
59
|
+
// );
|
|
60
|
+
// const spotMarketIndexes = spotMarketProgramAccounts.map(
|
|
61
|
+
// (a) => a.account.marketIndex
|
|
62
|
+
// );
|
|
63
|
+
// const oracleInfos = [
|
|
64
|
+
// {
|
|
65
|
+
// publicKey: new PublicKey('BERaNi6cpEresbq6HC1EQGaB1H1UjvEo4NGnmYSSJof4'),
|
|
66
|
+
// source: OracleSource.PYTH_LAZER,
|
|
67
|
+
// },
|
|
68
|
+
// {
|
|
69
|
+
// publicKey: new PublicKey('BERaNi6cpEresbq6HC1EQGaB1H1UjvEo4NGnmYSSJof4'),
|
|
70
|
+
// source: OracleSource.PYTH_LAZER_1M,
|
|
71
|
+
// },
|
|
72
|
+
// ];
|
|
73
|
+
|
|
74
|
+
const seen = new Set<string>();
|
|
75
|
+
const oracleInfos: OracleInfo[] = [];
|
|
76
|
+
for (const acct of perpMarketProgramAccounts) {
|
|
77
|
+
const key = `${acct.account.amm.oracle.toBase58()}-${Object.keys(
|
|
78
|
+
acct.account.amm.oracleSource ?? {}
|
|
79
|
+
)?.[0]}`;
|
|
80
|
+
if (!seen.has(key)) {
|
|
81
|
+
seen.add(key);
|
|
82
|
+
oracleInfos.push({
|
|
83
|
+
publicKey: acct.account.amm.oracle,
|
|
84
|
+
source: acct.account.amm.oracleSource,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const acct of spotMarketProgramAccounts) {
|
|
89
|
+
const key = `${acct.account.oracle.toBase58()}-${Object.keys(
|
|
90
|
+
acct.account.oracleSource ?? {}
|
|
91
|
+
)?.[0]}`;
|
|
92
|
+
if (!seen.has(key)) {
|
|
93
|
+
seen.add(key);
|
|
94
|
+
oracleInfos.push({
|
|
95
|
+
publicKey: acct.account.oracle,
|
|
96
|
+
source: acct.account.oracleSource,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const baseAccountSubscription = {
|
|
102
|
+
type: 'grpc' as const,
|
|
103
|
+
grpcConfigs: {
|
|
104
|
+
endpoint: GRPC_ENDPOINT,
|
|
105
|
+
token: TOKEN,
|
|
106
|
+
commitmentLevel: 'confirmed' as unknown as CommitmentLevel,
|
|
107
|
+
channelOptions: {
|
|
108
|
+
'grpc.keepalive_time_ms': 10_000,
|
|
109
|
+
'grpc.keepalive_timeout_ms': 1_000,
|
|
110
|
+
'grpc.keepalive_permit_without_calls': 1,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
63
113
|
};
|
|
64
114
|
|
|
65
|
-
const
|
|
115
|
+
const configV2: DriftClientConfig = {
|
|
66
116
|
connection,
|
|
67
117
|
wallet,
|
|
68
118
|
programID: new PublicKey(DRIFT_PROGRAM_ID),
|
|
69
119
|
accountSubscription: {
|
|
70
|
-
|
|
71
|
-
grpcConfigs: {
|
|
72
|
-
endpoint: GRPC_ENDPOINT,
|
|
73
|
-
token: TOKEN,
|
|
74
|
-
commitmentLevel: 'confirmed' as unknown as CommitmentLevel,
|
|
75
|
-
channelOptions: {
|
|
76
|
-
'grpc.keepalive_time_ms': 10_000,
|
|
77
|
-
'grpc.keepalive_timeout_ms': 1_000,
|
|
78
|
-
'grpc.keepalive_permit_without_calls': 1,
|
|
79
|
-
},
|
|
80
|
-
},
|
|
120
|
+
...baseAccountSubscription,
|
|
81
121
|
driftClientAccountSubscriber: grpcDriftClientAccountSubscriberV2,
|
|
82
122
|
},
|
|
83
|
-
perpMarketIndexes
|
|
84
|
-
spotMarketIndexes
|
|
85
|
-
oracleInfos
|
|
123
|
+
perpMarketIndexes,
|
|
124
|
+
spotMarketIndexes,
|
|
125
|
+
oracleInfos,
|
|
86
126
|
};
|
|
87
127
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
'Perp market account update:',
|
|
101
|
-
decodeName(data.name),
|
|
102
|
-
'mmOracleSequenceId:',
|
|
103
|
-
data.amm.mmOracleSequenceId.toString()
|
|
104
|
-
);
|
|
105
|
-
// const perpMarketData = driftClient.getPerpMarketAccount(
|
|
106
|
-
// data.marketIndex
|
|
107
|
-
// );
|
|
108
|
-
// console.log(
|
|
109
|
-
// 'Perp market data market index:',
|
|
110
|
-
// perpMarketData?.marketIndex
|
|
111
|
-
// );
|
|
112
|
-
// const oracle = driftClient.getOracleDataForPerpMarket(data.marketIndex);
|
|
113
|
-
// const mmOracle = driftClient.getMMOracleDataForPerpMarket(
|
|
114
|
-
// data.marketIndex
|
|
115
|
-
// );
|
|
116
|
-
// console.log('Perp oracle price:', oracle.price.toString());
|
|
117
|
-
// console.log('Perp MM oracle price:', mmOracle.price.toString());
|
|
118
|
-
// console.log(
|
|
119
|
-
// 'Perp MM oracle sequence id:',
|
|
120
|
-
// perpMarketData?.amm?.mmOracleSequenceId?.toString()
|
|
121
|
-
// );
|
|
122
|
-
perpMarketUpdateCount++;
|
|
123
|
-
if (
|
|
124
|
-
perpMarketUpdateCount >= 10 &&
|
|
125
|
-
spotMarketUpdateCount >= 10 &&
|
|
126
|
-
oraclePriceUpdateCount >= 10 &&
|
|
127
|
-
userAccountUpdateCount >= 2
|
|
128
|
-
) {
|
|
129
|
-
resolve();
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
driftClient.accountSubscriber.eventEmitter.on(
|
|
135
|
-
'spotMarketAccountUpdate',
|
|
136
|
-
(data) => {
|
|
137
|
-
console.log('Spot market account update:', decodeName(data.name));
|
|
138
|
-
const spotMarketData = driftClient.getSpotMarketAccount(
|
|
139
|
-
data.marketIndex
|
|
140
|
-
);
|
|
141
|
-
console.log(
|
|
142
|
-
'Spot market data market index:',
|
|
143
|
-
spotMarketData?.marketIndex
|
|
144
|
-
);
|
|
145
|
-
const oracle = driftClient.getOracleDataForSpotMarket(data.marketIndex);
|
|
146
|
-
console.log('Spot oracle price:', oracle.price.toString());
|
|
147
|
-
spotMarketUpdateCount++;
|
|
148
|
-
if (
|
|
149
|
-
perpMarketUpdateCount >= 10 &&
|
|
150
|
-
spotMarketUpdateCount >= 10 &&
|
|
151
|
-
oraclePriceUpdateCount >= 10 &&
|
|
152
|
-
userAccountUpdateCount >= 2
|
|
153
|
-
) {
|
|
154
|
-
resolve();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
driftClient.accountSubscriber.eventEmitter.on(
|
|
160
|
-
'oraclePriceUpdate',
|
|
161
|
-
(data) => {
|
|
162
|
-
console.log('Oracle price update:', data.toBase58());
|
|
163
|
-
oraclePriceUpdateCount++;
|
|
164
|
-
if (
|
|
165
|
-
perpMarketUpdateCount >= 10 &&
|
|
166
|
-
spotMarketUpdateCount >= 10 &&
|
|
167
|
-
oraclePriceUpdateCount >= 10 &&
|
|
168
|
-
userAccountUpdateCount >= 2
|
|
169
|
-
) {
|
|
170
|
-
resolve();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
driftClient.accountSubscriber.eventEmitter.on(
|
|
176
|
-
'userAccountUpdate',
|
|
177
|
-
(data) => {
|
|
178
|
-
console.log('User account update:', decodeName(data.name));
|
|
179
|
-
userAccountUpdateCount++;
|
|
180
|
-
if (
|
|
181
|
-
perpMarketUpdateCount >= 10 &&
|
|
182
|
-
spotMarketUpdateCount >= 10 &&
|
|
183
|
-
oraclePriceUpdateCount >= 10 &&
|
|
184
|
-
userAccountUpdateCount >= 2
|
|
185
|
-
) {
|
|
186
|
-
resolve();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
await driftClient.subscribe();
|
|
193
|
-
console.log('DriftClient initialized and listening for updates.');
|
|
194
|
-
|
|
195
|
-
for (const marketIndex of config.perpMarketIndexes) {
|
|
196
|
-
const oracle = driftClient.getOracleDataForPerpMarket(marketIndex);
|
|
197
|
-
const mmOracle = driftClient.getMMOracleDataForPerpMarket(marketIndex);
|
|
198
|
-
console.log('Initial perp oracle price:', oracle.price.toString());
|
|
199
|
-
console.log('Initial perp MM oracle price:', mmOracle.price.toString());
|
|
200
|
-
}
|
|
128
|
+
const configV1: DriftClientConfig = {
|
|
129
|
+
connection,
|
|
130
|
+
wallet,
|
|
131
|
+
programID: new PublicKey(DRIFT_PROGRAM_ID),
|
|
132
|
+
accountSubscription: {
|
|
133
|
+
...baseAccountSubscription,
|
|
134
|
+
driftClientAccountSubscriber: grpcDriftClientAccountSubscriber,
|
|
135
|
+
},
|
|
136
|
+
perpMarketIndexes,
|
|
137
|
+
spotMarketIndexes,
|
|
138
|
+
oracleInfos,
|
|
139
|
+
};
|
|
201
140
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
141
|
+
const clientV2 = new DriftClient(configV2);
|
|
142
|
+
const clientV1 = new DriftClient(configV1);
|
|
143
|
+
|
|
144
|
+
await Promise.all([clientV1.subscribe(), clientV2.subscribe()]);
|
|
145
|
+
const compare = () => {
|
|
146
|
+
for (const idx of perpMarketIndexes) {
|
|
147
|
+
const p1 = clientV1.getOracleDataForPerpMarket(idx).price;
|
|
148
|
+
const p2 = clientV2.getOracleDataForPerpMarket(idx).price;
|
|
149
|
+
console.log(
|
|
150
|
+
`perp mkt ${idx} | v1 ${p1.toString()} | v2 ${p2.toString()}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
for (const idx of spotMarketIndexes) {
|
|
154
|
+
const s1 = clientV1.getOracleDataForSpotMarket(idx).price;
|
|
155
|
+
const s2 = clientV2.getOracleDataForSpotMarket(idx).price;
|
|
156
|
+
console.log(
|
|
157
|
+
`spot mkt ${idx} | v1 ${s1.toString()} | v2 ${s2.toString()}`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
compare();
|
|
163
|
+
const interval = setInterval(compare, 1000);
|
|
206
164
|
|
|
207
|
-
const
|
|
208
|
-
|
|
165
|
+
const cleanup = async () => {
|
|
166
|
+
clearInterval(interval);
|
|
167
|
+
await Promise.all([clientV1.unsubscribe(), clientV2.unsubscribe()]);
|
|
168
|
+
process.exit(0);
|
|
169
|
+
};
|
|
209
170
|
|
|
210
|
-
|
|
211
|
-
|
|
171
|
+
process.on('SIGINT', cleanup);
|
|
172
|
+
process.on('SIGTERM', cleanup);
|
|
212
173
|
}
|
|
213
174
|
|
|
214
|
-
|
|
175
|
+
initializeGrpcDriftClientV2VersusV1().catch(console.error);
|
|
@@ -37,7 +37,10 @@ export class grpcDriftClientAccountSubscriberV2
|
|
|
37
37
|
private grpcConfigs: GrpcConfigs;
|
|
38
38
|
private perpMarketsSubscriber?: grpcMultiAccountSubscriber<PerpMarketAccount>;
|
|
39
39
|
private spotMarketsSubscriber?: grpcMultiAccountSubscriber<SpotMarketAccount>;
|
|
40
|
-
private oracleMultiSubscriber?: grpcMultiAccountSubscriber<
|
|
40
|
+
private oracleMultiSubscriber?: grpcMultiAccountSubscriber<
|
|
41
|
+
OraclePriceData,
|
|
42
|
+
OracleInfo
|
|
43
|
+
>;
|
|
41
44
|
private perpMarketIndexToAccountPubkeyMap = new Map<number, string>();
|
|
42
45
|
private spotMarketIndexToAccountPubkeyMap = new Map<number, string>();
|
|
43
46
|
private delistedMarketSetting: DelistedMarketSetting;
|
|
@@ -60,6 +63,10 @@ export class grpcDriftClientAccountSubscriberV2
|
|
|
60
63
|
public perpOracleStringMap = new Map<number, string>();
|
|
61
64
|
public spotOracleMap = new Map<number, PublicKey>();
|
|
62
65
|
public spotOracleStringMap = new Map<number, string>();
|
|
66
|
+
private oracleIdToOracleDataMap = new Map<
|
|
67
|
+
string,
|
|
68
|
+
DataAndSlot<OraclePriceData>
|
|
69
|
+
>();
|
|
63
70
|
public stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
64
71
|
oracleClientCache = new OracleClientCache();
|
|
65
72
|
private resubOpts?: ResubOpts;
|
|
@@ -360,8 +367,9 @@ export class grpcDriftClientAccountSubscriberV2
|
|
|
360
367
|
oracleId: string
|
|
361
368
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
362
369
|
this.assertIsSubscribed();
|
|
363
|
-
|
|
364
|
-
return
|
|
370
|
+
// we need to rely on a map we store in this class because the grpcMultiAccountSubscriber does not track a mapping or oracle ID.
|
|
371
|
+
// 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).
|
|
372
|
+
return this.oracleIdToOracleDataMap.get(oracleId);
|
|
365
373
|
}
|
|
366
374
|
|
|
367
375
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -577,80 +585,80 @@ export class grpcDriftClientAccountSubscriberV2
|
|
|
577
585
|
}
|
|
578
586
|
|
|
579
587
|
async subscribeToOracles(): Promise<boolean> {
|
|
580
|
-
const
|
|
588
|
+
const oraclePubkeyToInfosMap = new Map<string, OracleInfo[]>();
|
|
581
589
|
for (const info of this.oracleInfos) {
|
|
582
|
-
|
|
583
|
-
|
|
590
|
+
const pubkey = info.publicKey.toBase58();
|
|
591
|
+
if (!oraclePubkeyToInfosMap.has(pubkey)) {
|
|
592
|
+
oraclePubkeyToInfosMap.set(pubkey, []);
|
|
584
593
|
}
|
|
585
|
-
|
|
586
|
-
let sources = pubkeyToSources.get(key);
|
|
587
|
-
if (!sources) {
|
|
588
|
-
sources = new Set<OracleInfo['source']>();
|
|
589
|
-
pubkeyToSources.set(key, sources);
|
|
590
|
-
}
|
|
591
|
-
sources.add(info.source);
|
|
594
|
+
oraclePubkeyToInfosMap.get(pubkey).push(info);
|
|
592
595
|
}
|
|
593
596
|
|
|
594
|
-
const oraclePubkeys = Array.from(
|
|
595
|
-
(
|
|
597
|
+
const oraclePubkeys = Array.from(
|
|
598
|
+
new Set(this.oracleInfos.map((info) => info.publicKey))
|
|
596
599
|
);
|
|
597
600
|
|
|
598
|
-
this.oracleMultiSubscriber =
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
);
|
|
627
|
-
}
|
|
628
|
-
await this.subscribeToOracles();
|
|
629
|
-
} catch (e) {
|
|
630
|
-
console.error('Oracle resubscribe failed:', e);
|
|
601
|
+
this.oracleMultiSubscriber = await grpcMultiAccountSubscriber.create<
|
|
602
|
+
OraclePriceData,
|
|
603
|
+
OracleInfo
|
|
604
|
+
>(
|
|
605
|
+
this.grpcConfigs,
|
|
606
|
+
'oracle',
|
|
607
|
+
this.program,
|
|
608
|
+
(buffer: Buffer, pubkey?: string, accountProps?: OracleInfo) => {
|
|
609
|
+
if (!pubkey) {
|
|
610
|
+
throw new Error('Oracle pubkey missing in decode');
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const client = this.oracleClientCache.get(
|
|
614
|
+
accountProps.source,
|
|
615
|
+
this.program.provider.connection,
|
|
616
|
+
this.program
|
|
617
|
+
);
|
|
618
|
+
const price = client.getOraclePriceDataFromBuffer(buffer);
|
|
619
|
+
return price;
|
|
620
|
+
},
|
|
621
|
+
this.resubOpts,
|
|
622
|
+
undefined,
|
|
623
|
+
async () => {
|
|
624
|
+
try {
|
|
625
|
+
if (this.resubOpts?.logResubMessages) {
|
|
626
|
+
console.log(
|
|
627
|
+
'[grpcDriftClientAccountSubscriberV2] oracle subscriber unsubscribed; resubscribing'
|
|
628
|
+
);
|
|
631
629
|
}
|
|
630
|
+
await this.subscribeToOracles();
|
|
631
|
+
} catch (e) {
|
|
632
|
+
console.error('Oracle resubscribe failed:', e);
|
|
632
633
|
}
|
|
633
|
-
|
|
634
|
+
},
|
|
635
|
+
oraclePubkeyToInfosMap
|
|
636
|
+
);
|
|
634
637
|
|
|
635
638
|
for (const data of this.initialOraclePriceData.entries()) {
|
|
636
639
|
const { publicKey } = getPublicKeyAndSourceFromOracleId(data[0]);
|
|
637
640
|
this.oracleMultiSubscriber.setAccountData(publicKey.toBase58(), data[1]);
|
|
641
|
+
this.oracleIdToOracleDataMap.set(data[0], {
|
|
642
|
+
data: data[1],
|
|
643
|
+
slot: 0,
|
|
644
|
+
});
|
|
638
645
|
}
|
|
639
646
|
|
|
640
647
|
await this.oracleMultiSubscriber.subscribe(
|
|
641
648
|
oraclePubkeys,
|
|
642
|
-
(accountId, data) => {
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
649
|
+
(accountId, data, context, _b, accountProps) => {
|
|
650
|
+
const oracleId = getOracleId(accountId, accountProps.source);
|
|
651
|
+
this.oracleIdToOracleDataMap.set(oracleId, {
|
|
652
|
+
data,
|
|
653
|
+
slot: context.slot,
|
|
654
|
+
});
|
|
655
|
+
this.eventEmitter.emit(
|
|
656
|
+
'oraclePriceUpdate',
|
|
657
|
+
accountId,
|
|
658
|
+
accountProps.source,
|
|
659
|
+
data
|
|
660
|
+
);
|
|
661
|
+
|
|
654
662
|
this.eventEmitter.emit('update');
|
|
655
663
|
}
|
|
656
664
|
);
|