@drift-labs/sdk 2.66.0-beta.4 → 2.67.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/pollingDriftClientAccountSubscriber.d.ts +6 -0
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +58 -0
- package/lib/accounts/types.d.ts +2 -0
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +6 -0
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +68 -2
- package/lib/driftClient.js +2 -6
- package/lib/idl/drift.json +1 -1
- package/lib/user.js +7 -11
- package/package.json +1 -1
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +70 -0
- package/src/accounts/types.ts +6 -0
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +81 -2
- package/src/driftClient.ts +6 -8
- package/src/idl/drift.json +1 -1
- package/src/user.ts +14 -25
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.67.0-beta.1
|
|
@@ -23,7 +23,9 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
23
23
|
errorCallbackId?: string;
|
|
24
24
|
state?: DataAndSlot<StateAccount>;
|
|
25
25
|
perpMarket: Map<number, DataAndSlot<PerpMarketAccount>>;
|
|
26
|
+
perpOracleMap: Map<number, PublicKey>;
|
|
26
27
|
spotMarket: Map<number, DataAndSlot<SpotMarketAccount>>;
|
|
28
|
+
spotOracleMap: Map<number, PublicKey>;
|
|
27
29
|
oracles: Map<string, DataAndSlot<OraclePriceData>>;
|
|
28
30
|
user?: DataAndSlot<UserAccount>;
|
|
29
31
|
private isSubscribing;
|
|
@@ -47,6 +49,8 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
47
49
|
addSpotMarket(marketIndex: number): Promise<boolean>;
|
|
48
50
|
addPerpMarket(marketIndex: number): Promise<boolean>;
|
|
49
51
|
addOracle(oracleInfo: OracleInfo): Promise<boolean>;
|
|
52
|
+
private setPerpOracleMap;
|
|
53
|
+
private setSpotOracleMap;
|
|
50
54
|
assertIsSubscribed(): void;
|
|
51
55
|
getStateAccountAndSlot(): DataAndSlot<StateAccount>;
|
|
52
56
|
getMarketAccountAndSlot(marketIndex: number): DataAndSlot<PerpMarketAccount> | undefined;
|
|
@@ -54,5 +58,7 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
54
58
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
55
59
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
56
60
|
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
|
|
61
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
62
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
57
63
|
updateAccountLoaderPollingFrequency(pollingFrequency: number): void;
|
|
58
64
|
}
|
|
@@ -15,7 +15,9 @@ class PollingDriftClientAccountSubscriber {
|
|
|
15
15
|
this.accountsToPoll = new Map();
|
|
16
16
|
this.oraclesToPoll = new Map();
|
|
17
17
|
this.perpMarket = new Map();
|
|
18
|
+
this.perpOracleMap = new Map();
|
|
18
19
|
this.spotMarket = new Map();
|
|
20
|
+
this.spotOracleMap = new Map();
|
|
19
21
|
this.oracles = new Map();
|
|
20
22
|
this.isSubscribing = false;
|
|
21
23
|
this.isSubscribed = false;
|
|
@@ -57,6 +59,8 @@ class PollingDriftClientAccountSubscriber {
|
|
|
57
59
|
if (subscriptionSucceeded) {
|
|
58
60
|
this.eventEmitter.emit('update');
|
|
59
61
|
}
|
|
62
|
+
this.setPerpOracleMap();
|
|
63
|
+
this.setSpotOracleMap();
|
|
60
64
|
this.isSubscribing = false;
|
|
61
65
|
this.isSubscribed = subscriptionSucceeded;
|
|
62
66
|
this.subscriptionPromiseResolver(subscriptionSucceeded);
|
|
@@ -229,6 +233,7 @@ class PollingDriftClientAccountSubscriber {
|
|
|
229
233
|
await this.addSpotMarketAccountToPoll(marketIndex);
|
|
230
234
|
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
231
235
|
await this.addAccountToAccountLoader(accountToPoll);
|
|
236
|
+
this.setSpotOracleMap();
|
|
232
237
|
return true;
|
|
233
238
|
}
|
|
234
239
|
async addPerpMarket(marketIndex) {
|
|
@@ -239,6 +244,7 @@ class PollingDriftClientAccountSubscriber {
|
|
|
239
244
|
await this.addPerpMarketAccountToPoll(marketIndex);
|
|
240
245
|
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
241
246
|
await this.addAccountToAccountLoader(accountToPoll);
|
|
247
|
+
this.setPerpOracleMap();
|
|
242
248
|
return true;
|
|
243
249
|
}
|
|
244
250
|
async addOracle(oracleInfo) {
|
|
@@ -251,6 +257,24 @@ class PollingDriftClientAccountSubscriber {
|
|
|
251
257
|
await this.addOracleToAccountLoader(oracleToPoll);
|
|
252
258
|
return true;
|
|
253
259
|
}
|
|
260
|
+
setPerpOracleMap() {
|
|
261
|
+
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
262
|
+
for (const perpMarket of perpMarkets) {
|
|
263
|
+
const perpMarketAccount = perpMarket.data;
|
|
264
|
+
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
265
|
+
const oracle = perpMarketAccount.amm.oracle;
|
|
266
|
+
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
setSpotOracleMap() {
|
|
270
|
+
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
271
|
+
for (const spotMarket of spotMarkets) {
|
|
272
|
+
const spotMarketAccount = spotMarket.data;
|
|
273
|
+
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
274
|
+
const oracle = spotMarketAccount.oracle;
|
|
275
|
+
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
254
278
|
assertIsSubscribed() {
|
|
255
279
|
if (!this.isSubscribed) {
|
|
256
280
|
throw new types_1.NotSubscribedError('You must call `subscribe` before using this function');
|
|
@@ -282,6 +306,40 @@ class PollingDriftClientAccountSubscriber {
|
|
|
282
306
|
}
|
|
283
307
|
return this.oracles.get(oraclePublicKey.toString());
|
|
284
308
|
}
|
|
309
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
|
|
310
|
+
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
311
|
+
const oracle = this.perpOracleMap.get(marketIndex);
|
|
312
|
+
if (!perpMarketAccount || !oracle) {
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
316
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
317
|
+
this.addOracle({
|
|
318
|
+
source: perpMarketAccount.data.amm.oracleSource,
|
|
319
|
+
publicKey: perpMarketAccount.data.amm.oracle,
|
|
320
|
+
}).then(() => {
|
|
321
|
+
this.setPerpOracleMap();
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
325
|
+
}
|
|
326
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
|
|
327
|
+
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
328
|
+
const oracle = this.spotOracleMap.get(marketIndex);
|
|
329
|
+
if (!spotMarketAccount || !oracle) {
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
333
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
334
|
+
this.addOracle({
|
|
335
|
+
source: spotMarketAccount.data.oracleSource,
|
|
336
|
+
publicKey: spotMarketAccount.data.oracle,
|
|
337
|
+
}).then(() => {
|
|
338
|
+
this.setSpotOracleMap();
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
342
|
+
}
|
|
285
343
|
updateAccountLoaderPollingFrequency(pollingFrequency) {
|
|
286
344
|
this.accountLoader.updatePollingFrequency(pollingFrequency);
|
|
287
345
|
}
|
package/lib/accounts/types.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface DriftClientAccountSubscriber {
|
|
|
47
47
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
48
48
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
49
49
|
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
|
|
50
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
51
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
50
52
|
updateAccountLoaderPollingFrequency?: (pollingFrequency: number) => void;
|
|
51
53
|
}
|
|
52
54
|
export interface UserAccountEvents {
|
|
@@ -21,7 +21,9 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
21
21
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
22
22
|
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
23
23
|
perpMarketAccountSubscribers: Map<number, AccountSubscriber<PerpMarketAccount>>;
|
|
24
|
+
perpOracleMap: Map<number, PublicKey>;
|
|
24
25
|
spotMarketAccountSubscribers: Map<number, AccountSubscriber<SpotMarketAccount>>;
|
|
26
|
+
spotOracleMap: Map<number, PublicKey>;
|
|
25
27
|
oracleSubscribers: Map<string, AccountSubscriber<OraclePriceData>>;
|
|
26
28
|
private isSubscribing;
|
|
27
29
|
private subscriptionPromise;
|
|
@@ -42,6 +44,8 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
42
44
|
addSpotMarket(marketIndex: number): Promise<boolean>;
|
|
43
45
|
addPerpMarket(marketIndex: number): Promise<boolean>;
|
|
44
46
|
addOracle(oracleInfo: OracleInfo): Promise<boolean>;
|
|
47
|
+
private setPerpOracleMap;
|
|
48
|
+
private setSpotOracleMap;
|
|
45
49
|
assertIsSubscribed(): void;
|
|
46
50
|
getStateAccountAndSlot(): DataAndSlot<StateAccount>;
|
|
47
51
|
getMarketAccountAndSlot(marketIndex: number): DataAndSlot<PerpMarketAccount> | undefined;
|
|
@@ -49,4 +53,6 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
49
53
|
getSpotMarketAccountAndSlot(marketIndex: number): DataAndSlot<SpotMarketAccount> | undefined;
|
|
50
54
|
getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
|
|
51
55
|
getOraclePriceDataAndSlot(oraclePublicKey: PublicKey): DataAndSlot<OraclePriceData> | undefined;
|
|
56
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
57
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex: number): DataAndSlot<OraclePriceData> | undefined;
|
|
52
58
|
}
|
|
@@ -13,7 +13,9 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
13
13
|
constructor(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles, resubTimeoutMs, commitment) {
|
|
14
14
|
this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
|
|
15
15
|
this.perpMarketAccountSubscribers = new Map();
|
|
16
|
+
this.perpOracleMap = new Map();
|
|
16
17
|
this.spotMarketAccountSubscribers = new Map();
|
|
18
|
+
this.spotOracleMap = new Map();
|
|
17
19
|
this.oracleSubscribers = new Map();
|
|
18
20
|
this.isSubscribing = false;
|
|
19
21
|
this.isSubscribed = false;
|
|
@@ -57,6 +59,8 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
57
59
|
// subscribe to oracles
|
|
58
60
|
await this.subscribeToOracles();
|
|
59
61
|
this.eventEmitter.emit('update');
|
|
62
|
+
this.setPerpOracleMap();
|
|
63
|
+
this.setSpotOracleMap();
|
|
60
64
|
this.isSubscribing = false;
|
|
61
65
|
this.isSubscribed = true;
|
|
62
66
|
this.subscriptionPromiseResolver(true);
|
|
@@ -152,13 +156,17 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
152
156
|
if (this.spotMarketAccountSubscribers.has(marketIndex)) {
|
|
153
157
|
return true;
|
|
154
158
|
}
|
|
155
|
-
|
|
159
|
+
const subscriptionSuccess = this.subscribeToSpotMarketAccount(marketIndex);
|
|
160
|
+
this.setSpotOracleMap();
|
|
161
|
+
return subscriptionSuccess;
|
|
156
162
|
}
|
|
157
163
|
async addPerpMarket(marketIndex) {
|
|
158
164
|
if (this.perpMarketAccountSubscribers.has(marketIndex)) {
|
|
159
165
|
return true;
|
|
160
166
|
}
|
|
161
|
-
|
|
167
|
+
const subscriptionSuccess = this.subscribeToPerpMarketAccount(marketIndex);
|
|
168
|
+
this.setPerpOracleMap();
|
|
169
|
+
return subscriptionSuccess;
|
|
162
170
|
}
|
|
163
171
|
async addOracle(oracleInfo) {
|
|
164
172
|
if (this.oracleSubscribers.has(oracleInfo.publicKey.toString())) {
|
|
@@ -169,6 +177,30 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
169
177
|
}
|
|
170
178
|
return this.subscribeToOracle(oracleInfo);
|
|
171
179
|
}
|
|
180
|
+
setPerpOracleMap() {
|
|
181
|
+
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
182
|
+
for (const perpMarket of perpMarkets) {
|
|
183
|
+
if (!perpMarket) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const perpMarketAccount = perpMarket.data;
|
|
187
|
+
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
188
|
+
const oracle = perpMarketAccount.amm.oracle;
|
|
189
|
+
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
setSpotOracleMap() {
|
|
193
|
+
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
194
|
+
for (const spotMarket of spotMarkets) {
|
|
195
|
+
if (!spotMarket) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const spotMarketAccount = spotMarket.data;
|
|
199
|
+
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
200
|
+
const oracle = spotMarketAccount.oracle;
|
|
201
|
+
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
172
204
|
assertIsSubscribed() {
|
|
173
205
|
if (!this.isSubscribed) {
|
|
174
206
|
throw new types_1.NotSubscribedError('You must call `subscribe` before using this function');
|
|
@@ -202,5 +234,39 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
202
234
|
}
|
|
203
235
|
return this.oracleSubscribers.get(oraclePublicKey.toString()).dataAndSlot;
|
|
204
236
|
}
|
|
237
|
+
getOraclePriceDataAndSlotForPerpMarket(marketIndex) {
|
|
238
|
+
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
239
|
+
const oracle = this.perpOracleMap.get(marketIndex);
|
|
240
|
+
if (!perpMarketAccount || !oracle) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
244
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
245
|
+
this.addOracle({
|
|
246
|
+
source: perpMarketAccount.data.amm.oracleSource,
|
|
247
|
+
publicKey: perpMarketAccount.data.amm.oracle,
|
|
248
|
+
}).then(() => {
|
|
249
|
+
this.setPerpOracleMap();
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
253
|
+
}
|
|
254
|
+
getOraclePriceDataAndSlotForSpotMarket(marketIndex) {
|
|
255
|
+
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
256
|
+
const oracle = this.spotOracleMap.get(marketIndex);
|
|
257
|
+
if (!spotMarketAccount || !oracle) {
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
261
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
262
|
+
this.addOracle({
|
|
263
|
+
source: spotMarketAccount.data.oracleSource,
|
|
264
|
+
publicKey: spotMarketAccount.data.oracle,
|
|
265
|
+
}).then(() => {
|
|
266
|
+
this.setSpotOracleMap();
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
270
|
+
}
|
|
205
271
|
}
|
|
206
272
|
exports.WebSocketDriftClientAccountSubscriber = WebSocketDriftClientAccountSubscriber;
|
package/lib/driftClient.js
CHANGED
|
@@ -3169,14 +3169,10 @@ class DriftClient {
|
|
|
3169
3169
|
this.eventEmitter.emit(eventName, data);
|
|
3170
3170
|
}
|
|
3171
3171
|
getOracleDataForPerpMarket(marketIndex) {
|
|
3172
|
-
|
|
3173
|
-
const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
|
|
3174
|
-
return oracleData;
|
|
3172
|
+
return this.accountSubscriber.getOraclePriceDataAndSlotForPerpMarket(marketIndex).data;
|
|
3175
3173
|
}
|
|
3176
3174
|
getOracleDataForSpotMarket(marketIndex) {
|
|
3177
|
-
|
|
3178
|
-
const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
|
|
3179
|
-
return oracleData;
|
|
3175
|
+
return this.accountSubscriber.getOraclePriceDataAndSlotForSpotMarket(marketIndex).data;
|
|
3180
3176
|
}
|
|
3181
3177
|
async initializeInsuranceFundStake(marketIndex, txParams) {
|
|
3182
3178
|
const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getInitializeInsuranceFundStakeIx(marketIndex), txParams), [], this.opts);
|
package/lib/idl/drift.json
CHANGED
package/lib/user.js
CHANGED
|
@@ -717,7 +717,7 @@ class User {
|
|
|
717
717
|
marginRatio = numericConstants_1.ZERO;
|
|
718
718
|
}
|
|
719
719
|
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
|
|
720
|
-
const quoteOraclePriceData = this.driftClient.
|
|
720
|
+
const quoteOraclePriceData = this.driftClient.getOracleDataForSpotMarket(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
|
|
721
721
|
let quotePrice;
|
|
722
722
|
if (strict) {
|
|
723
723
|
quotePrice = _1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
|
|
@@ -1198,7 +1198,7 @@ class User {
|
|
|
1198
1198
|
calculateFreeCollateralDeltaForSpot(market, signedTokenAmount, marginCategory = 'Maintenance') {
|
|
1199
1199
|
const tokenPrecision = new _1.BN(Math.pow(10, market.decimals));
|
|
1200
1200
|
if (signedTokenAmount.gt(numericConstants_1.ZERO)) {
|
|
1201
|
-
const assetWeight = (0, spotBalance_1.calculateAssetWeight)(signedTokenAmount, this.driftClient.
|
|
1201
|
+
const assetWeight = (0, spotBalance_1.calculateAssetWeight)(signedTokenAmount, this.driftClient.getOracleDataForSpotMarket(market.marketIndex).price, market, marginCategory);
|
|
1202
1202
|
return numericConstants_1.QUOTE_PRECISION.mul(assetWeight)
|
|
1203
1203
|
.div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
|
|
1204
1204
|
.mul(signedTokenAmount)
|
|
@@ -1320,7 +1320,7 @@ class User {
|
|
|
1320
1320
|
*/
|
|
1321
1321
|
getMaxTradeSizeUSDCForSpot(targetMarketIndex, direction, currentQuoteAssetValue, currentSpotMarketNetValue) {
|
|
1322
1322
|
const market = this.driftClient.getSpotMarketAccount(targetMarketIndex);
|
|
1323
|
-
const oraclePrice = this.driftClient.
|
|
1323
|
+
const oraclePrice = this.driftClient.getOracleDataForSpotMarket(targetMarketIndex).price;
|
|
1324
1324
|
currentQuoteAssetValue = this.getSpotMarketAssetValue(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
|
|
1325
1325
|
currentSpotMarketNetValue =
|
|
1326
1326
|
currentSpotMarketNetValue !== null && currentSpotMarketNetValue !== void 0 ? currentSpotMarketNetValue : this.getSpotPositionValue(targetMarketIndex);
|
|
@@ -1872,12 +1872,12 @@ class User {
|
|
|
1872
1872
|
for (const perpPosition of this.getActivePerpPositions()) {
|
|
1873
1873
|
const settledLpPosition = this.getPerpPositionWithLPSettle(perpPosition.marketIndex, perpPosition)[0];
|
|
1874
1874
|
const perpMarket = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
|
|
1875
|
-
const oraclePriceData = this.driftClient.
|
|
1875
|
+
const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(perpMarket.marketIndex);
|
|
1876
1876
|
const oraclePrice = oraclePriceData.price;
|
|
1877
1877
|
const worstCaseBaseAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(settledLpPosition);
|
|
1878
1878
|
const marginRatio = new _1.BN((0, _1.calculateMarketMarginRatio)(perpMarket, worstCaseBaseAmount.abs(), marginCategory, this.getUserAccount().maxMarginRatio));
|
|
1879
1879
|
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(perpMarket.quoteSpotMarketIndex);
|
|
1880
|
-
const quoteOraclePriceData = this.driftClient.
|
|
1880
|
+
const quoteOraclePriceData = this.driftClient.getOracleDataForSpotMarket(numericConstants_1.QUOTE_SPOT_MARKET_INDEX);
|
|
1881
1881
|
const baseAssetValue = worstCaseBaseAmount
|
|
1882
1882
|
.abs()
|
|
1883
1883
|
.mul(oraclePrice)
|
|
@@ -1999,14 +1999,10 @@ class User {
|
|
|
1999
1999
|
return this.getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders).sub(currentPerpPositionValueUSDC);
|
|
2000
2000
|
}
|
|
2001
2001
|
getOracleDataForPerpMarket(marketIndex) {
|
|
2002
|
-
|
|
2003
|
-
const oracleData = this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
|
|
2004
|
-
return oracleData;
|
|
2002
|
+
return this.driftClient.getOracleDataForPerpMarket(marketIndex);
|
|
2005
2003
|
}
|
|
2006
2004
|
getOracleDataForSpotMarket(marketIndex) {
|
|
2007
|
-
|
|
2008
|
-
const oracleData = this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
|
|
2009
|
-
return oracleData;
|
|
2005
|
+
return this.driftClient.getOracleDataForSpotMarket(marketIndex);
|
|
2010
2006
|
}
|
|
2011
2007
|
}
|
|
2012
2008
|
exports.User = User;
|
package/package.json
CHANGED
|
@@ -49,7 +49,9 @@ export class PollingDriftClientAccountSubscriber
|
|
|
49
49
|
|
|
50
50
|
state?: DataAndSlot<StateAccount>;
|
|
51
51
|
perpMarket = new Map<number, DataAndSlot<PerpMarketAccount>>();
|
|
52
|
+
perpOracleMap = new Map<number, PublicKey>();
|
|
52
53
|
spotMarket = new Map<number, DataAndSlot<SpotMarketAccount>>();
|
|
54
|
+
spotOracleMap = new Map<number, PublicKey>();
|
|
53
55
|
oracles = new Map<string, DataAndSlot<OraclePriceData>>();
|
|
54
56
|
user?: DataAndSlot<UserAccount>;
|
|
55
57
|
|
|
@@ -114,6 +116,9 @@ export class PollingDriftClientAccountSubscriber
|
|
|
114
116
|
this.eventEmitter.emit('update');
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
this.setPerpOracleMap();
|
|
120
|
+
this.setSpotOracleMap();
|
|
121
|
+
|
|
117
122
|
this.isSubscribing = false;
|
|
118
123
|
this.isSubscribed = subscriptionSucceeded;
|
|
119
124
|
this.subscriptionPromiseResolver(subscriptionSucceeded);
|
|
@@ -367,6 +372,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
367
372
|
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
368
373
|
|
|
369
374
|
await this.addAccountToAccountLoader(accountToPoll);
|
|
375
|
+
this.setSpotOracleMap();
|
|
370
376
|
return true;
|
|
371
377
|
}
|
|
372
378
|
|
|
@@ -383,6 +389,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
383
389
|
await this.addPerpMarketAccountToPoll(marketIndex);
|
|
384
390
|
const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
|
|
385
391
|
await this.addAccountToAccountLoader(accountToPoll);
|
|
392
|
+
this.setPerpOracleMap();
|
|
386
393
|
return true;
|
|
387
394
|
}
|
|
388
395
|
|
|
@@ -402,6 +409,26 @@ export class PollingDriftClientAccountSubscriber
|
|
|
402
409
|
return true;
|
|
403
410
|
}
|
|
404
411
|
|
|
412
|
+
private setPerpOracleMap() {
|
|
413
|
+
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
414
|
+
for (const perpMarket of perpMarkets) {
|
|
415
|
+
const perpMarketAccount = perpMarket.data;
|
|
416
|
+
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
417
|
+
const oracle = perpMarketAccount.amm.oracle;
|
|
418
|
+
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private setSpotOracleMap() {
|
|
423
|
+
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
424
|
+
for (const spotMarket of spotMarkets) {
|
|
425
|
+
const spotMarketAccount = spotMarket.data;
|
|
426
|
+
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
427
|
+
const oracle = spotMarketAccount.oracle;
|
|
428
|
+
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
405
432
|
assertIsSubscribed(): void {
|
|
406
433
|
if (!this.isSubscribed) {
|
|
407
434
|
throw new NotSubscribedError(
|
|
@@ -449,6 +476,49 @@ export class PollingDriftClientAccountSubscriber
|
|
|
449
476
|
return this.oracles.get(oraclePublicKey.toString());
|
|
450
477
|
}
|
|
451
478
|
|
|
479
|
+
public getOraclePriceDataAndSlotForPerpMarket(
|
|
480
|
+
marketIndex: number
|
|
481
|
+
): DataAndSlot<OraclePriceData> | undefined {
|
|
482
|
+
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
483
|
+
const oracle = this.perpOracleMap.get(marketIndex);
|
|
484
|
+
if (!perpMarketAccount || !oracle) {
|
|
485
|
+
return undefined;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
489
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
490
|
+
this.addOracle({
|
|
491
|
+
source: perpMarketAccount.data.amm.oracleSource,
|
|
492
|
+
publicKey: perpMarketAccount.data.amm.oracle,
|
|
493
|
+
}).then(() => {
|
|
494
|
+
this.setPerpOracleMap();
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
public getOraclePriceDataAndSlotForSpotMarket(
|
|
502
|
+
marketIndex: number
|
|
503
|
+
): DataAndSlot<OraclePriceData> | undefined {
|
|
504
|
+
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
505
|
+
const oracle = this.spotOracleMap.get(marketIndex);
|
|
506
|
+
if (!spotMarketAccount || !oracle) {
|
|
507
|
+
return undefined;
|
|
508
|
+
}
|
|
509
|
+
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
510
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
511
|
+
this.addOracle({
|
|
512
|
+
source: spotMarketAccount.data.oracleSource,
|
|
513
|
+
publicKey: spotMarketAccount.data.oracle,
|
|
514
|
+
}).then(() => {
|
|
515
|
+
this.setSpotOracleMap();
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
520
|
+
}
|
|
521
|
+
|
|
452
522
|
public updateAccountLoaderPollingFrequency(pollingFrequency: number): void {
|
|
453
523
|
this.accountLoader.updatePollingFrequency(pollingFrequency);
|
|
454
524
|
}
|
package/src/accounts/types.ts
CHANGED
|
@@ -71,6 +71,12 @@ export interface DriftClientAccountSubscriber {
|
|
|
71
71
|
getOraclePriceDataAndSlot(
|
|
72
72
|
oraclePublicKey: PublicKey
|
|
73
73
|
): DataAndSlot<OraclePriceData> | undefined;
|
|
74
|
+
getOraclePriceDataAndSlotForPerpMarket(
|
|
75
|
+
marketIndex: number
|
|
76
|
+
): DataAndSlot<OraclePriceData> | undefined;
|
|
77
|
+
getOraclePriceDataAndSlotForSpotMarket(
|
|
78
|
+
marketIndex: number
|
|
79
|
+
): DataAndSlot<OraclePriceData> | undefined;
|
|
74
80
|
|
|
75
81
|
updateAccountLoaderPollingFrequency?: (pollingFrequency: number) => void;
|
|
76
82
|
}
|
|
@@ -41,10 +41,12 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
41
41
|
number,
|
|
42
42
|
AccountSubscriber<PerpMarketAccount>
|
|
43
43
|
>();
|
|
44
|
+
perpOracleMap = new Map<number, PublicKey>();
|
|
44
45
|
spotMarketAccountSubscribers = new Map<
|
|
45
46
|
number,
|
|
46
47
|
AccountSubscriber<SpotMarketAccount>
|
|
47
48
|
>();
|
|
49
|
+
spotOracleMap = new Map<number, PublicKey>();
|
|
48
50
|
oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
|
|
49
51
|
|
|
50
52
|
private isSubscribing = false;
|
|
@@ -123,6 +125,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
123
125
|
|
|
124
126
|
this.eventEmitter.emit('update');
|
|
125
127
|
|
|
128
|
+
this.setPerpOracleMap();
|
|
129
|
+
this.setSpotOracleMap();
|
|
130
|
+
|
|
126
131
|
this.isSubscribing = false;
|
|
127
132
|
this.isSubscribed = true;
|
|
128
133
|
this.subscriptionPromiseResolver(true);
|
|
@@ -280,14 +285,18 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
280
285
|
if (this.spotMarketAccountSubscribers.has(marketIndex)) {
|
|
281
286
|
return true;
|
|
282
287
|
}
|
|
283
|
-
|
|
288
|
+
const subscriptionSuccess = this.subscribeToSpotMarketAccount(marketIndex);
|
|
289
|
+
this.setSpotOracleMap();
|
|
290
|
+
return subscriptionSuccess;
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
async addPerpMarket(marketIndex: number): Promise<boolean> {
|
|
287
294
|
if (this.perpMarketAccountSubscribers.has(marketIndex)) {
|
|
288
295
|
return true;
|
|
289
296
|
}
|
|
290
|
-
|
|
297
|
+
const subscriptionSuccess = this.subscribeToPerpMarketAccount(marketIndex);
|
|
298
|
+
this.setPerpOracleMap();
|
|
299
|
+
return subscriptionSuccess;
|
|
291
300
|
}
|
|
292
301
|
|
|
293
302
|
async addOracle(oracleInfo: OracleInfo): Promise<boolean> {
|
|
@@ -302,6 +311,32 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
302
311
|
return this.subscribeToOracle(oracleInfo);
|
|
303
312
|
}
|
|
304
313
|
|
|
314
|
+
private setPerpOracleMap() {
|
|
315
|
+
const perpMarkets = this.getMarketAccountsAndSlots();
|
|
316
|
+
for (const perpMarket of perpMarkets) {
|
|
317
|
+
if (!perpMarket) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const perpMarketAccount = perpMarket.data;
|
|
321
|
+
const perpMarketIndex = perpMarketAccount.marketIndex;
|
|
322
|
+
const oracle = perpMarketAccount.amm.oracle;
|
|
323
|
+
this.perpOracleMap.set(perpMarketIndex, oracle);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private setSpotOracleMap() {
|
|
328
|
+
const spotMarkets = this.getSpotMarketAccountsAndSlots();
|
|
329
|
+
for (const spotMarket of spotMarkets) {
|
|
330
|
+
if (!spotMarket) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const spotMarketAccount = spotMarket.data;
|
|
334
|
+
const spotMarketIndex = spotMarketAccount.marketIndex;
|
|
335
|
+
const oracle = spotMarketAccount.oracle;
|
|
336
|
+
this.spotOracleMap.set(spotMarketIndex, oracle);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
305
340
|
assertIsSubscribed(): void {
|
|
306
341
|
if (!this.isSubscribed) {
|
|
307
342
|
throw new NotSubscribedError(
|
|
@@ -353,4 +388,48 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
353
388
|
}
|
|
354
389
|
return this.oracleSubscribers.get(oraclePublicKey.toString()).dataAndSlot;
|
|
355
390
|
}
|
|
391
|
+
|
|
392
|
+
public getOraclePriceDataAndSlotForPerpMarket(
|
|
393
|
+
marketIndex: number
|
|
394
|
+
): DataAndSlot<OraclePriceData> | undefined {
|
|
395
|
+
const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
|
|
396
|
+
const oracle = this.perpOracleMap.get(marketIndex);
|
|
397
|
+
if (!perpMarketAccount || !oracle) {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (!perpMarketAccount.data.amm.oracle.equals(oracle)) {
|
|
402
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
403
|
+
this.addOracle({
|
|
404
|
+
source: perpMarketAccount.data.amm.oracleSource,
|
|
405
|
+
publicKey: perpMarketAccount.data.amm.oracle,
|
|
406
|
+
}).then(() => {
|
|
407
|
+
this.setPerpOracleMap();
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
public getOraclePriceDataAndSlotForSpotMarket(
|
|
415
|
+
marketIndex: number
|
|
416
|
+
): DataAndSlot<OraclePriceData> | undefined {
|
|
417
|
+
const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
|
|
418
|
+
const oracle = this.spotOracleMap.get(marketIndex);
|
|
419
|
+
if (!spotMarketAccount || !oracle) {
|
|
420
|
+
return undefined;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!spotMarketAccount.data.oracle.equals(oracle)) {
|
|
424
|
+
// If the oracle has changed, we need to update the oracle map in background
|
|
425
|
+
this.addOracle({
|
|
426
|
+
source: spotMarketAccount.data.oracleSource,
|
|
427
|
+
publicKey: spotMarketAccount.data.oracle,
|
|
428
|
+
}).then(() => {
|
|
429
|
+
this.setSpotOracleMap();
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return this.getOraclePriceDataAndSlot(oracle);
|
|
434
|
+
}
|
|
356
435
|
}
|
package/src/driftClient.ts
CHANGED
|
@@ -5873,17 +5873,15 @@ export class DriftClient {
|
|
|
5873
5873
|
}
|
|
5874
5874
|
|
|
5875
5875
|
public getOracleDataForPerpMarket(marketIndex: number): OraclePriceData {
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
return oracleData;
|
|
5876
|
+
return this.accountSubscriber.getOraclePriceDataAndSlotForPerpMarket(
|
|
5877
|
+
marketIndex
|
|
5878
|
+
).data;
|
|
5880
5879
|
}
|
|
5881
5880
|
|
|
5882
5881
|
public getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
return oracleData;
|
|
5882
|
+
return this.accountSubscriber.getOraclePriceDataAndSlotForSpotMarket(
|
|
5883
|
+
marketIndex
|
|
5884
|
+
).data;
|
|
5887
5885
|
}
|
|
5888
5886
|
|
|
5889
5887
|
public async initializeInsuranceFundStake(
|
package/src/idl/drift.json
CHANGED
package/src/user.ts
CHANGED
|
@@ -1307,9 +1307,9 @@ export class User {
|
|
|
1307
1307
|
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
1308
1308
|
market.quoteSpotMarketIndex
|
|
1309
1309
|
);
|
|
1310
|
-
const quoteOraclePriceData = this.driftClient.
|
|
1311
|
-
|
|
1312
|
-
)
|
|
1310
|
+
const quoteOraclePriceData = this.driftClient.getOracleDataForSpotMarket(
|
|
1311
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1312
|
+
);
|
|
1313
1313
|
|
|
1314
1314
|
let quotePrice;
|
|
1315
1315
|
if (strict) {
|
|
@@ -2205,7 +2205,7 @@ export class User {
|
|
|
2205
2205
|
if (signedTokenAmount.gt(ZERO)) {
|
|
2206
2206
|
const assetWeight = calculateAssetWeight(
|
|
2207
2207
|
signedTokenAmount,
|
|
2208
|
-
this.driftClient.
|
|
2208
|
+
this.driftClient.getOracleDataForSpotMarket(market.marketIndex).price,
|
|
2209
2209
|
market,
|
|
2210
2210
|
marginCategory
|
|
2211
2211
|
);
|
|
@@ -2388,9 +2388,8 @@ export class User {
|
|
|
2388
2388
|
currentSpotMarketNetValue?: BN
|
|
2389
2389
|
): BN {
|
|
2390
2390
|
const market = this.driftClient.getSpotMarketAccount(targetMarketIndex);
|
|
2391
|
-
const oraclePrice =
|
|
2392
|
-
|
|
2393
|
-
).data.price;
|
|
2391
|
+
const oraclePrice =
|
|
2392
|
+
this.driftClient.getOracleDataForSpotMarket(targetMarketIndex).price;
|
|
2394
2393
|
|
|
2395
2394
|
currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
2396
2395
|
QUOTE_SPOT_MARKET_INDEX
|
|
@@ -3401,9 +3400,9 @@ export class User {
|
|
|
3401
3400
|
const perpMarket = this.driftClient.getPerpMarketAccount(
|
|
3402
3401
|
perpPosition.marketIndex
|
|
3403
3402
|
);
|
|
3404
|
-
const oraclePriceData = this.driftClient.
|
|
3405
|
-
perpMarket.
|
|
3406
|
-
)
|
|
3403
|
+
const oraclePriceData = this.driftClient.getOracleDataForPerpMarket(
|
|
3404
|
+
perpMarket.marketIndex
|
|
3405
|
+
);
|
|
3407
3406
|
const oraclePrice = oraclePriceData.price;
|
|
3408
3407
|
const worstCaseBaseAmount =
|
|
3409
3408
|
calculateWorstCaseBaseAssetAmount(settledLpPosition);
|
|
@@ -3420,9 +3419,9 @@ export class User {
|
|
|
3420
3419
|
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(
|
|
3421
3420
|
perpMarket.quoteSpotMarketIndex
|
|
3422
3421
|
);
|
|
3423
|
-
const quoteOraclePriceData = this.driftClient.
|
|
3424
|
-
|
|
3425
|
-
)
|
|
3422
|
+
const quoteOraclePriceData = this.driftClient.getOracleDataForSpotMarket(
|
|
3423
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
3424
|
+
);
|
|
3426
3425
|
|
|
3427
3426
|
const baseAssetValue = worstCaseBaseAmount
|
|
3428
3427
|
.abs()
|
|
@@ -3645,20 +3644,10 @@ export class User {
|
|
|
3645
3644
|
}
|
|
3646
3645
|
|
|
3647
3646
|
private getOracleDataForPerpMarket(marketIndex: number): OraclePriceData {
|
|
3648
|
-
|
|
3649
|
-
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
3650
|
-
const oracleData =
|
|
3651
|
-
this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
|
|
3652
|
-
|
|
3653
|
-
return oracleData;
|
|
3647
|
+
return this.driftClient.getOracleDataForPerpMarket(marketIndex);
|
|
3654
3648
|
}
|
|
3655
3649
|
|
|
3656
3650
|
private getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
const oracleData =
|
|
3660
|
-
this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
|
|
3661
|
-
|
|
3662
|
-
return oracleData;
|
|
3651
|
+
return this.driftClient.getOracleDataForSpotMarket(marketIndex);
|
|
3663
3652
|
}
|
|
3664
3653
|
}
|