@metamask-previews/transaction-controller 24.0.0-preview.6dad403 → 24.0.0-preview.d78968a2

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.
@@ -22,9 +22,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
22
22
  var __importDefault = (this && this.__importDefault) || function (mod) {
23
23
  return (mod && mod.__esModule) ? mod : { "default": mod };
24
24
  };
25
- var _TransactionController_instances, _TransactionController_incomingTransactionOptions, _TransactionController_pendingTransactionOptions, _TransactionController_multichainTrackingHelper, _TransactionController_createNonceTracker, _TransactionController_createIncomingTransactionHelper, _TransactionController_createPendingTransactionTracker, _TransactionController_checkForPendingTransactionAndStartPolling, _TransactionController_stopAllTracking, _TransactionController_removeIncomingTransactionHelperListeners, _TransactionController_addIncomingTransactionHelperListeners, _TransactionController_removePendingTransactionTrackerListeners, _TransactionController_addPendingTransactionTrackerListeners, _TransactionController_getNonceTrackerPendingTransactions, _TransactionController_getGasFeeFlows, _TransactionController_updateTransactionInternal;
25
+ var _TransactionController_instances, _TransactionController_internalEvents, _TransactionController_incomingTransactionOptions, _TransactionController_pendingTransactionOptions, _TransactionController_transactionHistoryLimit, _TransactionController_multichainTrackingHelper, _TransactionController_createNonceTracker, _TransactionController_createIncomingTransactionHelper, _TransactionController_createPendingTransactionTracker, _TransactionController_checkForPendingTransactionAndStartPolling, _TransactionController_stopAllTracking, _TransactionController_removeIncomingTransactionHelperListeners, _TransactionController_addIncomingTransactionHelperListeners, _TransactionController_removePendingTransactionTrackerListeners, _TransactionController_addPendingTransactionTrackerListeners, _TransactionController_getNonceTrackerPendingTransactions, _TransactionController_getGasFeeFlows, _TransactionController_updateTransactionInternal;
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.TransactionController = exports.SPEED_UP_RATE = exports.CANCEL_RATE = exports.HARDFORK = void 0;
27
+ exports.TransactionController = exports.ApprovalState = exports.SPEED_UP_RATE = exports.CANCEL_RATE = exports.HARDFORK = void 0;
28
28
  const common_1 = require("@ethereumjs/common");
29
29
  const tx_1 = require("@ethereumjs/tx");
30
30
  const util_1 = require("@ethereumjs/util");
@@ -58,6 +58,24 @@ const swaps_1 = require("./utils/swaps");
58
58
  const transaction_type_1 = require("./utils/transaction-type");
59
59
  const utils_2 = require("./utils/utils");
60
60
  const validation_1 = require("./utils/validation");
61
+ /**
62
+ * Metadata for the TransactionController state, describing how to "anonymize"
63
+ * the state and which parts should be persisted.
64
+ */
65
+ const metadata = {
66
+ transactions: {
67
+ persist: true,
68
+ anonymous: false,
69
+ },
70
+ methodData: {
71
+ persist: true,
72
+ anonymous: false,
73
+ },
74
+ lastFetchedBlockNumbers: {
75
+ persist: true,
76
+ anonymous: false,
77
+ },
78
+ };
61
79
  exports.HARDFORK = common_1.Hardfork.London;
62
80
  /**
63
81
  * Multiplier used to determine a transaction's increased gas fee during cancellation
@@ -71,42 +89,82 @@ exports.SPEED_UP_RATE = 1.1;
71
89
  * The name of the {@link TransactionController}.
72
90
  */
73
91
  const controllerName = 'TransactionController';
92
+ /**
93
+ * Possible states of the approve transaction step.
94
+ */
95
+ var ApprovalState;
96
+ (function (ApprovalState) {
97
+ ApprovalState["Approved"] = "approved";
98
+ ApprovalState["NotApproved"] = "not-approved";
99
+ ApprovalState["SkippedViaBeforePublishHook"] = "skipped-via-before-publish-hook";
100
+ })(ApprovalState = exports.ApprovalState || (exports.ApprovalState = {}));
101
+ /**
102
+ * Get the default TransactionsController state.
103
+ *
104
+ * @returns The default TransactionsController state.
105
+ */
106
+ function getDefaultTransactionControllerState() {
107
+ return {
108
+ methodData: {},
109
+ transactions: [],
110
+ lastFetchedBlockNumbers: {},
111
+ };
112
+ }
74
113
  /**
75
114
  * Controller responsible for submitting and managing transactions.
76
115
  */
77
- class TransactionController extends base_controller_1.BaseControllerV1 {
78
- constructor({ blockTracker, disableHistory, disableSendFlowHistory, disableSwaps, getCurrentAccountEIP1559Compatibility, getCurrentNetworkEIP1559Compatibility, getExternalPendingTransactions, getGasFeeEstimates, getNetworkState, getPermittedAccounts, getSavedGasFees, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, pendingTransactions = {}, provider, securityProviderRequest, getNetworkClientRegistry, isMultichainEnabled = false, hooks, }, config, state) {
116
+ class TransactionController extends base_controller_1.BaseController {
117
+ /**
118
+ * Constructs a TransactionController.
119
+ *
120
+ * @param options - The controller options.
121
+ * @param options.blockTracker - The block tracker used to poll for new blocks data.
122
+ * @param options.disableHistory - Whether to disable storing history in transaction metadata.
123
+ * @param options.disableSendFlowHistory - Explicitly disable transaction metadata history.
124
+ * @param options.disableSwaps - Whether to disable additional processing on swaps transactions.
125
+ * @param options.getCurrentAccountEIP1559Compatibility - Whether or not the account supports EIP-1559.
126
+ * @param options.getCurrentNetworkEIP1559Compatibility - Whether or not the network supports EIP-1559.
127
+ * @param options.getExternalPendingTransactions - Callback to retrieve pending transactions from external sources.
128
+ * @param options.getGasFeeEstimates - Callback to retrieve gas fee estimates.
129
+ * @param options.getNetworkClientRegistry - Gets the network client registry.
130
+ * @param options.getNetworkState - Gets the state of the network controller.
131
+ * @param options.getPermittedAccounts - Get accounts that a given origin has permissions for.
132
+ * @param options.getSavedGasFees - Gets the saved gas fee config.
133
+ * @param options.getSelectedAddress - Gets the address of the currently selected account.
134
+ * @param options.incomingTransactions - Configuration options for incoming transaction support.
135
+ * @param options.isMultichainEnabled - Enable multichain support.
136
+ * @param options.messenger - The controller messenger.
137
+ * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
138
+ * @param options.pendingTransactions - Configuration options for pending transaction support.
139
+ * @param options.provider - The provider used to create the underlying EthQuery instance.
140
+ * @param options.securityProviderRequest - A function for verifying a transaction, whether it is malicious or not.
141
+ * @param options.sign - Function used to sign transactions.
142
+ * @param options.state - Initial state to set on this controller.
143
+ * @param options.transactionHistoryLimit - Transaction history limit.
144
+ * @param options.hooks - The controller hooks.
145
+ */
146
+ constructor({ blockTracker, disableHistory, disableSendFlowHistory, disableSwaps, getCurrentAccountEIP1559Compatibility, getCurrentNetworkEIP1559Compatibility, getExternalPendingTransactions, getGasFeeEstimates, getNetworkClientRegistry, getNetworkState, getPermittedAccounts, getSavedGasFees, getSelectedAddress, incomingTransactions = {}, isMultichainEnabled = false, messenger, onNetworkStateChange, pendingTransactions = {}, provider, securityProviderRequest, sign, state, transactionHistoryLimit = 40, hooks, }) {
79
147
  var _a, _b, _c, _d, _e, _f;
80
- super(config, state);
148
+ super({
149
+ name: controllerName,
150
+ metadata,
151
+ messenger,
152
+ state: Object.assign(Object.assign({}, getDefaultTransactionControllerState()), state),
153
+ });
81
154
  _TransactionController_instances.add(this);
155
+ _TransactionController_internalEvents.set(this, new events_1.EventEmitter());
82
156
  this.inProcessOfSigning = new Set();
83
157
  this.mutex = new async_mutex_1.Mutex();
84
158
  _TransactionController_incomingTransactionOptions.set(this, void 0);
85
159
  _TransactionController_pendingTransactionOptions.set(this, void 0);
86
160
  this.signAbortCallbacks = new Map();
161
+ _TransactionController_transactionHistoryLimit.set(this, void 0);
87
162
  _TransactionController_multichainTrackingHelper.set(this, void 0);
88
- /**
89
- * EventEmitter instance used to listen to specific transactional events
90
- */
91
- this.hub = new events_1.EventEmitter();
92
- /**
93
- * Name of this controller used during composition
94
- */
95
- this.name = 'TransactionController';
96
163
  _TransactionController_checkForPendingTransactionAndStartPolling.set(this, () => {
97
164
  // PendingTransactionTracker reads state through its getTransactions hook
98
165
  this.pendingTransactionTracker.startIfPendingTransactions();
99
166
  __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").checkForPendingTransactionAndStartPolling();
100
167
  });
101
- this.defaultConfig = {
102
- txHistoryLimit: 40,
103
- };
104
- this.defaultState = {
105
- methodData: {},
106
- transactions: [],
107
- lastFetchedBlockNumbers: {},
108
- };
109
- this.initialize();
110
168
  this.messagingSystem = messenger;
111
169
  this.getNetworkState = getNetworkState;
112
170
  this.isSendFlowHistoryDisabled = disableSendFlowHistory !== null && disableSendFlowHistory !== void 0 ? disableSendFlowHistory : false;
@@ -128,6 +186,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
128
186
  this.securityProviderRequest = securityProviderRequest;
129
187
  __classPrivateFieldSet(this, _TransactionController_incomingTransactionOptions, incomingTransactions, "f");
130
188
  __classPrivateFieldSet(this, _TransactionController_pendingTransactionOptions, pendingTransactions, "f");
189
+ __classPrivateFieldSet(this, _TransactionController_transactionHistoryLimit, transactionHistoryLimit, "f");
190
+ this.sign = sign;
131
191
  this.afterSign = (_a = hooks === null || hooks === void 0 ? void 0 : hooks.afterSign) !== null && _a !== void 0 ? _a : (() => true);
132
192
  this.beforeApproveOnInit = (_b = hooks === null || hooks === void 0 ? void 0 : hooks.beforeApproveOnInit) !== null && _b !== void 0 ? _b : (() => true);
133
193
  this.beforeCheckPendingTransaction =
@@ -187,13 +247,13 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
187
247
  getGasFeeControllerEstimates: this.getGasFeeEstimates,
188
248
  getTransactions: () => this.state.transactions,
189
249
  onStateChange: (listener) => {
190
- this.subscribe(listener);
250
+ this.messagingSystem.subscribe('TransactionController:stateChange', listener);
191
251
  },
192
252
  });
193
253
  gasFeePoller.hub.on('transaction-updated', (transactionMeta) => __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_updateTransactionInternal).call(this, transactionMeta, { skipHistory: true }));
194
254
  // when transactionsController state changes
195
255
  // check for pending transactions and start polling if there are any
196
- this.subscribe(__classPrivateFieldGet(this, _TransactionController_checkForPendingTransactionAndStartPolling, "f"));
256
+ this.messagingSystem.subscribe('TransactionController:stateChange', __classPrivateFieldGet(this, _TransactionController_checkForPendingTransactionAndStartPolling, "f"));
197
257
  // TODO once v2 is merged make sure this only runs when
198
258
  // selectedNetworkClientId changes
199
259
  onNetworkStateChange(() => {
@@ -204,19 +264,29 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
204
264
  this.onBootCleanup();
205
265
  }
206
266
  failTransaction(transactionMeta, error, actionId) {
207
- const newTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { error: (0, utils_2.normalizeTxError)(error), status: types_1.TransactionStatus.failed });
208
- this.hub.emit('transaction-failed', {
267
+ const newTransactionMeta = (0, lodash_1.merge)({}, transactionMeta, {
268
+ error: (0, utils_2.normalizeTxError)(error),
269
+ status: types_1.TransactionStatus.failed,
270
+ });
271
+ this.messagingSystem.publish(`${controllerName}:transactionFailed`, {
209
272
  actionId,
210
273
  error: error.message,
211
274
  transactionMeta: newTransactionMeta,
212
275
  });
213
276
  this.updateTransaction(newTransactionMeta, 'TransactionController#failTransaction - Add error message and set status to failed');
214
277
  this.onTransactionStatusChange(newTransactionMeta);
215
- this.hub.emit(`${transactionMeta.id}:finished`, newTransactionMeta);
278
+ this.messagingSystem.publish(`${controllerName}:transactionFinished`, newTransactionMeta);
279
+ __classPrivateFieldGet(this, _TransactionController_internalEvents, "f").emit(`${transactionMeta.id}:finished`, newTransactionMeta);
216
280
  }
217
281
  registryLookup(fourBytePrefix) {
218
282
  return __awaiter(this, void 0, void 0, function* () {
219
283
  const registryMethod = yield this.registry.lookup(fourBytePrefix);
284
+ if (!registryMethod) {
285
+ return {
286
+ registryMethod: '',
287
+ parsedRegistryMethod: { name: undefined, args: undefined },
288
+ };
289
+ }
220
290
  const parsedRegistryMethod = this.registry.parse(registryMethod);
221
291
  return { registryMethod, parsedRegistryMethod };
222
292
  });
@@ -243,8 +313,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
243
313
  return methodData[fourBytePrefix];
244
314
  }
245
315
  const registry = yield this.registryLookup(fourBytePrefix);
246
- this.update({
247
- methodData: Object.assign(Object.assign({}, methodData), { [fourBytePrefix]: registry }),
316
+ this.update((state) => {
317
+ state.methodData[fourBytePrefix] = registry;
248
318
  });
249
319
  return registry;
250
320
  }
@@ -296,55 +366,56 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
296
366
  const transactionType = type !== null && type !== void 0 ? type : (yield (0, transaction_type_1.determineTransactionType)(txParams, ethQuery)).type;
297
367
  const existingTransactionMeta = this.getTransactionWithActionId(actionId);
298
368
  // If a request to add a transaction with the same actionId is submitted again, a new transaction will not be created for it.
299
- const transactionMeta = existingTransactionMeta || {
300
- // Add actionId to txMeta to check if same actionId is seen again
301
- actionId,
302
- chainId,
303
- dappSuggestedGasFees,
304
- deviceConfirmedOn,
305
- id: (0, uuid_1.v1)(),
306
- origin,
307
- securityAlertResponse,
308
- status: types_1.TransactionStatus.unapproved,
309
- time: Date.now(),
310
- txParams,
311
- userEditedGasLimit: false,
312
- verifiedOnBlockchain: false,
313
- type: transactionType,
314
- networkClientId,
315
- };
316
- yield this.updateGasProperties(transactionMeta);
369
+ let addedTransactionMeta = existingTransactionMeta
370
+ ? (0, lodash_1.cloneDeep)(existingTransactionMeta)
371
+ : {
372
+ // Add actionId to txMeta to check if same actionId is seen again
373
+ actionId,
374
+ chainId,
375
+ dappSuggestedGasFees,
376
+ deviceConfirmedOn,
377
+ id: (0, uuid_1.v1)(),
378
+ origin,
379
+ securityAlertResponse,
380
+ status: types_1.TransactionStatus.unapproved,
381
+ time: Date.now(),
382
+ txParams,
383
+ userEditedGasLimit: false,
384
+ verifiedOnBlockchain: false,
385
+ type: transactionType,
386
+ networkClientId,
387
+ };
388
+ yield this.updateGasProperties(addedTransactionMeta);
317
389
  // Checks if a transaction already exists with a given actionId
318
390
  if (!existingTransactionMeta) {
319
391
  // Set security provider response
320
392
  if (method && this.securityProviderRequest) {
321
- const securityProviderResponse = yield this.securityProviderRequest(transactionMeta, method);
322
- transactionMeta.securityProviderResponse = securityProviderResponse;
393
+ const securityProviderResponse = yield this.securityProviderRequest(addedTransactionMeta, method);
394
+ addedTransactionMeta.securityProviderResponse =
395
+ securityProviderResponse;
323
396
  }
324
397
  if (!this.isSendFlowHistoryDisabled) {
325
- transactionMeta.sendFlowHistory = sendFlowHistory !== null && sendFlowHistory !== void 0 ? sendFlowHistory : [];
398
+ addedTransactionMeta.sendFlowHistory = sendFlowHistory !== null && sendFlowHistory !== void 0 ? sendFlowHistory : [];
326
399
  }
327
400
  // Initial history push
328
401
  if (!this.isHistoryDisabled) {
329
- (0, history_1.addInitialHistorySnapshot)(transactionMeta);
402
+ addedTransactionMeta = (0, history_1.addInitialHistorySnapshot)(addedTransactionMeta);
330
403
  }
331
- yield (0, swaps_1.updateSwapsTransaction)(transactionMeta, transactionType, swaps, {
404
+ addedTransactionMeta = (0, swaps_1.updateSwapsTransaction)(addedTransactionMeta, transactionType, swaps, {
332
405
  isSwapsDisabled: this.isSwapsDisabled,
333
406
  cancelTransaction: this.cancelTransaction.bind(this),
334
- // TODO: Replace `any` with type
335
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
336
- controllerHubEmitter: this.hub.emit.bind(this.hub),
407
+ messenger: this.messagingSystem,
337
408
  });
338
- this.addMetadata(transactionMeta);
339
- this.hub.emit(`unapprovedTransaction`, transactionMeta);
409
+ this.addMetadata(addedTransactionMeta);
410
+ this.messagingSystem.publish(`${controllerName}:unapprovedTransactionAdded`, addedTransactionMeta);
340
411
  }
341
412
  return {
342
- result: this.processApproval(transactionMeta, {
413
+ result: this.processApproval(addedTransactionMeta, {
343
414
  isExisting: Boolean(existingTransactionMeta),
344
415
  requireApproval,
345
416
  actionId,
346
417
  }),
347
- transactionMeta,
418
+ transactionMeta: addedTransactionMeta,
348
419
  };
349
420
  });
350
421
  }
@@ -476,15 +547,16 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
476
547
  };
477
548
  this.addMetadata(cancelTransactionMeta);
478
549
  // stopTransaction has no approval request, so we assume the user has already approved the transaction
479
- this.hub.emit('transaction-approved', {
550
+ this.messagingSystem.publish(`${controllerName}:transactionApproved`, {
480
551
  transactionMeta: cancelTransactionMeta,
481
552
  actionId,
482
553
  });
483
- this.hub.emit('transaction-submitted', {
554
+ this.messagingSystem.publish(`${controllerName}:transactionSubmitted`, {
484
555
  transactionMeta: cancelTransactionMeta,
485
556
  actionId,
486
557
  });
487
- this.hub.emit(`${cancelTransactionMeta.id}:finished`, cancelTransactionMeta);
558
+ this.messagingSystem.publish(`${controllerName}:transactionFinished`, cancelTransactionMeta);
559
+ __classPrivateFieldGet(this, _TransactionController_internalEvents, "f").emit(`${transactionMeta.id}:finished`, cancelTransactionMeta);
488
560
  });
489
561
  }
490
562
  /**
@@ -542,33 +614,33 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
542
614
  ? Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type: types_1.TransactionEnvelopeType.feeMarket }) : Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, gasPrice: newGasPrice });
543
615
  const unsignedEthTx = this.prepareUnsignedEthTx(transactionMeta.chainId, txParams);
544
616
  const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
545
- yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
617
+ const transactionMetaWithRsv = yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
546
618
  const rawTx = (0, util_1.bufferToHex)(signedTx.serialize());
547
619
  const newFee = (_c = txParams.maxFeePerGas) !== null && _c !== void 0 ? _c : txParams.gasPrice;
548
620
  const oldFee = txParams.maxFeePerGas
549
- ? transactionMeta.txParams.maxFeePerGas
550
- : transactionMeta.txParams.gasPrice;
621
+ ? transactionMetaWithRsv.txParams.maxFeePerGas
622
+ : transactionMetaWithRsv.txParams.gasPrice;
551
623
  (0, logger_1.projectLogger)('Submitting speed up transaction', { oldFee, newFee, txParams });
552
624
  const ethQuery = __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").getEthQuery({
553
625
  networkClientId: transactionMeta.networkClientId,
554
626
  chainId: transactionMeta.chainId,
555
627
  });
556
628
  const hash = yield this.publishTransactionForRetry(ethQuery, rawTx, transactionMeta);
557
- const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), hash,
629
+ const baseTransactionMeta = Object.assign(Object.assign({}, transactionMetaWithRsv), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), hash,
558
630
  actionId, originalGasEstimate: transactionMeta.txParams.gas, type: types_1.TransactionType.retry, originalType: transactionMeta.type });
559
631
  const newTransactionMeta = newMaxFeePerGas && newMaxPriorityFeePerGas
560
632
  ? Object.assign(Object.assign({}, baseTransactionMeta), { txParams: Object.assign(Object.assign({}, transactionMeta.txParams), { maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas }) }) : Object.assign(Object.assign({}, baseTransactionMeta), { txParams: Object.assign(Object.assign({}, transactionMeta.txParams), { gasPrice: newGasPrice }) });
561
633
  this.addMetadata(newTransactionMeta);
562
634
  // speedUpTransaction has no approval request, so we assume the user has already approved the transaction
563
- this.hub.emit('transaction-approved', {
635
+ this.messagingSystem.publish(`${controllerName}:transactionApproved`, {
564
636
  transactionMeta: newTransactionMeta,
565
637
  actionId,
566
638
  });
567
- this.hub.emit('transaction-submitted', {
639
+ this.messagingSystem.publish(`${controllerName}:transactionSubmitted`, {
568
640
  transactionMeta: newTransactionMeta,
569
641
  actionId,
570
642
  });
571
- this.hub.emit(`${transactionMeta.id}:speedup`, newTransactionMeta);
643
+ this.messagingSystem.publish(`${controllerName}:speedupTransactionAdded`, newTransactionMeta);
572
644
  });
573
645
  }
574
646
  /**
@@ -633,8 +705,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
633
705
  if (!transactionMeta) {
634
706
  throw new Error(`Cannot update security alert response as no transaction metadata found`);
635
707
  }
636
- const updatedMeta = (0, lodash_1.merge)(transactionMeta, { securityAlertResponse });
637
- this.updateTransaction(updatedMeta, 'TransactionController:updatesecurityAlertResponse - securityAlertResponse updated');
708
+ const updatedTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { securityAlertResponse });
709
+ this.updateTransaction(updatedTransactionMeta, `${controllerName}:updatesecurityAlertResponse - securityAlertResponse updated`);
638
710
  }
639
711
  /**
640
712
  * Removes all transactions from state, optionally based on the current network.
@@ -647,7 +719,9 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
647
719
  wipeTransactions(ignoreNetwork, address) {
648
720
  /* istanbul ignore next */
649
721
  if (ignoreNetwork && !address) {
650
- this.update({ transactions: [] });
722
+ this.update((state) => {
723
+ state.transactions = [];
724
+ });
651
725
  return;
652
726
  }
653
727
  const currentChainId = this.getChainId();
@@ -660,8 +734,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
660
734
  const isMatchingAddress = !address || ((_a = txParams.from) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === address.toLowerCase();
661
735
  return !isMatchingAddress;
662
736
  });
663
- this.update({
664
- transactions: this.trimTransactionsForState(newTransactions),
737
+ this.update((state) => {
738
+ state.transactions = this.trimTransactionsForState(newTransactions);
665
739
  });
666
740
  }
667
741
  /**
@@ -674,26 +748,23 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
674
748
  confirmExternalTransaction(transactionMeta, transactionReceipt, baseFeePerGas) {
675
749
  return __awaiter(this, void 0, void 0, function* () {
676
750
  // Run validation and add external transaction to state.
677
- this.addExternalTransaction(transactionMeta);
751
+ const newTransactionMeta = this.addExternalTransaction(transactionMeta);
678
752
  try {
679
- const transactionId = transactionMeta.id;
753
+ const transactionId = newTransactionMeta.id;
680
754
  // Make sure status is confirmed and define gasUsed as in receipt.
681
- transactionMeta.status = types_1.TransactionStatus.confirmed;
682
- transactionMeta.txReceipt = transactionReceipt;
755
+ const updatedTransactionMeta = Object.assign(Object.assign({}, newTransactionMeta), { status: types_1.TransactionStatus.confirmed, txReceipt: transactionReceipt });
683
756
  if (baseFeePerGas) {
684
- transactionMeta.baseFeePerGas = baseFeePerGas;
757
+ updatedTransactionMeta.baseFeePerGas = baseFeePerGas;
685
758
  }
686
759
  // Update same nonce local transactions as dropped and define replacedBy properties.
687
760
  this.markNonceDuplicatesDropped(transactionId);
688
761
  // Update external provided transaction with updated gas values and confirmed status.
689
- this.updateTransaction(transactionMeta, 'TransactionController:confirmExternalTransaction - Add external transaction');
690
- this.onTransactionStatusChange(transactionMeta);
762
+ this.updateTransaction(updatedTransactionMeta, `${controllerName}:confirmExternalTransaction - Add external transaction`);
763
+ this.onTransactionStatusChange(updatedTransactionMeta);
691
764
  // Intentional given potential duration of process.
692
765
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
693
- this.updatePostBalance(transactionMeta);
694
- this.hub.emit('transaction-confirmed', {
695
- transactionMeta,
696
- });
766
+ this.updatePostBalance(updatedTransactionMeta);
767
+ this.messagingSystem.publish(`${controllerName}:transactionConfirmed`, updatedTransactionMeta);
697
768
  }
698
769
  catch (error) {
699
770
  console.error('Failed to confirm external transaction', error);
@@ -709,7 +780,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
709
780
  * @returns The updated transactionMeta.
710
781
  */
711
782
  updateTransactionSendFlowHistory(transactionID, currentSendFlowHistoryLength, sendFlowHistoryToAdd) {
712
- var _a, _b;
783
+ var _a;
713
784
  if (this.isSendFlowHistoryDisabled) {
714
785
  throw new Error('Send flow history is disabled for the current transaction controller');
715
786
  }
@@ -718,13 +789,10 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
718
789
  throw new Error(`Cannot update send flow history as no transaction metadata found`);
719
790
  }
720
791
  (0, utils_2.validateIfTransactionUnapproved)(transactionMeta, 'updateTransactionSendFlowHistory');
721
- if (currentSendFlowHistoryLength ===
722
- (((_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.sendFlowHistory) === null || _a === void 0 ? void 0 : _a.length) || 0)) {
723
- transactionMeta.sendFlowHistory = [
724
- ...((_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.sendFlowHistory) !== null && _b !== void 0 ? _b : []),
725
- ...sendFlowHistoryToAdd,
726
- ];
727
- this.updateTransaction(transactionMeta, 'TransactionController:updateTransactionSendFlowHistory - sendFlowHistory updated');
792
+ const sendFlowHistory = (_a = transactionMeta.sendFlowHistory) !== null && _a !== void 0 ? _a : [];
793
+ if (currentSendFlowHistoryLength === sendFlowHistory.length) {
794
+ const updatedTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { sendFlowHistory: [...sendFlowHistory, ...sendFlowHistoryToAdd] });
795
+ this.updateTransaction(updatedTransactionMeta, `${controllerName}:updateTransactionSendFlowHistory - sendFlowHistory updated`);
728
796
  }
729
797
  return this.getTransaction(transactionID);
730
798
  }
@@ -773,8 +841,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
773
841
  transactionGasFees.txParams = (0, lodash_1.pickBy)(transactionGasFees.txParams);
774
842
  transactionGasFees = (0, lodash_1.pickBy)(transactionGasFees);
775
843
  // merge updated gas values with existing transaction meta
776
- const updatedMeta = (0, lodash_1.merge)(transactionMeta, transactionGasFees);
777
- this.updateTransaction(updatedMeta, 'TransactionController:updateTransactionGasFees - gas values updated');
844
+ const updatedMeta = (0, lodash_1.merge)({}, transactionMeta, transactionGasFees);
845
+ this.updateTransaction(updatedMeta, `${controllerName}:updateTransactionGasFees - gas values updated`);
778
846
  return this.getTransaction(transactionId);
779
847
  }
780
848
  /**
@@ -805,8 +873,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
805
873
  // only update what is defined
806
874
  transactionPreviousGas.previousGas = (0, lodash_1.pickBy)(transactionPreviousGas.previousGas);
807
875
  // merge updated previous gas values with existing transaction meta
808
- const updatedMeta = (0, lodash_1.merge)(transactionMeta, transactionPreviousGas);
809
- this.updateTransaction(updatedMeta, 'TransactionController:updatePreviousGasParams - Previous gas values updated');
876
+ const updatedMeta = (0, lodash_1.merge)({}, transactionMeta, transactionPreviousGas);
877
+ this.updateTransaction(updatedMeta, `${controllerName}:updatePreviousGasParams - Previous gas values updated`);
810
878
  return this.getTransaction(transactionId);
811
879
  }
812
880
  getNonceLock(address, networkClientId) {
@@ -845,7 +913,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
845
913
  },
846
914
  };
847
915
  editableParams.txParams = (0, lodash_1.pickBy)(editableParams.txParams);
848
- const updatedTransaction = (0, lodash_1.merge)(transactionMeta, editableParams);
916
+ const updatedTransaction = (0, lodash_1.merge)({}, transactionMeta, editableParams);
849
917
  const { type } = yield (0, transaction_type_1.determineTransactionType)(updatedTransaction.txParams, __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").getEthQuery({
850
918
  networkClientId: transactionMeta.networkClientId,
851
919
  chainId: transactionMeta.chainId,
@@ -950,16 +1018,16 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
950
1018
  ].includes(status)) {
951
1019
  throw new Error(`Cannot update custodial transaction with status: ${status}`);
952
1020
  }
953
- const updatedTransactionMeta = (0, lodash_1.merge)(transactionMeta, (0, lodash_1.pickBy)({ hash, status }));
1021
+ const updatedTransactionMeta = (0, lodash_1.merge)({}, transactionMeta, (0, lodash_1.pickBy)({ hash, status }));
954
1022
  if (status === types_1.TransactionStatus.submitted) {
955
1023
  updatedTransactionMeta.submittedTime = new Date().getTime();
956
1024
  }
957
1025
  if (status === types_1.TransactionStatus.failed) {
958
1026
  updatedTransactionMeta.error = (0, utils_2.normalizeTxError)(new Error(errorMessage));
959
1027
  }
960
- this.updateTransaction(updatedTransactionMeta, `TransactionController:updateCustodialTransaction - Custodial transaction updated`);
1028
+ this.updateTransaction(updatedTransactionMeta, `${controllerName}:updateCustodialTransaction - Custodial transaction updated`);
961
1029
  if ([types_1.TransactionStatus.submitted, types_1.TransactionStatus.failed].includes(status)) {
962
- this.hub.emit(`${transactionMeta.id}:finished`, updatedTransactionMeta);
1030
+ this.messagingSystem.publish(`${controllerName}:transactionFinished`, updatedTransactionMeta);
963
1031
  }
964
1032
  }
965
1033
  /**
@@ -1090,7 +1158,9 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1090
1158
  */
1091
1159
  clearUnapprovedTransactions() {
1092
1160
  const transactions = this.state.transactions.filter(({ status }) => status !== types_1.TransactionStatus.unapproved);
1093
- this.update({ transactions: this.trimTransactionsForState(transactions) });
1161
+ this.update((state) => {
1162
+ state.transactions = this.trimTransactionsForState(transactions);
1163
+ });
1094
1164
  }
1095
1165
  /**
1096
1166
  * Stop the signing process for a specific transaction.
@@ -1110,9 +1180,12 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1110
1180
  this.signAbortCallbacks.delete(transactionId);
1111
1181
  }
1112
1182
  addMetadata(transactionMeta) {
1113
- const { transactions } = this.state;
1114
- transactions.push(transactionMeta);
1115
- this.update({ transactions: this.trimTransactionsForState(transactions) });
1183
+ this.update((state) => {
1184
+ state.transactions = this.trimTransactionsForState([
1185
+ ...state.transactions,
1186
+ transactionMeta,
1187
+ ]);
1188
+ });
1116
1189
  }
1117
1190
  updateGasProperties(transactionMeta) {
1118
1191
  return __awaiter(this, void 0, void 0, function* () {
@@ -1176,13 +1249,6 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1176
1249
  shouldShowRequest,
1177
1250
  });
1178
1251
  resultCallbacks = acceptResult.resultCallbacks;
1179
- if (resultCallbacks) {
1180
- this.hub.once(`${transactionId}:publish-skip`, () => {
1181
- resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
1182
- // Remove the reference to prevent additional reports once submitted.
1183
- resultCallbacks = undefined;
1184
- });
1185
- }
1186
1252
  const approvalValue = acceptResult.value;
1187
1253
  const updatedTransaction = approvalValue === null || approvalValue === void 0 ? void 0 : approvalValue.txMeta;
1188
1254
  if (updatedTransaction) {
@@ -1195,9 +1261,13 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1195
1261
  }
1196
1262
  const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
1197
1263
  if (!isTxCompleted) {
1198
- yield this.approveTransaction(transactionId);
1264
+ const approvalResult = yield this.approveTransaction(transactionId);
1265
+ if (approvalResult === ApprovalState.SkippedViaBeforePublishHook &&
1266
+ resultCallbacks) {
1267
+ resultCallbacks.success();
1268
+ }
1199
1269
  const updatedTransactionMeta = this.getTransaction(transactionId);
1200
- this.hub.emit('transaction-approved', {
1270
+ this.messagingSystem.publish(`${controllerName}:transactionApproved`, {
1201
1271
  transactionMeta: updatedTransactionMeta,
1202
1272
  actionId,
1203
1273
  });
@@ -1247,42 +1317,42 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1247
1317
  const releaseLock = yield this.mutex.acquire();
1248
1318
  const index = transactions.findIndex(({ id }) => transactionId === id);
1249
1319
  const transactionMeta = transactions[index];
1320
+ const updatedTransactionMeta = (0, lodash_1.cloneDeep)(transactionMeta);
1250
1321
  const { txParams: { from }, networkClientId, } = transactionMeta;
1251
1322
  let releaseNonceLock;
1252
1323
  try {
1253
1324
  if (!this.sign) {
1254
1325
  releaseLock();
1255
1326
  this.failTransaction(transactionMeta, new Error('No sign method defined.'));
1256
- return;
1327
+ return ApprovalState.NotApproved;
1257
1328
  }
1258
1329
  else if (!transactionMeta.chainId) {
1259
1330
  releaseLock();
1260
1331
  this.failTransaction(transactionMeta, new Error('No chainId defined.'));
1261
- return;
1332
+ return ApprovalState.NotApproved;
1262
1333
  }
1263
1334
  if (this.inProcessOfSigning.has(transactionId)) {
1264
1335
  (0, logger_1.projectLogger)('Skipping approval as signing in progress', transactionId);
1265
- return;
1336
+ return ApprovalState.NotApproved;
1266
1337
  }
1267
1338
  const [nonce, releaseNonce] = yield (0, nonce_1.getNextNonce)(transactionMeta, (address) => __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").getNonceLock(address, networkClientId));
1268
1339
  releaseNonceLock = releaseNonce;
1269
- transactionMeta.status = types_1.TransactionStatus.approved;
1270
- transactionMeta.txParams.nonce = nonce;
1271
- transactionMeta.txParams.chainId = transactionMeta.chainId;
1272
- const baseTxParams = Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas });
1273
- this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction approved');
1274
- this.onTransactionStatusChange(transactionMeta);
1275
- const isEIP1559 = (0, utils_2.isEIP1559Transaction)(transactionMeta.txParams);
1340
+ updatedTransactionMeta.status = types_1.TransactionStatus.approved;
1341
+ updatedTransactionMeta.txParams = Object.assign(Object.assign({}, updatedTransactionMeta.txParams), { nonce, chainId: transactionMeta.chainId });
1342
+ const baseTxParams = Object.assign(Object.assign({}, updatedTransactionMeta.txParams), { gasLimit: updatedTransactionMeta.txParams.gas });
1343
+ this.updateTransaction(updatedTransactionMeta, 'TransactionController#approveTransaction - Transaction approved');
1344
+ this.onTransactionStatusChange(updatedTransactionMeta);
1345
+ const isEIP1559 = (0, utils_2.isEIP1559Transaction)(updatedTransactionMeta.txParams);
1276
1346
  const txParams = isEIP1559
1277
- ? Object.assign(Object.assign({}, baseTxParams), { estimatedBaseFee: transactionMeta.txParams.estimatedBaseFee, type: types_1.TransactionEnvelopeType.feeMarket }) : baseTxParams;
1278
- const rawTx = yield this.signTransaction(transactionMeta, txParams);
1279
- if (!this.beforePublish(transactionMeta)) {
1347
+ ? Object.assign(Object.assign({}, baseTxParams), { estimatedBaseFee: updatedTransactionMeta.txParams.estimatedBaseFee, type: types_1.TransactionEnvelopeType.feeMarket }) : baseTxParams;
1348
+ const rawTx = yield this.signTransaction(updatedTransactionMeta, txParams);
1349
+ if (!this.beforePublish(updatedTransactionMeta)) {
1280
1350
  (0, logger_1.projectLogger)('Skipping publishing transaction based on hook');
1281
- this.hub.emit(`${transactionMeta.id}:publish-skip`, transactionMeta);
1282
- return;
1351
+ this.messagingSystem.publish(`${controllerName}:transactionPublishingSkipped`, updatedTransactionMeta);
1352
+ return ApprovalState.SkippedViaBeforePublishHook;
1283
1353
  }
1284
1354
  if (!rawTx) {
1285
- return;
1355
+ return ApprovalState.NotApproved;
1286
1356
  }
1287
1357
  const ethQuery = __classPrivateFieldGet(this, _TransactionController_multichainTrackingHelper, "f").getEthQuery({
1288
1358
  networkClientId: transactionMeta.networkClientId,
@@ -1291,8 +1361,8 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1291
1361
  if (transactionMeta.type === types_1.TransactionType.swap) {
1292
1362
  (0, logger_1.projectLogger)('Determining pre-transaction balance');
1293
1363
  const preTxBalance = yield (0, controller_utils_1.query)(ethQuery, 'getBalance', [from]);
1294
- transactionMeta.preTxBalance = preTxBalance;
1295
- (0, logger_1.projectLogger)('Updated pre-transaction balance', transactionMeta.preTxBalance);
1364
+ updatedTransactionMeta.preTxBalance = preTxBalance;
1365
+ (0, logger_1.projectLogger)('Updated pre-transaction balance', updatedTransactionMeta.preTxBalance);
1296
1366
  }
1297
1367
  (0, logger_1.projectLogger)('Publishing transaction', txParams);
1298
1368
  let { transactionHash: hash } = yield this.publish(transactionMeta, rawTx);
@@ -1300,20 +1370,23 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1300
1370
  hash = yield this.publishTransaction(ethQuery, rawTx);
1301
1371
  }
1302
1372
  (0, logger_1.projectLogger)('Publish successful', hash);
1303
- transactionMeta.hash = hash;
1304
- transactionMeta.status = types_1.TransactionStatus.submitted;
1305
- transactionMeta.submittedTime = new Date().getTime();
1306
- this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
1307
- this.hub.emit('transaction-submitted', {
1308
- transactionMeta,
1373
+ updatedTransactionMeta.hash = hash;
1374
+ updatedTransactionMeta.status = types_1.TransactionStatus.submitted;
1375
+ updatedTransactionMeta.submittedTime = new Date().getTime();
1376
+ this.updateTransaction(updatedTransactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
1377
+ this.messagingSystem.publish(`${controllerName}:transactionSubmitted`, {
1378
+ transactionMeta: updatedTransactionMeta,
1309
1379
  });
1310
- this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
1311
- this.onTransactionStatusChange(transactionMeta);
1380
+ this.messagingSystem.publish(`${controllerName}:transactionFinished`, updatedTransactionMeta);
1381
+ __classPrivateFieldGet(this, _TransactionController_internalEvents, "f").emit(`${updatedTransactionMeta.id}:finished`, updatedTransactionMeta);
1382
+ this.onTransactionStatusChange(updatedTransactionMeta);
1383
+ return ApprovalState.Approved;
1312
1384
  // TODO: Replace `any` with type
1313
1385
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1314
1386
  }
1315
1387
  catch (error) {
1316
1388
  this.failTransaction(transactionMeta, error);
1389
+ return ApprovalState.NotApproved;
1317
1390
  }
1318
1391
  finally {
1319
1392
  this.inProcessOfSigning.delete(transactionId);
@@ -1340,15 +1413,18 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1340
1413
  if (!transactionMeta) {
1341
1414
  return;
1342
1415
  }
1343
- transactionMeta.status = types_1.TransactionStatus.rejected;
1344
- const transactions = this.state.transactions.filter(({ id }) => id !== transactionId);
1345
- this.update({ transactions: this.trimTransactionsForState(transactions) });
1346
- this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
1347
- this.hub.emit('transaction-rejected', {
1348
- transactionMeta,
1416
+ this.update((state) => {
1417
+ const transactions = state.transactions.filter(({ id }) => id !== transactionId);
1418
+ state.transactions = this.trimTransactionsForState(transactions);
1419
+ });
1420
+ const updatedTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { status: types_1.TransactionStatus.rejected });
1421
+ this.messagingSystem.publish(`${controllerName}:transactionFinished`, updatedTransactionMeta);
1422
+ __classPrivateFieldGet(this, _TransactionController_internalEvents, "f").emit(`${transactionMeta.id}:finished`, updatedTransactionMeta);
1423
+ this.messagingSystem.publish(`${controllerName}:transactionRejected`, {
1424
+ transactionMeta: updatedTransactionMeta,
1349
1425
  actionId,
1350
1426
  });
1351
- this.onTransactionStatusChange(transactionMeta);
1427
+ this.onTransactionStatusChange(updatedTransactionMeta);
1352
1428
  }
1353
1429
  /**
1354
1430
  * Trim the amount of transactions that are set on the state. Checks
@@ -1357,25 +1433,25 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1357
1433
  * Pending or unapproved transactions will not be removed by this
1358
1434
  * operation. For safety of presenting a fully functional transaction UI
1359
1435
  * representation, this function will not break apart transactions with the
1360
- * same nonce, created on the same day, per network. Not accounting for transactions of the same
1361
- * nonce, same day and network combo can result in confusing or broken experiences
1362
- * in the UI. The transactions are then updated using the BaseControllerV1 update.
1436
+ * same nonce, created on the same day, per network. Not accounting for
1437
+ * transactions of the same nonce, same day and network combo can result in
1438
+ * confusing or broken experiences in the UI.
1363
1439
  *
1364
1440
  * @param transactions - The transactions to be applied to the state.
1365
1441
  * @returns The trimmed list of transactions.
1366
1442
  */
1367
1443
  trimTransactionsForState(transactions) {
1368
1444
  const nonceNetworkSet = new Set();
1369
- const txsToKeep = transactions
1445
+ const txsToKeep = [...transactions]
1370
1446
  .sort((a, b) => (a.time > b.time ? -1 : 1)) // Descending time order
1371
1447
  .filter((tx) => {
1372
1448
  const { chainId, status, txParams, time } = tx;
1373
1449
  if (txParams) {
1374
- const key = `${txParams.nonce}-${(0, controller_utils_1.convertHexToDecimal)(chainId)}-${new Date(time).toDateString()}`;
1450
+ const key = `${String(txParams.nonce)}-${(0, controller_utils_1.convertHexToDecimal)(chainId)}-${new Date(time).toDateString()}`;
1375
1451
  if (nonceNetworkSet.has(key)) {
1376
1452
  return true;
1377
1453
  }
1378
- else if (nonceNetworkSet.size < this.config.txHistoryLimit ||
1454
+ else if (nonceNetworkSet.size < __classPrivateFieldGet(this, _TransactionController_transactionHistoryLimit, "f") ||
1379
1455
  !this.isFinalState(status)) {
1380
1456
  nonceNetworkSet.add(key);
1381
1457
  return true;
@@ -1472,21 +1548,23 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1472
1548
  return common_1.Common.custom(customChainParams);
1473
1549
  }
1474
1550
  onIncomingTransactions({ added, updated, }) {
1475
- const { transactions: currentTransactions } = this.state;
1476
- const updatedTransactions = [
1477
- ...added,
1478
- ...currentTransactions.map((originalTransaction) => {
1479
- const updatedTransaction = updated.find(({ hash }) => hash === originalTransaction.hash);
1480
- return updatedTransaction !== null && updatedTransaction !== void 0 ? updatedTransaction : originalTransaction;
1481
- }),
1482
- ];
1483
- this.update({
1484
- transactions: this.trimTransactionsForState(updatedTransactions),
1551
+ this.update((state) => {
1552
+ const { transactions: currentTransactions } = state;
1553
+ const updatedTransactions = [
1554
+ ...added,
1555
+ ...currentTransactions.map((originalTransaction) => {
1556
+ const updatedTransaction = updated.find(({ hash }) => hash === originalTransaction.hash);
1557
+ return updatedTransaction !== null && updatedTransaction !== void 0 ? updatedTransaction : originalTransaction;
1558
+ }),
1559
+ ];
1560
+ state.transactions = this.trimTransactionsForState(updatedTransactions);
1485
1561
  });
1486
1562
  }
1487
1563
  onUpdatedLastFetchedBlockNumbers({ lastFetchedBlockNumbers, blockNumber, }) {
1488
- this.update({ lastFetchedBlockNumbers });
1489
- this.hub.emit('incomingTransactionBlock', blockNumber);
1564
+ this.update((state) => {
1565
+ state.lastFetchedBlockNumbers = lastFetchedBlockNumbers;
1566
+ });
1567
+ this.messagingSystem.publish(`${controllerName}:incomingTransactionBlockReceived`, blockNumber);
1490
1568
  }
1491
1569
  generateDappSuggestedGasFees(txParams, origin) {
1492
1570
  if (!origin || origin === controller_utils_1.ORIGIN_METAMASK) {
@@ -1517,6 +1595,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1517
1595
  * Validates and adds external provided transaction to state.
1518
1596
  *
1519
1597
  * @param transactionMeta - Nominated external transaction to be added to state.
1598
+ * @returns The new transaction.
1520
1599
  */
1521
1600
  addExternalTransaction(transactionMeta) {
1522
1601
  var _a, _b;
@@ -1529,15 +1608,16 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1529
1608
  const pendingTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.submitted);
1530
1609
  (0, external_transactions_1.validateConfirmedExternalTransaction)(transactionMeta, confirmedTxs, pendingTxs);
1531
1610
  // Make sure provided external transaction has non empty history array
1532
- if (!((_b = transactionMeta.history) !== null && _b !== void 0 ? _b : []).length) {
1533
- if (!this.isHistoryDisabled) {
1534
- (0, history_1.addInitialHistorySnapshot)(transactionMeta);
1535
- }
1536
- }
1537
- const updatedTransactions = [...transactions, transactionMeta];
1538
- this.update({
1539
- transactions: this.trimTransactionsForState(updatedTransactions),
1611
+ const newTransactionMeta = ((_b = transactionMeta.history) !== null && _b !== void 0 ? _b : []).length === 0 && !this.isHistoryDisabled
1612
+ ? (0, history_1.addInitialHistorySnapshot)(transactionMeta)
1613
+ : transactionMeta;
1614
+ this.update((state) => {
1615
+ state.transactions = this.trimTransactionsForState([
1616
+ ...state.transactions,
1617
+ newTransactionMeta,
1618
+ ]);
1540
1619
  });
1620
+ return newTransactionMeta;
1541
1621
  }
1542
1622
  /**
1543
1623
  * Sets other txMeta statuses to dropped if the txMeta that has been confirmed has other transactions
@@ -1554,20 +1634,26 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1554
1634
  const nonce = (_a = transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.nonce;
1555
1635
  const from = (_b = transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.from;
1556
1636
  const { chainId } = transactionMeta;
1557
- const sameNonceTxs = this.state.transactions.filter((transaction) => transaction.id !== transactionId &&
1637
+ const sameNonceTransactions = this.state.transactions.filter((transaction) => transaction.id !== transactionId &&
1558
1638
  transaction.txParams.from === from &&
1559
1639
  transaction.txParams.nonce === nonce &&
1560
1640
  transaction.chainId === chainId &&
1561
1641
  transaction.type !== types_1.TransactionType.incoming);
1562
- if (!sameNonceTxs.length) {
1642
+ const sameNonceTransactionIds = sameNonceTransactions.map((transaction) => transaction.id);
1643
+ if (sameNonceTransactions.length === 0) {
1563
1644
  return;
1564
1645
  }
1565
- // Mark all same nonce transactions as dropped and give it a replacedBy hash
1566
- for (const transaction of sameNonceTxs) {
1567
- transaction.replacedBy = transactionMeta.hash;
1568
- transaction.replacedById = transactionMeta.id;
1569
- // Drop any transaction that wasn't previously failed (off chain failure)
1570
- if (transaction.status !== types_1.TransactionStatus.failed) {
1646
+ this.update((state) => {
1647
+ for (const transaction of state.transactions) {
1648
+ if (sameNonceTransactionIds.includes(transaction.id)) {
1649
+ transaction.replacedBy = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.hash;
1650
+ transaction.replacedById = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.id;
1651
+ }
1652
+ }
1653
+ });
1654
+ for (const transaction of this.state.transactions) {
1655
+ if (sameNonceTransactionIds.includes(transaction.id) &&
1656
+ transaction.status !== types_1.TransactionStatus.failed) {
1571
1657
  this.setTransactionStatusDropped(transaction);
1572
1658
  }
1573
1659
  }
@@ -1578,12 +1664,12 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1578
1664
  * @param transactionMeta - TransactionMeta of transaction to be marked as dropped.
1579
1665
  */
1580
1666
  setTransactionStatusDropped(transactionMeta) {
1581
- transactionMeta.status = types_1.TransactionStatus.dropped;
1582
- this.hub.emit('transaction-dropped', {
1583
- transactionMeta,
1667
+ const updatedTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { status: types_1.TransactionStatus.dropped });
1668
+ this.messagingSystem.publish(`${controllerName}:transactionDropped`, {
1669
+ transactionMeta: updatedTransactionMeta,
1584
1670
  });
1585
- this.updateTransaction(transactionMeta, 'TransactionController#setTransactionStatusDropped - Transaction dropped');
1586
- this.onTransactionStatusChange(transactionMeta);
1671
+ this.updateTransaction(updatedTransactionMeta, 'TransactionController#setTransactionStatusDropped - Transaction dropped');
1672
+ this.onTransactionStatusChange(updatedTransactionMeta);
1587
1673
  }
1588
1674
  /**
1589
1675
  * Get transaction with provided actionId.
@@ -1597,7 +1683,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1597
1683
  waitForTransactionFinished(transactionId) {
1598
1684
  return __awaiter(this, void 0, void 0, function* () {
1599
1685
  return new Promise((resolve) => {
1600
- this.hub.once(`${transactionId}:finished`, (txMeta) => {
1686
+ __classPrivateFieldGet(this, _TransactionController_internalEvents, "f").once(`${transactionId}:finished`, (txMeta) => {
1601
1687
  resolve(txMeta);
1602
1688
  });
1603
1689
  });
@@ -1612,13 +1698,15 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1612
1698
  */
1613
1699
  updateTransactionMetaRSV(transactionMeta, signedTx) {
1614
1700
  return __awaiter(this, void 0, void 0, function* () {
1701
+ const transactionMetaWithRsv = (0, lodash_1.cloneDeep)(transactionMeta);
1615
1702
  for (const key of ['r', 's', 'v']) {
1616
1703
  const value = signedTx[key];
1617
1704
  if (value === undefined || value === null) {
1618
1705
  continue;
1619
1706
  }
1620
- transactionMeta[key] = (0, utils_1.add0x)(value.toString(16));
1707
+ transactionMetaWithRsv[key] = (0, utils_1.add0x)(value.toString(16));
1621
1708
  }
1709
+ return transactionMetaWithRsv;
1622
1710
  });
1623
1711
  }
1624
1712
  getEIP1559Compatibility(networkClientId) {
@@ -1648,18 +1736,21 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1648
1736
  (0, logger_1.projectLogger)('Skipping signed status based on hook');
1649
1737
  return undefined;
1650
1738
  }
1651
- yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
1652
- transactionMeta.status = types_1.TransactionStatus.signed;
1653
- this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction signed');
1654
- this.onTransactionStatusChange(transactionMeta);
1739
+ const transactionMetaWithRsv = Object.assign(Object.assign({}, (yield this.updateTransactionMetaRSV(transactionMeta, signedTx))), { status: types_1.TransactionStatus.signed });
1740
+ this.updateTransaction(transactionMetaWithRsv, 'TransactionController#approveTransaction - Transaction signed');
1741
+ this.onTransactionStatusChange(transactionMetaWithRsv);
1655
1742
  const rawTx = (0, util_1.bufferToHex)(signedTx.serialize());
1656
- transactionMeta.rawTx = rawTx;
1657
- this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - RawTransaction added');
1743
+ const transactionMetaWithRawTx = (0, lodash_1.merge)({}, transactionMetaWithRsv, {
1744
+ rawTx,
1745
+ });
1746
+ this.updateTransaction(transactionMetaWithRawTx, 'TransactionController#approveTransaction - RawTransaction added');
1658
1747
  return rawTx;
1659
1748
  });
1660
1749
  }
1661
1750
  onTransactionStatusChange(transactionMeta) {
1662
- this.hub.emit('transaction-status-update', { transactionMeta });
1751
+ this.messagingSystem.publish(`${controllerName}:transactionStatusUpdated`, {
1752
+ transactionMeta,
1753
+ });
1663
1754
  }
1664
1755
  getNonceTrackerTransactions(status, address, chainId = this.getChainId()) {
1665
1756
  return (0, nonce_1.getAndFormatTransactionsForNonceTracker)(chainId, address, status, this.state.transactions);
@@ -1667,8 +1758,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1667
1758
  onConfirmedTransaction(transactionMeta) {
1668
1759
  (0, logger_1.projectLogger)('Processing confirmed transaction', transactionMeta.id);
1669
1760
  this.markNonceDuplicatesDropped(transactionMeta.id);
1670
- this.hub.emit('transaction-confirmed', { transactionMeta });
1671
- this.hub.emit(`${transactionMeta.id}:confirmed`, transactionMeta);
1761
+ this.messagingSystem.publish(`${controllerName}:transactionConfirmed`, transactionMeta);
1672
1762
  this.onTransactionStatusChange(transactionMeta);
1673
1763
  // Intentional given potential duration of process.
1674
1764
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -1689,7 +1779,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1689
1779
  getTransaction: this.getTransaction.bind(this),
1690
1780
  updateTransaction: this.updateTransaction.bind(this),
1691
1781
  });
1692
- this.hub.emit('post-transaction-balance-updated', {
1782
+ this.messagingSystem.publish(`${controllerName}:postTransactionBalanceUpdated`, {
1693
1783
  transactionMeta: updatedTransactionMeta,
1694
1784
  approvalTransactionMeta,
1695
1785
  });
@@ -1731,7 +1821,7 @@ class TransactionController extends base_controller_1.BaseControllerV1 {
1731
1821
  }
1732
1822
  }
1733
1823
  exports.TransactionController = TransactionController;
1734
- _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionController_pendingTransactionOptions = new WeakMap(), _TransactionController_multichainTrackingHelper = new WeakMap(), _TransactionController_checkForPendingTransactionAndStartPolling = new WeakMap(), _TransactionController_instances = new WeakSet(), _TransactionController_createNonceTracker = function _TransactionController_createNonceTracker({ provider, blockTracker, chainId, }) {
1824
+ _TransactionController_internalEvents = new WeakMap(), _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionController_pendingTransactionOptions = new WeakMap(), _TransactionController_transactionHistoryLimit = new WeakMap(), _TransactionController_multichainTrackingHelper = new WeakMap(), _TransactionController_checkForPendingTransactionAndStartPolling = new WeakMap(), _TransactionController_instances = new WeakSet(), _TransactionController_createNonceTracker = function _TransactionController_createNonceTracker({ provider, blockTracker, chainId, }) {
1735
1825
  return new nonce_tracker_1.NonceTracker({
1736
1826
  // TODO: Replace `any` with type
1737
1827
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1749,7 +1839,7 @@ _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionC
1749
1839
  isEnabled: __classPrivateFieldGet(this, _TransactionController_incomingTransactionOptions, "f").isEnabled,
1750
1840
  queryEntireHistory: __classPrivateFieldGet(this, _TransactionController_incomingTransactionOptions, "f").queryEntireHistory,
1751
1841
  remoteTransactionSource: etherscanRemoteTransactionSource,
1752
- transactionLimit: this.config.txHistoryLimit,
1842
+ transactionLimit: __classPrivateFieldGet(this, _TransactionController_transactionHistoryLimit, "f"),
1753
1843
  updateTransactions: __classPrivateFieldGet(this, _TransactionController_incomingTransactionOptions, "f").updateTransactions,
1754
1844
  });
1755
1845
  __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_addIncomingTransactionHelperListeners).call(this, incomingTransactionHelper);
@@ -1758,7 +1848,9 @@ _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionC
1758
1848
  const ethQuery = new eth_query_1.default(provider);
1759
1849
  const getChainId = chainId ? () => chainId : this.getChainId.bind(this);
1760
1850
  const pendingTransactionTracker = new PendingTransactionTracker_1.PendingTransactionTracker({
1761
- approveTransaction: this.approveTransaction.bind(this),
1851
+ approveTransaction: (transactionId) => __awaiter(this, void 0, void 0, function* () {
1852
+ yield this.approveTransaction(transactionId);
1853
+ }),
1762
1854
  blockTracker,
1763
1855
  getChainId,
1764
1856
  getEthQuery: () => ethQuery,
@@ -1804,14 +1896,14 @@ _TransactionController_incomingTransactionOptions = new WeakMap(), _TransactionC
1804
1896
  }, _TransactionController_getGasFeeFlows = function _TransactionController_getGasFeeFlows() {
1805
1897
  return [new LineaGasFeeFlow_1.LineaGasFeeFlow(), new DefaultGasFeeFlow_1.DefaultGasFeeFlow()];
1806
1898
  }, _TransactionController_updateTransactionInternal = function _TransactionController_updateTransactionInternal(transactionMeta, { note, skipHistory }) {
1807
- const { transactions } = this.state;
1808
- transactionMeta.txParams = (0, utils_2.normalizeTransactionParams)(transactionMeta.txParams);
1809
- (0, validation_1.validateTxParams)(transactionMeta.txParams);
1810
- if (skipHistory !== true) {
1811
- (0, history_1.updateTransactionHistory)(transactionMeta, note !== null && note !== void 0 ? note : 'Transaction updated');
1812
- }
1813
- const index = transactions.findIndex(({ id }) => transactionMeta.id === id);
1814
- transactions[index] = transactionMeta;
1815
- this.update({ transactions: this.trimTransactionsForState(transactions) });
1899
+ const normalizedTransaction = Object.assign(Object.assign({}, transactionMeta), { txParams: (0, utils_2.normalizeTransactionParams)(transactionMeta.txParams) });
1900
+ (0, validation_1.validateTxParams)(normalizedTransaction.txParams);
1901
+ const transactionWithUpdatedHistory = skipHistory === true
1902
+ ? normalizedTransaction
1903
+ : (0, history_1.updateTransactionHistory)(normalizedTransaction, note !== null && note !== void 0 ? note : 'Transaction updated');
1904
+ this.update((state) => {
1905
+ const index = state.transactions.findIndex(({ id }) => transactionMeta.id === id);
1906
+ state.transactions[index] = transactionWithUpdatedHistory;
1907
+ });
1816
1908
  };
1817
1909
  //# sourceMappingURL=TransactionController.js.map