@drift-labs/sdk 2.77.0-beta.0 → 2.77.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.77.0-beta.0
1
+ 2.77.0-beta.1
@@ -112,7 +112,8 @@ export declare class DriftClient {
112
112
  * Adds and subscribes to users based on params set by the constructor or by updateWallet.
113
113
  */
114
114
  addAndSubscribeToUsers(): Promise<boolean>;
115
- initializeUserAccount(subAccountId?: number, name?: string, referrerInfo?: ReferrerInfo): Promise<[TransactionSignature, PublicKey]>;
115
+ private getProcessedTransactionParams;
116
+ initializeUserAccount(subAccountId?: number, name?: string, referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<[TransactionSignature, PublicKey]>;
116
117
  getInitializeUserInstructions(subAccountId?: number, name?: string, referrerInfo?: ReferrerInfo): Promise<[PublicKey, TransactionInstruction]>;
117
118
  getInitializeUserStatsIx(): Promise<TransactionInstruction>;
118
119
  getNextSubAccountId(): Promise<number>;
@@ -249,7 +250,7 @@ export declare class DriftClient {
249
250
  * @returns
250
251
  */
251
252
  initializeUserAccountAndDepositCollateral(amount: BN, userTokenAccount: PublicKey, marketIndex?: number, subAccountId?: number, name?: string, fromSubAccountId?: number, referrerInfo?: ReferrerInfo, donateAmount?: BN, txParams?: TxParams, customMaxMarginRatio?: number): Promise<[TransactionSignature, PublicKey]>;
252
- initializeUserAccountForDevnet(subAccountId: number, name: string, marketIndex: number, tokenFaucet: TokenFaucet, amount: BN, referrerInfo?: ReferrerInfo): Promise<[TransactionSignature, PublicKey]>;
253
+ initializeUserAccountForDevnet(subAccountId: number, name: string, marketIndex: number, tokenFaucet: TokenFaucet, amount: BN, referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<[TransactionSignature, PublicKey]>;
253
254
  /**
254
255
  * Withdraws from a user account. If deposit doesn't already exist, creates a borrow
255
256
  * @param amount
@@ -661,6 +662,15 @@ export declare class DriftClient {
661
662
  } | undefined;
662
663
  private handleSignedTransaction;
663
664
  sendTransaction(tx: Transaction | VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
664
- buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[]): Promise<Transaction | VersionedTransaction>;
665
+ /**
666
+ *
667
+ * @param instructions
668
+ * @param txParams
669
+ * @param txVersion
670
+ * @param lookupTables
671
+ * @param forceVersionedTransaction Return a VersionedTransaction instance even if the version of the transaction is Legacy
672
+ * @returns
673
+ */
674
+ buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<Transaction | VersionedTransaction>;
665
675
  }
666
676
  export {};
@@ -56,6 +56,7 @@ const memcmp_1 = require("./memcmp");
56
56
  const marinade_1 = require("./marinade");
57
57
  const orderParams_1 = require("./orderParams");
58
58
  const utils_2 = require("./math/utils");
59
+ const txParamProcessor_1 = require("./tx/txParamProcessor");
59
60
  /**
60
61
  * # DriftClient
61
62
  * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
@@ -437,7 +438,23 @@ class DriftClient {
437
438
  }
438
439
  return result;
439
440
  }
440
- async initializeUserAccount(subAccountId = 0, name, referrerInfo) {
441
+ async getProcessedTransactionParams(txParams, txParamProcessingParams) {
442
+ const tx = await txParamProcessor_1.TransactionProcessor.process({
443
+ txProps: {
444
+ instructions: txParams.instructions,
445
+ txParams: txParams.txParams,
446
+ txVersion: txParams.txVersion,
447
+ lookupTables: txParams.lookupTables,
448
+ },
449
+ txBuilder: (updatedTxParams) => this.buildTransaction(updatedTxParams.instructions, updatedTxParams === null || updatedTxParams === void 0 ? void 0 : updatedTxParams.txParams, updatedTxParams.txVersion, updatedTxParams.lookupTables, true),
450
+ processConfig: txParamProcessingParams,
451
+ processParams: {
452
+ connection: this.connection,
453
+ },
454
+ });
455
+ return tx;
456
+ }
457
+ async initializeUserAccount(subAccountId = 0, name, referrerInfo, txParams) {
441
458
  const initializeIxs = [];
442
459
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(subAccountId, name, referrerInfo);
443
460
  if (subAccountId === 0) {
@@ -446,7 +463,7 @@ class DriftClient {
446
463
  }
447
464
  }
448
465
  initializeIxs.push(initializeUserAccountIx);
449
- const tx = await this.buildTransaction(initializeIxs);
466
+ const tx = await this.buildTransaction(initializeIxs, txParams);
450
467
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
451
468
  await this.addUser(subAccountId);
452
469
  return [txSig, userAccountPublicKey];
@@ -1147,21 +1164,11 @@ class DriftClient {
1147
1164
  * @returns
1148
1165
  */
1149
1166
  async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, marketIndex = 0, subAccountId = 0, name, fromSubAccountId, referrerInfo, donateAmount, txParams, customMaxMarginRatio) {
1150
- var _a;
1151
1167
  const ixs = [];
1152
1168
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(subAccountId, name, referrerInfo);
1153
1169
  const additionalSigners = [];
1154
1170
  const spotMarket = this.getSpotMarketAccount(marketIndex);
1155
1171
  const isSolMarket = spotMarket.mint.equals(spotMarkets_1.WRAPPED_SOL_MINT);
1156
- let params = {
1157
- computeUnits: (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a : 600000,
1158
- };
1159
- if (txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice) {
1160
- params = {
1161
- ...params,
1162
- computeUnitsPrice: txParams.computeUnitsPrice,
1163
- };
1164
- }
1165
1172
  const authority = this.wallet.publicKey;
1166
1173
  const isFromSubaccount = fromSubAccountId !== null &&
1167
1174
  fromSubAccountId !== undefined &&
@@ -1203,13 +1210,13 @@ class DriftClient {
1203
1210
  if (createWSOLTokenAccount) {
1204
1211
  ixs.push((0, spl_token_1.createCloseAccountInstruction)(wsolTokenAccount, authority, authority, []));
1205
1212
  }
1206
- const tx = await this.buildTransaction(ixs, params);
1213
+ const tx = await this.buildTransaction(ixs, txParams);
1207
1214
  const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
1208
1215
  this.spotMarketLastSlotCache.set(marketIndex, slot);
1209
1216
  await this.addUser(subAccountId);
1210
1217
  return [txSig, userAccountPublicKey];
1211
1218
  }
1212
- async initializeUserAccountForDevnet(subAccountId = 0, name = userName_1.DEFAULT_USER_NAME, marketIndex, tokenFaucet, amount, referrerInfo) {
1219
+ async initializeUserAccountForDevnet(subAccountId = 0, name = userName_1.DEFAULT_USER_NAME, marketIndex, tokenFaucet, amount, referrerInfo, txParams) {
1213
1220
  const ixs = [];
1214
1221
  const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
1215
1222
  const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(subAccountId, name, referrerInfo);
@@ -1221,7 +1228,7 @@ class DriftClient {
1221
1228
  }
1222
1229
  }
1223
1230
  ixs.push(initializeUserAccountIx, depositCollateralIx);
1224
- const tx = await this.buildTransaction(ixs);
1231
+ const tx = await this.buildTransaction(ixs, txParams);
1225
1232
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
1226
1233
  await this.addUser(subAccountId);
1227
1234
  return [txSig, userAccountPublicKey];
@@ -1258,10 +1265,7 @@ class DriftClient {
1258
1265
  if (createWSOLTokenAccount) {
1259
1266
  withdrawIxs.push((0, spl_token_1.createCloseAccountInstruction)(associatedTokenAddress, authority, authority, []));
1260
1267
  }
1261
- const tx = await this.buildTransaction(withdrawIxs, {
1262
- ...(txParams !== null && txParams !== void 0 ? txParams : this.txParams),
1263
- computeUnits: 1400000,
1264
- });
1268
+ const tx = await this.buildTransaction(withdrawIxs, txParams !== null && txParams !== void 0 ? txParams : this.txParams);
1265
1269
  const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
1266
1270
  this.spotMarketLastSlotCache.set(marketIndex, slot);
1267
1271
  return txSig;
@@ -2512,12 +2516,26 @@ class DriftClient {
2512
2516
  const bracketOrdersIx = await this.getPlaceOrdersIx(bracketOrdersParams, subAccountId);
2513
2517
  ixs.push(bracketOrdersIx);
2514
2518
  }
2515
- const placeAndTakeTx = (await this.buildTransaction(ixs, txParams));
2516
- // if param is passed, return early before the tx fails so ui can fallback to placeOrder
2517
- if (simulateFirst) {
2518
- const success = await this.txSender.simulateTransaction(placeAndTakeTx);
2519
- if (!success)
2519
+ const shouldUseSimulationComputeUnits = txParams === null || txParams === void 0 ? void 0 : txParams.useSimulatedComputeUnits;
2520
+ const shouldExitIfSimulationFails = simulateFirst;
2521
+ const txParamsWithoutImplicitSimulation = {
2522
+ ...txParams,
2523
+ useSimulationComputeUnits: false,
2524
+ };
2525
+ let placeAndTakeTx = await this.buildTransaction(ixs, txParamsWithoutImplicitSimulation);
2526
+ if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
2527
+ const simulationResult = await txParamProcessor_1.TransactionProcessor.getTxSimComputeUnits(
2528
+ // @ts-ignore :: TODO - TEST WITH LEGACY TRANSACTION
2529
+ placeAndTakeTx, this.connection);
2530
+ if (shouldExitIfSimulationFails && !simulationResult.success) {
2520
2531
  return;
2532
+ }
2533
+ if (shouldUseSimulationComputeUnits) {
2534
+ placeAndTakeTx = await this.buildTransaction(ixs, {
2535
+ ...txParamsWithoutImplicitSimulation,
2536
+ computeUnits: simulationResult.computeUnits,
2537
+ });
2538
+ }
2521
2539
  }
2522
2540
  let cancelExistingOrdersTx;
2523
2541
  if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
@@ -3506,23 +3524,63 @@ class DriftClient {
3506
3524
  onSignedCb: this.handleSignedTransaction.bind(this),
3507
3525
  }
3508
3526
  : undefined;
3509
- if (tx instanceof web3_js_1.VersionedTransaction) {
3527
+ const version = tx === null || tx === void 0 ? void 0 : tx.version;
3528
+ const isVersionedTx = tx instanceof web3_js_1.VersionedTransaction || version !== undefined;
3529
+ if (isVersionedTx) {
3510
3530
  return this.txSender.sendVersionedTransaction(tx, additionalSigners, opts, preSigned, extraConfirmationOptions);
3511
3531
  }
3512
3532
  else {
3513
3533
  return this.txSender.send(tx, additionalSigners, opts, preSigned, extraConfirmationOptions);
3514
3534
  }
3515
3535
  }
3516
- async buildTransaction(instructions, txParams, txVersion, lookupTables) {
3536
+ /**
3537
+ *
3538
+ * @param instructions
3539
+ * @param txParams
3540
+ * @param txVersion
3541
+ * @param lookupTables
3542
+ * @param forceVersionedTransaction Return a VersionedTransaction instance even if the version of the transaction is Legacy
3543
+ * @returns
3544
+ */
3545
+ async buildTransaction(instructions, txParams, txVersion, lookupTables, forceVersionedTransaction) {
3517
3546
  var _a, _b;
3547
+ txVersion = txVersion !== null && txVersion !== void 0 ? txVersion : this.txVersion;
3548
+ // # Collect and process Tx Params
3549
+ let baseTxParams = {
3550
+ computeUnits: (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a : this.txParams.computeUnits,
3551
+ computeUnitsPrice: (_b = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice) !== null && _b !== void 0 ? _b : this.txParams.computeUnitsPrice,
3552
+ };
3553
+ if (txParams === null || txParams === void 0 ? void 0 : txParams.useSimulatedComputeUnits) {
3554
+ const splitTxParams = {
3555
+ baseTxParams: {
3556
+ computeUnits: txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits,
3557
+ computeUnitsPrice: txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice,
3558
+ },
3559
+ txParamProcessingParams: {
3560
+ useSimulatedComputeUnits: txParams === null || txParams === void 0 ? void 0 : txParams.useSimulatedComputeUnits,
3561
+ computeUnitsBufferMultiplier: txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsBufferMultiplier,
3562
+ },
3563
+ };
3564
+ const processedTxParams = await this.getProcessedTransactionParams({
3565
+ instructions,
3566
+ txParams: splitTxParams.baseTxParams,
3567
+ txVersion,
3568
+ lookupTables,
3569
+ }, splitTxParams.txParamProcessingParams);
3570
+ baseTxParams = {
3571
+ ...baseTxParams,
3572
+ ...processedTxParams,
3573
+ };
3574
+ }
3575
+ // # Create Tx Instructions
3518
3576
  const allIx = [];
3519
- const computeUnits = (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a : this.txParams.computeUnits;
3577
+ const computeUnits = baseTxParams === null || baseTxParams === void 0 ? void 0 : baseTxParams.computeUnits;
3520
3578
  if (computeUnits !== 200000) {
3521
3579
  allIx.push(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
3522
3580
  units: computeUnits,
3523
3581
  }));
3524
3582
  }
3525
- const computeUnitsPrice = (_b = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice) !== null && _b !== void 0 ? _b : this.txParams.computeUnitsPrice;
3583
+ const computeUnitsPrice = baseTxParams === null || baseTxParams === void 0 ? void 0 : baseTxParams.computeUnitsPrice;
3526
3584
  if (computeUnitsPrice !== 0) {
3527
3585
  allIx.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
3528
3586
  microLamports: computeUnitsPrice,
@@ -3534,9 +3592,22 @@ class DriftClient {
3534
3592
  else {
3535
3593
  allIx.push(instructions);
3536
3594
  }
3537
- txVersion = txVersion !== null && txVersion !== void 0 ? txVersion : this.txVersion;
3595
+ const latestBlockHashAndContext = await this.connection.getLatestBlockhashAndContext({
3596
+ commitment: this.opts.preflightCommitment,
3597
+ });
3598
+ // # Create and return Transaction
3538
3599
  if (txVersion === 'legacy') {
3539
- return new web3_js_1.Transaction().add(...allIx);
3600
+ if (forceVersionedTransaction) {
3601
+ const message = new web3_js_1.TransactionMessage({
3602
+ payerKey: this.provider.wallet.publicKey,
3603
+ recentBlockhash: latestBlockHashAndContext.value.blockhash,
3604
+ instructions: allIx,
3605
+ }).compileToLegacyMessage();
3606
+ return new web3_js_1.VersionedTransaction(message);
3607
+ }
3608
+ else {
3609
+ return new web3_js_1.Transaction().add(...allIx);
3610
+ }
3540
3611
  }
3541
3612
  else {
3542
3613
  const marketLookupTable = await this.fetchMarketLookupTableAccount();
@@ -3545,7 +3616,7 @@ class DriftClient {
3545
3616
  : [marketLookupTable];
3546
3617
  const message = new web3_js_1.TransactionMessage({
3547
3618
  payerKey: this.provider.wallet.publicKey,
3548
- recentBlockhash: (await this.provider.connection.getRecentBlockhash(this.opts.preflightCommitment)).blockhash,
3619
+ recentBlockhash: latestBlockHashAndContext.value.blockhash,
3549
3620
  instructions: allIx,
3550
3621
  }).compileToV0Message(lookupTables);
3551
3622
  return new web3_js_1.VersionedTransaction(message);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.76.0",
2
+ "version": "2.75.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -1,3 +1,3 @@
1
1
  import { HeliusPriorityFeeLevels } from './heliusPriorityFeeMethod';
2
2
  export type DriftPriorityFeeResponse = HeliusPriorityFeeLevels[];
3
- export declare function fetchDriftPriorityFee(url: string, marketType: string, marketIndex: number): Promise<DriftPriorityFeeResponse>;
3
+ export declare function fetchDriftPriorityFee(url: string, marketTypes: string[], marketIndexs: number[]): Promise<DriftPriorityFeeResponse>;
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.fetchDriftPriorityFee = void 0;
7
7
  const node_fetch_1 = __importDefault(require("node-fetch"));
8
- async function fetchDriftPriorityFee(url, marketType, marketIndex) {
9
- const response = await (0, node_fetch_1.default)(`${url}?marketType=${marketType}&marketIndex=${marketIndex}`);
8
+ async function fetchDriftPriorityFee(url, marketTypes, marketIndexs) {
9
+ const response = await (0, node_fetch_1.default)(`${url}/batchPriorityFees?marketType=${marketTypes.join(',')}&marketIndex=${marketIndexs.join(',')}`);
10
10
  return await response.json();
11
11
  }
12
12
  exports.fetchDriftPriorityFee = fetchDriftPriorityFee;
@@ -3,7 +3,6 @@ import { PriorityFeeMethod, PriorityFeeStrategy, PriorityFeeSubscriberConfig } f
3
3
  import { AverageOverSlotsStrategy } from './averageOverSlotsStrategy';
4
4
  import { MaxOverSlotsStrategy } from './maxOverSlotsStrategy';
5
5
  import { HeliusPriorityFeeLevels, HeliusPriorityLevel } from './heliusPriorityFeeMethod';
6
- import { MarketType } from '..';
7
6
  export type DriftMarketInfo = {
8
7
  marketType: string;
9
8
  marketIndex: number;
@@ -12,7 +11,7 @@ export declare class PriorityFeeSubscriber {
12
11
  connection: Connection;
13
12
  frequencyMs: number;
14
13
  addresses: string[];
15
- driftMarket?: DriftMarketInfo;
14
+ driftMarkets?: DriftMarketInfo[];
16
15
  customStrategy?: PriorityFeeStrategy;
17
16
  averageStrategy: AverageOverSlotsStrategy;
18
17
  maxStrategy: MaxOverSlotsStrategy;
@@ -46,5 +45,5 @@ export declare class PriorityFeeSubscriber {
46
45
  load(): Promise<void>;
47
46
  unsubscribe(): Promise<void>;
48
47
  updateAddresses(addresses: PublicKey[]): void;
49
- updateMarketTypeAndIndex(marketType: MarketType, marketIndex: number): void;
48
+ updateMarketTypeAndIndex(driftMarkets: DriftMarketInfo[]): void;
50
49
  }
@@ -7,7 +7,6 @@ const maxOverSlotsStrategy_1 = require("./maxOverSlotsStrategy");
7
7
  const solanaPriorityFeeMethod_1 = require("./solanaPriorityFeeMethod");
8
8
  const heliusPriorityFeeMethod_1 = require("./heliusPriorityFeeMethod");
9
9
  const driftPriorityFeeMethod_1 = require("./driftPriorityFeeMethod");
10
- const __1 = require("..");
11
10
  class PriorityFeeSubscriber {
12
11
  constructor(config) {
13
12
  var _a, _b;
@@ -24,7 +23,7 @@ class PriorityFeeSubscriber {
24
23
  this.addresses = config.addresses
25
24
  ? config.addresses.map((address) => address.toBase58())
26
25
  : [];
27
- this.driftMarket = config.driftMarket;
26
+ this.driftMarkets = config.driftMarkets;
28
27
  if (config.customStrategy) {
29
28
  this.customStrategy = config.customStrategy;
30
29
  }
@@ -91,22 +90,15 @@ class PriorityFeeSubscriber {
91
90
  }
92
91
  }
93
92
  async loadForDrift() {
94
- if (!this.driftMarket) {
93
+ if (!this.driftMarkets) {
95
94
  return;
96
95
  }
97
- const sample = await (0, driftPriorityFeeMethod_1.fetchDriftPriorityFee)(this.driftPriorityFeeEndpoint, this.driftMarket.marketType, this.driftMarket.marketIndex);
96
+ const sample = await (0, driftPriorityFeeMethod_1.fetchDriftPriorityFee)(this.driftPriorityFeeEndpoint, this.driftMarkets.map((m) => m.marketType), this.driftMarkets.map((m) => m.marketIndex));
98
97
  if (sample.length > 0) {
99
98
  this.lastAvgStrategyResult = sample[heliusPriorityFeeMethod_1.HeliusPriorityLevel.MEDIUM];
100
99
  this.lastMaxStrategyResult = sample[heliusPriorityFeeMethod_1.HeliusPriorityLevel.UNSAFE_MAX];
101
100
  if (this.customStrategy) {
102
- // stay compatible with helius response
103
- this.lastCustomStrategyResult = this.customStrategy.calculate({
104
- jsonrpc: '',
105
- result: {
106
- priorityFeeLevels: sample[0],
107
- },
108
- id: '',
109
- });
101
+ this.lastCustomStrategyResult = this.customStrategy.calculate(sample);
110
102
  }
111
103
  }
112
104
  }
@@ -186,8 +178,8 @@ class PriorityFeeSubscriber {
186
178
  updateAddresses(addresses) {
187
179
  this.addresses = addresses.map((k) => k.toBase58());
188
180
  }
189
- updateMarketTypeAndIndex(marketType, marketIndex) {
190
- this.driftMarket = { marketType: (0, __1.getVariant)(marketType), marketIndex };
181
+ updateMarketTypeAndIndex(driftMarkets) {
182
+ this.driftMarkets = driftMarkets;
191
183
  }
192
184
  }
193
185
  exports.PriorityFeeSubscriber = PriorityFeeSubscriber;
@@ -2,8 +2,9 @@ import { Connection, PublicKey } from '@solana/web3.js';
2
2
  import { SolanaPriorityFeeResponse } from './solanaPriorityFeeMethod';
3
3
  import { HeliusPriorityFeeResponse } from './heliusPriorityFeeMethod';
4
4
  import { DriftMarketInfo } from './priorityFeeSubscriber';
5
+ import { DriftPriorityFeeResponse } from './driftPriorityFeeMethod';
5
6
  export interface PriorityFeeStrategy {
6
- calculate(samples: SolanaPriorityFeeResponse[] | HeliusPriorityFeeResponse): number;
7
+ calculate(samples: SolanaPriorityFeeResponse[] | HeliusPriorityFeeResponse | DriftPriorityFeeResponse): number;
7
8
  }
8
9
  export declare enum PriorityFeeMethod {
9
10
  SOLANA = "solana",
@@ -14,7 +15,7 @@ export type PriorityFeeSubscriberConfig = {
14
15
  connection?: Connection;
15
16
  frequencyMs: number;
16
17
  addresses?: PublicKey[];
17
- driftMarket?: DriftMarketInfo;
18
+ driftMarkets?: DriftMarketInfo[];
18
19
  customStrategy?: PriorityFeeStrategy;
19
20
  priorityFeeMethod?: PriorityFeeMethod;
20
21
  slotsToCheck?: number;
@@ -0,0 +1,28 @@
1
+ import { AddressLookupTableAccount, Connection, TransactionInstruction, TransactionVersion, VersionedTransaction } from '@solana/web3.js';
2
+ import { BaseTxParams, ProcessingTxParams } from '..';
3
+ type TransactionProps = {
4
+ instructions: TransactionInstruction | TransactionInstruction[];
5
+ txParams?: BaseTxParams;
6
+ txVersion?: TransactionVersion;
7
+ lookupTables?: AddressLookupTableAccount[];
8
+ forceVersionedTransaction?: boolean;
9
+ };
10
+ /**
11
+ * This class is responsible for running through a "processing" pipeline for a base transaction, to adjust the standard transaction parameters based on a given configuration.
12
+ */
13
+ export declare class TransactionProcessor {
14
+ private static getComputeUnitsFromSim;
15
+ static getTxSimComputeUnits(tx: VersionedTransaction, connection: Connection): Promise<{
16
+ success: boolean;
17
+ computeUnits: number;
18
+ }>;
19
+ static process(props: {
20
+ txProps: TransactionProps;
21
+ txBuilder: (baseTransactionProps: TransactionProps) => Promise<VersionedTransaction>;
22
+ processConfig: ProcessingTxParams;
23
+ processParams: {
24
+ connection: Connection;
25
+ };
26
+ }): Promise<BaseTxParams>;
27
+ }
28
+ export {};
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransactionProcessor = void 0;
4
+ const COMPUTE_UNIT_BUFFER_FACTOR = 1.2;
5
+ const TEST_SIMS_ALWAYS_FAIL = false;
6
+ /**
7
+ * This class is responsible for running through a "processing" pipeline for a base transaction, to adjust the standard transaction parameters based on a given configuration.
8
+ */
9
+ class TransactionProcessor {
10
+ static async getComputeUnitsFromSim(txSim) {
11
+ var _a, _b;
12
+ if ((_a = txSim === null || txSim === void 0 ? void 0 : txSim.value) === null || _a === void 0 ? void 0 : _a.unitsConsumed) {
13
+ return (_b = txSim === null || txSim === void 0 ? void 0 : txSim.value) === null || _b === void 0 ? void 0 : _b.unitsConsumed;
14
+ }
15
+ return undefined;
16
+ }
17
+ static async getTxSimComputeUnits(tx, connection) {
18
+ var _a, _b, _c;
19
+ try {
20
+ if (TEST_SIMS_ALWAYS_FAIL)
21
+ throw new Error('Test Error::SIMS_ALWAYS_FAIL');
22
+ const simTxResult = await connection.simulateTransaction(tx, {
23
+ replaceRecentBlockhash: true, // This is important to ensure that the blockhash is not too new.. Otherwise we will very often receive a "blockHashNotFound" error
24
+ });
25
+ if ((_a = simTxResult === null || simTxResult === void 0 ? void 0 : simTxResult.value) === null || _a === void 0 ? void 0 : _a.err) {
26
+ throw new Error((_c = (_b = simTxResult === null || simTxResult === void 0 ? void 0 : simTxResult.value) === null || _b === void 0 ? void 0 : _b.err) === null || _c === void 0 ? void 0 : _c.toString());
27
+ }
28
+ const computeUnits = await this.getComputeUnitsFromSim(simTxResult);
29
+ return {
30
+ success: true,
31
+ computeUnits: computeUnits,
32
+ };
33
+ }
34
+ catch (e) {
35
+ console.warn(`Failed to get Simulated Compute Units for txParamProcessor`, e);
36
+ return {
37
+ success: false,
38
+ computeUnits: undefined,
39
+ };
40
+ }
41
+ }
42
+ static async process(props) {
43
+ var _a;
44
+ // # Exit early if no process config is provided
45
+ if (!props.processConfig || Object.keys(props.processConfig).length === 0) {
46
+ return props.txProps.txParams;
47
+ }
48
+ // # Setup
49
+ const { txProps: txProps, txBuilder: txBuilder, processConfig, processParams: processProps, } = props;
50
+ const baseTransaction = await txBuilder(txProps);
51
+ const finalTxProps = {
52
+ ...txProps,
53
+ };
54
+ // # Run Processes
55
+ if (processConfig.useSimulatedComputeUnits) {
56
+ const txSimComputeUnitsResult = await this.getTxSimComputeUnits(baseTransaction, processProps.connection);
57
+ if (txSimComputeUnitsResult.success) {
58
+ const bufferedComputeUnits = txSimComputeUnitsResult.computeUnits *
59
+ ((_a = processConfig === null || processConfig === void 0 ? void 0 : processConfig.computeUnitsBufferMultiplier) !== null && _a !== void 0 ? _a : COMPUTE_UNIT_BUFFER_FACTOR);
60
+ // Adjust the transaction based on the simulated compute units
61
+ finalTxProps.txParams = {
62
+ ...txProps.txParams,
63
+ computeUnits: bufferedComputeUnits,
64
+ };
65
+ }
66
+ }
67
+ // # Return Final Tx Params
68
+ return finalTxProps.txParams;
69
+ }
70
+ }
71
+ exports.TransactionProcessor = TransactionProcessor;
@@ -59,18 +59,19 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
59
59
  }
60
60
  async sendVersionedTransaction(tx, additionalSigners, opts, preSigned, extraConfirmationOptions) {
61
61
  const latestBlockhash = await this.connection.getLatestBlockhash();
62
- tx.message.recentBlockhash = latestBlockhash.blockhash;
63
62
  let signedTx;
64
63
  if (preSigned) {
65
64
  signedTx = tx;
66
65
  // @ts-ignore
67
66
  }
68
67
  else if (this.wallet.payer) {
68
+ tx.message.recentBlockhash = latestBlockhash.blockhash;
69
69
  // @ts-ignore
70
70
  tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.wallet.payer));
71
71
  signedTx = tx;
72
72
  }
73
73
  else {
74
+ tx.message.recentBlockhash = latestBlockhash.blockhash;
74
75
  additionalSigners === null || additionalSigners === void 0 ? void 0 : additionalSigners.filter((s) => s !== undefined).forEach((kp) => {
75
76
  tx.sign([kp]);
76
77
  });
package/lib/types.d.ts CHANGED
@@ -1038,10 +1038,15 @@ export type ReferrerInfo = {
1038
1038
  referrer: PublicKey;
1039
1039
  referrerStats: PublicKey;
1040
1040
  };
1041
- export type TxParams = {
1041
+ export type BaseTxParams = {
1042
1042
  computeUnits?: number;
1043
1043
  computeUnitsPrice?: number;
1044
1044
  };
1045
+ export type ProcessingTxParams = {
1046
+ useSimulatedComputeUnits?: boolean;
1047
+ computeUnitsBufferMultiplier?: number;
1048
+ };
1049
+ export type TxParams = BaseTxParams & ProcessingTxParams;
1045
1050
  export declare class SwapReduceOnly {
1046
1051
  static readonly In: {
1047
1052
  in: {};
package/lib/user.js CHANGED
@@ -1690,8 +1690,14 @@ class User {
1690
1690
  const feeTier = this.getUserFeeTier(marketType);
1691
1691
  let takerFee = feeTier.feeNumerator / feeTier.feeDenominator;
1692
1692
  let makerFee = feeTier.makerRebateNumerator / feeTier.makerRebateDenominator;
1693
- if (marketIndex !== undefined && (0, types_1.isVariant)(marketType, 'perp')) {
1694
- const marketAccount = this.driftClient.getPerpMarketAccount(marketIndex);
1693
+ if (marketIndex !== undefined) {
1694
+ let marketAccount = null;
1695
+ if ((0, types_1.isVariant)(marketType, 'perp')) {
1696
+ marketAccount = this.driftClient.getPerpMarketAccount(marketIndex);
1697
+ }
1698
+ else {
1699
+ marketAccount = this.driftClient.getSpotMarketAccount(marketIndex);
1700
+ }
1695
1701
  takerFee += (takerFee * marketAccount.feeAdjustment) / 100;
1696
1702
  makerFee += (makerFee * marketAccount.feeAdjustment) / 100;
1697
1703
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.77.0-beta.0",
3
+ "version": "2.77.0-beta.1",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -42,6 +42,8 @@ import {
42
42
  PhoenixV1FulfillmentConfigAccount,
43
43
  ModifyOrderPolicy,
44
44
  SwapReduceOnly,
45
+ BaseTxParams,
46
+ ProcessingTxParams,
45
47
  } from './types';
46
48
  import * as anchor from '@coral-xyz/anchor';
47
49
  import driftIDL from './idl/drift.json';
@@ -125,6 +127,7 @@ import { UserStatsSubscriptionConfig } from './userStatsConfig';
125
127
  import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
126
128
  import { getOrderParams } from './orderParams';
127
129
  import { numberToSafeBN } from './math/utils';
130
+ import { TransactionProcessor as TransactionParamProcessor } from './tx/txParamProcessor';
128
131
 
129
132
  type RemainingAccountParams = {
130
133
  userAccounts: UserAccount[];
@@ -734,10 +737,44 @@ export class DriftClient {
734
737
  return result;
735
738
  }
736
739
 
740
+ private async getProcessedTransactionParams(
741
+ txParams: {
742
+ instructions: TransactionInstruction | TransactionInstruction[];
743
+ txParams?: BaseTxParams;
744
+ txVersion?: TransactionVersion;
745
+ lookupTables?: AddressLookupTableAccount[];
746
+ },
747
+ txParamProcessingParams: ProcessingTxParams
748
+ ): Promise<BaseTxParams> {
749
+ const tx = await TransactionParamProcessor.process({
750
+ txProps: {
751
+ instructions: txParams.instructions,
752
+ txParams: txParams.txParams,
753
+ txVersion: txParams.txVersion,
754
+ lookupTables: txParams.lookupTables,
755
+ },
756
+ txBuilder: (updatedTxParams) =>
757
+ this.buildTransaction(
758
+ updatedTxParams.instructions,
759
+ updatedTxParams?.txParams,
760
+ updatedTxParams.txVersion,
761
+ updatedTxParams.lookupTables,
762
+ true
763
+ ) as Promise<VersionedTransaction>,
764
+ processConfig: txParamProcessingParams,
765
+ processParams: {
766
+ connection: this.connection,
767
+ },
768
+ });
769
+
770
+ return tx;
771
+ }
772
+
737
773
  public async initializeUserAccount(
738
774
  subAccountId = 0,
739
775
  name?: string,
740
- referrerInfo?: ReferrerInfo
776
+ referrerInfo?: ReferrerInfo,
777
+ txParams?: TxParams
741
778
  ): Promise<[TransactionSignature, PublicKey]> {
742
779
  const initializeIxs = [];
743
780
 
@@ -757,7 +794,7 @@ export class DriftClient {
757
794
  }
758
795
 
759
796
  initializeIxs.push(initializeUserAccountIx);
760
- const tx = await this.buildTransaction(initializeIxs);
797
+ const tx = await this.buildTransaction(initializeIxs, txParams);
761
798
 
762
799
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
763
800
 
@@ -1992,17 +2029,6 @@ export class DriftClient {
1992
2029
 
1993
2030
  const isSolMarket = spotMarket.mint.equals(WRAPPED_SOL_MINT);
1994
2031
 
1995
- let params: TxParams = {
1996
- computeUnits: txParams?.computeUnits ?? 600_000,
1997
- };
1998
-
1999
- if (txParams?.computeUnitsPrice) {
2000
- params = {
2001
- ...params,
2002
- computeUnitsPrice: txParams.computeUnitsPrice,
2003
- };
2004
- }
2005
-
2006
2032
  const authority = this.wallet.publicKey;
2007
2033
 
2008
2034
  const isFromSubaccount =
@@ -2090,7 +2116,7 @@ export class DriftClient {
2090
2116
  );
2091
2117
  }
2092
2118
 
2093
- const tx = await this.buildTransaction(ixs, params);
2119
+ const tx = await this.buildTransaction(ixs, txParams);
2094
2120
 
2095
2121
  const { txSig, slot } = await this.sendTransaction(
2096
2122
  tx,
@@ -2110,7 +2136,8 @@ export class DriftClient {
2110
2136
  marketIndex: number,
2111
2137
  tokenFaucet: TokenFaucet,
2112
2138
  amount: BN,
2113
- referrerInfo?: ReferrerInfo
2139
+ referrerInfo?: ReferrerInfo,
2140
+ txParams?: TxParams
2114
2141
  ): Promise<[TransactionSignature, PublicKey]> {
2115
2142
  const ixs = [];
2116
2143
 
@@ -2147,7 +2174,7 @@ export class DriftClient {
2147
2174
  }
2148
2175
  ixs.push(initializeUserAccountIx, depositCollateralIx);
2149
2176
 
2150
- const tx = await this.buildTransaction(ixs);
2177
+ const tx = await this.buildTransaction(ixs, txParams);
2151
2178
 
2152
2179
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
2153
2180
 
@@ -2231,10 +2258,11 @@ export class DriftClient {
2231
2258
  );
2232
2259
  }
2233
2260
 
2234
- const tx = await this.buildTransaction(withdrawIxs, {
2235
- ...(txParams ?? this.txParams),
2236
- computeUnits: 1_400_000,
2237
- });
2261
+ const tx = await this.buildTransaction(
2262
+ withdrawIxs,
2263
+ txParams ?? this.txParams
2264
+ );
2265
+
2238
2266
  const { txSig, slot } = await this.sendTransaction(
2239
2267
  tx,
2240
2268
  additionalSigners,
@@ -4535,15 +4563,37 @@ export class DriftClient {
4535
4563
  ixs.push(bracketOrdersIx);
4536
4564
  }
4537
4565
 
4538
- const placeAndTakeTx = (await this.buildTransaction(
4566
+ const shouldUseSimulationComputeUnits = txParams?.useSimulatedComputeUnits;
4567
+ const shouldExitIfSimulationFails = simulateFirst;
4568
+
4569
+ const txParamsWithoutImplicitSimulation = {
4570
+ ...txParams,
4571
+ useSimulationComputeUnits: false,
4572
+ };
4573
+
4574
+ let placeAndTakeTx = await this.buildTransaction(
4539
4575
  ixs,
4540
- txParams
4541
- )) as VersionedTransaction;
4576
+ txParamsWithoutImplicitSimulation
4577
+ );
4578
+
4579
+ if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
4580
+ const simulationResult =
4581
+ await TransactionParamProcessor.getTxSimComputeUnits(
4582
+ // @ts-ignore :: TODO - TEST WITH LEGACY TRANSACTION
4583
+ placeAndTakeTx,
4584
+ this.connection
4585
+ );
4542
4586
 
4543
- // if param is passed, return early before the tx fails so ui can fallback to placeOrder
4544
- if (simulateFirst) {
4545
- const success = await this.txSender.simulateTransaction(placeAndTakeTx);
4546
- if (!success) return;
4587
+ if (shouldExitIfSimulationFails && !simulationResult.success) {
4588
+ return;
4589
+ }
4590
+
4591
+ if (shouldUseSimulationComputeUnits) {
4592
+ placeAndTakeTx = await this.buildTransaction(ixs, {
4593
+ ...txParamsWithoutImplicitSimulation,
4594
+ computeUnits: simulationResult.computeUnits,
4595
+ });
4596
+ }
4547
4597
  }
4548
4598
 
4549
4599
  let cancelExistingOrdersTx: Transaction;
@@ -6504,7 +6554,11 @@ export class DriftClient {
6504
6554
  }
6505
6555
  : undefined;
6506
6556
 
6507
- if (tx instanceof VersionedTransaction) {
6557
+ const version = (tx as VersionedTransaction)?.version;
6558
+ const isVersionedTx =
6559
+ tx instanceof VersionedTransaction || version !== undefined;
6560
+
6561
+ if (isVersionedTx) {
6508
6562
  return this.txSender.sendVersionedTransaction(
6509
6563
  tx as VersionedTransaction,
6510
6564
  additionalSigners,
@@ -6523,14 +6577,65 @@ export class DriftClient {
6523
6577
  }
6524
6578
  }
6525
6579
 
6580
+ /**
6581
+ *
6582
+ * @param instructions
6583
+ * @param txParams
6584
+ * @param txVersion
6585
+ * @param lookupTables
6586
+ * @param forceVersionedTransaction Return a VersionedTransaction instance even if the version of the transaction is Legacy
6587
+ * @returns
6588
+ */
6526
6589
  async buildTransaction(
6527
6590
  instructions: TransactionInstruction | TransactionInstruction[],
6528
6591
  txParams?: TxParams,
6529
6592
  txVersion?: TransactionVersion,
6530
- lookupTables?: AddressLookupTableAccount[]
6593
+ lookupTables?: AddressLookupTableAccount[],
6594
+ forceVersionedTransaction?: boolean
6531
6595
  ): Promise<Transaction | VersionedTransaction> {
6596
+ txVersion = txVersion ?? this.txVersion;
6597
+
6598
+ // # Collect and process Tx Params
6599
+ let baseTxParams: BaseTxParams = {
6600
+ computeUnits: txParams?.computeUnits ?? this.txParams.computeUnits,
6601
+ computeUnitsPrice:
6602
+ txParams?.computeUnitsPrice ?? this.txParams.computeUnitsPrice,
6603
+ };
6604
+
6605
+ if (txParams?.useSimulatedComputeUnits) {
6606
+ const splitTxParams: {
6607
+ baseTxParams: BaseTxParams;
6608
+ txParamProcessingParams: ProcessingTxParams;
6609
+ } = {
6610
+ baseTxParams: {
6611
+ computeUnits: txParams?.computeUnits,
6612
+ computeUnitsPrice: txParams?.computeUnitsPrice,
6613
+ },
6614
+ txParamProcessingParams: {
6615
+ useSimulatedComputeUnits: txParams?.useSimulatedComputeUnits,
6616
+ computeUnitsBufferMultiplier: txParams?.computeUnitsBufferMultiplier,
6617
+ },
6618
+ };
6619
+
6620
+ const processedTxParams = await this.getProcessedTransactionParams(
6621
+ {
6622
+ instructions,
6623
+ txParams: splitTxParams.baseTxParams,
6624
+ txVersion,
6625
+ lookupTables,
6626
+ },
6627
+ splitTxParams.txParamProcessingParams
6628
+ );
6629
+
6630
+ baseTxParams = {
6631
+ ...baseTxParams,
6632
+ ...processedTxParams,
6633
+ };
6634
+ }
6635
+
6636
+ // # Create Tx Instructions
6532
6637
  const allIx = [];
6533
- const computeUnits = txParams?.computeUnits ?? this.txParams.computeUnits;
6638
+ const computeUnits = baseTxParams?.computeUnits;
6534
6639
  if (computeUnits !== 200_000) {
6535
6640
  allIx.push(
6536
6641
  ComputeBudgetProgram.setComputeUnitLimit({
@@ -6538,8 +6643,7 @@ export class DriftClient {
6538
6643
  })
6539
6644
  );
6540
6645
  }
6541
- const computeUnitsPrice =
6542
- txParams?.computeUnitsPrice ?? this.txParams.computeUnitsPrice;
6646
+ const computeUnitsPrice = baseTxParams?.computeUnitsPrice;
6543
6647
  if (computeUnitsPrice !== 0) {
6544
6648
  allIx.push(
6545
6649
  ComputeBudgetProgram.setComputeUnitPrice({
@@ -6554,9 +6658,24 @@ export class DriftClient {
6554
6658
  allIx.push(instructions);
6555
6659
  }
6556
6660
 
6557
- txVersion = txVersion ?? this.txVersion;
6661
+ const latestBlockHashAndContext =
6662
+ await this.connection.getLatestBlockhashAndContext({
6663
+ commitment: this.opts.preflightCommitment,
6664
+ });
6665
+
6666
+ // # Create and return Transaction
6558
6667
  if (txVersion === 'legacy') {
6559
- return new Transaction().add(...allIx);
6668
+ if (forceVersionedTransaction) {
6669
+ const message = new TransactionMessage({
6670
+ payerKey: this.provider.wallet.publicKey,
6671
+ recentBlockhash: latestBlockHashAndContext.value.blockhash,
6672
+ instructions: allIx,
6673
+ }).compileToLegacyMessage();
6674
+
6675
+ return new VersionedTransaction(message);
6676
+ } else {
6677
+ return new Transaction().add(...allIx);
6678
+ }
6560
6679
  } else {
6561
6680
  const marketLookupTable = await this.fetchMarketLookupTableAccount();
6562
6681
  lookupTables = lookupTables
@@ -6564,11 +6683,7 @@ export class DriftClient {
6564
6683
  : [marketLookupTable];
6565
6684
  const message = new TransactionMessage({
6566
6685
  payerKey: this.provider.wallet.publicKey,
6567
- recentBlockhash: (
6568
- await this.provider.connection.getRecentBlockhash(
6569
- this.opts.preflightCommitment
6570
- )
6571
- ).blockhash,
6686
+ recentBlockhash: latestBlockHashAndContext.value.blockhash,
6572
6687
  instructions: allIx,
6573
6688
  }).compileToV0Message(lookupTables);
6574
6689
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.76.0",
2
+ "version": "2.75.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -5,11 +5,13 @@ export type DriftPriorityFeeResponse = HeliusPriorityFeeLevels[];
5
5
 
6
6
  export async function fetchDriftPriorityFee(
7
7
  url: string,
8
- marketType: string,
9
- marketIndex: number
8
+ marketTypes: string[],
9
+ marketIndexs: number[]
10
10
  ): Promise<DriftPriorityFeeResponse> {
11
11
  const response = await fetch(
12
- `${url}?marketType=${marketType}&marketIndex=${marketIndex}`
12
+ `${url}/batchPriorityFees?marketType=${marketTypes.join(
13
+ ','
14
+ )}&marketIndex=${marketIndexs.join(',')}`
13
15
  );
14
16
  return await response.json();
15
17
  }
@@ -13,7 +13,6 @@ import {
13
13
  fetchHeliusPriorityFee,
14
14
  } from './heliusPriorityFeeMethod';
15
15
  import { fetchDriftPriorityFee } from './driftPriorityFeeMethod';
16
- import { getVariant, MarketType } from '..';
17
16
 
18
17
  export type DriftMarketInfo = {
19
18
  marketType: string;
@@ -24,7 +23,7 @@ export class PriorityFeeSubscriber {
24
23
  connection: Connection;
25
24
  frequencyMs: number;
26
25
  addresses: string[];
27
- driftMarket?: DriftMarketInfo;
26
+ driftMarkets?: DriftMarketInfo[];
28
27
  customStrategy?: PriorityFeeStrategy;
29
28
  averageStrategy = new AverageOverSlotsStrategy();
30
29
  maxStrategy = new MaxOverSlotsStrategy();
@@ -51,7 +50,7 @@ export class PriorityFeeSubscriber {
51
50
  this.addresses = config.addresses
52
51
  ? config.addresses.map((address) => address.toBase58())
53
52
  : [];
54
- this.driftMarket = config.driftMarket;
53
+ this.driftMarkets = config.driftMarkets;
55
54
 
56
55
  if (config.customStrategy) {
57
56
  this.customStrategy = config.customStrategy;
@@ -137,26 +136,19 @@ export class PriorityFeeSubscriber {
137
136
  }
138
137
 
139
138
  private async loadForDrift(): Promise<void> {
140
- if (!this.driftMarket) {
139
+ if (!this.driftMarkets) {
141
140
  return;
142
141
  }
143
142
  const sample = await fetchDriftPriorityFee(
144
143
  this.driftPriorityFeeEndpoint!,
145
- this.driftMarket.marketType,
146
- this.driftMarket.marketIndex
144
+ this.driftMarkets.map((m) => m.marketType),
145
+ this.driftMarkets.map((m) => m.marketIndex)
147
146
  );
148
147
  if (sample.length > 0) {
149
148
  this.lastAvgStrategyResult = sample[HeliusPriorityLevel.MEDIUM];
150
149
  this.lastMaxStrategyResult = sample[HeliusPriorityLevel.UNSAFE_MAX];
151
150
  if (this.customStrategy) {
152
- // stay compatible with helius response
153
- this.lastCustomStrategyResult = this.customStrategy.calculate({
154
- jsonrpc: '',
155
- result: {
156
- priorityFeeLevels: sample[0],
157
- },
158
- id: '',
159
- });
151
+ this.lastCustomStrategyResult = this.customStrategy.calculate(sample);
160
152
  }
161
153
  }
162
154
  }
@@ -251,7 +243,7 @@ export class PriorityFeeSubscriber {
251
243
  this.addresses = addresses.map((k) => k.toBase58());
252
244
  }
253
245
 
254
- public updateMarketTypeAndIndex(marketType: MarketType, marketIndex: number) {
255
- this.driftMarket = { marketType: getVariant(marketType), marketIndex };
246
+ public updateMarketTypeAndIndex(driftMarkets: DriftMarketInfo[]) {
247
+ this.driftMarkets = driftMarkets;
256
248
  }
257
249
  }
@@ -2,12 +2,16 @@ import { Connection, PublicKey } from '@solana/web3.js';
2
2
  import { SolanaPriorityFeeResponse } from './solanaPriorityFeeMethod';
3
3
  import { HeliusPriorityFeeResponse } from './heliusPriorityFeeMethod';
4
4
  import { DriftMarketInfo } from './priorityFeeSubscriber';
5
+ import { DriftPriorityFeeResponse } from './driftPriorityFeeMethod';
5
6
 
6
7
  export interface PriorityFeeStrategy {
7
8
  // calculate the priority fee for a given set of samples.
8
9
  // expect samples to be sorted in descending order (by slot)
9
10
  calculate(
10
- samples: SolanaPriorityFeeResponse[] | HeliusPriorityFeeResponse
11
+ samples:
12
+ | SolanaPriorityFeeResponse[]
13
+ | HeliusPriorityFeeResponse
14
+ | DriftPriorityFeeResponse
11
15
  ): number;
12
16
  }
13
17
 
@@ -25,7 +29,7 @@ export type PriorityFeeSubscriberConfig = {
25
29
  /// addresses you plan to write lock, used to determine priority fees
26
30
  addresses?: PublicKey[];
27
31
  /// drift market type and index, optionally provide at initialization time if using priorityFeeMethod.DRIFT
28
- driftMarket?: DriftMarketInfo;
32
+ driftMarkets?: DriftMarketInfo[];
29
33
  /// custom strategy to calculate priority fees, defaults to AVERAGE
30
34
  customStrategy?: PriorityFeeStrategy;
31
35
  /// method for fetching priority fee samples
@@ -0,0 +1,126 @@
1
+ import {
2
+ AddressLookupTableAccount,
3
+ Connection,
4
+ RpcResponseAndContext,
5
+ SimulatedTransactionResponse,
6
+ TransactionInstruction,
7
+ TransactionVersion,
8
+ VersionedTransaction,
9
+ } from '@solana/web3.js';
10
+ import { BaseTxParams, ProcessingTxParams } from '..';
11
+
12
+ const COMPUTE_UNIT_BUFFER_FACTOR = 1.2;
13
+
14
+ const TEST_SIMS_ALWAYS_FAIL = false;
15
+
16
+ type TransactionProps = {
17
+ instructions: TransactionInstruction | TransactionInstruction[];
18
+ txParams?: BaseTxParams;
19
+ txVersion?: TransactionVersion;
20
+ lookupTables?: AddressLookupTableAccount[];
21
+ forceVersionedTransaction?: boolean;
22
+ };
23
+
24
+ /**
25
+ * This class is responsible for running through a "processing" pipeline for a base transaction, to adjust the standard transaction parameters based on a given configuration.
26
+ */
27
+ export class TransactionProcessor {
28
+ private static async getComputeUnitsFromSim(
29
+ txSim: RpcResponseAndContext<SimulatedTransactionResponse>
30
+ ) {
31
+ if (txSim?.value?.unitsConsumed) {
32
+ return txSim?.value?.unitsConsumed;
33
+ }
34
+
35
+ return undefined;
36
+ }
37
+
38
+ public static async getTxSimComputeUnits(
39
+ tx: VersionedTransaction,
40
+ connection: Connection
41
+ ): Promise<{ success: boolean; computeUnits: number }> {
42
+ try {
43
+ if (TEST_SIMS_ALWAYS_FAIL)
44
+ throw new Error('Test Error::SIMS_ALWAYS_FAIL');
45
+
46
+ const simTxResult = await connection.simulateTransaction(tx, {
47
+ replaceRecentBlockhash: true, // This is important to ensure that the blockhash is not too new.. Otherwise we will very often receive a "blockHashNotFound" error
48
+ });
49
+
50
+ if (simTxResult?.value?.err) {
51
+ throw new Error(simTxResult?.value?.err?.toString());
52
+ }
53
+
54
+ const computeUnits = await this.getComputeUnitsFromSim(simTxResult);
55
+
56
+ return {
57
+ success: true,
58
+ computeUnits: computeUnits,
59
+ };
60
+ } catch (e) {
61
+ console.warn(
62
+ `Failed to get Simulated Compute Units for txParamProcessor`,
63
+ e
64
+ );
65
+
66
+ return {
67
+ success: false,
68
+ computeUnits: undefined,
69
+ };
70
+ }
71
+ }
72
+
73
+ static async process(props: {
74
+ txProps: TransactionProps;
75
+ txBuilder: (
76
+ baseTransactionProps: TransactionProps
77
+ ) => Promise<VersionedTransaction>;
78
+ processConfig: ProcessingTxParams;
79
+ processParams: {
80
+ connection: Connection;
81
+ };
82
+ }): Promise<BaseTxParams> {
83
+ // # Exit early if no process config is provided
84
+ if (!props.processConfig || Object.keys(props.processConfig).length === 0) {
85
+ return props.txProps.txParams;
86
+ }
87
+
88
+ // # Setup
89
+ const {
90
+ txProps: txProps,
91
+ txBuilder: txBuilder,
92
+ processConfig,
93
+ processParams: processProps,
94
+ } = props;
95
+
96
+ const baseTransaction = await txBuilder(txProps);
97
+
98
+ const finalTxProps = {
99
+ ...txProps,
100
+ };
101
+
102
+ // # Run Processes
103
+ if (processConfig.useSimulatedComputeUnits) {
104
+ const txSimComputeUnitsResult = await this.getTxSimComputeUnits(
105
+ baseTransaction,
106
+ processProps.connection
107
+ );
108
+
109
+ if (txSimComputeUnitsResult.success) {
110
+ const bufferedComputeUnits =
111
+ txSimComputeUnitsResult.computeUnits *
112
+ (processConfig?.computeUnitsBufferMultiplier ??
113
+ COMPUTE_UNIT_BUFFER_FACTOR);
114
+
115
+ // Adjust the transaction based on the simulated compute units
116
+ finalTxProps.txParams = {
117
+ ...txProps.txParams,
118
+ computeUnits: bufferedComputeUnits,
119
+ };
120
+ }
121
+ }
122
+
123
+ // # Return Final Tx Params
124
+ return finalTxProps.txParams;
125
+ }
126
+ }
@@ -124,17 +124,18 @@ export class WhileValidTxSender extends BaseTxSender {
124
124
  extraConfirmationOptions?: ExtraConfirmationOptions
125
125
  ): Promise<TxSigAndSlot> {
126
126
  const latestBlockhash = await this.connection.getLatestBlockhash();
127
- tx.message.recentBlockhash = latestBlockhash.blockhash;
128
127
 
129
128
  let signedTx;
130
129
  if (preSigned) {
131
130
  signedTx = tx;
132
131
  // @ts-ignore
133
132
  } else if (this.wallet.payer) {
133
+ tx.message.recentBlockhash = latestBlockhash.blockhash;
134
134
  // @ts-ignore
135
135
  tx.sign((additionalSigners ?? []).concat(this.wallet.payer));
136
136
  signedTx = tx;
137
137
  } else {
138
+ tx.message.recentBlockhash = latestBlockhash.blockhash;
138
139
  additionalSigners
139
140
  ?.filter((s): s is Signer => s !== undefined)
140
141
  .forEach((kp) => {
package/src/types.ts CHANGED
@@ -999,11 +999,18 @@ export type ReferrerInfo = {
999
999
  referrerStats: PublicKey;
1000
1000
  };
1001
1001
 
1002
- export type TxParams = {
1002
+ export type BaseTxParams = {
1003
1003
  computeUnits?: number;
1004
1004
  computeUnitsPrice?: number;
1005
1005
  };
1006
1006
 
1007
+ export type ProcessingTxParams = {
1008
+ useSimulatedComputeUnits?: boolean;
1009
+ computeUnitsBufferMultiplier?: number;
1010
+ };
1011
+
1012
+ export type TxParams = BaseTxParams & ProcessingTxParams;
1013
+
1007
1014
  export class SwapReduceOnly {
1008
1015
  static readonly In = { in: {} };
1009
1016
  static readonly Out = { out: {} };
package/src/user.ts CHANGED
@@ -3123,8 +3123,13 @@ export class User {
3123
3123
  let makerFee =
3124
3124
  feeTier.makerRebateNumerator / feeTier.makerRebateDenominator;
3125
3125
 
3126
- if (marketIndex !== undefined && isVariant(marketType, 'perp')) {
3127
- const marketAccount = this.driftClient.getPerpMarketAccount(marketIndex);
3126
+ if (marketIndex !== undefined) {
3127
+ let marketAccount = null;
3128
+ if (isVariant(marketType, 'perp')) {
3129
+ marketAccount = this.driftClient.getPerpMarketAccount(marketIndex);
3130
+ } else {
3131
+ marketAccount = this.driftClient.getSpotMarketAccount(marketIndex);
3132
+ }
3128
3133
  takerFee += (takerFee * marketAccount.feeAdjustment) / 100;
3129
3134
  makerFee += (makerFee * marketAccount.feeAdjustment) / 100;
3130
3135
  }