@drift-labs/sdk 2.82.0-beta.8 → 2.83.0-beta.0

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 (68) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/types.d.ts +0 -3
  3. package/lib/accounts/webSocketAccountSubscriber.js +1 -1
  4. package/lib/clock/clockSubscriber.d.ts +29 -0
  5. package/lib/clock/clockSubscriber.js +74 -0
  6. package/lib/constants/perpMarkets.js +2 -2
  7. package/lib/constants/spotMarkets.js +11 -0
  8. package/lib/dlob/DLOB.js +2 -2
  9. package/lib/dlob/orderBookLevels.js +1 -0
  10. package/lib/driftClient.d.ts +11 -14
  11. package/lib/driftClient.js +157 -260
  12. package/lib/driftClientConfig.d.ts +2 -0
  13. package/lib/idl/drift.json +1 -1
  14. package/lib/index.d.ts +2 -0
  15. package/lib/index.js +2 -0
  16. package/lib/jupiter/jupiterClient.d.ts +2 -1
  17. package/lib/jupiter/jupiterClient.js +10 -6
  18. package/lib/math/exchangeStatus.d.ts +2 -2
  19. package/lib/math/orders.d.ts +1 -1
  20. package/lib/math/orders.js +2 -2
  21. package/lib/tx/baseTxSender.d.ts +8 -6
  22. package/lib/tx/baseTxSender.js +6 -49
  23. package/lib/tx/fastSingleTxSender.d.ts +6 -6
  24. package/lib/tx/fastSingleTxSender.js +3 -31
  25. package/lib/tx/forwardOnlyTxSender.d.ts +4 -2
  26. package/lib/tx/forwardOnlyTxSender.js +2 -1
  27. package/lib/tx/retryTxSender.d.ts +4 -2
  28. package/lib/tx/retryTxSender.js +2 -1
  29. package/lib/tx/txHandler.d.ts +138 -0
  30. package/lib/tx/txHandler.js +396 -0
  31. package/lib/tx/txParamProcessor.d.ts +6 -10
  32. package/lib/tx/txParamProcessor.js +13 -17
  33. package/lib/tx/types.d.ts +3 -7
  34. package/lib/tx/whileValidTxSender.d.ts +7 -6
  35. package/lib/tx/whileValidTxSender.js +7 -28
  36. package/lib/types.d.ts +24 -4
  37. package/lib/types.js +10 -1
  38. package/lib/util/chainClock.d.ts +17 -0
  39. package/lib/util/chainClock.js +29 -0
  40. package/package.json +3 -3
  41. package/src/accounts/types.ts +0 -4
  42. package/src/accounts/webSocketAccountSubscriber.ts +1 -1
  43. package/src/clock/clockSubscriber.ts +113 -0
  44. package/src/constants/perpMarkets.ts +2 -2
  45. package/src/constants/spotMarkets.ts +13 -0
  46. package/src/dlob/DLOB.ts +2 -2
  47. package/src/dlob/orderBookLevels.ts +2 -0
  48. package/src/driftClient.ts +247 -385
  49. package/src/driftClientConfig.ts +2 -0
  50. package/src/idl/drift.json +1 -1
  51. package/src/index.ts +2 -0
  52. package/src/jupiter/jupiterClient.ts +15 -6
  53. package/src/math/exchangeStatus.ts +2 -1
  54. package/src/math/orders.ts +3 -2
  55. package/src/tx/baseTxSender.ts +21 -75
  56. package/src/tx/fastSingleTxSender.ts +10 -55
  57. package/src/tx/forwardOnlyTxSender.ts +5 -1
  58. package/src/tx/retryTxSender.ts +5 -1
  59. package/src/tx/txHandler.ts +625 -0
  60. package/src/tx/txParamProcessor.ts +16 -28
  61. package/src/tx/types.ts +2 -18
  62. package/src/tx/whileValidTxSender.ts +24 -48
  63. package/src/types.ts +26 -2
  64. package/src/util/chainClock.ts +41 -0
  65. package/tests/dlob/helpers.ts +3 -0
  66. package/lib/tx/utils.d.ts +0 -6
  67. package/lib/tx/utils.js +0 -43
  68. package/src/tx/utils.ts +0 -68
@@ -42,8 +42,7 @@ import {
42
42
  PhoenixV1FulfillmentConfigAccount,
43
43
  ModifyOrderPolicy,
44
44
  SwapReduceOnly,
45
- BaseTxParams,
46
- ProcessingTxParams,
45
+ SignedTxData,
47
46
  } from './types';
48
47
  import * as anchor from '@coral-xyz/anchor';
49
48
  import driftIDL from './idl/drift.json';
@@ -60,11 +59,10 @@ import {
60
59
  LAMPORTS_PER_SOL,
61
60
  Signer,
62
61
  SystemProgram,
63
- ComputeBudgetProgram,
64
62
  AddressLookupTableAccount,
65
63
  TransactionVersion,
66
64
  VersionedTransaction,
67
- TransactionMessage,
65
+ BlockhashWithExpiryBlockHeight,
68
66
  } from '@solana/web3.js';
69
67
 
70
68
  import { TokenFaucet } from './tokenFaucet';
@@ -88,10 +86,9 @@ import {
88
86
  DriftClientAccountSubscriber,
89
87
  DriftClientAccountEvents,
90
88
  DataAndSlot,
91
- DriftClientMetricsEvents,
92
89
  } from './accounts/types';
93
- import { ExtraConfirmationOptions, TxSender, TxSigAndSlot } from './tx/types';
94
- import { getSignedTransactionMap, wrapInTx } from './tx/utils';
90
+ import { DriftClientMetricsEvents } from './types';
91
+ import { TxSender, TxSigAndSlot } from './tx/types';
95
92
  import {
96
93
  BASE_PRECISION,
97
94
  PRICE_PRECISION,
@@ -127,8 +124,9 @@ import { UserStatsSubscriptionConfig } from './userStatsConfig';
127
124
  import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
128
125
  import { getOrderParams } from './orderParams';
129
126
  import { numberToSafeBN } from './math/utils';
130
- import { TransactionProcessor as TransactionParamProcessor } from './tx/txParamProcessor';
127
+ import { TransactionParamProcessor } from './tx/txParamProcessor';
131
128
  import { isOracleValid } from './math/oracles';
129
+ import { TxHandler } from './tx/txHandler';
132
130
 
133
131
  type RemainingAccountParams = {
134
132
  userAccounts: UserAccount[];
@@ -176,6 +174,8 @@ export class DriftClient {
176
174
  txParams: TxParams;
177
175
  enableMetricsEvents?: boolean;
178
176
 
177
+ txHandler: TxHandler;
178
+
179
179
  public get isSubscribed() {
180
180
  return this._isSubscribed && this.accountSubscriber.isSubscribed;
181
181
  }
@@ -213,6 +213,19 @@ export class DriftClient {
213
213
  computeUnitsPrice: config.txParams?.computeUnitsPrice ?? 0,
214
214
  };
215
215
 
216
+ this.txHandler =
217
+ config?.txHandler ??
218
+ new TxHandler({
219
+ connection: this.connection,
220
+ wallet: this.provider.wallet,
221
+ confirmationOptions: this.opts,
222
+ opts: {
223
+ returnBlockHeightsWithSignedTxCallbackData:
224
+ config.enableMetricsEvents,
225
+ onSignedCb: this.handleSignedTransaction.bind(this),
226
+ },
227
+ });
228
+
216
229
  if (config.includeDelegates && config.subAccountIds) {
217
230
  throw new Error(
218
231
  'Can only pass one of includeDelegates or subAccountIds. If you want to specify subaccount ids for multiple authorities, pass authoritySubaccountMap instead'
@@ -309,9 +322,10 @@ export class DriftClient {
309
322
  }
310
323
  this.eventEmitter = this.accountSubscriber.eventEmitter;
311
324
 
325
+ this.metricsEventEmitter = new EventEmitter();
326
+
312
327
  if (config.enableMetricsEvents) {
313
328
  this.enableMetricsEvents = true;
314
- this.metricsEventEmitter = new EventEmitter();
315
329
  }
316
330
 
317
331
  this.txSender =
@@ -320,6 +334,7 @@ export class DriftClient {
320
334
  connection: this.connection,
321
335
  wallet: this.wallet,
322
336
  opts: this.opts,
337
+ txHandler: this.txHandler,
323
338
  });
324
339
  }
325
340
 
@@ -564,6 +579,7 @@ export class DriftClient {
564
579
  // Update provider for txSender with new wallet details
565
580
  this.txSender.wallet = newWallet;
566
581
  this.wallet = newWallet;
582
+ this.txHandler.updateWallet(newWallet);
567
583
  this.provider = newProvider;
568
584
  this.program = newProgram;
569
585
  this.authority = newWallet.publicKey;
@@ -747,39 +763,6 @@ export class DriftClient {
747
763
  return result;
748
764
  }
749
765
 
750
- private async getProcessedTransactionParams(
751
- txParams: {
752
- instructions: TransactionInstruction | TransactionInstruction[];
753
- txParams?: BaseTxParams;
754
- txVersion?: TransactionVersion;
755
- lookupTables?: AddressLookupTableAccount[];
756
- },
757
- txParamProcessingParams: ProcessingTxParams
758
- ): Promise<BaseTxParams> {
759
- const tx = await TransactionParamProcessor.process({
760
- txProps: {
761
- instructions: txParams.instructions,
762
- txParams: txParams.txParams,
763
- txVersion: txParams.txVersion,
764
- lookupTables: txParams.lookupTables,
765
- },
766
- txBuilder: (updatedTxParams) =>
767
- this.buildTransaction(
768
- updatedTxParams.instructions,
769
- updatedTxParams?.txParams,
770
- updatedTxParams.txVersion,
771
- updatedTxParams.lookupTables,
772
- true
773
- ) as Promise<VersionedTransaction>,
774
- processConfig: txParamProcessingParams,
775
- processParams: {
776
- connection: this.connection,
777
- },
778
- });
779
-
780
- return tx;
781
- }
782
-
783
766
  public async initializeUserAccount(
784
767
  subAccountId = 0,
785
768
  name?: string,
@@ -2763,11 +2746,14 @@ export class DriftClient {
2763
2746
  );
2764
2747
  }
2765
2748
 
2766
- public async sendSignedTx(tx: Transaction): Promise<TransactionSignature> {
2749
+ public async sendSignedTx(
2750
+ tx: Transaction,
2751
+ opts?: ConfirmOptions
2752
+ ): Promise<TransactionSignature> {
2767
2753
  const { txSig } = await this.sendTransaction(
2768
2754
  tx,
2769
2755
  undefined,
2770
- this.opts,
2756
+ opts ?? this.opts,
2771
2757
  true
2772
2758
  );
2773
2759
 
@@ -2809,173 +2795,90 @@ export class DriftClient {
2809
2795
  userAccount.subAccountId
2810
2796
  );
2811
2797
 
2798
+ const ixsToSign: { key: string; ix: TransactionInstruction }[] = [];
2799
+
2800
+ const keys = {
2801
+ signedCancelExistingOrdersTx: 'signedCancelExistingOrdersTx',
2802
+ signedSettlePnlTx: 'signedSettlePnlTx',
2803
+ signedFillTx: 'signedFillTx',
2804
+ signedMarketOrderTx: 'signedMarketOrderTx',
2805
+ };
2806
+
2812
2807
  /* Cancel open orders in market if requested */
2813
- let cancelExistingOrdersTx;
2814
- if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) {
2815
- const cancelOrdersIx = await this.getCancelOrdersIx(
2816
- orderParams.marketType,
2817
- orderParams.marketIndex,
2818
- null,
2819
- userAccount.subAccountId
2820
- );
2821
2808
 
2822
- //@ts-ignore
2823
- cancelExistingOrdersTx = await this.buildTransaction(
2824
- [cancelOrdersIx],
2825
- txParams,
2826
- this.txVersion
2827
- );
2809
+ if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) {
2810
+ ixsToSign.push({
2811
+ key: keys.signedCancelExistingOrdersTx,
2812
+ ix: await this.getCancelOrdersIx(
2813
+ orderParams.marketType,
2814
+ orderParams.marketIndex,
2815
+ null,
2816
+ userAccount.subAccountId
2817
+ ),
2818
+ });
2828
2819
  }
2829
2820
 
2830
2821
  /* Settle PnL after fill if requested */
2831
- let settlePnlTx;
2832
2822
  if (settlePnl && isVariant(orderParams.marketType, 'perp')) {
2833
- const settlePnlIx = await this.settlePNLIx(
2834
- userAccountPublicKey,
2835
- userAccount,
2836
- marketIndex
2837
- );
2838
-
2839
- //@ts-ignore
2840
- settlePnlTx = await this.buildTransaction(
2841
- [settlePnlIx],
2842
- txParams,
2843
- this.txVersion
2844
- );
2823
+ ixsToSign.push({
2824
+ key: keys.signedSettlePnlTx,
2825
+ ix: await this.settlePNLIx(
2826
+ userAccountPublicKey,
2827
+ userAccount,
2828
+ marketIndex
2829
+ ),
2830
+ });
2845
2831
  }
2846
2832
 
2847
2833
  // use versioned transactions if there is a lookup table account and wallet is compatible
2848
2834
  if (this.txVersion === 0) {
2849
- const versionedMarketOrderTx = await this.buildTransaction(
2850
- ordersIx,
2851
- txParams,
2852
- 0
2853
- );
2854
-
2855
- const fillPerpOrderIx = await this.getFillPerpOrderIx(
2856
- userAccountPublicKey,
2857
- userAccount,
2858
- {
2859
- orderId,
2860
- marketIndex,
2861
- },
2862
- makerInfo,
2863
- referrerInfo,
2864
- userAccount.subAccountId
2865
- );
2866
-
2867
- const versionedFillTx = await this.buildTransaction(
2868
- [fillPerpOrderIx],
2869
- txParams,
2870
- 0
2871
- );
2872
-
2873
- const allPossibleTxs = [
2874
- versionedMarketOrderTx,
2875
- versionedFillTx,
2876
- cancelExistingOrdersTx,
2877
- settlePnlTx,
2878
- ];
2879
- const txKeys = [
2880
- 'signedVersionedMarketOrderTx',
2881
- 'signedVersionedFillTx',
2882
- 'signedCancelExistingOrdersTx',
2883
- 'signedSettlePnlTx',
2884
- ];
2885
-
2886
- const {
2887
- signedVersionedMarketOrderTx,
2888
- signedVersionedFillTx,
2889
- signedCancelExistingOrdersTx,
2890
- signedSettlePnlTx,
2891
- } = await getSignedTransactionMap(
2892
- //@ts-ignore
2893
- this.provider.wallet,
2894
- allPossibleTxs,
2895
- txKeys
2896
- );
2897
-
2898
- const { txSig, slot } = await this.sendTransaction(
2899
- signedVersionedMarketOrderTx,
2900
- [],
2901
- this.opts,
2902
- true
2903
- );
2904
- this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2905
-
2906
- return {
2907
- txSig,
2908
- // @ts-ignore
2909
- signedFillTx: signedVersionedFillTx,
2910
- // @ts-ignore
2911
- signedCancelExistingOrdersTx,
2912
- // @ts-ignore
2913
- signedSettlePnlTx,
2914
- };
2915
- } else {
2916
- const marketOrderTx = wrapInTx(
2917
- ordersIx,
2918
- txParams?.computeUnits,
2919
- txParams?.computeUnitsPrice
2920
- );
2921
-
2922
- // Apply the latest blockhash to the txs so that we can sign before sending them
2923
- const currentBlockHash = (
2924
- await this.connection.getLatestBlockhash('finalized')
2925
- ).blockhash;
2926
- marketOrderTx.recentBlockhash = currentBlockHash;
2835
+ ixsToSign.push({
2836
+ key: keys.signedFillTx,
2837
+ ix: await this.getFillPerpOrderIx(
2838
+ userAccountPublicKey,
2839
+ userAccount,
2840
+ {
2841
+ orderId,
2842
+ marketIndex,
2843
+ },
2844
+ makerInfo,
2845
+ referrerInfo,
2846
+ userAccount.subAccountId
2847
+ ),
2848
+ });
2849
+ }
2927
2850
 
2928
- marketOrderTx.feePayer = userAccount.authority;
2851
+ // Apply the latest blockhash to the txs so that we can sign before sending them
2852
+ ixsToSign.push({
2853
+ key: keys.signedMarketOrderTx,
2854
+ ix: ordersIx,
2855
+ });
2929
2856
 
2930
- if (cancelExistingOrdersTx) {
2931
- cancelExistingOrdersTx.recentBlockhash = currentBlockHash;
2932
- cancelExistingOrdersTx.feePayer = userAccount.authority;
2933
- }
2857
+ const signedTransactions = await this.buildAndSignBulkTransactions(
2858
+ ixsToSign.map((ix) => ix.ix),
2859
+ ixsToSign.map((ix) => ix.key),
2860
+ txParams
2861
+ );
2934
2862
 
2935
- if (settlePnlTx) {
2936
- settlePnlTx.recentBlockhash = currentBlockHash;
2937
- settlePnlTx.feePayer = userAccount.authority;
2938
- }
2863
+ const { txSig, slot } = await this.sendTransaction(
2864
+ signedTransactions[keys.signedMarketOrderTx],
2865
+ [],
2866
+ this.opts,
2867
+ true
2868
+ );
2939
2869
 
2940
- const allPossibleTxs = [
2941
- marketOrderTx,
2942
- cancelExistingOrdersTx,
2943
- settlePnlTx,
2944
- ];
2945
- const txKeys = [
2946
- 'signedMarketOrderTx',
2947
- 'signedCancelExistingOrdersTx',
2948
- 'signedSettlePnlTx',
2949
- ];
2950
-
2951
- const {
2952
- signedMarketOrderTx,
2953
- signedCancelExistingOrdersTx,
2954
- signedSettlePnlTx,
2955
- } = await getSignedTransactionMap(
2956
- //@ts-ignore
2957
- this.provider.wallet,
2958
- allPossibleTxs,
2959
- txKeys
2960
- );
2870
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2961
2871
 
2962
- const { txSig, slot } = await this.sendTransaction(
2963
- signedMarketOrderTx,
2964
- [],
2965
- this.opts,
2966
- true
2967
- );
2968
- this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2969
-
2970
- return {
2971
- txSig,
2972
- signedFillTx: undefined,
2973
- //@ts-ignore
2974
- signedCancelExistingOrdersTx,
2975
- //@ts-ignore
2976
- signedSettlePnlTx,
2977
- };
2978
- }
2872
+ return {
2873
+ txSig,
2874
+ signedFillTx: signedTransactions?.[keys.signedFillTx] as Transaction,
2875
+ signedCancelExistingOrdersTx: signedTransactions?.[
2876
+ keys.signedCancelExistingOrdersTx
2877
+ ] as Transaction,
2878
+ signedSettlePnlTx: signedTransactions?.[
2879
+ keys.signedSettlePnlTx
2880
+ ] as Transaction,
2881
+ };
2979
2882
  }
2980
2883
 
2981
2884
  public async placePerpOrder(
@@ -4086,7 +3989,7 @@ export class DriftClient {
4086
3989
  const { beginSwapIx, endSwapIx } = await this.getSwapIx({
4087
3990
  outMarketIndex,
4088
3991
  inMarketIndex,
4089
- amountIn: amount,
3992
+ amountIn: new BN(route.inAmount),
4090
3993
  inTokenAccount: inAssociatedTokenAccount,
4091
3994
  outTokenAccount: outAssociatedTokenAccount,
4092
3995
  reduceOnly,
@@ -4216,7 +4119,7 @@ export class DriftClient {
4216
4119
  const { beginSwapIx, endSwapIx } = await this.getSwapIx({
4217
4120
  outMarketIndex,
4218
4121
  inMarketIndex,
4219
- amountIn: amount,
4122
+ amountIn: new BN(quote.inAmount),
4220
4123
  inTokenAccount: inAssociatedTokenAccount,
4221
4124
  outTokenAccount: outAssociatedTokenAccount,
4222
4125
  reduceOnly,
@@ -4625,7 +4528,7 @@ export class DriftClient {
4625
4528
  signedCancelExistingOrdersTx?: Transaction;
4626
4529
  signedSettlePnlTx?: Transaction;
4627
4530
  }> {
4628
- const ixs = [];
4531
+ const placeAndTakeIxs: TransactionInstruction[] = [];
4629
4532
 
4630
4533
  const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx(
4631
4534
  orderParams,
@@ -4634,14 +4537,25 @@ export class DriftClient {
4634
4537
  subAccountId
4635
4538
  );
4636
4539
 
4637
- ixs.push(placeAndTakeIx);
4540
+ const txsToSign: {
4541
+ key: string;
4542
+ tx: Transaction | VersionedTransaction;
4543
+ }[] = [];
4544
+
4545
+ const keys = {
4546
+ placeAndTakeIx: 'placeAndTakeIx',
4547
+ cancelExistingOrdersTx: 'cancelExistingOrdersTx',
4548
+ settlePnlTx: 'settlePnlTx',
4549
+ };
4550
+
4551
+ placeAndTakeIxs.push(placeAndTakeIx);
4638
4552
 
4639
4553
  if (bracketOrdersParams.length > 0) {
4640
4554
  const bracketOrdersIx = await this.getPlaceOrdersIx(
4641
4555
  bracketOrdersParams,
4642
4556
  subAccountId
4643
4557
  );
4644
- ixs.push(bracketOrdersIx);
4558
+ placeAndTakeIxs.push(bracketOrdersIx);
4645
4559
  }
4646
4560
 
4647
4561
  const shouldUseSimulationComputeUnits = txParams?.useSimulatedComputeUnits;
@@ -4652,29 +4566,23 @@ export class DriftClient {
4652
4566
  useSimulationComputeUnits: false,
4653
4567
  };
4654
4568
 
4655
- let placeAndTakeTx = await this.buildTransaction(
4656
- ixs,
4657
- txParamsWithoutImplicitSimulation
4658
- );
4569
+ // Get recent block hash so that we can re-use it for all transactions. Makes this logic run faster with fewer RPC requests
4570
+ const recentBlockHash =
4571
+ await this.txHandler.getLatestBlockhashForTransaction();
4659
4572
 
4660
4573
  if (shouldUseSimulationComputeUnits || shouldExitIfSimulationFails) {
4661
- let versionedPlaceAndTakeTx: VersionedTransaction;
4662
-
4663
- if (this.isVersionedTransaction(placeAndTakeTx)) {
4664
- versionedPlaceAndTakeTx = placeAndTakeTx as VersionedTransaction;
4665
- } else {
4666
- versionedPlaceAndTakeTx = (await this.buildTransaction(
4667
- ixs,
4668
- txParamsWithoutImplicitSimulation,
4669
- undefined,
4670
- undefined,
4671
- true
4672
- )) as VersionedTransaction;
4673
- }
4574
+ const placeAndTakeTxToSim = (await this.buildTransaction(
4575
+ placeAndTakeIxs,
4576
+ txParamsWithoutImplicitSimulation,
4577
+ undefined,
4578
+ undefined,
4579
+ true,
4580
+ recentBlockHash
4581
+ )) as VersionedTransaction;
4674
4582
 
4675
4583
  const simulationResult =
4676
4584
  await TransactionParamProcessor.getTxSimComputeUnits(
4677
- versionedPlaceAndTakeTx,
4585
+ placeAndTakeTxToSim,
4678
4586
  this.connection
4679
4587
  );
4680
4588
 
@@ -4682,15 +4590,34 @@ export class DriftClient {
4682
4590
  return;
4683
4591
  }
4684
4592
 
4685
- if (shouldUseSimulationComputeUnits) {
4686
- placeAndTakeTx = await this.buildTransaction(ixs, {
4687
- ...txParamsWithoutImplicitSimulation,
4688
- computeUnits: simulationResult.computeUnits,
4689
- });
4690
- }
4593
+ txsToSign.push({
4594
+ key: keys.placeAndTakeIx,
4595
+ tx: await this.buildTransaction(
4596
+ placeAndTakeIxs,
4597
+ {
4598
+ ...txParamsWithoutImplicitSimulation,
4599
+ computeUnits: simulationResult.computeUnits,
4600
+ },
4601
+ undefined,
4602
+ undefined,
4603
+ undefined,
4604
+ recentBlockHash
4605
+ ),
4606
+ });
4607
+ } else {
4608
+ txsToSign.push({
4609
+ key: keys.placeAndTakeIx,
4610
+ tx: await this.buildTransaction(
4611
+ placeAndTakeIxs,
4612
+ txParamsWithoutImplicitSimulation,
4613
+ undefined,
4614
+ undefined,
4615
+ undefined,
4616
+ recentBlockHash
4617
+ ),
4618
+ });
4691
4619
  }
4692
4620
 
4693
- let cancelExistingOrdersTx: Transaction;
4694
4621
  if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) {
4695
4622
  const cancelOrdersIx = await this.getCancelOrdersIx(
4696
4623
  orderParams.marketType,
@@ -4699,16 +4626,19 @@ export class DriftClient {
4699
4626
  subAccountId
4700
4627
  );
4701
4628
 
4702
- //@ts-ignore
4703
- cancelExistingOrdersTx = await this.buildTransaction(
4704
- [cancelOrdersIx],
4705
- txParams,
4706
- this.txVersion
4707
- );
4629
+ txsToSign.push({
4630
+ key: keys.cancelExistingOrdersTx,
4631
+ tx: await this.buildTransaction(
4632
+ [cancelOrdersIx],
4633
+ txParams,
4634
+ this.txVersion,
4635
+ undefined,
4636
+ undefined,
4637
+ recentBlockHash
4638
+ ),
4639
+ });
4708
4640
  }
4709
4641
 
4710
- /* Settle PnL after fill if requested */
4711
- let settlePnlTx: Transaction;
4712
4642
  if (settlePnl && isVariant(orderParams.marketType, 'perp')) {
4713
4643
  const userAccountPublicKey = await this.getUserAccountPublicKey(
4714
4644
  subAccountId
@@ -4720,46 +4650,40 @@ export class DriftClient {
4720
4650
  orderParams.marketIndex
4721
4651
  );
4722
4652
 
4723
- //@ts-ignore
4724
- settlePnlTx = await this.buildTransaction(
4725
- [settlePnlIx],
4726
- txParams,
4727
- this.txVersion
4728
- );
4653
+ txsToSign.push({
4654
+ key: keys.settlePnlTx,
4655
+ tx: await this.buildTransaction(
4656
+ [settlePnlIx],
4657
+ txParams,
4658
+ this.txVersion,
4659
+ undefined,
4660
+ undefined,
4661
+ recentBlockHash
4662
+ ),
4663
+ });
4729
4664
  }
4730
4665
 
4731
- const allPossibleTxs = [
4732
- placeAndTakeTx,
4733
- cancelExistingOrdersTx,
4734
- settlePnlTx,
4735
- ];
4736
- const txKeys = [
4737
- 'signedPlaceAndTakeTx',
4738
- 'signedCancelExistingOrdersTx',
4739
- 'signedSettlePnlTx',
4740
- ];
4741
-
4742
- const {
4743
- signedPlaceAndTakeTx,
4744
- signedCancelExistingOrdersTx,
4745
- signedSettlePnlTx,
4746
- } = await getSignedTransactionMap(
4747
- //@ts-ignore
4748
- this.provider.wallet,
4749
- allPossibleTxs,
4750
- txKeys
4666
+ const signedTxs = await this.txHandler.getSignedTransactionMap(
4667
+ txsToSign.map((tx) => tx.tx),
4668
+ txsToSign.map((tx) => tx.key),
4669
+ this.provider.wallet
4751
4670
  );
4752
4671
 
4753
4672
  const { txSig, slot } = await this.sendTransaction(
4754
- signedPlaceAndTakeTx,
4673
+ signedTxs[keys.placeAndTakeIx],
4755
4674
  [],
4756
4675
  this.opts,
4757
4676
  true
4758
4677
  );
4759
4678
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
4760
4679
 
4761
- //@ts-ignore
4762
- return { txSig, signedCancelExistingOrdersTx, signedSettlePnlTx };
4680
+ return {
4681
+ txSig,
4682
+ signedCancelExistingOrdersTx: signedTxs[
4683
+ keys.cancelExistingOrdersTx
4684
+ ] as Transaction,
4685
+ signedSettlePnlTx: signedTxs[keys.settlePnlTx] as Transaction,
4686
+ };
4763
4687
  }
4764
4688
 
4765
4689
  public async getPlaceAndTakePerpOrderIx(
@@ -6718,8 +6642,10 @@ export class DriftClient {
6718
6642
  return undefined;
6719
6643
  }
6720
6644
 
6721
- private handleSignedTransaction() {
6722
- this.metricsEventEmitter.emit('txSigned');
6645
+ private handleSignedTransaction(signedTxs: SignedTxData[]) {
6646
+ if (this.enableMetricsEvents && this.metricsEventEmitter) {
6647
+ this.metricsEventEmitter.emit('txSigned', signedTxs);
6648
+ }
6723
6649
  }
6724
6650
 
6725
6651
  private isVersionedTransaction(
@@ -6738,13 +6664,6 @@ export class DriftClient {
6738
6664
  opts?: ConfirmOptions,
6739
6665
  preSigned?: boolean
6740
6666
  ): Promise<TxSigAndSlot> {
6741
- const extraConfirmationOptions: ExtraConfirmationOptions = this
6742
- .enableMetricsEvents
6743
- ? {
6744
- onSignedCb: this.handleSignedTransaction.bind(this),
6745
- }
6746
- : undefined;
6747
-
6748
6667
  const isVersionedTx = this.isVersionedTransaction(tx);
6749
6668
 
6750
6669
  if (isVersionedTx) {
@@ -6752,136 +6671,79 @@ export class DriftClient {
6752
6671
  tx as VersionedTransaction,
6753
6672
  additionalSigners,
6754
6673
  opts,
6755
- preSigned,
6756
- extraConfirmationOptions
6674
+ preSigned
6757
6675
  );
6758
6676
  } else {
6759
6677
  return this.txSender.send(
6760
6678
  tx as Transaction,
6761
6679
  additionalSigners,
6762
6680
  opts,
6763
- preSigned,
6764
- extraConfirmationOptions
6681
+ preSigned
6765
6682
  );
6766
6683
  }
6767
6684
  }
6768
6685
 
6769
- /**
6770
- *
6771
- * @param instructions
6772
- * @param txParams
6773
- * @param txVersion
6774
- * @param lookupTables
6775
- * @param forceVersionedTransaction Return a VersionedTransaction instance even if the version of the transaction is Legacy
6776
- * @returns
6777
- */
6778
6686
  async buildTransaction(
6779
6687
  instructions: TransactionInstruction | TransactionInstruction[],
6780
6688
  txParams?: TxParams,
6781
6689
  txVersion?: TransactionVersion,
6782
6690
  lookupTables?: AddressLookupTableAccount[],
6783
- forceVersionedTransaction?: boolean
6691
+ forceVersionedTransaction?: boolean,
6692
+ recentBlockHash?: BlockhashWithExpiryBlockHeight
6784
6693
  ): Promise<Transaction | VersionedTransaction> {
6785
- txVersion = txVersion ?? this.txVersion;
6786
-
6787
- // # Collect and process Tx Params
6788
- let baseTxParams: BaseTxParams = {
6789
- computeUnits: txParams?.computeUnits ?? this.txParams.computeUnits,
6790
- computeUnitsPrice:
6791
- txParams?.computeUnitsPrice ?? this.txParams.computeUnitsPrice,
6792
- };
6793
-
6794
- if (txParams?.useSimulatedComputeUnits) {
6795
- const splitTxParams: {
6796
- baseTxParams: BaseTxParams;
6797
- txParamProcessingParams: ProcessingTxParams;
6798
- } = {
6799
- baseTxParams: {
6800
- computeUnits: txParams?.computeUnits,
6801
- computeUnitsPrice: txParams?.computeUnitsPrice,
6802
- },
6803
- txParamProcessingParams: {
6804
- useSimulatedComputeUnits: txParams?.useSimulatedComputeUnits,
6805
- computeUnitsBufferMultiplier: txParams?.computeUnitsBufferMultiplier,
6806
- useSimulatedComputeUnitsForCUPriceCalculation:
6807
- txParams?.useSimulatedComputeUnitsForCUPriceCalculation,
6808
- getCUPriceFromComputeUnits: txParams?.getCUPriceFromComputeUnits,
6809
- },
6810
- };
6811
-
6812
- const processedTxParams = await this.getProcessedTransactionParams(
6813
- {
6814
- instructions,
6815
- txParams: splitTxParams.baseTxParams,
6816
- txVersion,
6817
- lookupTables,
6818
- },
6819
- splitTxParams.txParamProcessingParams
6820
- );
6821
-
6822
- baseTxParams = {
6823
- ...baseTxParams,
6824
- ...processedTxParams,
6825
- };
6826
- }
6827
-
6828
- // # Create Tx Instructions
6829
- const allIx = [];
6830
- const computeUnits = baseTxParams?.computeUnits;
6831
- if (computeUnits !== 200_000) {
6832
- allIx.push(
6833
- ComputeBudgetProgram.setComputeUnitLimit({
6834
- units: computeUnits,
6835
- })
6836
- );
6837
- }
6838
-
6839
- const computeUnitsPrice = baseTxParams?.computeUnitsPrice;
6840
-
6841
- if (computeUnitsPrice !== 0) {
6842
- allIx.push(
6843
- ComputeBudgetProgram.setComputeUnitPrice({
6844
- microLamports: computeUnitsPrice,
6845
- })
6846
- );
6847
- }
6848
-
6849
- if (Array.isArray(instructions)) {
6850
- allIx.push(...instructions);
6851
- } else {
6852
- allIx.push(instructions);
6853
- }
6854
-
6855
- const latestBlockHashAndContext =
6856
- await this.connection.getLatestBlockhashAndContext({
6857
- commitment: this.opts.preflightCommitment,
6858
- });
6694
+ return this.txHandler.buildTransaction({
6695
+ instructions,
6696
+ txVersion: txVersion ?? this.txVersion,
6697
+ txParams,
6698
+ connection: this.connection,
6699
+ preFlightCommitment: this.opts.preflightCommitment,
6700
+ fetchMarketLookupTableAccount:
6701
+ this.fetchMarketLookupTableAccount.bind(this),
6702
+ lookupTables,
6703
+ forceVersionedTransaction,
6704
+ recentBlockHash,
6705
+ });
6706
+ }
6859
6707
 
6860
- // # Create and return Transaction
6861
- if (txVersion === 'legacy') {
6862
- if (forceVersionedTransaction) {
6863
- const message = new TransactionMessage({
6864
- payerKey: this.provider.wallet.publicKey,
6865
- recentBlockhash: latestBlockHashAndContext.value.blockhash,
6866
- instructions: allIx,
6867
- }).compileToLegacyMessage();
6708
+ async buildBulkTransactions(
6709
+ instructions: (TransactionInstruction | TransactionInstruction[])[],
6710
+ txParams?: TxParams,
6711
+ txVersion?: TransactionVersion,
6712
+ lookupTables?: AddressLookupTableAccount[],
6713
+ forceVersionedTransaction?: boolean
6714
+ ): Promise<(Transaction | VersionedTransaction)[]> {
6715
+ return this.txHandler.buildBulkTransactions({
6716
+ instructions,
6717
+ txVersion: txVersion ?? this.txVersion,
6718
+ txParams,
6719
+ connection: this.connection,
6720
+ preFlightCommitment: this.opts.preflightCommitment,
6721
+ fetchMarketLookupTableAccount:
6722
+ this.fetchMarketLookupTableAccount.bind(this),
6723
+ lookupTables,
6724
+ forceVersionedTransaction,
6725
+ });
6726
+ }
6868
6727
 
6869
- return new VersionedTransaction(message);
6870
- } else {
6871
- return new Transaction().add(...allIx);
6872
- }
6873
- } else {
6874
- const marketLookupTable = await this.fetchMarketLookupTableAccount();
6875
- lookupTables = lookupTables
6876
- ? [...lookupTables, marketLookupTable]
6877
- : [marketLookupTable];
6878
- const message = new TransactionMessage({
6879
- payerKey: this.provider.wallet.publicKey,
6880
- recentBlockhash: latestBlockHashAndContext.value.blockhash,
6881
- instructions: allIx,
6882
- }).compileToV0Message(lookupTables);
6883
-
6884
- return new VersionedTransaction(message);
6885
- }
6728
+ async buildAndSignBulkTransactions(
6729
+ instructions: (TransactionInstruction | TransactionInstruction[])[],
6730
+ keys: string[],
6731
+ txParams?: TxParams,
6732
+ txVersion?: TransactionVersion,
6733
+ lookupTables?: AddressLookupTableAccount[],
6734
+ forceVersionedTransaction?: boolean
6735
+ ) {
6736
+ return this.txHandler.buildAndSignTransactionMap({
6737
+ instructions,
6738
+ txVersion: txVersion ?? this.txVersion,
6739
+ txParams,
6740
+ connection: this.connection,
6741
+ preFlightCommitment: this.opts.preflightCommitment,
6742
+ fetchMarketLookupTableAccount:
6743
+ this.fetchMarketLookupTableAccount.bind(this),
6744
+ lookupTables,
6745
+ forceVersionedTransaction,
6746
+ keys,
6747
+ });
6886
6748
  }
6887
6749
  }