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

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 +66 -6
  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 +125 -12
  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.20",
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,81 @@ 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
214
+ .filter((_, i) => !!oracleAccountInfos[i])
215
+ .map((oracleInfo, i) => {
216
+ const oracleClient = this.oracleClientCache.get(
217
+ oracleInfo.source,
218
+ connection,
219
+ this.program
220
+ );
221
+ const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(
222
+ oracleAccountInfos[i].data
223
+ );
224
+ return [oracleInfo.publicKey.toString(), oraclePriceData];
225
+ })
226
+ );
227
+ }
228
+
229
+ removeInitialData() {
230
+ this.initialPerpMarketAccountData = new Map();
231
+ this.initialSpotMarketAccountData = new Map();
232
+ this.initialOraclePriceData = new Map();
233
+ }
234
+
138
235
  async subscribeToPerpMarketAccounts(): Promise<boolean> {
139
236
  await Promise.all(
140
237
  this.perpMarketIndexes.map((marketIndex) =>
@@ -157,6 +254,9 @@ export class WebSocketDriftClientAccountSubscriber
157
254
  this.resubOpts,
158
255
  this.commitment
159
256
  );
257
+ accountSubscriber.setData(
258
+ this.initialPerpMarketAccountData.get(marketIndex)
259
+ );
160
260
  await accountSubscriber.subscribe((data: PerpMarketAccount) => {
161
261
  this.eventEmitter.emit('perpMarketAccountUpdate', data);
162
262
  this.eventEmitter.emit('update');
@@ -187,6 +287,9 @@ export class WebSocketDriftClientAccountSubscriber
187
287
  this.resubOpts,
188
288
  this.commitment
189
289
  );
290
+ accountSubscriber.setData(
291
+ this.initialSpotMarketAccountData.get(marketIndex)
292
+ );
190
293
  await accountSubscriber.subscribe((data: SpotMarketAccount) => {
191
294
  this.eventEmitter.emit('spotMarketAccountUpdate', data);
192
295
  this.eventEmitter.emit('update');
@@ -206,6 +309,7 @@ export class WebSocketDriftClientAccountSubscriber
206
309
  }
207
310
 
208
311
  async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
312
+ const oracleString = oracleInfo.publicKey.toString();
209
313
  const client = this.oracleClientCache.get(
210
314
  oracleInfo.source,
211
315
  this.program.provider.connection,
@@ -221,16 +325,17 @@ export class WebSocketDriftClientAccountSubscriber
221
325
  this.resubOpts,
222
326
  this.commitment
223
327
  );
224
-
328
+ const initialOraclePriceData =
329
+ this.initialOraclePriceData.get(oracleString);
330
+ if (initialOraclePriceData) {
331
+ accountSubscriber.setData(initialOraclePriceData);
332
+ }
225
333
  await accountSubscriber.subscribe((data: OraclePriceData) => {
226
334
  this.eventEmitter.emit('oraclePriceUpdate', oracleInfo.publicKey, data);
227
335
  this.eventEmitter.emit('update');
228
336
  });
229
337
 
230
- this.oracleSubscribers.set(
231
- oracleInfo.publicKey.toString(),
232
- accountSubscriber
233
- );
338
+ this.oracleSubscribers.set(oracleString, accountSubscriber);
234
339
  return true;
235
340
  }
236
341
 
@@ -341,6 +446,7 @@ export class WebSocketDriftClientAccountSubscriber
341
446
  );
342
447
  }
343
448
  this.perpOracleMap.set(perpMarketIndex, oracle);
449
+ this.perpOracleStringMap.set(perpMarketIndex, oracle.toBase58());
344
450
  }
345
451
  await Promise.all(addOraclePromises);
346
452
  }
@@ -364,6 +470,7 @@ export class WebSocketDriftClientAccountSubscriber
364
470
  );
365
471
  }
366
472
  this.spotOracleMap.set(spotMarketIndex, oracle);
473
+ this.spotOracleStringMap.set(spotMarketIndex, oracle.toBase58());
367
474
  }
368
475
  await Promise.all(addOraclePromises);
369
476
  }
@@ -408,16 +515,20 @@ export class WebSocketDriftClientAccountSubscriber
408
515
  }
409
516
 
410
517
  public getOraclePriceDataAndSlot(
411
- oraclePublicKey: PublicKey
518
+ oraclePublicKey: PublicKey | string
412
519
  ): DataAndSlot<OraclePriceData> | undefined {
413
520
  this.assertIsSubscribed();
414
- if (oraclePublicKey.equals(PublicKey.default)) {
521
+ const oracleString =
522
+ typeof oraclePublicKey === 'string'
523
+ ? oraclePublicKey
524
+ : oraclePublicKey.toBase58();
525
+ if (oracleString === ORACLE_DEFAULT_KEY) {
415
526
  return {
416
527
  data: QUOTE_ORACLE_PRICE_DATA,
417
528
  slot: 0,
418
529
  };
419
530
  }
420
- return this.oracleSubscribers.get(oraclePublicKey.toString()).dataAndSlot;
531
+ return this.oracleSubscribers.get(oracleString).dataAndSlot;
421
532
  }
422
533
 
423
534
  public getOraclePriceDataAndSlotForPerpMarket(
@@ -425,6 +536,7 @@ export class WebSocketDriftClientAccountSubscriber
425
536
  ): DataAndSlot<OraclePriceData> | undefined {
426
537
  const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
427
538
  const oracle = this.perpOracleMap.get(marketIndex);
539
+ const oracleString = this.perpOracleStringMap.get(marketIndex);
428
540
  if (!perpMarketAccount || !oracle) {
429
541
  return undefined;
430
542
  }
@@ -434,7 +546,7 @@ export class WebSocketDriftClientAccountSubscriber
434
546
  this.setPerpOracleMap();
435
547
  }
436
548
 
437
- return this.getOraclePriceDataAndSlot(oracle);
549
+ return this.getOraclePriceDataAndSlot(oracleString);
438
550
  }
439
551
 
440
552
  public getOraclePriceDataAndSlotForSpotMarket(
@@ -442,6 +554,7 @@ export class WebSocketDriftClientAccountSubscriber
442
554
  ): DataAndSlot<OraclePriceData> | undefined {
443
555
  const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
444
556
  const oracle = this.spotOracleMap.get(marketIndex);
557
+ const oracleString = this.spotOracleStringMap.get(marketIndex);
445
558
  if (!spotMarketAccount || !oracle) {
446
559
  return undefined;
447
560
  }
@@ -451,6 +564,6 @@ export class WebSocketDriftClientAccountSubscriber
451
564
  this.setSpotOracleMap();
452
565
  }
453
566
 
454
- return this.getOraclePriceDataAndSlot(oracle);
567
+ return this.getOraclePriceDataAndSlot(oracleString);
455
568
  }
456
569
  }
@@ -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
  });
@@ -11,7 +11,17 @@ export function parseLogs(
11
11
  logs: string[],
12
12
  programId = driftProgramId
13
13
  ): Event[] {
14
+ const { events } = parseLogsWithRaw(program, logs, programId);
15
+ return events;
16
+ }
17
+
18
+ export function parseLogsWithRaw(
19
+ program: Program,
20
+ logs: string[],
21
+ programId = driftProgramId
22
+ ): { events: Event[]; rawLogs: string[] } {
14
23
  const events = [];
24
+ const rawLogs = [];
15
25
  const execution = new ExecutionContext();
16
26
  for (const log of logs) {
17
27
  if (log.startsWith('Log truncated')) {
@@ -26,6 +36,7 @@ export function parseLogs(
26
36
  );
27
37
  if (event) {
28
38
  events.push(event);
39
+ rawLogs.push(log);
29
40
  }
30
41
  if (newProgram) {
31
42
  execution.push(newProgram);
@@ -34,7 +45,7 @@ export function parseLogs(
34
45
  execution.pop();
35
46
  }
36
47
  }
37
- return events;
48
+ return { events, rawLogs };
38
49
  }
39
50
 
40
51
  function handleLog(