@drift-labs/sdk 2.95.0-beta.2 → 2.95.0-beta.21

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.
Files changed (36) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/pollingDriftClientAccountSubscriber.d.ts +3 -1
  3. package/lib/accounts/pollingDriftClientAccountSubscriber.js +14 -4
  4. package/lib/accounts/types.d.ts +1 -1
  5. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +8 -1
  6. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +70 -8
  7. package/lib/addresses/pda.d.ts +2 -0
  8. package/lib/addresses/pda.js +15 -1
  9. package/lib/config.d.ts +3 -0
  10. package/lib/config.js +2 -0
  11. package/lib/constants/perpMarkets.js +25 -4
  12. package/lib/constants/spotMarkets.js +10 -0
  13. package/lib/driftClient.js +6 -2
  14. package/lib/events/parse.d.ts +4 -0
  15. package/lib/events/parse.js +10 -3
  16. package/lib/idl/drift.json +8 -3
  17. package/lib/math/auction.d.ts +5 -1
  18. package/lib/math/auction.js +5 -1
  19. package/lib/math/insurance.d.ts +3 -1
  20. package/lib/math/insurance.js +31 -1
  21. package/lib/math/spotBalance.d.ts +3 -3
  22. package/lib/math/spotBalance.js +7 -7
  23. package/package.json +1 -1
  24. package/src/accounts/pollingDriftClientAccountSubscriber.ts +17 -5
  25. package/src/accounts/types.ts +1 -1
  26. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +132 -14
  27. package/src/addresses/pda.ts +26 -0
  28. package/src/config.ts +8 -0
  29. package/src/constants/perpMarkets.ts +26 -4
  30. package/src/constants/spotMarkets.ts +11 -0
  31. package/src/driftClient.ts +11 -2
  32. package/src/events/parse.ts +12 -1
  33. package/src/idl/drift.json +8 -3
  34. package/src/math/auction.ts +16 -0
  35. package/src/math/insurance.ts +48 -2
  36. package/src/math/spotBalance.ts +13 -7
@@ -1,8 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.unstakeSharesToAmountWithOpenRequest = exports.unstakeSharesToAmount = exports.stakeAmountToShares = void 0;
3
+ exports.unstakeSharesToAmountWithOpenRequest = exports.unstakeSharesToAmount = exports.stakeAmountToShares = exports.nextRevenuePoolSettleApr = void 0;
4
4
  const numericConstants_1 = require("../constants/numericConstants");
5
5
  const index_1 = require("../index");
6
+ const spotBalance_1 = require("../math/spotBalance");
7
+ function nextRevenuePoolSettleApr(spotMarket, vaultBalance, // vault token amount
8
+ amount // delta token amount
9
+ ) {
10
+ const MAX_APR = new index_1.BN(10).mul(numericConstants_1.PERCENTAGE_PRECISION); // 1000% APR
11
+ // Conmputing the APR:
12
+ const revenuePoolBN = (0, spotBalance_1.getTokenAmount)(spotMarket.revenuePool.scaledBalance, spotMarket, index_1.SpotBalanceType.DEPOSIT);
13
+ const payoutRatio = 0.1;
14
+ const ratioForStakers = spotMarket.insuranceFund.totalFactor > 0 &&
15
+ spotMarket.insuranceFund.userFactor > 0 &&
16
+ spotMarket.insuranceFund.revenueSettlePeriod.gt(numericConstants_1.ZERO)
17
+ ? spotMarket.insuranceFund.userFactor /
18
+ spotMarket.insuranceFund.totalFactor
19
+ : 0;
20
+ // Settle periods from on-chain data:
21
+ const revSettlePeriod = spotMarket.insuranceFund.revenueSettlePeriod.toNumber() * 1000;
22
+ const settlesPerYear = 31536000000 / revSettlePeriod;
23
+ const projectedAnnualRev = revenuePoolBN
24
+ .muln(settlesPerYear)
25
+ .muln(payoutRatio);
26
+ const uncappedApr = vaultBalance.add(amount).eq(numericConstants_1.ZERO)
27
+ ? 0
28
+ : projectedAnnualRev.muln(1000).div(vaultBalance.add(amount)).toNumber() *
29
+ 100 *
30
+ 1000;
31
+ const cappedApr = Math.min(uncappedApr, MAX_APR.toNumber());
32
+ const nextApr = cappedApr * ratioForStakers;
33
+ return nextApr;
34
+ }
35
+ exports.nextRevenuePoolSettleApr = nextRevenuePoolSettleApr;
6
36
  function stakeAmountToShares(amount, totalIfShares, insuranceFundVaultBalance) {
7
37
  let nShares;
8
38
  if (insuranceFundVaultBalance.gt(numericConstants_1.ZERO)) {
@@ -62,9 +62,9 @@ export declare function calculateSpotMarketBorrowCapacity(spotMarketAccount: Spo
62
62
  totalCapacity: BN;
63
63
  remainingCapacity: BN;
64
64
  };
65
- export declare function calculateInterestRate(bank: SpotMarketAccount, delta?: BN): BN;
66
- export declare function calculateDepositRate(bank: SpotMarketAccount, delta?: BN): BN;
67
- export declare function calculateBorrowRate(bank: SpotMarketAccount, delta?: BN): BN;
65
+ export declare function calculateInterestRate(bank: SpotMarketAccount, delta?: BN, currentUtilization?: BN): BN;
66
+ export declare function calculateDepositRate(bank: SpotMarketAccount, delta?: BN, currentUtilization?: BN): BN;
67
+ export declare function calculateBorrowRate(bank: SpotMarketAccount, delta?: BN, currentUtilization?: BN): BN;
68
68
  export declare function calculateInterestAccumulated(bank: SpotMarketAccount, now: BN): {
69
69
  borrowInterest: BN;
70
70
  depositInterest: BN;
@@ -246,8 +246,8 @@ function calculateSpotMarketBorrowCapacity(spotMarketAccount, targetBorrowRate)
246
246
  return { totalCapacity, remainingCapacity };
247
247
  }
248
248
  exports.calculateSpotMarketBorrowCapacity = calculateSpotMarketBorrowCapacity;
249
- function calculateInterestRate(bank, delta = numericConstants_1.ZERO) {
250
- const utilization = calculateUtilization(bank, delta);
249
+ function calculateInterestRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) {
250
+ const utilization = currentUtilization || calculateUtilization(bank, delta);
251
251
  let interestRate;
252
252
  if (utilization.gt(new anchor_1.BN(bank.optimalUtilization))) {
253
253
  const surplusUtilization = utilization.sub(new anchor_1.BN(bank.optimalUtilization));
@@ -269,11 +269,11 @@ function calculateInterestRate(bank, delta = numericConstants_1.ZERO) {
269
269
  return anchor_1.BN.max(interestRate, new anchor_1.BN(bank.minBorrowRate).mul(numericConstants_2.PERCENTAGE_PRECISION.divn(200)));
270
270
  }
271
271
  exports.calculateInterestRate = calculateInterestRate;
272
- function calculateDepositRate(bank, delta = numericConstants_1.ZERO) {
272
+ function calculateDepositRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) {
273
273
  // positive delta => adding to deposit
274
274
  // negative delta => adding to borrow
275
- const utilization = calculateUtilization(bank, delta);
276
- const borrowRate = calculateBorrowRate(bank, delta);
275
+ const utilization = currentUtilization || calculateUtilization(bank, delta);
276
+ const borrowRate = calculateBorrowRate(bank, delta, utilization);
277
277
  const depositRate = borrowRate
278
278
  .mul(numericConstants_2.PERCENTAGE_PRECISION.sub(new anchor_1.BN(bank.insuranceFund.totalFactor)))
279
279
  .mul(utilization)
@@ -282,8 +282,8 @@ function calculateDepositRate(bank, delta = numericConstants_1.ZERO) {
282
282
  return depositRate;
283
283
  }
284
284
  exports.calculateDepositRate = calculateDepositRate;
285
- function calculateBorrowRate(bank, delta = numericConstants_1.ZERO) {
286
- return calculateInterestRate(bank, delta);
285
+ function calculateBorrowRate(bank, delta = numericConstants_1.ZERO, currentUtilization = null) {
286
+ return calculateInterestRate(bank, delta, currentUtilization);
287
287
  }
288
288
  exports.calculateBorrowRate = calculateBorrowRate;
289
289
  function calculateInterestAccumulated(bank, now) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.95.0-beta.2",
3
+ "version": "2.95.0-beta.21",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -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
- if (oraclePublicKey.equals(PublicKey.default)) {
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(oraclePublicKey.toString());
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(oracle);
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(oracle);
588
+ return this.getOraclePriceDataAndSlot(oracleString);
577
589
  }
578
590
 
579
591
  public updateAccountLoaderPollingFrequency(pollingFrequency: number): void {
@@ -72,7 +72,7 @@ export interface DriftClientAccountSubscriber {
72
72
  ): DataAndSlot<SpotMarketAccount> | undefined;
73
73
  getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[];
74
74
  getOraclePriceDataAndSlot(
75
- oraclePublicKey: PublicKey
75
+ oraclePublicKey: PublicKey | string
76
76
  ): DataAndSlot<OraclePriceData> | undefined;
77
77
  getOraclePriceDataAndSlotForPerpMarket(
78
78
  marketIndex: number
@@ -13,6 +13,8 @@ import {
13
13
  getDriftStateAccountPublicKey,
14
14
  getSpotMarketPublicKey,
15
15
  getPerpMarketPublicKey,
16
+ getPerpMarketPublicKeySync,
17
+ getSpotMarketPublicKeySync,
16
18
  } from '../addresses/pda';
17
19
  import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
18
20
  import { Commitment, PublicKey } from '@solana/web3.js';
@@ -22,6 +24,8 @@ import * as Buffer from 'buffer';
22
24
  import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
23
25
  import { findAllMarketAndOracles } from '../config';
24
26
 
27
+ const ORACLE_DEFAULT_KEY = PublicKey.default.toBase58();
28
+
25
29
  export class WebSocketDriftClientAccountSubscriber
26
30
  implements DriftClientAccountSubscriber
27
31
  {
@@ -43,13 +47,19 @@ export class WebSocketDriftClientAccountSubscriber
43
47
  AccountSubscriber<PerpMarketAccount>
44
48
  >();
45
49
  perpOracleMap = new Map<number, PublicKey>();
50
+ perpOracleStringMap = new Map<number, string>();
46
51
  spotMarketAccountSubscribers = new Map<
47
52
  number,
48
53
  AccountSubscriber<SpotMarketAccount>
49
54
  >();
50
55
  spotOracleMap = new Map<number, PublicKey>();
56
+ spotOracleStringMap = new Map<number, string>();
51
57
  oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
52
58
 
59
+ initialPerpMarketAccountData: Map<number, PerpMarketAccount>;
60
+ initialSpotMarketAccountData: Map<number, SpotMarketAccount>;
61
+ initialOraclePriceData: Map<string, OraclePriceData>;
62
+
53
63
  private isSubscribing = false;
54
64
  private subscriptionPromise: Promise<boolean>;
55
65
  private subscriptionPromiseResolver: (val: boolean) => void;
@@ -90,11 +100,23 @@ export class WebSocketDriftClientAccountSubscriber
90
100
  });
91
101
 
92
102
  if (this.shouldFindAllMarketsAndOracles) {
93
- const { perpMarketIndexes, spotMarketIndexes, oracleInfos } =
94
- await findAllMarketAndOracles(this.program);
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
- if (oraclePublicKey.equals(PublicKey.default)) {
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(oraclePublicKey.toString()).dataAndSlot;
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(oracle);
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(oracle);
572
+ return this.getOraclePriceDataAndSlot(oracleString);
455
573
  }
456
574
  }
@@ -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
  }
@@ -81,11 +81,11 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
81
81
  symbol: 'MATIC-PERP',
82
82
  baseAssetSymbol: 'MATIC',
83
83
  marketIndex: 5,
84
- oracle: new PublicKey('5Wf1WrXLeNJghU8WRo5odvwAjpjSSF4THbjdxbKmwVsi'),
84
+ oracle: new PublicKey('BrzyDgwELy4jjjsqLQpBeUxzrsueYyMhuWpYBaUYcXvi'),
85
85
  launchTs: 1677690149000, //todo
86
86
  oracleSource: OracleSource.PYTH_PULL,
87
87
  pythFeedId:
88
- '0x5de33a9112c2b700b8d30b8a3402c103578ccfa2765696471cc672bd5cf6ac52',
88
+ '0xffd11c5a1cfd42f80afb2df4d9f264c15f956d68153335374ec10722edd70472',
89
89
  },
90
90
  {
91
91
  fullName: 'Arbitrum',
@@ -416,11 +416,11 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
416
416
  symbol: 'MATIC-PERP',
417
417
  baseAssetSymbol: 'MATIC',
418
418
  marketIndex: 5,
419
- oracle: new PublicKey('5Wf1WrXLeNJghU8WRo5odvwAjpjSSF4THbjdxbKmwVsi'),
419
+ oracle: new PublicKey('BrzyDgwELy4jjjsqLQpBeUxzrsueYyMhuWpYBaUYcXvi'),
420
420
  launchTs: 1677690149000, //todo
421
421
  oracleSource: OracleSource.PYTH_PULL,
422
422
  pythFeedId:
423
- '0x5de33a9112c2b700b8d30b8a3402c103578ccfa2765696471cc672bd5cf6ac52',
423
+ '0xffd11c5a1cfd42f80afb2df4d9f264c15f956d68153335374ec10722edd70472',
424
424
  },
425
425
  {
426
426
  fullName: 'Arbitrum',
@@ -830,6 +830,28 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
830
830
  launchTs: 1724250126000,
831
831
  oracleSource: OracleSource.Prelaunch,
832
832
  },
833
+ {
834
+ fullName: 'DEMOCRATS-WIN-MICHIGAN-BET',
835
+ category: ['Prediction', 'Election'],
836
+ symbol: 'DEMOCRATS-WIN-MICHIGAN-BET',
837
+ baseAssetSymbol: 'DEMOCRATS-WIN-MICHIGAN',
838
+ marketIndex: 41,
839
+ oracle: new PublicKey('8HTDLjhb2esGU5mu11v3pq3eWeFqmvKPkQNCnTTwKAyB'),
840
+ launchTs: 1725551484000,
841
+ oracleSource: OracleSource.Prelaunch,
842
+ },
843
+ {
844
+ fullName: 'TON',
845
+ category: ['L1'],
846
+ symbol: 'TON-PERP',
847
+ baseAssetSymbol: 'TON',
848
+ marketIndex: 42,
849
+ oracle: new PublicKey('BNjCXrpEqjdBnuRy2SAUgm5Pq8B73wGFwsf6RYFJiLPY'),
850
+ launchTs: 1725551484000,
851
+ oracleSource: OracleSource.PYTH_PULL,
852
+ pythFeedId:
853
+ '0x8963217838ab4cf5cadc172203c1f0b763fbaa45f346d8ee50ba994bbcac3026',
854
+ },
833
855
  ];
834
856
 
835
857
  export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
@@ -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[] } = {
@@ -538,7 +538,9 @@ export class DriftClient {
538
538
  public getOraclePriceDataAndSlot(
539
539
  oraclePublicKey: PublicKey
540
540
  ): DataAndSlot<OraclePriceData> | undefined {
541
- return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
541
+ return this.accountSubscriber.getOraclePriceDataAndSlot(
542
+ oraclePublicKey.toBase58()
543
+ );
542
544
  }
543
545
 
544
546
  public async getSerumV3FulfillmentConfig(
@@ -3221,11 +3223,18 @@ export class DriftClient {
3221
3223
  writablePerpMarketIndexes: [marketIndex],
3222
3224
  writableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
3223
3225
  });
3226
+ const perpMarketPublicKey = await getPerpMarketPublicKey(
3227
+ this.program.programId,
3228
+ marketIndex
3229
+ );
3224
3230
 
3225
3231
  return await this.program.instruction.settleExpiredMarket(marketIndex, {
3226
3232
  accounts: {
3227
3233
  state: await this.getStatePublicKey(),
3228
- authority: this.wallet.publicKey,
3234
+ admin: this.isSubscribed
3235
+ ? this.getStateAccount().admin
3236
+ : this.wallet.publicKey,
3237
+ perpMarket: perpMarketPublicKey,
3229
3238
  },
3230
3239
  remainingAccounts,
3231
3240
  });