@metamask/transaction-controller 52.0.0 → 52.2.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 (96) hide show
  1. package/CHANGELOG.md +52 -4
  2. package/dist/TransactionController.cjs +113 -36
  3. package/dist/TransactionController.cjs.map +1 -1
  4. package/dist/TransactionController.d.cts +38 -5
  5. package/dist/TransactionController.d.cts.map +1 -1
  6. package/dist/TransactionController.d.mts +38 -5
  7. package/dist/TransactionController.d.mts.map +1 -1
  8. package/dist/TransactionController.mjs +114 -37
  9. package/dist/TransactionController.mjs.map +1 -1
  10. package/dist/helpers/GasFeePoller.cjs +73 -1
  11. package/dist/helpers/GasFeePoller.cjs.map +1 -1
  12. package/dist/helpers/GasFeePoller.d.cts +20 -2
  13. package/dist/helpers/GasFeePoller.d.cts.map +1 -1
  14. package/dist/helpers/GasFeePoller.d.mts +20 -2
  15. package/dist/helpers/GasFeePoller.d.mts.map +1 -1
  16. package/dist/helpers/GasFeePoller.mjs +72 -1
  17. package/dist/helpers/GasFeePoller.mjs.map +1 -1
  18. package/dist/hooks/CollectPublishHook.cjs +84 -0
  19. package/dist/hooks/CollectPublishHook.cjs.map +1 -0
  20. package/dist/hooks/CollectPublishHook.d.cts +29 -0
  21. package/dist/hooks/CollectPublishHook.d.cts.map +1 -0
  22. package/dist/hooks/CollectPublishHook.d.mts +29 -0
  23. package/dist/hooks/CollectPublishHook.d.mts.map +1 -0
  24. package/dist/hooks/CollectPublishHook.mjs +80 -0
  25. package/dist/hooks/CollectPublishHook.mjs.map +1 -0
  26. package/dist/hooks/ExtraTransactionsPublishHook.cjs +90 -0
  27. package/dist/hooks/ExtraTransactionsPublishHook.cjs.map +1 -0
  28. package/dist/hooks/ExtraTransactionsPublishHook.d.cts +18 -0
  29. package/dist/hooks/ExtraTransactionsPublishHook.d.cts.map +1 -0
  30. package/dist/hooks/ExtraTransactionsPublishHook.d.mts +18 -0
  31. package/dist/hooks/ExtraTransactionsPublishHook.d.mts.map +1 -0
  32. package/dist/hooks/ExtraTransactionsPublishHook.mjs +86 -0
  33. package/dist/hooks/ExtraTransactionsPublishHook.mjs.map +1 -0
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +1 -1
  36. package/dist/index.d.cts.map +1 -1
  37. package/dist/index.d.mts +1 -1
  38. package/dist/index.d.mts.map +1 -1
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/types.cjs.map +1 -1
  41. package/dist/types.d.cts +143 -2
  42. package/dist/types.d.cts.map +1 -1
  43. package/dist/types.d.mts +143 -2
  44. package/dist/types.d.mts.map +1 -1
  45. package/dist/types.mjs.map +1 -1
  46. package/dist/utils/batch.cjs +142 -1
  47. package/dist/utils/batch.cjs.map +1 -1
  48. package/dist/utils/batch.d.cts +7 -1
  49. package/dist/utils/batch.d.cts.map +1 -1
  50. package/dist/utils/batch.d.mts +7 -1
  51. package/dist/utils/batch.d.mts.map +1 -1
  52. package/dist/utils/batch.mjs +142 -1
  53. package/dist/utils/batch.mjs.map +1 -1
  54. package/dist/utils/eip7702.cjs +12 -0
  55. package/dist/utils/eip7702.cjs.map +1 -1
  56. package/dist/utils/eip7702.d.cts.map +1 -1
  57. package/dist/utils/eip7702.d.mts.map +1 -1
  58. package/dist/utils/eip7702.mjs +12 -0
  59. package/dist/utils/eip7702.mjs.map +1 -1
  60. package/dist/utils/feature-flags.cjs +2 -2
  61. package/dist/utils/feature-flags.cjs.map +1 -1
  62. package/dist/utils/feature-flags.d.cts +2 -2
  63. package/dist/utils/feature-flags.d.mts +2 -2
  64. package/dist/utils/feature-flags.mjs +2 -2
  65. package/dist/utils/feature-flags.mjs.map +1 -1
  66. package/dist/utils/gas.cjs +115 -11
  67. package/dist/utils/gas.cjs.map +1 -1
  68. package/dist/utils/gas.d.cts +16 -5
  69. package/dist/utils/gas.d.cts.map +1 -1
  70. package/dist/utils/gas.d.mts +16 -5
  71. package/dist/utils/gas.d.mts.map +1 -1
  72. package/dist/utils/gas.mjs +115 -11
  73. package/dist/utils/gas.mjs.map +1 -1
  74. package/dist/utils/nonce.cjs +3 -3
  75. package/dist/utils/nonce.cjs.map +1 -1
  76. package/dist/utils/nonce.d.cts +2 -2
  77. package/dist/utils/nonce.d.cts.map +1 -1
  78. package/dist/utils/nonce.d.mts +2 -2
  79. package/dist/utils/nonce.d.mts.map +1 -1
  80. package/dist/utils/nonce.mjs +3 -3
  81. package/dist/utils/nonce.mjs.map +1 -1
  82. package/dist/utils/simulation-api.cjs.map +1 -1
  83. package/dist/utils/simulation-api.d.cts +46 -5
  84. package/dist/utils/simulation-api.d.cts.map +1 -1
  85. package/dist/utils/simulation-api.d.mts +46 -5
  86. package/dist/utils/simulation-api.d.mts.map +1 -1
  87. package/dist/utils/simulation-api.mjs.map +1 -1
  88. package/dist/utils/simulation.cjs +46 -7
  89. package/dist/utils/simulation.cjs.map +1 -1
  90. package/dist/utils/simulation.d.cts +6 -2
  91. package/dist/utils/simulation.d.cts.map +1 -1
  92. package/dist/utils/simulation.d.mts +6 -2
  93. package/dist/utils/simulation.d.mts.map +1 -1
  94. package/dist/utils/simulation.mjs +46 -7
  95. package/dist/utils/simulation.mjs.map +1 -1
  96. package/package.json +2 -2
@@ -9,7 +9,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _TransactionController_instances, _TransactionController_internalEvents, _TransactionController_methodDataHelper, _TransactionController_incomingTransactionHelper, _TransactionController_incomingTransactionOptions, _TransactionController_pendingTransactionOptions, _TransactionController_publicKeyEIP7702, _TransactionController_trace, _TransactionController_transactionHistoryLimit, _TransactionController_isFirstTimeInteractionEnabled, _TransactionController_isSimulationEnabled, _TransactionController_testGasFeeFlows, _TransactionController_multichainTrackingHelper, _TransactionController_retryTransaction, _TransactionController_rejectTransaction, _TransactionController_getChainId, _TransactionController_getNetworkClientId, _TransactionController_getEthQuery, _TransactionController_getProvider, _TransactionController_createNonceTracker, _TransactionController_createPendingTransactionTracker, _TransactionController_checkForPendingTransactionAndStartPolling, _TransactionController_stopAllTracking, _TransactionController_addIncomingTransactionHelperListeners, _TransactionController_removePendingTransactionTrackerListeners, _TransactionController_addPendingTransactionTrackerListeners, _TransactionController_getNonceTrackerPendingTransactions, _TransactionController_getGasFeeFlows, _TransactionController_getLayer1GasFeeFlows, _TransactionController_updateTransactionInternal, _TransactionController_updateFirstTimeInteraction, _TransactionController_updateSimulationData, _TransactionController_onGasFeePollerTransactionUpdate, _TransactionController_getSelectedAccount, _TransactionController_getInternalAccounts, _TransactionController_updateSubmitHistory, _TransactionController_updateGasEstimate, _TransactionController_deleteTransaction, _TransactionController_isRejectError, _TransactionController_rejectTransactionAndThrow;
12
+ var _TransactionController_instances, _TransactionController_internalEvents, _TransactionController_methodDataHelper, _TransactionController_incomingTransactionHelper, _TransactionController_incomingTransactionOptions, _TransactionController_pendingTransactionOptions, _TransactionController_publishBatchHook, _TransactionController_publicKeyEIP7702, _TransactionController_trace, _TransactionController_transactionHistoryLimit, _TransactionController_isFirstTimeInteractionEnabled, _TransactionController_isSimulationEnabled, _TransactionController_testGasFeeFlows, _TransactionController_multichainTrackingHelper, _TransactionController_retryTransaction, _TransactionController_rejectTransaction, _TransactionController_getChainId, _TransactionController_getNetworkClientId, _TransactionController_getEthQuery, _TransactionController_getProvider, _TransactionController_createNonceTracker, _TransactionController_createPendingTransactionTracker, _TransactionController_checkForPendingTransactionAndStartPolling, _TransactionController_stopAllTracking, _TransactionController_addIncomingTransactionHelperListeners, _TransactionController_removePendingTransactionTrackerListeners, _TransactionController_addPendingTransactionTrackerListeners, _TransactionController_getNonceTrackerPendingTransactions, _TransactionController_getGasFeeFlows, _TransactionController_getLayer1GasFeeFlows, _TransactionController_updateTransactionInternal, _TransactionController_updateFirstTimeInteraction, _TransactionController_updateSimulationData, _TransactionController_onGasFeePollerTransactionUpdate, _TransactionController_getSelectedAccount, _TransactionController_getInternalAccounts, _TransactionController_updateSubmitHistory, _TransactionController_updateGasEstimate, _TransactionController_deleteTransaction, _TransactionController_isRejectError, _TransactionController_rejectTransactionAndThrow;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -24,7 +24,6 @@ import { NetworkClientType } from "@metamask/network-controller";
24
24
  import { NonceTracker } from "@metamask/nonce-tracker";
25
25
  import { errorCodes, rpcErrors, providerErrors } from "@metamask/rpc-errors";
26
26
  import { add0x, hexToNumber } from "@metamask/utils";
27
- import { Mutex } from "async-mutex";
28
27
  // This package purposefully relies on Node's EventEmitter module.
29
28
  // eslint-disable-next-line import-x/no-nodejs-modules
30
29
  import { EventEmitter } from "events";
@@ -38,12 +37,13 @@ import { OptimismLayer1GasFeeFlow } from "./gas-flows/OptimismLayer1GasFeeFlow.m
38
37
  import { ScrollLayer1GasFeeFlow } from "./gas-flows/ScrollLayer1GasFeeFlow.mjs";
39
38
  import { TestGasFeeFlow } from "./gas-flows/TestGasFeeFlow.mjs";
40
39
  import { AccountsApiRemoteTransactionSource } from "./helpers/AccountsApiRemoteTransactionSource.mjs";
41
- import { GasFeePoller } from "./helpers/GasFeePoller.mjs";
40
+ import { GasFeePoller, updateTransactionGasFees } from "./helpers/GasFeePoller.mjs";
42
41
  import { IncomingTransactionHelper } from "./helpers/IncomingTransactionHelper.mjs";
43
42
  import { MethodDataHelper } from "./helpers/MethodDataHelper.mjs";
44
43
  import { MultichainTrackingHelper } from "./helpers/MultichainTrackingHelper.mjs";
45
44
  import { PendingTransactionTracker } from "./helpers/PendingTransactionTracker.mjs";
46
45
  import { ResimulateHelper, hasSimulationDataChanged, shouldResimulate } from "./helpers/ResimulateHelper.mjs";
46
+ import { ExtraTransactionsPublishHook } from "./hooks/ExtraTransactionsPublishHook.mjs";
47
47
  import { projectLogger as log } from "./logger.mjs";
48
48
  import { TransactionEnvelopeType, TransactionType, TransactionStatus, SimulationErrorCode } from "./types.mjs";
49
49
  import { addTransactionBatch, isAtomicBatchSupported } from "./utils/batch.mjs";
@@ -158,7 +158,7 @@ export class TransactionController extends BaseController {
158
158
  * @param options - The controller options.
159
159
  */
160
160
  constructor(options) {
161
- const { disableHistory, disableSendFlowHistory, disableSwaps, getCurrentAccountEIP1559Compatibility, getCurrentNetworkEIP1559Compatibility, getExternalPendingTransactions, getGasFeeEstimates, getNetworkClientRegistry, getNetworkState, getPermittedAccounts, getSavedGasFees, incomingTransactions = {}, isFirstTimeInteractionEnabled, isSimulationEnabled, messenger, pendingTransactions = {}, publicKeyEIP7702, securityProviderRequest, sign, state, testGasFeeFlows, trace, transactionHistoryLimit = 40, hooks, } = options;
161
+ const { disableHistory, disableSendFlowHistory, disableSwaps, enableTxParamsGasFeeUpdates, getCurrentAccountEIP1559Compatibility, getCurrentNetworkEIP1559Compatibility, getExternalPendingTransactions, getGasFeeEstimates, getNetworkClientRegistry, getNetworkState, getPermittedAccounts, getSavedGasFees, incomingTransactions = {}, isFirstTimeInteractionEnabled, isSimulationEnabled, messenger, pendingTransactions = {}, publicKeyEIP7702, securityProviderRequest, sign, state, testGasFeeFlows, trace, transactionHistoryLimit = 40, hooks, } = options;
162
162
  super({
163
163
  name: controllerName,
164
164
  metadata,
@@ -172,10 +172,10 @@ export class TransactionController extends BaseController {
172
172
  _TransactionController_internalEvents.set(this, new EventEmitter());
173
173
  this.approvingTransactionIds = new Set();
174
174
  _TransactionController_methodDataHelper.set(this, void 0);
175
- this.mutex = new Mutex();
176
175
  _TransactionController_incomingTransactionHelper.set(this, void 0);
177
176
  _TransactionController_incomingTransactionOptions.set(this, void 0);
178
177
  _TransactionController_pendingTransactionOptions.set(this, void 0);
178
+ _TransactionController_publishBatchHook.set(this, void 0);
179
179
  _TransactionController_publicKeyEIP7702.set(this, void 0);
180
180
  this.signAbortCallbacks = new Map();
181
181
  _TransactionController_trace.set(this, void 0);
@@ -188,6 +188,7 @@ export class TransactionController extends BaseController {
188
188
  __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").checkForPendingTransactionAndStartPolling();
189
189
  });
190
190
  this.messagingSystem = messenger;
191
+ this.isTxParamsGasFeeUpdatesEnabled = enableTxParamsGasFeeUpdates ?? false;
191
192
  this.getNetworkState = getNetworkState;
192
193
  this.isSendFlowHistoryDisabled = disableSendFlowHistory ?? false;
193
194
  this.isHistoryDisabled = disableHistory ?? false;
@@ -207,6 +208,7 @@ export class TransactionController extends BaseController {
207
208
  this.securityProviderRequest = securityProviderRequest;
208
209
  __classPrivateFieldSet(this, _TransactionController_incomingTransactionOptions, incomingTransactions, "f");
209
210
  __classPrivateFieldSet(this, _TransactionController_pendingTransactionOptions, pendingTransactions, "f");
211
+ __classPrivateFieldSet(this, _TransactionController_publishBatchHook, hooks?.publishBatch, "f");
210
212
  __classPrivateFieldSet(this, _TransactionController_publicKeyEIP7702, publicKeyEIP7702, "f");
211
213
  __classPrivateFieldSet(this, _TransactionController_transactionHistoryLimit, transactionHistoryLimit, "f");
212
214
  this.sign = sign;
@@ -321,9 +323,12 @@ export class TransactionController extends BaseController {
321
323
  getChainId: __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getChainId).bind(this),
322
324
  getEthQuery: (networkClientId) => __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getEthQuery).call(this, { networkClientId }),
323
325
  getInternalAccounts: __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getInternalAccounts).bind(this),
326
+ getTransaction: (transactionId) => this.getTransactionOrThrow(transactionId),
324
327
  messenger: this.messagingSystem,
328
+ publishBatchHook: __classPrivateFieldGet(this, _TransactionController_publishBatchHook, "f"),
325
329
  publicKeyEIP7702: __classPrivateFieldGet(this, _TransactionController_publicKeyEIP7702, "f"),
326
330
  request,
331
+ updateTransaction: __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_updateTransactionInternal).bind(this),
327
332
  });
328
333
  }
329
334
  /**
@@ -350,9 +355,11 @@ export class TransactionController extends BaseController {
350
355
  * @param options.actionId - Unique ID to prevent duplicate requests.
351
356
  * @param options.batchId - A custom ID for the batch this transaction belongs to.
352
357
  * @param options.deviceConfirmedOn - An enum to indicate what device confirmed the transaction.
358
+ * @param options.disableGasBuffer - Whether to disable the gas estimation buffer.
353
359
  * @param options.method - RPC method that requested the transaction.
354
360
  * @param options.nestedTransactions - Params for any nested transactions encoded in the data.
355
361
  * @param options.origin - The origin of the transaction request, such as a dApp hostname.
362
+ * @param options.publishHook - Custom logic to publish the transaction.
356
363
  * @param options.requireApproval - Whether the transaction requires approval by the user, defaults to true unless explicitly disabled.
357
364
  * @param options.securityAlertResponse - Response from security validator.
358
365
  * @param options.sendFlowHistory - The sendFlowHistory entries to add.
@@ -366,7 +373,7 @@ export class TransactionController extends BaseController {
366
373
  */
367
374
  async addTransaction(txParams, options) {
368
375
  log('Adding transaction', txParams, options);
369
- const { actionId, batchId, deviceConfirmedOn, method, nestedTransactions, networkClientId, origin, requireApproval, securityAlertResponse, sendFlowHistory, swaps = {}, traceContext, type, } = options;
376
+ const { actionId, batchId, deviceConfirmedOn, disableGasBuffer, method, nestedTransactions, networkClientId, origin, publishHook, requireApproval, securityAlertResponse, sendFlowHistory, swaps = {}, traceContext, type, } = options;
370
377
  txParams = normalizeTransactionParams(txParams);
371
378
  if (!__classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").has(networkClientId)) {
372
379
  throw new Error(`Network client not found - ${networkClientId}`);
@@ -395,7 +402,7 @@ export class TransactionController extends BaseController {
395
402
  validateTxParams(txParams, isEIP1559Compatible);
396
403
  const isDuplicateBatchId = batchId?.length &&
397
404
  this.state.transactions.some((tx) => tx.batchId?.toLowerCase() === batchId?.toLowerCase());
398
- if (isDuplicateBatchId) {
405
+ if (isDuplicateBatchId && origin && origin !== ORIGIN_METAMASK) {
399
406
  throw rpcErrors.invalidInput('Batch ID already exists');
400
407
  }
401
408
  const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin);
@@ -413,6 +420,7 @@ export class TransactionController extends BaseController {
413
420
  dappSuggestedGasFees,
414
421
  delegationAddress,
415
422
  deviceConfirmedOn,
423
+ disableGasBuffer,
416
424
  id: random(),
417
425
  isFirstTimeInteraction: undefined,
418
426
  nestedTransactions,
@@ -470,9 +478,10 @@ export class TransactionController extends BaseController {
470
478
  }
471
479
  return {
472
480
  result: this.processApproval(addedTransactionMeta, {
481
+ actionId,
473
482
  isExisting: Boolean(existingTransactionMeta),
483
+ publishHook,
474
484
  requireApproval,
475
- actionId,
476
485
  traceContext,
477
486
  }),
478
487
  transactionMeta: addedTransactionMeta,
@@ -551,7 +560,12 @@ export class TransactionController extends BaseController {
551
560
  const ethQuery = __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getEthQuery).call(this, {
552
561
  networkClientId,
553
562
  });
554
- const { estimatedGas, simulationFails } = await estimateGas(transaction, ethQuery);
563
+ const { estimatedGas, simulationFails } = await estimateGas({
564
+ chainId: __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getChainId).call(this, networkClientId),
565
+ ethQuery,
566
+ isSimulationEnabled: __classPrivateFieldGet(this, _TransactionController_isSimulationEnabled, "f").call(this),
567
+ txParams: transaction,
568
+ });
555
569
  return { gas: estimatedGas, simulationFails };
556
570
  }
557
571
  /**
@@ -566,7 +580,12 @@ export class TransactionController extends BaseController {
566
580
  const ethQuery = __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getEthQuery).call(this, {
567
581
  networkClientId,
568
582
  });
569
- const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas(transaction, ethQuery);
583
+ const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas({
584
+ chainId: __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getChainId).call(this, networkClientId),
585
+ ethQuery,
586
+ isSimulationEnabled: __classPrivateFieldGet(this, _TransactionController_isSimulationEnabled, "f").call(this),
587
+ txParams: transaction,
588
+ });
570
589
  const gas = addGasBuffer(estimatedGas, blockGasLimit, multiplier);
571
590
  return {
572
591
  gas,
@@ -785,14 +804,16 @@ export class TransactionController extends BaseController {
785
804
  * @param txId - The ID of the transaction to update.
786
805
  * @param params - The editable parameters to update.
787
806
  * @param params.data - Data to pass with the transaction.
807
+ * @param params.from - Address to send the transaction from.
788
808
  * @param params.gas - Maximum number of units of gas to use for the transaction.
789
809
  * @param params.gasPrice - Price per gas for legacy transactions.
790
- * @param params.from - Address to send the transaction from.
810
+ * @param params.maxFeePerGas - Maximum amount per gas to pay for the transaction, including the priority fee.
811
+ * @param params.maxPriorityFeePerGas - Maximum amount per gas to give to validator as incentive.
791
812
  * @param params.to - Address to send the transaction to.
792
813
  * @param params.value - Value associated with the transaction.
793
814
  * @returns The updated transaction metadata.
794
815
  */
795
- async updateEditableParams(txId, { data, gas, gasPrice, from, to, value, }) {
816
+ async updateEditableParams(txId, { data, from, gas, gasPrice, maxFeePerGas, maxPriorityFeePerGas, to, value, }) {
796
817
  const transactionMeta = this.getTransaction(txId);
797
818
  if (!transactionMeta) {
798
819
  throw new Error(`Cannot update editable params as no transaction metadata found`);
@@ -806,6 +827,8 @@ export class TransactionController extends BaseController {
806
827
  value,
807
828
  gas,
808
829
  gasPrice,
830
+ maxFeePerGas,
831
+ maxPriorityFeePerGas,
809
832
  },
810
833
  };
811
834
  editableParams.txParams = pickBy(editableParams.txParams);
@@ -1158,6 +1181,38 @@ export class TransactionController extends BaseController {
1158
1181
  });
1159
1182
  return updatedTransactionMeta.txParams.data;
1160
1183
  }
1184
+ /**
1185
+ * Update the batch transactions associated with a transaction.
1186
+ * These transactions will be submitted with the main transaction as a batch.
1187
+ *
1188
+ * @param request - The request object.
1189
+ * @param request.transactionId - The ID of the transaction to update.
1190
+ * @param request.batchTransactions - The new batch transactions.
1191
+ */
1192
+ updateBatchTransactions({ transactionId, batchTransactions, }) {
1193
+ log('Updating batch transactions', { transactionId, batchTransactions });
1194
+ __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_updateTransactionInternal).call(this, {
1195
+ transactionId,
1196
+ note: 'TransactionController#updateBatchTransactions - Batch transactions updated',
1197
+ }, (transactionMeta) => {
1198
+ transactionMeta.batchTransactions = batchTransactions;
1199
+ });
1200
+ }
1201
+ /**
1202
+ * Update the selected gas fee token for a transaction.
1203
+ *
1204
+ * @param transactionId - The ID of the transaction to update.
1205
+ * @param contractAddress - The contract address of the selected gas fee token.
1206
+ */
1207
+ updateSelectedGasFeeToken(transactionId, contractAddress) {
1208
+ __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_updateTransactionInternal).call(this, { transactionId }, (transactionMeta) => {
1209
+ const hasMatchingGasFeeToken = transactionMeta.gasFeeTokens?.some((token) => token.tokenAddress.toLowerCase() === contractAddress?.toLowerCase());
1210
+ if (contractAddress && !hasMatchingGasFeeToken) {
1211
+ throw new Error(`No matching gas fee token found with address - ${contractAddress}`);
1212
+ }
1213
+ transactionMeta.selectedGasFeeToken = contractAddress;
1214
+ });
1215
+ }
1161
1216
  addMetadata(transactionMeta) {
1162
1217
  validateTxParams(transactionMeta.txParams);
1163
1218
  this.update((state) => {
@@ -1200,7 +1255,7 @@ export class TransactionController extends BaseController {
1200
1255
  this.failTransaction(transactionMeta, new Error('Transaction incomplete at startup'));
1201
1256
  }
1202
1257
  }
1203
- async processApproval(transactionMeta, { isExisting = false, requireApproval, shouldShowRequest = true, actionId, traceContext, }) {
1258
+ async processApproval(transactionMeta, { actionId, isExisting = false, publishHook, requireApproval, shouldShowRequest = true, traceContext, }) {
1204
1259
  const transactionId = transactionMeta.id;
1205
1260
  let resultCallbacks;
1206
1261
  const { meta, isCompleted } = this.isTransactionCompleted(transactionId);
@@ -1227,7 +1282,7 @@ export class TransactionController extends BaseController {
1227
1282
  }
1228
1283
  const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
1229
1284
  if (!isTxCompleted) {
1230
- const approvalResult = await this.approveTransaction(transactionId, traceContext);
1285
+ const approvalResult = await this.approveTransaction(transactionId, traceContext, publishHook);
1231
1286
  if (approvalResult === ApprovalState.SkippedViaBeforePublishHook &&
1232
1287
  resultCallbacks) {
1233
1288
  resultCallbacks.success();
@@ -1275,12 +1330,14 @@ export class TransactionController extends BaseController {
1275
1330
  *
1276
1331
  * @param transactionId - The ID of the transaction to approve.
1277
1332
  * @param traceContext - The parent context for any new traces.
1333
+ * @param publishHookOverride - Custom logic to publish the transaction.
1278
1334
  * @returns The state of the approval.
1279
1335
  */
1280
- async approveTransaction(transactionId, traceContext) {
1281
- const cleanupTasks = new Array();
1282
- cleanupTasks.push(await this.mutex.acquire());
1336
+ async approveTransaction(transactionId, traceContext, publishHookOverride) {
1337
+ let clearApprovingTransactionId;
1338
+ let clearNonceLock;
1283
1339
  let transactionMeta = this.getTransactionOrThrow(transactionId);
1340
+ log('Approving transaction', transactionMeta);
1284
1341
  try {
1285
1342
  if (!this.sign) {
1286
1343
  this.failTransaction(transactionMeta, new Error('No sign method defined.'));
@@ -1295,10 +1352,9 @@ export class TransactionController extends BaseController {
1295
1352
  return ApprovalState.NotApproved;
1296
1353
  }
1297
1354
  this.approvingTransactionIds.add(transactionId);
1298
- cleanupTasks.push(() => this.approvingTransactionIds.delete(transactionId));
1355
+ clearApprovingTransactionId = () => this.approvingTransactionIds.delete(transactionId);
1299
1356
  const [nonce, releaseNonce] = await getNextNonce(transactionMeta, (address) => __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").getNonceLock(address, transactionMeta.networkClientId));
1300
- // must set transaction to submitted/failed before releasing lock
1301
- releaseNonce && cleanupTasks.push(releaseNonce);
1357
+ clearNonceLock = releaseNonce;
1302
1358
  transactionMeta = __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_updateTransactionInternal).call(this, {
1303
1359
  transactionId,
1304
1360
  note: 'TransactionController#approveTransaction - Transaction approved',
@@ -1335,8 +1391,19 @@ export class TransactionController extends BaseController {
1335
1391
  }
1336
1392
  log('Publishing transaction', transactionMeta.txParams);
1337
1393
  let hash;
1394
+ clearNonceLock?.();
1395
+ clearNonceLock = undefined;
1396
+ if (transactionMeta.batchTransactions?.length) {
1397
+ log('Found batch transactions', transactionMeta.batchTransactions);
1398
+ const extraTransactionsPublishHook = new ExtraTransactionsPublishHook({
1399
+ addTransactionBatch: this.addTransactionBatch.bind(this),
1400
+ transactions: transactionMeta.batchTransactions,
1401
+ });
1402
+ publishHookOverride = extraTransactionsPublishHook.getHook();
1403
+ }
1338
1404
  await __classPrivateFieldGet(this, _TransactionController_trace, "f").call(this, { name: 'Publish', parentContext: traceContext }, async () => {
1339
- ({ transactionHash: hash } = await this.publish(transactionMeta, rawTx));
1405
+ const publishHook = publishHookOverride ?? this.publish;
1406
+ ({ transactionHash: hash } = await publishHook(transactionMeta, rawTx));
1340
1407
  if (hash === undefined) {
1341
1408
  hash = await this.publishTransaction(ethQuery, {
1342
1409
  ...transactionMeta,
@@ -1372,7 +1439,8 @@ export class TransactionController extends BaseController {
1372
1439
  return ApprovalState.NotApproved;
1373
1440
  }
1374
1441
  finally {
1375
- cleanupTasks.forEach((task) => task());
1442
+ clearApprovingTransactionId?.();
1443
+ clearNonceLock?.();
1376
1444
  }
1377
1445
  }
1378
1446
  async publishTransaction(ethQuery, transactionMeta, { skipSubmitHistory } = {}) {
@@ -1699,8 +1767,8 @@ export class TransactionController extends BaseController {
1699
1767
  transactionMeta,
1700
1768
  });
1701
1769
  }
1702
- getNonceTrackerTransactions(status, address, chainId) {
1703
- return getAndFormatTransactionsForNonceTracker(chainId, address, status, this.state.transactions);
1770
+ getNonceTrackerTransactions(statuses, address, chainId) {
1771
+ return getAndFormatTransactionsForNonceTracker(chainId, address, statuses, this.state.transactions);
1704
1772
  }
1705
1773
  onConfirmedTransaction(transactionMeta) {
1706
1774
  log('Processing confirmed transaction', transactionMeta.id);
@@ -1760,7 +1828,7 @@ export class TransactionController extends BaseController {
1760
1828
  error?.data?.message?.includes('nonce too low'));
1761
1829
  }
1762
1830
  }
1763
- _TransactionController_internalEvents = new WeakMap(), _TransactionController_methodDataHelper = new WeakMap(), _TransactionController_incomingTransactionHelper = new WeakMap(), _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionController_pendingTransactionOptions = new WeakMap(), _TransactionController_publicKeyEIP7702 = new WeakMap(), _TransactionController_trace = new WeakMap(), _TransactionController_transactionHistoryLimit = new WeakMap(), _TransactionController_isFirstTimeInteractionEnabled = new WeakMap(), _TransactionController_isSimulationEnabled = new WeakMap(), _TransactionController_testGasFeeFlows = new WeakMap(), _TransactionController_multichainTrackingHelper = new WeakMap(), _TransactionController_checkForPendingTransactionAndStartPolling = new WeakMap(), _TransactionController_instances = new WeakSet(), _TransactionController_retryTransaction = async function _TransactionController_retryTransaction({ actionId, afterSubmit, estimatedBaseFee, gasValues, label, prepareTransactionParams, rate, transactionId, transactionType, }) {
1831
+ _TransactionController_internalEvents = new WeakMap(), _TransactionController_methodDataHelper = new WeakMap(), _TransactionController_incomingTransactionHelper = new WeakMap(), _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionController_pendingTransactionOptions = new WeakMap(), _TransactionController_publishBatchHook = new WeakMap(), _TransactionController_publicKeyEIP7702 = new WeakMap(), _TransactionController_trace = new WeakMap(), _TransactionController_transactionHistoryLimit = new WeakMap(), _TransactionController_isFirstTimeInteractionEnabled = new WeakMap(), _TransactionController_isSimulationEnabled = new WeakMap(), _TransactionController_testGasFeeFlows = new WeakMap(), _TransactionController_multichainTrackingHelper = new WeakMap(), _TransactionController_checkForPendingTransactionAndStartPolling = new WeakMap(), _TransactionController_instances = new WeakSet(), _TransactionController_retryTransaction = async function _TransactionController_retryTransaction({ actionId, afterSubmit, estimatedBaseFee, gasValues, label, prepareTransactionParams, rate, transactionId, transactionType, }) {
1764
1832
  // If transaction is found for same action id, do not create a new transaction.
1765
1833
  if (this.getTransactionWithActionId(actionId)) {
1766
1834
  return;
@@ -1868,7 +1936,7 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me
1868
1936
  // TODO: Fix types
1869
1937
  blockTracker,
1870
1938
  getPendingTransactions: __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getNonceTrackerPendingTransactions).bind(this, chainId),
1871
- getConfirmedTransactions: this.getNonceTrackerTransactions.bind(this, TransactionStatus.confirmed, chainId),
1939
+ getConfirmedTransactions: this.getNonceTrackerTransactions.bind(this, [TransactionStatus.confirmed], chainId),
1872
1940
  });
1873
1941
  }, _TransactionController_createPendingTransactionTracker = function _TransactionController_createPendingTransactionTracker({ provider, blockTracker, chainId, networkClientId, }) {
1874
1942
  const ethQuery = new EthQuery(provider);
@@ -1907,7 +1975,11 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me
1907
1975
  pendingTransactionTracker.hub.on('transaction-failed', this.failTransaction.bind(this));
1908
1976
  pendingTransactionTracker.hub.on('transaction-updated', this.updateTransaction.bind(this));
1909
1977
  }, _TransactionController_getNonceTrackerPendingTransactions = function _TransactionController_getNonceTrackerPendingTransactions(chainId, address) {
1910
- const standardPendingTransactions = this.getNonceTrackerTransactions(TransactionStatus.submitted, address, chainId);
1978
+ const standardPendingTransactions = this.getNonceTrackerTransactions([
1979
+ TransactionStatus.approved,
1980
+ TransactionStatus.signed,
1981
+ TransactionStatus.submitted,
1982
+ ], address, chainId);
1911
1983
  const externalPendingTransactions = this.getExternalPendingTransactions(address, chainId);
1912
1984
  return [...standardPendingTransactions, ...externalPendingTransactions];
1913
1985
  }, _TransactionController_getGasFeeFlows = function _TransactionController_getGasFeeFlows() {
@@ -2002,8 +2074,9 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me
2002
2074
  },
2003
2075
  tokenBalanceChanges: [],
2004
2076
  };
2077
+ let gasFeeTokens = [];
2005
2078
  if (__classPrivateFieldGet(this, _TransactionController_isSimulationEnabled, "f").call(this)) {
2006
- simulationData = await __classPrivateFieldGet(this, _TransactionController_trace, "f").call(this, { name: 'Simulate', parentContext: traceContext }, () => getSimulationData({
2079
+ const result = await __classPrivateFieldGet(this, _TransactionController_trace, "f").call(this, { name: 'Simulate', parentContext: traceContext }, () => getSimulationData({
2007
2080
  chainId,
2008
2081
  from: from,
2009
2082
  to: to,
@@ -2012,6 +2085,8 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me
2012
2085
  }, {
2013
2086
  blockTime,
2014
2087
  }));
2088
+ gasFeeTokens = result?.gasFeeTokens;
2089
+ simulationData = result?.simulationData;
2015
2090
  if (blockTime &&
2016
2091
  prevSimulationData &&
2017
2092
  hasSimulationDataChanged(prevSimulationData, simulationData)) {
@@ -2032,20 +2107,21 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me
2032
2107
  note: 'TransactionController#updateSimulationData - Update simulation data',
2033
2108
  skipResimulateCheck: Boolean(blockTime),
2034
2109
  }, (txMeta) => {
2110
+ txMeta.gasFeeTokens = gasFeeTokens;
2035
2111
  txMeta.simulationData = simulationData;
2036
2112
  });
2037
2113
  log('Updated simulation data', transactionId, simulationData);
2038
2114
  }, _TransactionController_onGasFeePollerTransactionUpdate = function _TransactionController_onGasFeePollerTransactionUpdate({ transactionId, gasFeeEstimates, gasFeeEstimatesLoaded, layer1GasFee, }) {
2039
2115
  __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_updateTransactionInternal).call(this, { transactionId, skipHistory: true }, (txMeta) => {
2040
- if (gasFeeEstimates) {
2041
- txMeta.gasFeeEstimates = gasFeeEstimates;
2042
- }
2043
- if (gasFeeEstimatesLoaded !== undefined) {
2044
- txMeta.gasFeeEstimatesLoaded = gasFeeEstimatesLoaded;
2045
- }
2046
- if (layer1GasFee) {
2047
- txMeta.layer1GasFee = layer1GasFee;
2048
- }
2116
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
2117
+ updateTransactionGasFees({
2118
+ txMeta,
2119
+ gasFeeEstimates,
2120
+ gasFeeEstimatesLoaded,
2121
+ getEIP1559Compatibility: this.getEIP1559Compatibility.bind(this),
2122
+ isTxParamsGasFeeUpdatesEnabled: this.isTxParamsGasFeeUpdatesEnabled,
2123
+ layer1GasFee,
2124
+ });
2049
2125
  });
2050
2126
  }, _TransactionController_getSelectedAccount = function _TransactionController_getSelectedAccount() {
2051
2127
  return this.messagingSystem.call('AccountsController:getSelectedAccount');
@@ -2088,6 +2164,7 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me
2088
2164
  chainId,
2089
2165
  ethQuery,
2090
2166
  isCustomNetwork,
2167
+ isSimulationEnabled: __classPrivateFieldGet(this, _TransactionController_isSimulationEnabled, "f").call(this),
2091
2168
  txMeta: transactionMeta,
2092
2169
  });
2093
2170
  }, _TransactionController_deleteTransaction = function _TransactionController_deleteTransaction(transactionId) {