@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 CHANGED
@@ -1 +1 @@
1
- 2.66.0-beta.4
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
  }
@@ -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
- return this.subscribeToSpotMarketAccount(marketIndex);
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
- return this.subscribeToPerpMarketAccount(marketIndex);
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;
@@ -3169,14 +3169,10 @@ class DriftClient {
3169
3169
  this.eventEmitter.emit(eventName, data);
3170
3170
  }
3171
3171
  getOracleDataForPerpMarket(marketIndex) {
3172
- const oracleKey = this.getPerpMarketAccount(marketIndex).amm.oracle;
3173
- const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
3174
- return oracleData;
3172
+ return this.accountSubscriber.getOraclePriceDataAndSlotForPerpMarket(marketIndex).data;
3175
3173
  }
3176
3174
  getOracleDataForSpotMarket(marketIndex) {
3177
- const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
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);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.65.0",
2
+ "version": "2.66.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
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.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
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.getOraclePriceDataAndSlot(market.oracle).data.price, market, marginCategory);
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.getOraclePriceDataAndSlot(market.oracle).data.price;
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.getOraclePriceDataAndSlot(perpMarket.amm.oracle).data;
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.getOraclePriceDataAndSlot(quoteSpotMarket.oracle).data;
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
- const oracleKey = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
2003
- const oracleData = this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
2004
- return oracleData;
2002
+ return this.driftClient.getOracleDataForPerpMarket(marketIndex);
2005
2003
  }
2006
2004
  getOracleDataForSpotMarket(marketIndex) {
2007
- const oracleKey = this.driftClient.getSpotMarketAccount(marketIndex).oracle;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.66.0-beta.4",
3
+ "version": "2.67.0-beta.1",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -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
  }
@@ -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
- return this.subscribeToSpotMarketAccount(marketIndex);
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
- return this.subscribeToPerpMarketAccount(marketIndex);
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
  }
@@ -5873,17 +5873,15 @@ export class DriftClient {
5873
5873
  }
5874
5874
 
5875
5875
  public getOracleDataForPerpMarket(marketIndex: number): OraclePriceData {
5876
- const oracleKey = this.getPerpMarketAccount(marketIndex).amm.oracle;
5877
- const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
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
- const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
5884
- const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
5885
-
5886
- return oracleData;
5882
+ return this.accountSubscriber.getOraclePriceDataAndSlotForSpotMarket(
5883
+ marketIndex
5884
+ ).data;
5887
5885
  }
5888
5886
 
5889
5887
  public async initializeInsuranceFundStake(
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.65.0",
2
+ "version": "2.66.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
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.getOraclePriceDataAndSlot(
1311
- quoteSpotMarket.oracle
1312
- ).data;
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.getOraclePriceDataAndSlot(market.oracle).data.price,
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 = this.driftClient.getOraclePriceDataAndSlot(
2392
- market.oracle
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.getOraclePriceDataAndSlot(
3405
- perpMarket.amm.oracle
3406
- ).data;
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.getOraclePriceDataAndSlot(
3424
- quoteSpotMarket.oracle
3425
- ).data;
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
- const oracleKey =
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
- const oracleKey = this.driftClient.getSpotMarketAccount(marketIndex).oracle;
3658
-
3659
- const oracleData =
3660
- this.driftClient.getOraclePriceDataAndSlot(oracleKey).data;
3661
-
3662
- return oracleData;
3651
+ return this.driftClient.getOracleDataForSpotMarket(marketIndex);
3663
3652
  }
3664
3653
  }