@drift-labs/sdk 2.95.0-beta.9 → 2.96.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/accounts/grpcAccountSubscriber.d.ts +16 -0
- package/lib/accounts/grpcAccountSubscriber.js +155 -0
- package/lib/accounts/grpcDriftClientAccountSubscriber.d.ts +13 -0
- package/lib/accounts/grpcDriftClientAccountSubscriber.js +96 -0
- package/lib/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts +10 -0
- package/lib/accounts/grpcInsuranceFundStakeAccountSubscriber.js +30 -0
- package/lib/accounts/grpcProgramAccountSubscriber.d.ts +19 -0
- package/lib/accounts/grpcProgramAccountSubscriber.js +161 -0
- package/lib/accounts/grpcUserAccountSubscriber.d.ts +10 -0
- package/lib/accounts/grpcUserAccountSubscriber.js +28 -0
- package/lib/accounts/grpcUserStatsAccountSubscriber.d.ts +10 -0
- package/lib/accounts/grpcUserStatsAccountSubscriber.js +28 -0
- package/lib/accounts/pollingDriftClientAccountSubscriber.d.ts +3 -1
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +14 -4
- package/lib/accounts/types.d.ts +9 -1
- package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +11 -4
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +70 -8
- package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +1 -1
- 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/constants/spotMarkets.js +10 -0
- package/lib/driftClient.js +41 -16
- package/lib/driftClientConfig.d.ts +6 -0
- package/lib/events/parse.js +1 -17
- package/lib/idl/drift.json +9 -4
- package/lib/math/insurance.d.ts +3 -1
- package/lib/math/insurance.js +31 -1
- package/lib/math/spotBalance.d.ts +3 -3
- package/lib/math/spotBalance.js +7 -7
- package/lib/orderSubscriber/OrderSubscriber.d.ts +2 -1
- package/lib/orderSubscriber/OrderSubscriber.js +19 -4
- package/lib/orderSubscriber/grpcSubscription.d.ts +25 -0
- package/lib/orderSubscriber/grpcSubscription.js +68 -0
- package/lib/orderSubscriber/types.d.ts +9 -0
- package/lib/user.js +11 -4
- package/lib/userConfig.d.ts +6 -1
- package/lib/userMap/grpcSubscription.d.ts +26 -0
- package/lib/userMap/grpcSubscription.js +42 -0
- package/lib/userMap/userMap.js +14 -0
- package/lib/userMap/userMapConfig.d.ts +7 -0
- package/lib/userStatsConfig.d.ts +6 -0
- package/package.json +3 -1
- package/src/accounts/grpcAccountSubscriber.ts +158 -0
- package/src/accounts/grpcDriftClientAccountSubscriber.ts +196 -0
- package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +62 -0
- package/src/accounts/grpcProgramAccountSubscriber.ts +181 -0
- package/src/accounts/grpcUserAccountSubscriber.ts +48 -0
- package/src/accounts/grpcUserStatsAccountSubscriber.ts +51 -0
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +17 -5
- package/src/accounts/types.ts +10 -1
- package/src/accounts/webSocketAccountSubscriber.ts +1 -1
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +135 -17
- package/src/accounts/webSocketProgramAccountSubscriber.ts +1 -1
- package/src/addresses/pda.ts +26 -0
- package/src/config.ts +8 -0
- package/src/constants/spotMarkets.ts +11 -0
- package/src/driftClient.ts +39 -2
- package/src/driftClientConfig.ts +7 -0
- package/src/events/parse.ts +1 -23
- package/src/idl/drift.json +9 -4
- package/src/math/insurance.ts +48 -2
- package/src/math/spotBalance.ts +13 -7
- package/src/orderSubscriber/OrderSubscriber.ts +15 -1
- package/src/orderSubscriber/grpcSubscription.ts +126 -0
- package/src/orderSubscriber/types.ts +10 -0
- package/src/user.ts +11 -0
- package/src/userConfig.ts +7 -1
- package/src/userMap/grpcSubscription.ts +83 -0
- package/src/userMap/userMap.ts +17 -1
- package/src/userMap/userMapConfig.ts +8 -0
- package/src/userStatsConfig.ts +7 -0
|
@@ -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
|
@@ -12,6 +12,8 @@ import { EventEmitter } from 'events';
|
|
|
12
12
|
import { Context, PublicKey } from '@solana/web3.js';
|
|
13
13
|
import { Account } from '@solana/spl-token';
|
|
14
14
|
import { OracleInfo, OraclePriceData } from '..';
|
|
15
|
+
import { CommitmentLevel } from '@triton-one/yellowstone-grpc';
|
|
16
|
+
import { ChannelOptions } from '@grpc/grpc-js';
|
|
15
17
|
|
|
16
18
|
export interface AccountSubscriber<T> {
|
|
17
19
|
dataAndSlot?: DataAndSlot<T>;
|
|
@@ -72,7 +74,7 @@ export interface DriftClientAccountSubscriber {
|
|
|
72
74
|
): DataAndSlot<SpotMarketAccount> | undefined;
|
|
73
75
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
74
76
|
getOraclePriceDataAndSlot(
|
|
75
|
-
oraclePublicKey: PublicKey
|
|
77
|
+
oraclePublicKey: PublicKey | string
|
|
76
78
|
): DataAndSlot<OraclePriceData> | undefined;
|
|
77
79
|
getOraclePriceDataAndSlotForPerpMarket(
|
|
78
80
|
marketIndex: number
|
|
@@ -201,3 +203,10 @@ export interface UserStatsAccountSubscriber {
|
|
|
201
203
|
|
|
202
204
|
getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
|
|
203
205
|
}
|
|
206
|
+
|
|
207
|
+
export type GrpcConfigs = {
|
|
208
|
+
endpoint: string;
|
|
209
|
+
token: string;
|
|
210
|
+
commitmentLevel?: CommitmentLevel;
|
|
211
|
+
channelOptions?: ChannelOptions;
|
|
212
|
+
};
|
|
@@ -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,16 +47,22 @@ 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
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
|
|
60
|
+
initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
|
|
61
|
+
initialOraclePriceData: Map<string, OraclePriceData>;
|
|
62
|
+
|
|
63
|
+
protected isSubscribing = false;
|
|
64
|
+
protected subscriptionPromise: Promise<boolean>;
|
|
65
|
+
protected subscriptionPromiseResolver: (val: boolean) => void;
|
|
56
66
|
|
|
57
67
|
public constructor(
|
|
58
68
|
program: Program,
|
|
@@ -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,86 @@ 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
|
|
178
|
+
.filter((accountInfo) => !!accountInfo)
|
|
179
|
+
.map((accountInfo) => {
|
|
180
|
+
const perpMarket = this.program.coder.accounts.decode(
|
|
181
|
+
'PerpMarket',
|
|
182
|
+
accountInfo.data
|
|
183
|
+
);
|
|
184
|
+
return [perpMarket.marketIndex, perpMarket];
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!this.initialSpotMarketAccountData) {
|
|
190
|
+
const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) =>
|
|
191
|
+
getSpotMarketPublicKeySync(this.program.programId, marketIndex)
|
|
192
|
+
);
|
|
193
|
+
const spotMarketAccountInfos = await connection.getMultipleAccountsInfo(
|
|
194
|
+
spotMarketPublicKeys
|
|
195
|
+
);
|
|
196
|
+
this.initialSpotMarketAccountData = new Map(
|
|
197
|
+
spotMarketAccountInfos
|
|
198
|
+
.filter((accountInfo) => !!accountInfo)
|
|
199
|
+
.map((accountInfo) => {
|
|
200
|
+
const spotMarket = this.program.coder.accounts.decode(
|
|
201
|
+
'SpotMarket',
|
|
202
|
+
accountInfo.data
|
|
203
|
+
);
|
|
204
|
+
return [spotMarket.marketIndex, spotMarket];
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const oracleAccountInfos = await connection.getMultipleAccountsInfo(
|
|
210
|
+
this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey)
|
|
211
|
+
);
|
|
212
|
+
this.initialOraclePriceData = new Map(
|
|
213
|
+
this.oracleInfos.reduce((result, oracleInfo, i) => {
|
|
214
|
+
if (!oracleAccountInfos[i]) {
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const oracleClient = this.oracleClientCache.get(
|
|
219
|
+
oracleInfo.source,
|
|
220
|
+
connection,
|
|
221
|
+
this.program
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(
|
|
225
|
+
oracleAccountInfos[i].data
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
result.push([oracleInfo.publicKey.toString(), oraclePriceData]);
|
|
229
|
+
return result;
|
|
230
|
+
}, [])
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
removeInitialData() {
|
|
235
|
+
this.initialPerpMarketAccountData = new Map();
|
|
236
|
+
this.initialSpotMarketAccountData = new Map();
|
|
237
|
+
this.initialOraclePriceData = new Map();
|
|
238
|
+
}
|
|
239
|
+
|
|
138
240
|
async subscribeToPerpMarketAccounts(): Promise<boolean> {
|
|
139
241
|
await Promise.all(
|
|
140
242
|
this.perpMarketIndexes.map((marketIndex) =>
|
|
@@ -157,6 +259,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
157
259
|
this.resubOpts,
|
|
158
260
|
this.commitment
|
|
159
261
|
);
|
|
262
|
+
accountSubscriber.setData(
|
|
263
|
+
this.initialPerpMarketAccountData.get(marketIndex)
|
|
264
|
+
);
|
|
160
265
|
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
161
266
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
162
267
|
this.eventEmitter.emit('update');
|
|
@@ -187,6 +292,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
187
292
|
this.resubOpts,
|
|
188
293
|
this.commitment
|
|
189
294
|
);
|
|
295
|
+
accountSubscriber.setData(
|
|
296
|
+
this.initialSpotMarketAccountData.get(marketIndex)
|
|
297
|
+
);
|
|
190
298
|
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
191
299
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
192
300
|
this.eventEmitter.emit('update');
|
|
@@ -206,6 +314,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
206
314
|
}
|
|
207
315
|
|
|
208
316
|
async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
|
|
317
|
+
const oracleString = oracleInfo.publicKey.toString();
|
|
209
318
|
const client = this.oracleClientCache.get(
|
|
210
319
|
oracleInfo.source,
|
|
211
320
|
this.program.provider.connection,
|
|
@@ -221,16 +330,17 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
221
330
|
this.resubOpts,
|
|
222
331
|
this.commitment
|
|
223
332
|
);
|
|
224
|
-
|
|
333
|
+
const initialOraclePriceData =
|
|
334
|
+
this.initialOraclePriceData.get(oracleString);
|
|
335
|
+
if (initialOraclePriceData) {
|
|
336
|
+
accountSubscriber.setData(initialOraclePriceData);
|
|
337
|
+
}
|
|
225
338
|
await accountSubscriber.subscribe((data: OraclePriceData) => {
|
|
226
339
|
this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
|
|
227
340
|
this.eventEmitter.emit('update');
|
|
228
341
|
});
|
|
229
342
|
|
|
230
|
-
this.oracleSubscribers.set(
|
|
231
|
-
oracleInfo.publicKey.toString(),
|
|
232
|
-
accountSubscriber
|
|
233
|
-
);
|
|
343
|
+
this.oracleSubscribers.set(oracleString, accountSubscriber);
|
|
234
344
|
return true;
|
|
235
345
|
}
|
|
236
346
|
|
|
@@ -326,7 +436,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
326
436
|
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
327
437
|
const addOraclePromises = [];
|
|
328
438
|
for (const perpMarket of perpMarkets) {
|
|
329
|
-
if (!perpMarket) {
|
|
439
|
+
if (!perpMarket || !perpMarket.data) {
|
|
330
440
|
continue;
|
|
331
441
|
}
|
|
332
442
|
const perpMarketAccount = perpMarket.data;
|
|
@@ -341,6 +451,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
341
451
|
);
|
|
342
452
|
}
|
|
343
453
|
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
454
|
+
this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
|
|
344
455
|
}
|
|
345
456
|
await Promise.all(addOraclePromises);
|
|
346
457
|
}
|
|
@@ -349,7 +460,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
349
460
|
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
350
461
|
const addOraclePromises = [];
|
|
351
462
|
for (const spotMarket of spotMarkets) {
|
|
352
|
-
if (!spotMarket) {
|
|
463
|
+
if (!spotMarket || !spotMarket.data) {
|
|
353
464
|
continue;
|
|
354
465
|
}
|
|
355
466
|
const spotMarketAccount = spotMarket.data;
|
|
@@ -364,6 +475,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
364
475
|
);
|
|
365
476
|
}
|
|
366
477
|
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
478
|
+
this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
|
|
367
479
|
}
|
|
368
480
|
await Promise.all(addOraclePromises);
|
|
369
481
|
}
|
|
@@ -408,16 +520,20 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
408
520
|
}
|
|
409
521
|
|
|
410
522
|
public getOraclePriceDataAndSlot(
|
|
411
|
-
oraclePublicKey: PublicKey
|
|
523
|
+
oraclePublicKey: PublicKey | string
|
|
412
524
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
413
525
|
this.assertIsSubscribed();
|
|
414
|
-
|
|
526
|
+
const oracleString =
|
|
527
|
+
typeof oraclePublicKey === 'string'
|
|
528
|
+
? oraclePublicKey
|
|
529
|
+
: oraclePublicKey.toBase58();
|
|
530
|
+
if (oracleString === ORACLE_DEFAULT_KEY) {
|
|
415
531
|
return {
|
|
416
532
|
data: QUOTE_ORACLE_PRICE_DATA,
|
|
417
533
|
slot: 0,
|
|
418
534
|
};
|
|
419
535
|
}
|
|
420
|
-
return this.oracleSubscribers.get(
|
|
536
|
+
return this.oracleSubscribers.get(oracleString).dataAndSlot;
|
|
421
537
|
}
|
|
422
538
|
|
|
423
539
|
public getOraclePriceDataAndSlotForPerpMarket(
|
|
@@ -425,6 +541,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
425
541
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
426
542
|
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
427
543
|
const oracle = this.perpOracleMap.get(marketIndex);
|
|
544
|
+
const oracleString = this.perpOracleStringMap.get(marketIndex);
|
|
428
545
|
if (!perpMarketAccount || !oracle) {
|
|
429
546
|
return undefined;
|
|
430
547
|
}
|
|
@@ -434,7 +551,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
434
551
|
this.setPerpOracleMap();
|
|
435
552
|
}
|
|
436
553
|
|
|
437
|
-
return this.getOraclePriceDataAndSlot(
|
|
554
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
438
555
|
}
|
|
439
556
|
|
|
440
557
|
public getOraclePriceDataAndSlotForSpotMarket(
|
|
@@ -442,6 +559,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
442
559
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
443
560
|
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
444
561
|
const oracle = this.spotOracleMap.get(marketIndex);
|
|
562
|
+
const oracleString = this.spotOracleStringMap.get(marketIndex);
|
|
445
563
|
if (!spotMarketAccount || !oracle) {
|
|
446
564
|
return undefined;
|
|
447
565
|
}
|
|
@@ -451,6 +569,6 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
451
569
|
this.setSpotOracleMap();
|
|
452
570
|
}
|
|
453
571
|
|
|
454
|
-
return this.getOraclePriceDataAndSlot(
|
|
572
|
+
return this.getOraclePriceDataAndSlot(oracleString);
|
|
455
573
|
}
|
|
456
574
|
}
|
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
|
}
|
|
@@ -412,6 +412,17 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
|
|
|
412
412
|
pythFeedId:
|
|
413
413
|
'0xca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c',
|
|
414
414
|
},
|
|
415
|
+
{
|
|
416
|
+
symbol: 'BNSOL',
|
|
417
|
+
marketIndex: 25,
|
|
418
|
+
oracle: new PublicKey('BAtFj4kQttZRVep3UZS2aZRDixkGYgWsbqTBVDbnSsPF'),
|
|
419
|
+
oracleSource: OracleSource.PYTH_PULL,
|
|
420
|
+
mint: new PublicKey('BNso1VUJnh4zcfpZa6986Ea66P6TCp59hvtNJ8b1X85'),
|
|
421
|
+
precision: LAMPORTS_PRECISION,
|
|
422
|
+
precisionExp: LAMPORTS_EXP,
|
|
423
|
+
pythFeedId:
|
|
424
|
+
'0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d',
|
|
425
|
+
},
|
|
415
426
|
];
|
|
416
427
|
|
|
417
428
|
export const SpotMarkets: { [key in DriftEnv]: SpotMarketConfig[] } = {
|
package/src/driftClient.ts
CHANGED
|
@@ -152,6 +152,7 @@ import { isVersionedTransaction } from './tx/utils';
|
|
|
152
152
|
import pythSolanaReceiverIdl from './idl/pyth_solana_receiver.json';
|
|
153
153
|
import { asV0Tx, PullFeed } from '@switchboard-xyz/on-demand';
|
|
154
154
|
import switchboardOnDemandIdl from './idl/switchboard_on_demand_30.json';
|
|
155
|
+
import { gprcDriftClientAccountSubscriber } from './accounts/grpcDriftClientAccountSubscriber';
|
|
155
156
|
|
|
156
157
|
type RemainingAccountParams = {
|
|
157
158
|
userAccounts: UserAccount[];
|
|
@@ -292,6 +293,19 @@ export class DriftClient {
|
|
|
292
293
|
type: 'polling',
|
|
293
294
|
accountLoader: config.accountSubscription.accountLoader,
|
|
294
295
|
};
|
|
296
|
+
} else if (config.accountSubscription?.type === 'grpc') {
|
|
297
|
+
this.userAccountSubscriptionConfig = {
|
|
298
|
+
type: 'grpc',
|
|
299
|
+
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
300
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
301
|
+
configs: config.accountSubscription?.configs,
|
|
302
|
+
};
|
|
303
|
+
this.userStatsAccountSubscriptionConfig = {
|
|
304
|
+
type: 'grpc',
|
|
305
|
+
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
306
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
307
|
+
configs: config.accountSubscription?.configs,
|
|
308
|
+
};
|
|
295
309
|
} else {
|
|
296
310
|
this.userAccountSubscriptionConfig = {
|
|
297
311
|
type: 'websocket',
|
|
@@ -338,6 +352,19 @@ export class DriftClient {
|
|
|
338
352
|
config.oracleInfos ?? [],
|
|
339
353
|
noMarketsAndOraclesSpecified
|
|
340
354
|
);
|
|
355
|
+
} else if (config.accountSubscription?.type === 'grpc') {
|
|
356
|
+
this.accountSubscriber = new gprcDriftClientAccountSubscriber(
|
|
357
|
+
config.accountSubscription.configs,
|
|
358
|
+
this.program,
|
|
359
|
+
config.perpMarketIndexes ?? [],
|
|
360
|
+
config.spotMarketIndexes ?? [],
|
|
361
|
+
config.oracleInfos ?? [],
|
|
362
|
+
noMarketsAndOraclesSpecified,
|
|
363
|
+
{
|
|
364
|
+
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
365
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
366
|
+
}
|
|
367
|
+
);
|
|
341
368
|
} else {
|
|
342
369
|
this.accountSubscriber = new WebSocketDriftClientAccountSubscriber(
|
|
343
370
|
this.program,
|
|
@@ -352,6 +379,7 @@ export class DriftClient {
|
|
|
352
379
|
config.accountSubscription?.commitment
|
|
353
380
|
);
|
|
354
381
|
}
|
|
382
|
+
|
|
355
383
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
356
384
|
|
|
357
385
|
this.metricsEventEmitter = new EventEmitter();
|
|
@@ -538,7 +566,9 @@ export class DriftClient {
|
|
|
538
566
|
public getOraclePriceDataAndSlot(
|
|
539
567
|
oraclePublicKey: PublicKey
|
|
540
568
|
): DataAndSlot<OraclePriceData> | undefined {
|
|
541
|
-
return this.accountSubscriber.getOraclePriceDataAndSlot(
|
|
569
|
+
return this.accountSubscriber.getOraclePriceDataAndSlot(
|
|
570
|
+
oraclePublicKey.toBase58()
|
|
571
|
+
);
|
|
542
572
|
}
|
|
543
573
|
|
|
544
574
|
public async getSerumV3FulfillmentConfig(
|
|
@@ -3221,11 +3251,18 @@ export class DriftClient {
|
|
|
3221
3251
|
writablePerpMarketIndexes: [marketIndex],
|
|
3222
3252
|
writableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
|
|
3223
3253
|
});
|
|
3254
|
+
const perpMarketPublicKey = await getPerpMarketPublicKey(
|
|
3255
|
+
this.program.programId,
|
|
3256
|
+
marketIndex
|
|
3257
|
+
);
|
|
3224
3258
|
|
|
3225
3259
|
return await this.program.instruction.settleExpiredMarket(marketIndex, {
|
|
3226
3260
|
accounts: {
|
|
3227
3261
|
state: await this.getStatePublicKey(),
|
|
3228
|
-
|
|
3262
|
+
admin: this.isSubscribed
|
|
3263
|
+
? this.getStateAccount().admin
|
|
3264
|
+
: this.wallet.publicKey,
|
|
3265
|
+
perpMarket: perpMarketPublicKey,
|
|
3229
3266
|
},
|
|
3230
3267
|
remainingAccounts,
|
|
3231
3268
|
});
|
package/src/driftClientConfig.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
|
11
11
|
import { DriftEnv } from './config';
|
|
12
12
|
import { TxSender } from './tx/types';
|
|
13
13
|
import { TxHandler, TxHandlerConfig } from './tx/txHandler';
|
|
14
|
+
import { GrpcConfigs } from './accounts/types';
|
|
14
15
|
|
|
15
16
|
export type DriftClientConfig = {
|
|
16
17
|
connection: Connection;
|
|
@@ -48,4 +49,10 @@ export type DriftClientSubscriptionConfig =
|
|
|
48
49
|
| {
|
|
49
50
|
type: 'polling';
|
|
50
51
|
accountLoader: BulkAccountLoader;
|
|
52
|
+
}
|
|
53
|
+
| {
|
|
54
|
+
type: 'grpc';
|
|
55
|
+
configs: GrpcConfigs;
|
|
56
|
+
resubTimeoutMs?: number;
|
|
57
|
+
logResubMessages?: boolean;
|
|
51
58
|
};
|
package/src/events/parse.ts
CHANGED
|
@@ -11,29 +11,7 @@ export function parseLogs(
|
|
|
11
11
|
logs: string[],
|
|
12
12
|
programId = driftProgramId
|
|
13
13
|
): Event[] {
|
|
14
|
-
const events =
|
|
15
|
-
const execution = new ExecutionContext();
|
|
16
|
-
for (const log of logs) {
|
|
17
|
-
if (log.startsWith('Log truncated')) {
|
|
18
|
-
break;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const [event, newProgram, didPop] = handleLog(
|
|
22
|
-
execution,
|
|
23
|
-
log,
|
|
24
|
-
program,
|
|
25
|
-
programId
|
|
26
|
-
);
|
|
27
|
-
if (event) {
|
|
28
|
-
events.push(event);
|
|
29
|
-
}
|
|
30
|
-
if (newProgram) {
|
|
31
|
-
execution.push(newProgram);
|
|
32
|
-
}
|
|
33
|
-
if (didPop) {
|
|
34
|
-
execution.pop();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
14
|
+
const { events } = parseLogsWithRaw(program, logs, programId);
|
|
37
15
|
return events;
|
|
38
16
|
}
|
|
39
17
|
|
package/src/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.95.0",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -1606,15 +1606,20 @@
|
|
|
1606
1606
|
{
|
|
1607
1607
|
"name": "settleExpiredMarket",
|
|
1608
1608
|
"accounts": [
|
|
1609
|
+
{
|
|
1610
|
+
"name": "admin",
|
|
1611
|
+
"isMut": false,
|
|
1612
|
+
"isSigner": true
|
|
1613
|
+
},
|
|
1609
1614
|
{
|
|
1610
1615
|
"name": "state",
|
|
1611
1616
|
"isMut": false,
|
|
1612
1617
|
"isSigner": false
|
|
1613
1618
|
},
|
|
1614
1619
|
{
|
|
1615
|
-
"name": "
|
|
1616
|
-
"isMut":
|
|
1617
|
-
"isSigner":
|
|
1620
|
+
"name": "perpMarket",
|
|
1621
|
+
"isMut": true,
|
|
1622
|
+
"isSigner": false
|
|
1618
1623
|
}
|
|
1619
1624
|
],
|
|
1620
1625
|
"args": [
|