@drift-labs/sdk 2.82.0-beta.1 → 2.82.0-beta.11

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 (82) hide show
  1. package/README.md +65 -47
  2. package/VERSION +1 -1
  3. package/lib/accounts/types.d.ts +4 -0
  4. package/lib/accounts/webSocketAccountSubscriber.d.ts +3 -3
  5. package/lib/accounts/webSocketAccountSubscriber.js +15 -8
  6. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +3 -3
  7. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +5 -5
  8. package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +2 -2
  9. package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +5 -3
  10. package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +3 -3
  11. package/lib/accounts/webSocketProgramAccountSubscriber.js +15 -9
  12. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +3 -3
  13. package/lib/accounts/webSocketUserAccountSubscriber.js +3 -3
  14. package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +3 -3
  15. package/lib/accounts/webSocketUserStatsAccountSubsriber.js +3 -3
  16. package/lib/auctionSubscriber/auctionSubscriber.d.ts +2 -2
  17. package/lib/auctionSubscriber/auctionSubscriber.js +3 -3
  18. package/lib/auctionSubscriber/types.d.ts +1 -0
  19. package/lib/constants/perpMarkets.js +2 -2
  20. package/lib/driftClient.d.ts +12 -1
  21. package/lib/driftClient.js +59 -16
  22. package/lib/driftClientConfig.d.ts +1 -0
  23. package/lib/orderSubscriber/OrderSubscriber.js +6 -3
  24. package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -3
  25. package/lib/orderSubscriber/WebsocketSubscription.js +3 -3
  26. package/lib/orderSubscriber/types.d.ts +1 -0
  27. package/lib/priorityFee/driftPriorityFeeMethod.d.ts +13 -3
  28. package/lib/priorityFee/driftPriorityFeeMethod.js +2 -2
  29. package/lib/priorityFee/index.d.ts +2 -0
  30. package/lib/priorityFee/index.js +2 -0
  31. package/lib/priorityFee/priorityFeeSubscriber.d.ts +1 -4
  32. package/lib/priorityFee/priorityFeeSubscriber.js +5 -4
  33. package/lib/priorityFee/priorityFeeSubscriberMap.d.ts +48 -0
  34. package/lib/priorityFee/priorityFeeSubscriberMap.js +88 -0
  35. package/lib/priorityFee/types.d.ts +8 -3
  36. package/lib/priorityFee/types.js +2 -1
  37. package/lib/tx/baseTxSender.js +3 -2
  38. package/lib/tx/types.d.ts +5 -0
  39. package/lib/tx/types.js +12 -1
  40. package/lib/tx/utils.js +5 -1
  41. package/lib/user.d.ts +0 -10
  42. package/lib/user.js +6 -29
  43. package/lib/userConfig.d.ts +1 -0
  44. package/lib/userMap/WebsocketSubscription.d.ts +4 -3
  45. package/lib/userMap/WebsocketSubscription.js +3 -3
  46. package/lib/userMap/userMap.js +4 -1
  47. package/lib/userMap/userMapConfig.d.ts +1 -0
  48. package/lib/userStats.js +6 -3
  49. package/lib/userStatsConfig.d.ts +1 -0
  50. package/package.json +3 -3
  51. package/src/accounts/types.ts +5 -0
  52. package/src/accounts/webSocketAccountSubscriber.ts +34 -22
  53. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +7 -6
  54. package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +6 -4
  55. package/src/accounts/webSocketProgramAccountSubscriber.ts +32 -22
  56. package/src/accounts/webSocketUserAccountSubscriber.ts +5 -4
  57. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +5 -4
  58. package/src/auctionSubscriber/auctionSubscriber.ts +10 -4
  59. package/src/auctionSubscriber/types.ts +1 -0
  60. package/src/blockhashSubscriber/types.ts +4 -0
  61. package/src/constants/perpMarkets.ts +2 -2
  62. package/src/driftClient.ts +70 -12
  63. package/src/driftClientConfig.ts +1 -0
  64. package/src/orderSubscriber/OrderSubscriber.ts +4 -1
  65. package/src/orderSubscriber/WebsocketSubscription.ts +6 -5
  66. package/src/orderSubscriber/types.ts +1 -0
  67. package/src/priorityFee/driftPriorityFeeMethod.ts +16 -4
  68. package/src/priorityFee/index.ts +2 -0
  69. package/src/priorityFee/priorityFeeSubscriber.ts +7 -7
  70. package/src/priorityFee/priorityFeeSubscriberMap.ts +112 -0
  71. package/src/priorityFee/types.ts +16 -3
  72. package/src/tx/baseTxSender.ts +8 -4
  73. package/src/tx/types.ts +12 -0
  74. package/src/tx/utils.ts +5 -1
  75. package/src/user.ts +7 -32
  76. package/src/userConfig.ts +1 -0
  77. package/src/userMap/WebsocketSubscription.ts +6 -5
  78. package/src/userMap/userMap.ts +4 -1
  79. package/src/userMap/userMapConfig.ts +1 -0
  80. package/src/userStats.ts +4 -1
  81. package/src/userStatsConfig.ts +1 -0
  82. package/tests/dlob/helpers.ts +4 -0
@@ -6,20 +6,26 @@ import { EventEmitter } from 'events';
6
6
  import { UserAccount } from '../types';
7
7
  import { ConfirmOptions, Context, PublicKey } from '@solana/web3.js';
8
8
  import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
9
+ import { ResubOpts } from '../accounts/types';
9
10
 
10
11
  export class AuctionSubscriber {
11
12
  private driftClient: DriftClient;
12
13
  private opts: ConfirmOptions;
13
- private resubTimeoutMs?: number;
14
+ private resubOpts?: ResubOpts;
14
15
 
15
16
  eventEmitter: StrictEventEmitter<EventEmitter, AuctionSubscriberEvents>;
16
17
  private subscriber: WebSocketProgramAccountSubscriber<UserAccount>;
17
18
 
18
- constructor({ driftClient, opts, resubTimeoutMs }: AuctionSubscriberConfig) {
19
+ constructor({
20
+ driftClient,
21
+ opts,
22
+ resubTimeoutMs,
23
+ logResubMessages,
24
+ }: AuctionSubscriberConfig) {
19
25
  this.driftClient = driftClient;
20
26
  this.opts = opts || this.driftClient.opts;
21
27
  this.eventEmitter = new EventEmitter();
22
- this.resubTimeoutMs = resubTimeoutMs;
28
+ this.resubOpts = { resubTimeoutMs, logResubMessages };
23
29
  }
24
30
 
25
31
  public async subscribe() {
@@ -35,7 +41,7 @@ export class AuctionSubscriber {
35
41
  filters: [getUserFilter(), getUserWithAuctionFilter()],
36
42
  commitment: this.opts.commitment,
37
43
  },
38
- this.resubTimeoutMs
44
+ this.resubOpts
39
45
  );
40
46
  }
41
47
 
@@ -6,6 +6,7 @@ export type AuctionSubscriberConfig = {
6
6
  driftClient: DriftClient;
7
7
  opts?: ConfirmOptions;
8
8
  resubTimeoutMs?: number;
9
+ logResubMessages?: boolean;
9
10
  };
10
11
 
11
12
  export interface AuctionSubscriberEvents {
@@ -1,8 +1,12 @@
1
1
  import { Commitment, Connection } from '@solana/web3.js';
2
2
 
3
3
  export type BlockhashSubscriberConfig = {
4
+ /// rpcUrl to poll block hashes from, one of rpcUrl or Connection must provided
4
5
  rpcUrl?: string;
6
+ /// connection to poll block hashes from, one of rpcUrl or Connection must provided
5
7
  connection?: Connection;
8
+ /// commitment to poll block hashes with, default is 'confirmed'
6
9
  commitment?: Commitment;
10
+ /// interval to poll block hashes, default is 1000 ms
7
11
  updateIntervalMs?: number;
8
12
  };
@@ -553,9 +553,9 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
553
553
  symbol: 'KMNO-PERP',
554
554
  baseAssetSymbol: 'KMNO',
555
555
  marketIndex: 28,
556
- oracle: new PublicKey('sDAQaZQJQ4RXAxH3x526mbEXyQZT15ktkL84d7hmk7M'),
556
+ oracle: new PublicKey('6ynsvjkE2UoiRScbDx7ZxbBsyn7wyvg5P1vENvhtkG1C'),
557
557
  launchTs: 1712240681000,
558
- oracleSource: OracleSource.Prelaunch,
558
+ oracleSource: OracleSource.SWITCHBOARD,
559
559
  },
560
560
  {
561
561
  fullName: 'Tensor',
@@ -251,11 +251,13 @@ export class DriftClient {
251
251
  this.userAccountSubscriptionConfig = {
252
252
  type: 'websocket',
253
253
  resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
254
+ logResubMessages: config.accountSubscription?.logResubMessages,
254
255
  commitment: config.accountSubscription?.commitment,
255
256
  };
256
257
  this.userStatsAccountSubscriptionConfig = {
257
258
  type: 'websocket',
258
259
  resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
260
+ logResubMessages: config.accountSubscription?.logResubMessages,
259
261
  commitment: config.accountSubscription?.commitment,
260
262
  };
261
263
  }
@@ -298,7 +300,10 @@ export class DriftClient {
298
300
  config.spotMarketIndexes ?? [],
299
301
  config.oracleInfos ?? [],
300
302
  noMarketsAndOraclesSpecified,
301
- config.accountSubscription?.resubTimeoutMs,
303
+ {
304
+ resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
305
+ logResubMessages: config.accountSubscription?.logResubMessages,
306
+ },
302
307
  config.accountSubscription?.commitment
303
308
  );
304
309
  }
@@ -6488,18 +6493,33 @@ export class DriftClient {
6488
6493
  }
6489
6494
 
6490
6495
  public async settleRevenueToInsuranceFund(
6491
- marketIndex: number
6496
+ spotMarketIndex: number,
6497
+ subAccountId?: number,
6498
+ txParams?: TxParams
6492
6499
  ): Promise<TransactionSignature> {
6493
- const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
6500
+ const tx = await this.buildTransaction(
6501
+ await this.getSettleRevenueToInsuranceFundIx(
6502
+ spotMarketIndex,
6503
+ subAccountId
6504
+ ),
6505
+ txParams
6506
+ );
6507
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
6508
+ return txSig;
6509
+ }
6494
6510
 
6511
+ public async getSettleRevenueToInsuranceFundIx(
6512
+ spotMarketIndex: number,
6513
+ subAccountId?: number
6514
+ ): Promise<TransactionInstruction> {
6515
+ const spotMarketAccount = this.getSpotMarketAccount(spotMarketIndex);
6495
6516
  const remainingAccounts = this.getRemainingAccounts({
6496
- userAccounts: [this.getUserAccount()],
6517
+ userAccounts: [this.getUserAccount(subAccountId)],
6497
6518
  useMarketLastSlotCache: true,
6498
- writableSpotMarketIndexes: [marketIndex],
6519
+ writableSpotMarketIndexes: [spotMarketIndex],
6499
6520
  });
6500
-
6501
6521
  const ix = await this.program.instruction.settleRevenueToInsuranceFund(
6502
- marketIndex,
6522
+ spotMarketIndex,
6503
6523
  {
6504
6524
  accounts: {
6505
6525
  state: await this.getStatePublicKey(),
@@ -6512,11 +6532,7 @@ export class DriftClient {
6512
6532
  remainingAccounts,
6513
6533
  }
6514
6534
  );
6515
-
6516
- const tx = await this.buildTransaction(ix);
6517
-
6518
- const { txSig } = await this.sendTransaction(tx, [], this.opts);
6519
- return txSig;
6535
+ return ix;
6520
6536
  }
6521
6537
 
6522
6538
  public async resolvePerpPnlDeficit(
@@ -6629,6 +6645,48 @@ export class DriftClient {
6629
6645
  return extendedInfo;
6630
6646
  }
6631
6647
 
6648
+ /**
6649
+ * Calculates taker / maker fee (as a percentage, e.g. .001 = 10 basis points) for particular marketType
6650
+ * @param marketType
6651
+ * @param positionMarketIndex
6652
+ * @returns : {takerFee: number, makerFee: number} Precision None
6653
+ */
6654
+ public getMarketFees(
6655
+ marketType: MarketType,
6656
+ marketIndex?: number,
6657
+ user?: User
6658
+ ) {
6659
+ let feeTier;
6660
+ if (user) {
6661
+ feeTier = user.getUserFeeTier(marketType);
6662
+ } else {
6663
+ const state = this.getStateAccount();
6664
+ feeTier = isVariant(marketType, 'perp')
6665
+ ? state.perpFeeStructure.feeTiers[0]
6666
+ : state.spotFeeStructure.feeTiers[0];
6667
+ }
6668
+
6669
+ let takerFee = feeTier.feeNumerator / feeTier.feeDenominator;
6670
+ let makerFee =
6671
+ feeTier.makerRebateNumerator / feeTier.makerRebateDenominator;
6672
+
6673
+ if (marketIndex !== undefined) {
6674
+ let marketAccount = null;
6675
+ if (isVariant(marketType, 'perp')) {
6676
+ marketAccount = this.getPerpMarketAccount(marketIndex);
6677
+ } else {
6678
+ marketAccount = this.getSpotMarketAccount(marketIndex);
6679
+ }
6680
+ takerFee += (takerFee * marketAccount.feeAdjustment) / 100;
6681
+ makerFee += (makerFee * marketAccount.feeAdjustment) / 100;
6682
+ }
6683
+
6684
+ return {
6685
+ takerFee,
6686
+ makerFee,
6687
+ };
6688
+ }
6689
+
6632
6690
  /**
6633
6691
  * Returns the market index and type for a given market name
6634
6692
  * E.g. "SOL-PERP" -> { marketIndex: 0, marketType: MarketType.PERP }
@@ -39,6 +39,7 @@ export type DriftClientSubscriptionConfig =
39
39
  | {
40
40
  type: 'websocket';
41
41
  resubTimeoutMs?: number;
42
+ logResubMessages?: boolean;
42
43
  commitment?: Commitment;
43
44
  }
44
45
  | {
@@ -39,7 +39,10 @@ export class OrderSubscriber {
39
39
  orderSubscriber: this,
40
40
  commitment: this.commitment,
41
41
  skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
42
- resubTimeoutMs: config.subscriptionConfig.resubTimeoutMs,
42
+ resubOpts: {
43
+ resubTimeoutMs: config.subscriptionConfig?.resubTimeoutMs,
44
+ logResubMessages: config.subscriptionConfig?.logResubMessages,
45
+ },
43
46
  resyncIntervalMs: config.subscriptionConfig.resyncIntervalMs,
44
47
  decoded: config.decodeData,
45
48
  });
@@ -3,12 +3,13 @@ import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
3
3
  import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
4
4
  import { UserAccount } from '../types';
5
5
  import { Commitment, Context, PublicKey } from '@solana/web3.js';
6
+ import { ResubOpts } from '../accounts/types';
6
7
 
7
8
  export class WebsocketSubscription {
8
9
  private orderSubscriber: OrderSubscriber;
9
10
  private commitment: Commitment;
10
11
  private skipInitialLoad: boolean;
11
- private resubTimeoutMs?: number;
12
+ private resubOpts?: ResubOpts;
12
13
  private resyncIntervalMs?: number;
13
14
 
14
15
  private subscriber?: WebSocketProgramAccountSubscriber<UserAccount>;
@@ -20,21 +21,21 @@ export class WebsocketSubscription {
20
21
  orderSubscriber,
21
22
  commitment,
22
23
  skipInitialLoad = false,
23
- resubTimeoutMs,
24
+ resubOpts,
24
25
  resyncIntervalMs,
25
26
  decoded = true,
26
27
  }: {
27
28
  orderSubscriber: OrderSubscriber;
28
29
  commitment: Commitment;
29
30
  skipInitialLoad?: boolean;
30
- resubTimeoutMs?: number;
31
+ resubOpts?: ResubOpts;
31
32
  resyncIntervalMs?: number;
32
33
  decoded?: boolean;
33
34
  }) {
34
35
  this.orderSubscriber = orderSubscriber;
35
36
  this.commitment = commitment;
36
37
  this.skipInitialLoad = skipInitialLoad;
37
- this.resubTimeoutMs = resubTimeoutMs;
38
+ this.resubOpts = resubOpts;
38
39
  this.resyncIntervalMs = resyncIntervalMs;
39
40
  this.decoded = decoded;
40
41
  }
@@ -53,7 +54,7 @@ export class WebsocketSubscription {
53
54
  filters: [getUserFilter(), getNonIdleUserFilter()],
54
55
  commitment: this.commitment,
55
56
  },
56
- this.resubTimeoutMs
57
+ this.resubOpts
57
58
  );
58
59
 
59
60
  await this.subscriber.subscribe(
@@ -14,6 +14,7 @@ export type OrderSubscriberConfig = {
14
14
  type: 'websocket';
15
15
  skipInitialLoad?: boolean;
16
16
  resubTimeoutMs?: number;
17
+ logResubMessages?: boolean;
17
18
  resyncIntervalMs?: number;
18
19
  commitment?: Commitment;
19
20
  };
@@ -1,18 +1,30 @@
1
1
  import fetch from 'node-fetch';
2
- import { HeliusPriorityFeeLevels } from './heliusPriorityFeeMethod';
2
+ import { HeliusPriorityLevel } from './heliusPriorityFeeMethod';
3
3
 
4
- export type DriftPriorityFeeResponse = HeliusPriorityFeeLevels[];
4
+ export type DriftMarketInfo = {
5
+ marketType: string;
6
+ marketIndex: number;
7
+ };
8
+
9
+ export type DriftPriorityFeeLevels = {
10
+ [key in HeliusPriorityLevel]: number;
11
+ } & {
12
+ marketType: 'perp' | 'spot';
13
+ marketIndex: number;
14
+ };
15
+
16
+ export type DriftPriorityFeeResponse = DriftPriorityFeeLevels[];
5
17
 
6
18
  export async function fetchDriftPriorityFee(
7
19
  url: string,
8
20
  marketTypes: string[],
9
- marketIndexs: number[]
21
+ marketIndexes: number[]
10
22
  ): Promise<DriftPriorityFeeResponse> {
11
23
  try {
12
24
  const response = await fetch(
13
25
  `${url}/batchPriorityFees?marketType=${marketTypes.join(
14
26
  ','
15
- )}&marketIndex=${marketIndexs.join(',')}`
27
+ )}&marketIndex=${marketIndexes.join(',')}`
16
28
  );
17
29
  if (!response.ok) {
18
30
  throw new Error(`HTTP error! status: ${response.status}`);
@@ -4,6 +4,8 @@ export * from './ewmaStrategy';
4
4
  export * from './maxOverSlotsStrategy';
5
5
  export * from './maxStrategy';
6
6
  export * from './priorityFeeSubscriber';
7
+ export * from './priorityFeeSubscriberMap';
7
8
  export * from './solanaPriorityFeeMethod';
8
9
  export * from './heliusPriorityFeeMethod';
10
+ export * from './driftPriorityFeeMethod';
9
11
  export * from './types';
@@ -1,5 +1,6 @@
1
1
  import { Connection, PublicKey } from '@solana/web3.js';
2
2
  import {
3
+ DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS,
3
4
  PriorityFeeMethod,
4
5
  PriorityFeeStrategy,
5
6
  PriorityFeeSubscriberConfig,
@@ -12,12 +13,10 @@ import {
12
13
  HeliusPriorityLevel,
13
14
  fetchHeliusPriorityFee,
14
15
  } from './heliusPriorityFeeMethod';
15
- import { fetchDriftPriorityFee } from './driftPriorityFeeMethod';
16
-
17
- export type DriftMarketInfo = {
18
- marketType: string;
19
- marketIndex: number;
20
- };
16
+ import {
17
+ fetchDriftPriorityFee,
18
+ DriftMarketInfo,
19
+ } from './driftPriorityFeeMethod';
21
20
 
22
21
  export class PriorityFeeSubscriber {
23
22
  connection: Connection;
@@ -46,7 +45,8 @@ export class PriorityFeeSubscriber {
46
45
 
47
46
  public constructor(config: PriorityFeeSubscriberConfig) {
48
47
  this.connection = config.connection;
49
- this.frequencyMs = config.frequencyMs;
48
+ this.frequencyMs =
49
+ config.frequencyMs ?? DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS;
50
50
  this.addresses = config.addresses
51
51
  ? config.addresses.map((address) => address.toBase58())
52
52
  : [];
@@ -0,0 +1,112 @@
1
+ import {
2
+ DriftMarketInfo,
3
+ DriftPriorityFeeLevels,
4
+ DriftPriorityFeeResponse,
5
+ fetchDriftPriorityFee,
6
+ } from './driftPriorityFeeMethod';
7
+ import {
8
+ DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS,
9
+ PriorityFeeSubscriberMapConfig,
10
+ } from './types';
11
+
12
+ /**
13
+ * takes advantage of /batchPriorityFees endpoint from drift hosted priority fee service
14
+ */
15
+ export class PriorityFeeSubscriberMap {
16
+ frequencyMs: number;
17
+ intervalId?: ReturnType<typeof setTimeout>;
18
+
19
+ driftMarkets?: DriftMarketInfo[];
20
+ driftPriorityFeeEndpoint?: string;
21
+ feesMap: Map<string, Map<number, DriftPriorityFeeLevels>>; // marketType -> marketIndex -> priority fee
22
+
23
+ public constructor(config: PriorityFeeSubscriberMapConfig) {
24
+ this.frequencyMs = config.frequencyMs;
25
+ this.frequencyMs =
26
+ config.frequencyMs ?? DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS;
27
+ this.driftPriorityFeeEndpoint = config.driftPriorityFeeEndpoint;
28
+ this.driftMarkets = config.driftMarkets;
29
+ this.feesMap = new Map<string, Map<number, DriftPriorityFeeLevels>>();
30
+ this.feesMap.set('perp', new Map<number, DriftPriorityFeeLevels>());
31
+ this.feesMap.set('spot', new Map<number, DriftPriorityFeeLevels>());
32
+ }
33
+
34
+ private updateFeesMap(driftPriorityFeeResponse: DriftPriorityFeeResponse) {
35
+ driftPriorityFeeResponse.forEach((fee: DriftPriorityFeeLevels) => {
36
+ this.feesMap.get(fee.marketType)!.set(fee.marketIndex, fee);
37
+ });
38
+ }
39
+
40
+ public async subscribe(): Promise<void> {
41
+ if (this.intervalId) {
42
+ return;
43
+ }
44
+
45
+ await this.load();
46
+ this.intervalId = setInterval(this.load.bind(this), this.frequencyMs);
47
+ }
48
+
49
+ public async unsubscribe(): Promise<void> {
50
+ if (this.intervalId) {
51
+ clearInterval(this.intervalId);
52
+ this.intervalId = undefined;
53
+ }
54
+ }
55
+
56
+ public async load(): Promise<void> {
57
+ try {
58
+ if (!this.driftMarkets) {
59
+ return;
60
+ }
61
+ const fees = await fetchDriftPriorityFee(
62
+ this.driftPriorityFeeEndpoint!,
63
+ this.driftMarkets.map((m) => m.marketType),
64
+ this.driftMarkets.map((m) => m.marketIndex)
65
+ );
66
+ this.updateFeesMap(fees);
67
+ } catch (e) {
68
+ console.error('Error fetching drift priority fees', e);
69
+ }
70
+ }
71
+
72
+ public updateMarketTypeAndIndex(driftMarkets: DriftMarketInfo[]) {
73
+ this.driftMarkets = driftMarkets;
74
+ }
75
+
76
+ public getPriorityFees(
77
+ marketType: string,
78
+ marketIndex: number
79
+ ): DriftPriorityFeeLevels | undefined {
80
+ return this.feesMap.get(marketType)?.get(marketIndex);
81
+ }
82
+ }
83
+
84
+ /** Example usage:
85
+ async function main() {
86
+ const driftMarkets: DriftMarketInfo[] = [
87
+ { marketType: 'perp', marketIndex: 0 },
88
+ { marketType: 'perp', marketIndex: 1 },
89
+ { marketType: 'spot', marketIndex: 2 }
90
+ ];
91
+
92
+ const subscriber = new PriorityFeeSubscriberMap({
93
+ driftPriorityFeeEndpoint: 'https://dlob.drift.trade',
94
+ frequencyMs: 5000,
95
+ driftMarkets
96
+ });
97
+ await subscriber.subscribe();
98
+
99
+ for (let i = 0; i < 20; i++) {
100
+ await new Promise(resolve => setTimeout(resolve, 1000));
101
+ driftMarkets.forEach(market => {
102
+ const fees = subscriber.getPriorityFees(market.marketType, market.marketIndex);
103
+ console.log(`Priority fees for ${market.marketType} market ${market.marketIndex}:`, fees);
104
+ });
105
+ }
106
+
107
+
108
+ await subscriber.unsubscribe();
109
+ }
110
+
111
+ main().catch(console.error);
112
+ */
@@ -1,8 +1,12 @@
1
1
  import { Connection, PublicKey } from '@solana/web3.js';
2
2
  import { SolanaPriorityFeeResponse } from './solanaPriorityFeeMethod';
3
3
  import { HeliusPriorityFeeResponse } from './heliusPriorityFeeMethod';
4
- import { DriftMarketInfo } from './priorityFeeSubscriber';
5
- import { DriftPriorityFeeResponse } from './driftPriorityFeeMethod';
4
+ import {
5
+ DriftMarketInfo,
6
+ DriftPriorityFeeResponse,
7
+ } from './driftPriorityFeeMethod';
8
+
9
+ export const DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS = 10_000;
6
10
 
7
11
  export interface PriorityFeeStrategy {
8
12
  // calculate the priority fee for a given set of samples.
@@ -25,7 +29,7 @@ export type PriorityFeeSubscriberConfig = {
25
29
  /// rpc connection, optional if using priorityFeeMethod.HELIUS
26
30
  connection?: Connection;
27
31
  /// frequency to make RPC calls to update priority fee samples, in milliseconds
28
- frequencyMs: number;
32
+ frequencyMs?: number;
29
33
  /// addresses you plan to write lock, used to determine priority fees
30
34
  addresses?: PublicKey[];
31
35
  /// drift market type and index, optionally provide at initialization time if using priorityFeeMethod.DRIFT
@@ -45,3 +49,12 @@ export type PriorityFeeSubscriberConfig = {
45
49
  /// multiplier applied to priority fee before maxFeeMicroLamports, defaults to 1.0
46
50
  priorityFeeMultiplier?: number;
47
51
  };
52
+
53
+ export type PriorityFeeSubscriberMapConfig = {
54
+ /// frequency to make RPC calls to update priority fee samples, in milliseconds
55
+ frequencyMs?: number;
56
+ /// drift market type and associated market index to query
57
+ driftMarkets?: DriftMarketInfo[];
58
+ /// url for drift cached priority fee endpoint
59
+ driftPriorityFeeEndpoint: string;
60
+ };
@@ -2,6 +2,7 @@ import {
2
2
  ConfirmationStrategy,
3
3
  ExtraConfirmationOptions,
4
4
  TxSender,
5
+ TxSendError,
5
6
  TxSigAndSlot,
6
7
  } from './types';
7
8
  import {
@@ -25,6 +26,7 @@ import bs58 from 'bs58';
25
26
  import { IWallet } from '../types';
26
27
 
27
28
  const DEFAULT_TIMEOUT = 35000;
29
+ const NOT_CONFIRMED_ERROR_CODE = -1001;
28
30
 
29
31
  export abstract class BaseTxSender implements TxSender {
30
32
  connection: Connection;
@@ -282,10 +284,11 @@ export abstract class BaseTxSender implements TxSender {
282
284
  }
283
285
  this.timeoutCount += 1;
284
286
  const duration = (Date.now() - start) / 1000;
285
- throw new Error(
287
+ throw new TxSendError(
286
288
  `Transaction was not confirmed in ${duration.toFixed(
287
289
  2
288
- )} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`
290
+ )} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`,
291
+ NOT_CONFIRMED_ERROR_CODE
289
292
  );
290
293
  }
291
294
 
@@ -317,10 +320,11 @@ export abstract class BaseTxSender implements TxSender {
317
320
  // Transaction not confirmed within 30 seconds
318
321
  this.timeoutCount += 1;
319
322
  const duration = (Date.now() - start) / 1000;
320
- throw new Error(
323
+ throw new TxSendError(
321
324
  `Transaction was not confirmed in ${duration.toFixed(
322
325
  2
323
- )} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`
326
+ )} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`,
327
+ NOT_CONFIRMED_ERROR_CODE
324
328
  );
325
329
  }
326
330
 
package/src/tx/types.ts CHANGED
@@ -60,3 +60,15 @@ export interface TxSender {
60
60
 
61
61
  getTimeoutCount(): number;
62
62
  }
63
+
64
+ export class TxSendError extends Error {
65
+ constructor(
66
+ public message: string,
67
+ public code: number
68
+ ) {
69
+ super(message);
70
+ if (Error.captureStackTrace) {
71
+ Error.captureStackTrace(this, TxSendError);
72
+ }
73
+ }
74
+ }
package/src/tx/utils.ts CHANGED
@@ -53,7 +53,11 @@ export async function getSignedTransactionMap(
53
53
  });
54
54
 
55
55
  const signedTxs = await wallet.signAllTransactions(
56
- txsToSign.filter((tx) => tx !== undefined)
56
+ txsToSign
57
+ .map((tx) => {
58
+ return tx as Transaction;
59
+ })
60
+ .filter((tx) => tx !== undefined)
57
61
  );
58
62
 
59
63
  signedTxs.forEach((signedTx, index) => {
package/src/user.ts CHANGED
@@ -118,7 +118,10 @@ export class User {
118
118
  this.accountSubscriber = new WebSocketUserAccountSubscriber(
119
119
  config.driftClient.program,
120
120
  config.userAccountPublicKey,
121
- config.accountSubscription?.resubTimeoutMs,
121
+ {
122
+ resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
123
+ logResubMessages: config.accountSubscription?.logResubMessages,
124
+ },
122
125
  config.accountSubscription?.commitment
123
126
  );
124
127
  }
@@ -3162,35 +3165,6 @@ export class User {
3162
3165
  return state.spotFeeStructure.feeTiers[feeTierIndex];
3163
3166
  }
3164
3167
 
3165
- /**
3166
- * Calculates taker / maker fee (as a percentage, e.g. .001 = 10 basis points) for particular marketType
3167
- * @param marketType
3168
- * @param positionMarketIndex
3169
- * @returns : {takerFee: number, makerFee: number} Precision None
3170
- */
3171
- public getMarketFees(marketType: MarketType, marketIndex?: number) {
3172
- const feeTier = this.getUserFeeTier(marketType);
3173
- let takerFee = feeTier.feeNumerator / feeTier.feeDenominator;
3174
- let makerFee =
3175
- feeTier.makerRebateNumerator / feeTier.makerRebateDenominator;
3176
-
3177
- if (marketIndex !== undefined) {
3178
- let marketAccount = null;
3179
- if (isVariant(marketType, 'perp')) {
3180
- marketAccount = this.driftClient.getPerpMarketAccount(marketIndex);
3181
- } else {
3182
- marketAccount = this.driftClient.getSpotMarketAccount(marketIndex);
3183
- }
3184
- takerFee += (takerFee * marketAccount.feeAdjustment) / 100;
3185
- makerFee += (makerFee * marketAccount.feeAdjustment) / 100;
3186
- }
3187
-
3188
- return {
3189
- takerFee,
3190
- makerFee,
3191
- };
3192
- }
3193
-
3194
3168
  /**
3195
3169
  * Calculates how much perp fee will be taken for a given sized trade
3196
3170
  * @param quoteAmount
@@ -3198,9 +3172,10 @@ export class User {
3198
3172
  */
3199
3173
  public calculateFeeForQuoteAmount(quoteAmount: BN, marketIndex?: number): BN {
3200
3174
  if (marketIndex !== undefined) {
3201
- const takerFeeMultiplier = this.getMarketFees(
3175
+ const takerFeeMultiplier = this.driftClient.getMarketFees(
3202
3176
  MarketType.PERP,
3203
- marketIndex
3177
+ marketIndex,
3178
+ this
3204
3179
  ).takerFee;
3205
3180
  const feeAmountNum =
3206
3181
  BigNum.from(quoteAmount, QUOTE_PRECISION_EXP).toNum() *
package/src/userConfig.ts CHANGED
@@ -13,6 +13,7 @@ export type UserSubscriptionConfig =
13
13
  | {
14
14
  type: 'websocket';
15
15
  resubTimeoutMs?: number;
16
+ logResubMessages?: boolean;
16
17
  commitment?: Commitment;
17
18
  }
18
19
  | {