@metamask/transaction-controller 10.0.0 → 12.0.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 (44) hide show
  1. package/CHANGELOG.md +50 -4
  2. package/dist/EtherscanRemoteTransactionSource.d.ts +3 -3
  3. package/dist/EtherscanRemoteTransactionSource.d.ts.map +1 -1
  4. package/dist/EtherscanRemoteTransactionSource.js +48 -25
  5. package/dist/EtherscanRemoteTransactionSource.js.map +1 -1
  6. package/dist/IncomingTransactionHelper.d.ts +4 -3
  7. package/dist/IncomingTransactionHelper.d.ts.map +1 -1
  8. package/dist/IncomingTransactionHelper.js +41 -31
  9. package/dist/IncomingTransactionHelper.js.map +1 -1
  10. package/dist/TransactionController.d.ts +77 -26
  11. package/dist/TransactionController.d.ts.map +1 -1
  12. package/dist/TransactionController.js +241 -124
  13. package/dist/TransactionController.js.map +1 -1
  14. package/dist/constants.d.ts +5 -19
  15. package/dist/constants.d.ts.map +1 -1
  16. package/dist/constants.js +40 -45
  17. package/dist/constants.js.map +1 -1
  18. package/dist/etherscan.d.ts +5 -6
  19. package/dist/etherscan.d.ts.map +1 -1
  20. package/dist/etherscan.js +7 -14
  21. package/dist/etherscan.js.map +1 -1
  22. package/dist/external-transactions.js +5 -5
  23. package/dist/external-transactions.js.map +1 -1
  24. package/dist/history.d.ts +15 -0
  25. package/dist/history.d.ts.map +1 -0
  26. package/dist/history.js +75 -0
  27. package/dist/history.js.map +1 -0
  28. package/dist/logger.d.ts +6 -0
  29. package/dist/logger.d.ts.map +1 -0
  30. package/dist/logger.js +8 -0
  31. package/dist/logger.js.map +1 -0
  32. package/dist/transaction-type.d.ts +14 -0
  33. package/dist/transaction-type.d.ts.map +1 -0
  34. package/dist/transaction-type.js +114 -0
  35. package/dist/transaction-type.js.map +1 -0
  36. package/dist/types.d.ts +227 -27
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/types.js +99 -1
  39. package/dist/types.js.map +1 -1
  40. package/dist/utils.d.ts +16 -18
  41. package/dist/utils.d.ts.map +1 -1
  42. package/dist/utils.js +44 -48
  43. package/dist/utils.js.map +1 -1
  44. package/package.json +8 -4
@@ -23,11 +23,14 @@ const eth_method_registry_1 = __importDefault(require("eth-method-registry"));
23
23
  const eth_rpc_errors_1 = require("eth-rpc-errors");
24
24
  const ethereumjs_util_1 = require("ethereumjs-util");
25
25
  const events_1 = require("events");
26
+ const lodash_1 = require("lodash");
26
27
  const nonce_tracker_1 = __importDefault(require("nonce-tracker"));
27
28
  const uuid_1 = require("uuid");
28
29
  const EtherscanRemoteTransactionSource_1 = require("./EtherscanRemoteTransactionSource");
29
30
  const external_transactions_1 = require("./external-transactions");
31
+ const history_1 = require("./history");
30
32
  const IncomingTransactionHelper_1 = require("./IncomingTransactionHelper");
33
+ const transaction_type_1 = require("./transaction-type");
31
34
  const types_1 = require("./types");
32
35
  const utils_1 = require("./utils");
33
36
  exports.HARDFORK = common_1.Hardfork.London;
@@ -52,20 +55,22 @@ class TransactionController extends base_controller_1.BaseController {
52
55
  *
53
56
  * @param options - The controller options.
54
57
  * @param options.blockTracker - The block tracker used to poll for new blocks data.
58
+ * @param options.disableHistory - Whether to disable storing history in transaction metadata.
59
+ * @param options.disableSendFlowHistory - Explicitly disable transaction metadata history.
55
60
  * @param options.getNetworkState - Gets the state of the network controller.
56
61
  * @param options.getSelectedAddress - Gets the address of the currently selected account.
57
62
  * @param options.incomingTransactions - Configuration options for incoming transaction support.
58
- * @param options.incomingTransactions.apiKey - An optional API key to use when fetching remote transaction data.
59
63
  * @param options.incomingTransactions.includeTokenTransfers - Whether or not to include ERC20 token transfers.
60
64
  * @param options.incomingTransactions.isEnabled - Whether or not incoming transaction retrieval is enabled.
61
- * @param options.incomingTransactions.updateTransactions - Whether or not to update local transactions using remote transaction data.
65
+ * @param options.incomingTransactions.queryEntireHistory - Whether to initially query the entire transaction history or only recent blocks.
66
+ * @param options.incomingTransactions.updateTransactions - Whether to update local transactions using remote transaction data.
62
67
  * @param options.messenger - The controller messenger.
63
68
  * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
64
69
  * @param options.provider - The provider used to create the underlying EthQuery instance.
65
70
  * @param config - Initial options used to configure this controller.
66
71
  * @param state - Initial state to set on this controller.
67
72
  */
68
- constructor({ blockTracker, getNetworkState, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, provider, }, config, state) {
73
+ constructor({ blockTracker, disableHistory, disableSendFlowHistory, getNetworkState, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, provider, }, config, state) {
69
74
  super(config, state);
70
75
  this.mutex = new async_mutex_1.Mutex();
71
76
  /**
@@ -90,6 +95,8 @@ class TransactionController extends base_controller_1.BaseController {
90
95
  this.messagingSystem = messenger;
91
96
  this.getNetworkState = getNetworkState;
92
97
  this.ethQuery = new eth_query_1.default(provider);
98
+ this.isSendFlowHistoryDisabled = disableSendFlowHistory !== null && disableSendFlowHistory !== void 0 ? disableSendFlowHistory : false;
99
+ this.isHistoryDisabled = disableHistory !== null && disableHistory !== void 0 ? disableHistory : false;
93
100
  this.registry = new eth_method_registry_1.default({ provider });
94
101
  this.nonceTracker = new nonce_tracker_1.default({
95
102
  provider,
@@ -100,10 +107,11 @@ class TransactionController extends base_controller_1.BaseController {
100
107
  this.incomingTransactionHelper = new IncomingTransactionHelper_1.IncomingTransactionHelper({
101
108
  blockTracker,
102
109
  getCurrentAccount: getSelectedAddress,
110
+ getLastFetchedBlockNumbers: () => this.state.lastFetchedBlockNumbers,
103
111
  getNetworkState,
104
112
  isEnabled: incomingTransactions.isEnabled,
113
+ queryEntireHistory: incomingTransactions.queryEntireHistory,
105
114
  remoteTransactionSource: new EtherscanRemoteTransactionSource_1.EtherscanRemoteTransactionSource({
106
- apiKey: incomingTransactions.apiKey,
107
115
  includeTokenTransfers: incomingTransactions.includeTokenTransfers,
108
116
  }),
109
117
  transactionLimit: this.config.txHistoryLimit,
@@ -119,7 +127,7 @@ class TransactionController extends base_controller_1.BaseController {
119
127
  }
120
128
  failTransaction(transactionMeta, error) {
121
129
  const newTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { error, status: types_1.TransactionStatus.failed });
122
- this.updateTransaction(newTransactionMeta);
130
+ this.updateTransaction(newTransactionMeta, 'TransactionController#failTransaction - Add error message and set status to failed');
123
131
  this.hub.emit(`${transactionMeta.id}:finished`, newTransactionMeta);
124
132
  }
125
133
  registryLookup(fourBytePrefix) {
@@ -175,43 +183,48 @@ class TransactionController extends base_controller_1.BaseController {
175
183
  * unique transaction id will be generated, and gas and gasPrice will be calculated
176
184
  * if not provided. If A `<tx.id>:unapproved` hub event will be emitted once added.
177
185
  *
178
- * @param transaction - The transaction object to add.
186
+ * @param txParams - Standard parameters for an Ethereum transaction.
179
187
  * @param opts - Additional options to control how the transaction is added.
180
188
  * @param opts.actionId - Unique ID to prevent duplicate requests.
181
189
  * @param opts.deviceConfirmedOn - An enum to indicate what device confirmed the transaction.
182
190
  * @param opts.origin - The origin of the transaction request, such as a dApp hostname.
183
191
  * @param opts.requireApproval - Whether the transaction requires approval by the user, defaults to true unless explicitly disabled.
184
192
  * @param opts.securityAlertResponse - Response from security validator.
193
+ * @param opts.sendFlowHistory - The sendFlowHistory entries to add.
194
+ * @param opts.type - Type of transaction to add, such as 'cancel' or 'swap'.
185
195
  * @returns Object containing a promise resolving to the transaction hash if approved.
186
196
  */
187
- addTransaction(transaction, { actionId, deviceConfirmedOn, origin, requireApproval, securityAlertResponse, } = {}) {
197
+ addTransaction(txParams, { actionId, deviceConfirmedOn, origin, requireApproval, securityAlertResponse, sendFlowHistory, type, } = {}) {
188
198
  return __awaiter(this, void 0, void 0, function* () {
189
- const { chainId, networkId } = this.getChainAndNetworkId();
199
+ const chainId = this.getChainId();
190
200
  const { transactions } = this.state;
191
- transaction = (0, utils_1.normalizeTransaction)(transaction);
192
- (0, utils_1.validateTransaction)(transaction);
193
- const dappSuggestedGasFees = this.generateDappSuggestedGasFees(transaction, origin);
201
+ txParams = (0, utils_1.normalizeTxParams)(txParams);
202
+ (0, utils_1.validateTxParams)(txParams);
203
+ const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin);
204
+ const transactionType = type !== null && type !== void 0 ? type : (yield (0, transaction_type_1.determineTransactionType)(txParams, this.ethQuery)).type;
194
205
  const existingTransactionMeta = this.getTransactionWithActionId(actionId);
195
206
  // If a request to add a transaction with the same actionId is submitted again, a new transaction will not be created for it.
196
207
  const transactionMeta = existingTransactionMeta || {
197
- id: (0, uuid_1.v1)(),
198
- networkID: networkId !== null && networkId !== void 0 ? networkId : undefined,
208
+ // Add actionId to txMeta to check if same actionId is seen again
209
+ actionId,
199
210
  chainId,
211
+ dappSuggestedGasFees,
212
+ deviceConfirmedOn,
213
+ id: (0, uuid_1.v1)(),
200
214
  origin,
215
+ securityAlertResponse,
201
216
  status: types_1.TransactionStatus.unapproved,
202
217
  time: Date.now(),
203
- transaction,
204
- deviceConfirmedOn,
218
+ txParams,
219
+ userEditedGasLimit: false,
205
220
  verifiedOnBlockchain: false,
206
- dappSuggestedGasFees,
207
- securityAlertResponse,
208
- // Add actionId to txMeta to check if same actionId is seen again
209
- actionId,
221
+ type: transactionType,
210
222
  };
211
223
  try {
212
- const { gas, estimateGasError } = yield this.estimateGas(transaction);
213
- transaction.gas = gas;
214
- transaction.estimateGasError = estimateGasError;
224
+ const { gas, estimateGasError } = yield this.estimateGas(txParams);
225
+ txParams.gas = gas;
226
+ txParams.estimateGasError = estimateGasError;
227
+ transactionMeta.originalGasEstimate = gas;
215
228
  }
216
229
  catch (error) {
217
230
  this.failTransaction(transactionMeta, error);
@@ -219,6 +232,13 @@ class TransactionController extends base_controller_1.BaseController {
219
232
  }
220
233
  // Checks if a transaction already exists with a given actionId
221
234
  if (!existingTransactionMeta) {
235
+ if (!this.isSendFlowHistoryDisabled) {
236
+ transactionMeta.sendFlowHistory = sendFlowHistory !== null && sendFlowHistory !== void 0 ? sendFlowHistory : [];
237
+ }
238
+ // Initial history push
239
+ if (!this.isHistoryDisabled) {
240
+ (0, history_1.addInitialHistorySnapshot)(transactionMeta);
241
+ }
222
242
  transactions.push(transactionMeta);
223
243
  this.update({
224
244
  transactions: this.trimTransactionsForState(transactions),
@@ -249,9 +269,9 @@ class TransactionController extends base_controller_1.BaseController {
249
269
  * Creates approvals for all unapproved transactions persisted.
250
270
  */
251
271
  initApprovals() {
252
- const { networkId, chainId } = this.getChainAndNetworkId();
272
+ const chainId = this.getChainId();
253
273
  const unapprovedTxs = this.state.transactions.filter((transaction) => transaction.status === types_1.TransactionStatus.unapproved &&
254
- (0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
274
+ transaction.chainId === chainId);
255
275
  for (const txMeta of unapprovedTxs) {
256
276
  this.processApproval(txMeta, {
257
277
  shouldShowRequest: false,
@@ -265,18 +285,18 @@ class TransactionController extends base_controller_1.BaseController {
265
285
  * Attempts to cancel a transaction based on its ID by setting its status to "rejected"
266
286
  * and emitting a `<tx.id>:finished` hub event.
267
287
  *
268
- * @param transactionID - The ID of the transaction to cancel.
288
+ * @param transactionId - The ID of the transaction to cancel.
269
289
  * @param gasValues - The gas values to use for the cancellation transaction.
270
290
  * @param options - The options for the cancellation transaction.
271
291
  * @param options.estimatedBaseFee - The estimated base fee of the transaction.
272
292
  */
273
- stopTransaction(transactionID, gasValues, { estimatedBaseFee } = {}) {
293
+ stopTransaction(transactionId, gasValues, { estimatedBaseFee } = {}) {
274
294
  var _a, _b;
275
295
  return __awaiter(this, void 0, void 0, function* () {
276
296
  if (gasValues) {
277
297
  (0, utils_1.validateGasValues)(gasValues);
278
298
  }
279
- const transactionMeta = this.state.transactions.find(({ id }) => id === transactionID);
299
+ const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
280
300
  if (!transactionMeta) {
281
301
  return;
282
302
  }
@@ -284,20 +304,20 @@ class TransactionController extends base_controller_1.BaseController {
284
304
  throw new Error('No sign method defined.');
285
305
  }
286
306
  // gasPrice (legacy non EIP1559)
287
- const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.transaction.gasPrice, exports.CANCEL_RATE);
307
+ const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.txParams.gasPrice, exports.CANCEL_RATE);
288
308
  const gasPriceFromValues = (0, utils_1.isGasPriceValue)(gasValues) && gasValues.gasPrice;
289
309
  const newGasPrice = (gasPriceFromValues &&
290
310
  (0, utils_1.validateMinimumIncrease)(gasPriceFromValues, minGasPrice)) ||
291
311
  minGasPrice;
292
312
  // maxFeePerGas (EIP1559)
293
- const existingMaxFeePerGas = (_a = transactionMeta.transaction) === null || _a === void 0 ? void 0 : _a.maxFeePerGas;
313
+ const existingMaxFeePerGas = (_a = transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.maxFeePerGas;
294
314
  const minMaxFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxFeePerGas, exports.CANCEL_RATE);
295
315
  const maxFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxFeePerGas;
296
316
  const newMaxFeePerGas = (maxFeePerGasValues &&
297
317
  (0, utils_1.validateMinimumIncrease)(maxFeePerGasValues, minMaxFeePerGas)) ||
298
318
  (existingMaxFeePerGas && minMaxFeePerGas);
299
319
  // maxPriorityFeePerGas (EIP1559)
300
- const existingMaxPriorityFeePerGas = (_b = transactionMeta.transaction) === null || _b === void 0 ? void 0 : _b.maxPriorityFeePerGas;
320
+ const existingMaxPriorityFeePerGas = (_b = transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.maxPriorityFeePerGas;
301
321
  const minMaxPriorityFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxPriorityFeePerGas, exports.CANCEL_RATE);
302
322
  const maxPriorityFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxPriorityFeePerGas;
303
323
  const newMaxPriorityFeePerGas = (maxPriorityFeePerGasValues &&
@@ -305,25 +325,26 @@ class TransactionController extends base_controller_1.BaseController {
305
325
  (existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
306
326
  const txParams = newMaxFeePerGas && newMaxPriorityFeePerGas
307
327
  ? {
308
- from: transactionMeta.transaction.from,
309
- gasLimit: transactionMeta.transaction.gas,
328
+ from: transactionMeta.txParams.from,
329
+ gasLimit: transactionMeta.txParams.gas,
310
330
  maxFeePerGas: newMaxFeePerGas,
311
331
  maxPriorityFeePerGas: newMaxPriorityFeePerGas,
312
332
  type: 2,
313
- nonce: transactionMeta.transaction.nonce,
314
- to: transactionMeta.transaction.from,
333
+ nonce: transactionMeta.txParams.nonce,
334
+ to: transactionMeta.txParams.from,
315
335
  value: '0x0',
316
336
  }
317
337
  : {
318
- from: transactionMeta.transaction.from,
319
- gasLimit: transactionMeta.transaction.gas,
338
+ from: transactionMeta.txParams.from,
339
+ gasLimit: transactionMeta.txParams.gas,
320
340
  gasPrice: newGasPrice,
321
- nonce: transactionMeta.transaction.nonce,
322
- to: transactionMeta.transaction.from,
341
+ nonce: transactionMeta.txParams.nonce,
342
+ to: transactionMeta.txParams.from,
323
343
  value: '0x0',
324
344
  };
325
345
  const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
326
- const signedTx = yield this.sign(unsignedEthTx, transactionMeta.transaction.from);
346
+ const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
347
+ yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
327
348
  const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
328
349
  yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
329
350
  transactionMeta.estimatedBaseFee = estimatedBaseFee;
@@ -334,13 +355,13 @@ class TransactionController extends base_controller_1.BaseController {
334
355
  /**
335
356
  * Attempts to speed up a transaction increasing transaction gasPrice by ten percent.
336
357
  *
337
- * @param transactionID - The ID of the transaction to speed up.
358
+ * @param transactionId - The ID of the transaction to speed up.
338
359
  * @param gasValues - The gas values to use for the speed up transaction.
339
360
  * @param options - The options for the speed up transaction.
340
361
  * @param options.actionId - Unique ID to prevent duplicate requests
341
362
  * @param options.estimatedBaseFee - The estimated base fee of the transaction.
342
363
  */
343
- speedUpTransaction(transactionID, gasValues, { actionId, estimatedBaseFee, } = {}) {
364
+ speedUpTransaction(transactionId, gasValues, { actionId, estimatedBaseFee, } = {}) {
344
365
  var _a, _b;
345
366
  return __awaiter(this, void 0, void 0, function* () {
346
367
  // If transaction is found for same action id, do not create a new speed up transaction.
@@ -350,7 +371,7 @@ class TransactionController extends base_controller_1.BaseController {
350
371
  if (gasValues) {
351
372
  (0, utils_1.validateGasValues)(gasValues);
352
373
  }
353
- const transactionMeta = this.state.transactions.find(({ id }) => id === transactionID);
374
+ const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
354
375
  /* istanbul ignore next */
355
376
  if (!transactionMeta) {
356
377
  return;
@@ -361,37 +382,36 @@ class TransactionController extends base_controller_1.BaseController {
361
382
  }
362
383
  const { transactions } = this.state;
363
384
  // gasPrice (legacy non EIP1559)
364
- const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.transaction.gasPrice, exports.SPEED_UP_RATE);
385
+ const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.txParams.gasPrice, exports.SPEED_UP_RATE);
365
386
  const gasPriceFromValues = (0, utils_1.isGasPriceValue)(gasValues) && gasValues.gasPrice;
366
387
  const newGasPrice = (gasPriceFromValues &&
367
388
  (0, utils_1.validateMinimumIncrease)(gasPriceFromValues, minGasPrice)) ||
368
389
  minGasPrice;
369
390
  // maxFeePerGas (EIP1559)
370
- const existingMaxFeePerGas = (_a = transactionMeta.transaction) === null || _a === void 0 ? void 0 : _a.maxFeePerGas;
391
+ const existingMaxFeePerGas = (_a = transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.maxFeePerGas;
371
392
  const minMaxFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxFeePerGas, exports.SPEED_UP_RATE);
372
393
  const maxFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxFeePerGas;
373
394
  const newMaxFeePerGas = (maxFeePerGasValues &&
374
395
  (0, utils_1.validateMinimumIncrease)(maxFeePerGasValues, minMaxFeePerGas)) ||
375
396
  (existingMaxFeePerGas && minMaxFeePerGas);
376
397
  // maxPriorityFeePerGas (EIP1559)
377
- const existingMaxPriorityFeePerGas = (_b = transactionMeta.transaction) === null || _b === void 0 ? void 0 : _b.maxPriorityFeePerGas;
398
+ const existingMaxPriorityFeePerGas = (_b = transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.maxPriorityFeePerGas;
378
399
  const minMaxPriorityFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxPriorityFeePerGas, exports.SPEED_UP_RATE);
379
400
  const maxPriorityFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxPriorityFeePerGas;
380
401
  const newMaxPriorityFeePerGas = (maxPriorityFeePerGasValues &&
381
402
  (0, utils_1.validateMinimumIncrease)(maxPriorityFeePerGasValues, minMaxPriorityFeePerGas)) ||
382
403
  (existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
383
404
  const txParams = newMaxFeePerGas && newMaxPriorityFeePerGas
384
- ? Object.assign(Object.assign({}, transactionMeta.transaction), { gasLimit: transactionMeta.transaction.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type: 2 }) : Object.assign(Object.assign({}, transactionMeta.transaction), { gasLimit: transactionMeta.transaction.gas, gasPrice: newGasPrice });
405
+ ? Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type: 2 }) : Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, gasPrice: newGasPrice });
385
406
  const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
386
- const signedTx = yield this.sign(unsignedEthTx, transactionMeta.transaction.from);
407
+ const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
408
+ yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
387
409
  const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
388
- const transactionHash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [
389
- rawTx,
390
- ]);
391
- const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), transactionHash,
392
- actionId });
410
+ const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
411
+ const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), hash,
412
+ actionId, originalGasEstimate: transactionMeta.txParams.gas, type: types_1.TransactionType.retry });
393
413
  const newTransactionMeta = newMaxFeePerGas && newMaxPriorityFeePerGas
394
- ? Object.assign(Object.assign({}, baseTransactionMeta), { transaction: Object.assign(Object.assign({}, transactionMeta.transaction), { maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas }) }) : Object.assign(Object.assign({}, baseTransactionMeta), { transaction: Object.assign(Object.assign({}, transactionMeta.transaction), { gasPrice: newGasPrice }) });
414
+ ? 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 }) });
395
415
  transactions.push(newTransactionMeta);
396
416
  this.update({ transactions: this.trimTransactionsForState(transactions) });
397
417
  this.hub.emit(`${transactionMeta.id}:speedup`, newTransactionMeta);
@@ -421,7 +441,7 @@ class TransactionController extends base_controller_1.BaseController {
421
441
  false,
422
442
  ]);
423
443
  // 2. If to is not defined or this is not a contract address, and there is no data use 0x5208 / 21000.
424
- // If the newtwork is a custom network then bypass this check and fetch 'estimateGas'.
444
+ // If the network is a custom network then bypass this check and fetch 'estimateGas'.
425
445
  /* istanbul ignore next */
426
446
  const code = to ? yield (0, controller_utils_1.query)(this.ethQuery, 'getCode', [to]) : undefined;
427
447
  /* istanbul ignore next */
@@ -475,14 +495,10 @@ class TransactionController extends base_controller_1.BaseController {
475
495
  queryTransactionStatuses() {
476
496
  return __awaiter(this, void 0, void 0, function* () {
477
497
  const { transactions } = this.state;
478
- const { chainId: currentChainId, networkId: currentNetworkID } = this.getChainAndNetworkId();
498
+ const currentChainId = this.getChainId();
479
499
  let gotUpdates = false;
480
500
  yield (0, controller_utils_1.safelyExecute)(() => Promise.all(transactions.map((meta, index) => __awaiter(this, void 0, void 0, function* () {
481
- // Using fallback to networkID only when there is no chainId present.
482
- // Should be removed when networkID is completely removed.
483
- const txBelongsToCurrentChain = meta.chainId === currentChainId ||
484
- (!meta.chainId && meta.networkID === currentNetworkID);
485
- if (!meta.verifiedOnBlockchain && txBelongsToCurrentChain) {
501
+ if (!meta.verifiedOnBlockchain && meta.chainId === currentChainId) {
486
502
  const [reconciledTx, updateRequired] = yield this.blockchainTransactionStateReconciler(meta);
487
503
  if (updateRequired) {
488
504
  transactions[index] = reconciledTx;
@@ -502,11 +518,15 @@ class TransactionController extends base_controller_1.BaseController {
502
518
  * Updates an existing transaction in state.
503
519
  *
504
520
  * @param transactionMeta - The new transaction to store in state.
521
+ * @param note - A note or update reason to include in the transaction history.
505
522
  */
506
- updateTransaction(transactionMeta) {
523
+ updateTransaction(transactionMeta, note) {
507
524
  const { transactions } = this.state;
508
- transactionMeta.transaction = (0, utils_1.normalizeTransaction)(transactionMeta.transaction);
509
- (0, utils_1.validateTransaction)(transactionMeta.transaction);
525
+ transactionMeta.txParams = (0, utils_1.normalizeTxParams)(transactionMeta.txParams);
526
+ (0, utils_1.validateTxParams)(transactionMeta.txParams);
527
+ if (!this.isHistoryDisabled) {
528
+ (0, history_1.updateTransactionHistory)(transactionMeta, note);
529
+ }
510
530
  const index = transactions.findIndex(({ id }) => transactionMeta.id === id);
511
531
  transactions[index] = transactionMeta;
512
532
  this.update({ transactions: this.trimTransactionsForState(transactions) });
@@ -525,17 +545,14 @@ class TransactionController extends base_controller_1.BaseController {
525
545
  this.update({ transactions: [] });
526
546
  return;
527
547
  }
528
- const { chainId: currentChainId, networkId: currentNetworkID } = this.getChainAndNetworkId();
529
- const newTransactions = this.state.transactions.filter(({ networkID, chainId, transaction }) => {
548
+ const currentChainId = this.getChainId();
549
+ const newTransactions = this.state.transactions.filter(({ chainId, txParams }) => {
530
550
  var _a;
531
- // Using fallback to networkID only when there is no chainId present. Should be removed when networkID is completely removed.
532
- const isMatchingNetwork = ignoreNetwork ||
533
- chainId === currentChainId ||
534
- (!chainId && networkID === currentNetworkID);
551
+ const isMatchingNetwork = ignoreNetwork || chainId === currentChainId;
535
552
  if (!isMatchingNetwork) {
536
553
  return true;
537
554
  }
538
- const isMatchingAddress = !address || ((_a = transaction.from) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === address.toLowerCase();
555
+ const isMatchingAddress = !address || ((_a = txParams.from) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === address.toLowerCase();
539
556
  return !isMatchingAddress;
540
557
  });
541
558
  this.update({
@@ -570,13 +587,88 @@ class TransactionController extends base_controller_1.BaseController {
570
587
  // Update same nonce local transactions as dropped and define replacedBy properties.
571
588
  this.markNonceDuplicatesDropped(transactionId);
572
589
  // Update external provided transaction with updated gas values and confirmed status.
573
- this.updateTransaction(transactionMeta);
590
+ this.updateTransaction(transactionMeta, 'TransactionController:confirmExternalTransaction - Add external transaction');
574
591
  }
575
592
  catch (error) {
576
593
  console.error(error);
577
594
  }
578
595
  });
579
596
  }
597
+ /**
598
+ * Append new send flow history to a transaction.
599
+ *
600
+ * @param transactionID - The ID of the transaction to update.
601
+ * @param currentSendFlowHistoryLength - The length of the current sendFlowHistory array.
602
+ * @param sendFlowHistoryToAdd - The sendFlowHistory entries to add.
603
+ * @returns The updated transactionMeta.
604
+ */
605
+ updateTransactionSendFlowHistory(transactionID, currentSendFlowHistoryLength, sendFlowHistoryToAdd) {
606
+ var _a, _b;
607
+ if (this.isSendFlowHistoryDisabled) {
608
+ throw new Error('Send flow history is disabled for the current transaction controller');
609
+ }
610
+ const transactionMeta = this.getTransaction(transactionID);
611
+ if (!transactionMeta) {
612
+ throw new Error(`Cannot update send flow history as no transaction metadata found`);
613
+ }
614
+ (0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updateTransactionSendFlowHistory');
615
+ if (currentSendFlowHistoryLength ===
616
+ (((_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.sendFlowHistory) === null || _a === void 0 ? void 0 : _a.length) || 0)) {
617
+ transactionMeta.sendFlowHistory = [
618
+ ...((_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.sendFlowHistory) !== null && _b !== void 0 ? _b : []),
619
+ ...sendFlowHistoryToAdd,
620
+ ];
621
+ this.updateTransaction(transactionMeta, 'TransactionController:updateTransactionSendFlowHistory - sendFlowHistory updated');
622
+ }
623
+ return this.getTransaction(transactionID);
624
+ }
625
+ /**
626
+ * Update the gas values of a transaction.
627
+ *
628
+ * @param transactionId - The ID of the transaction to update.
629
+ * @param gasValues - Gas values to update.
630
+ * @param gasValues.gas - Same as transaction.gasLimit.
631
+ * @param gasValues.gasLimit - Maxmimum number of units of gas to use for this transaction.
632
+ * @param gasValues.gasPrice - Price per gas for legacy transactions.
633
+ * @param gasValues.maxPriorityFeePerGas - Maximum amount per gas to give to validator as incentive.
634
+ * @param gasValues.maxFeePerGas - Maximum amount per gas to pay for the transaction, including the priority fee.
635
+ * @param gasValues.estimateUsed - Which estimate level was used.
636
+ * @param gasValues.estimateSuggested - Which estimate level that the API suggested.
637
+ * @param gasValues.defaultGasEstimates - The default estimate for gas.
638
+ * @param gasValues.originalGasEstimate - Original estimate for gas.
639
+ * @param gasValues.userEditedGasLimit - The gas limit supplied by user.
640
+ * @param gasValues.userFeeLevel - Estimate level user selected.
641
+ * @returns The updated transactionMeta.
642
+ */
643
+ updateTransactionGasFees(transactionId, { defaultGasEstimates, estimateUsed, estimateSuggested, gas, gasLimit, gasPrice, maxPriorityFeePerGas, maxFeePerGas, originalGasEstimate, userEditedGasLimit, userFeeLevel, }) {
644
+ const transactionMeta = this.getTransaction(transactionId);
645
+ if (!transactionMeta) {
646
+ throw new Error(`Cannot update transaction as no transaction metadata found`);
647
+ }
648
+ (0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updateTransactionGasFees');
649
+ let transactionGasFees = {
650
+ txParams: {
651
+ gas,
652
+ gasLimit,
653
+ gasPrice,
654
+ maxPriorityFeePerGas,
655
+ maxFeePerGas,
656
+ },
657
+ defaultGasEstimates,
658
+ estimateUsed,
659
+ estimateSuggested,
660
+ originalGasEstimate,
661
+ userEditedGasLimit,
662
+ userFeeLevel,
663
+ };
664
+ // only update what is defined
665
+ transactionGasFees.txParams = (0, lodash_1.pickBy)(transactionGasFees.txParams);
666
+ transactionGasFees = (0, lodash_1.pickBy)(transactionGasFees);
667
+ // merge updated gas values with existing transaction meta
668
+ const updatedMeta = (0, lodash_1.merge)(transactionMeta, transactionGasFees);
669
+ this.updateTransaction(updatedMeta, 'TransactionController:updateTransactionGasFees - gas values updated');
670
+ return this.getTransaction(transactionId);
671
+ }
580
672
  processApproval(transactionMeta, { isExisting = false, requireApproval, shouldShowRequest = true, }) {
581
673
  return __awaiter(this, void 0, void 0, function* () {
582
674
  const transactionId = transactionMeta.id;
@@ -622,7 +714,7 @@ class TransactionController extends base_controller_1.BaseController {
622
714
  throw cancelError;
623
715
  case types_1.TransactionStatus.submitted:
624
716
  resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
625
- return finalMeta.transactionHash;
717
+ return finalMeta.hash;
626
718
  default:
627
719
  const internalError = eth_rpc_errors_1.ethErrors.rpc.internal(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finalMeta || transactionId)}`);
628
720
  resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.error(internalError);
@@ -636,16 +728,16 @@ class TransactionController extends base_controller_1.BaseController {
636
728
  * using the sign configuration property, then published to the blockchain.
637
729
  * A `<tx.id>:finished` hub event is fired after success or failure.
638
730
  *
639
- * @param transactionID - The ID of the transaction to approve.
731
+ * @param transactionId - The ID of the transaction to approve.
640
732
  */
641
- approveTransaction(transactionID) {
733
+ approveTransaction(transactionId) {
642
734
  return __awaiter(this, void 0, void 0, function* () {
643
735
  const { transactions } = this.state;
644
736
  const releaseLock = yield this.mutex.acquire();
645
- const { chainId } = this.getChainAndNetworkId();
646
- const index = transactions.findIndex(({ id }) => transactionID === id);
737
+ const chainId = this.getChainId();
738
+ const index = transactions.findIndex(({ id }) => transactionId === id);
647
739
  const transactionMeta = transactions[index];
648
- const { transaction: { nonce, from }, } = transactionMeta;
740
+ const { txParams: { nonce, from }, } = transactionMeta;
649
741
  let nonceLock;
650
742
  try {
651
743
  if (!this.sign) {
@@ -667,12 +759,12 @@ class TransactionController extends base_controller_1.BaseController {
667
759
  nonceToUse = (0, ethereumjs_util_1.addHexPrefix)(nonceLock.nextNonce.toString(16));
668
760
  }
669
761
  transactionMeta.status = status;
670
- transactionMeta.transaction.nonce = nonceToUse;
671
- transactionMeta.transaction.chainId = chainId;
672
- const baseTxParams = Object.assign(Object.assign({}, transactionMeta.transaction), { gasLimit: transactionMeta.transaction.gas });
673
- const isEIP1559 = (0, utils_1.isEIP1559Transaction)(transactionMeta.transaction);
762
+ transactionMeta.txParams.nonce = nonceToUse;
763
+ transactionMeta.txParams.chainId = chainId;
764
+ const baseTxParams = Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas });
765
+ const isEIP1559 = (0, utils_1.isEIP1559Transaction)(transactionMeta.txParams);
674
766
  const txParams = isEIP1559
675
- ? Object.assign(Object.assign({}, baseTxParams), { maxFeePerGas: transactionMeta.transaction.maxFeePerGas, maxPriorityFeePerGas: transactionMeta.transaction.maxPriorityFeePerGas, estimatedBaseFee: transactionMeta.transaction.estimatedBaseFee,
767
+ ? Object.assign(Object.assign({}, baseTxParams), { maxFeePerGas: transactionMeta.txParams.maxFeePerGas, maxPriorityFeePerGas: transactionMeta.txParams.maxPriorityFeePerGas, estimatedBaseFee: transactionMeta.txParams.estimatedBaseFee,
676
768
  // specify type 2 if maxFeePerGas and maxPriorityFeePerGas are set
677
769
  type: 2 }) : baseTxParams;
678
770
  // delete gasPrice if maxFeePerGas and maxPriorityFeePerGas are set
@@ -681,18 +773,17 @@ class TransactionController extends base_controller_1.BaseController {
681
773
  }
682
774
  const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
683
775
  const signedTx = yield this.sign(unsignedEthTx, from);
776
+ yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
684
777
  transactionMeta.status = types_1.TransactionStatus.signed;
685
- this.updateTransaction(transactionMeta);
778
+ this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction signed');
686
779
  const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
687
780
  transactionMeta.rawTx = rawTx;
688
- this.updateTransaction(transactionMeta);
689
- const transactionHash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [
690
- rawTx,
691
- ]);
692
- transactionMeta.transactionHash = transactionHash;
781
+ this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - RawTransaction added');
782
+ const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
783
+ transactionMeta.hash = hash;
693
784
  transactionMeta.status = types_1.TransactionStatus.submitted;
694
785
  transactionMeta.submittedTime = new Date().getTime();
695
- this.updateTransaction(transactionMeta);
786
+ this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
696
787
  this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
697
788
  }
698
789
  catch (error) {
@@ -711,16 +802,16 @@ class TransactionController extends base_controller_1.BaseController {
711
802
  * Cancels a transaction based on its ID by setting its status to "rejected"
712
803
  * and emitting a `<tx.id>:finished` hub event.
713
804
  *
714
- * @param transactionID - The ID of the transaction to cancel.
805
+ * @param transactionId - The ID of the transaction to cancel.
715
806
  */
716
- cancelTransaction(transactionID) {
717
- const transactionMeta = this.state.transactions.find(({ id }) => id === transactionID);
807
+ cancelTransaction(transactionId) {
808
+ const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
718
809
  if (!transactionMeta) {
719
810
  return;
720
811
  }
721
812
  transactionMeta.status = types_1.TransactionStatus.rejected;
722
813
  this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
723
- const transactions = this.state.transactions.filter(({ id }) => id !== transactionID);
814
+ const transactions = this.state.transactions.filter(({ id }) => id !== transactionId);
724
815
  this.update({ transactions: this.trimTransactionsForState(transactions) });
725
816
  }
726
817
  /**
@@ -739,10 +830,12 @@ class TransactionController extends base_controller_1.BaseController {
739
830
  */
740
831
  trimTransactionsForState(transactions) {
741
832
  const nonceNetworkSet = new Set();
742
- const txsToKeep = transactions.reverse().filter((tx) => {
743
- const { chainId, networkID, status, transaction, time } = tx;
744
- if (transaction) {
745
- const key = `${transaction.nonce}-${chainId ? (0, controller_utils_1.convertHexToDecimal)(chainId) : networkID}-${new Date(time).toDateString()}`;
833
+ const txsToKeep = transactions
834
+ .sort((a, b) => (a.time > b.time ? -1 : 1)) // Descending time order
835
+ .filter((tx) => {
836
+ const { chainId, status, txParams, time } = tx;
837
+ if (txParams) {
838
+ const key = `${txParams.nonce}-${(0, controller_utils_1.convertHexToDecimal)(chainId)}-${new Date(time).toDateString()}`;
746
839
  if (nonceNetworkSet.has(key)) {
747
840
  return true;
748
841
  }
@@ -754,7 +847,7 @@ class TransactionController extends base_controller_1.BaseController {
754
847
  }
755
848
  return false;
756
849
  });
757
- txsToKeep.reverse();
850
+ txsToKeep.reverse(); // Ascending time order
758
851
  return txsToKeep;
759
852
  }
760
853
  /**
@@ -792,11 +885,11 @@ class TransactionController extends base_controller_1.BaseController {
792
885
  */
793
886
  blockchainTransactionStateReconciler(meta) {
794
887
  return __awaiter(this, void 0, void 0, function* () {
795
- const { status, transactionHash } = meta;
888
+ const { status, hash } = meta;
796
889
  switch (status) {
797
890
  case types_1.TransactionStatus.confirmed:
798
891
  const txReceipt = yield (0, controller_utils_1.query)(this.ethQuery, 'getTransactionReceipt', [
799
- transactionHash,
892
+ hash,
800
893
  ]);
801
894
  if (!txReceipt) {
802
895
  return [meta, false];
@@ -805,7 +898,7 @@ class TransactionController extends base_controller_1.BaseController {
805
898
  txReceipt.blockHash,
806
899
  ]);
807
900
  meta.verifiedOnBlockchain = true;
808
- meta.transaction.gasUsed = txReceipt.gasUsed;
901
+ meta.txParams.gasUsed = txReceipt.gasUsed;
809
902
  meta.txReceipt = txReceipt;
810
903
  meta.baseFeePerGas = txBlock === null || txBlock === void 0 ? void 0 : txBlock.baseFeePerGas;
811
904
  meta.blockTimestamp = txBlock === null || txBlock === void 0 ? void 0 : txBlock.timestamp;
@@ -819,10 +912,10 @@ class TransactionController extends base_controller_1.BaseController {
819
912
  return [meta, true];
820
913
  case types_1.TransactionStatus.submitted:
821
914
  const txObj = yield (0, controller_utils_1.query)(this.ethQuery, 'getTransactionByHash', [
822
- transactionHash,
915
+ hash,
823
916
  ]);
824
917
  if (!txObj) {
825
- const receiptShowsFailedStatus = yield this.checkTxReceiptStatusIsFailed(transactionHash);
918
+ const receiptShowsFailedStatus = yield this.checkTxReceiptStatusIsFailed(hash);
826
919
  // Case the txObj is evaluated as false, a second check will
827
920
  // determine if the tx failed or it is pending or confirmed
828
921
  if (receiptShowsFailedStatus) {
@@ -893,10 +986,9 @@ class TransactionController extends base_controller_1.BaseController {
893
986
  const isCompleted = this.isLocalFinalState(transaction.status);
894
987
  return { meta: transaction, isCompleted };
895
988
  }
896
- getChainAndNetworkId() {
897
- const { networkId, providerConfig } = this.getNetworkState();
898
- const chainId = providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.chainId;
899
- return { networkId, chainId };
989
+ getChainId() {
990
+ const { providerConfig } = this.getNetworkState();
991
+ return providerConfig.chainId;
900
992
  }
901
993
  prepareUnsignedEthTx(txParams) {
902
994
  return tx_1.TransactionFactory.fromTxData(txParams, {
@@ -914,7 +1006,7 @@ class TransactionController extends base_controller_1.BaseController {
914
1006
  * @returns common configuration object
915
1007
  */
916
1008
  getCommonConfiguration() {
917
- const { networkId, providerConfig: { type: chain, chainId, nickname: name }, } = this.getNetworkState();
1009
+ const { providerConfig: { type: chain, chainId, nickname: name }, } = this.getNetworkState();
918
1010
  if (chain !== controller_utils_1.RPC &&
919
1011
  chain !== controller_utils_1.NetworkType['linea-goerli'] &&
920
1012
  chain !== controller_utils_1.NetworkType['linea-mainnet']) {
@@ -923,7 +1015,6 @@ class TransactionController extends base_controller_1.BaseController {
923
1015
  const customChainParams = {
924
1016
  name,
925
1017
  chainId: parseInt(chainId, 16),
926
- networkId: networkId === null ? NaN : parseInt(networkId, undefined),
927
1018
  defaultHardfork: exports.HARDFORK,
928
1019
  };
929
1020
  return common_1.Common.custom(customChainParams);
@@ -933,7 +1024,7 @@ class TransactionController extends base_controller_1.BaseController {
933
1024
  const updatedTransactions = [
934
1025
  ...added,
935
1026
  ...currentTransactions.map((originalTransaction) => {
936
- const updatedTransaction = updated.find(({ transactionHash }) => transactionHash === originalTransaction.transactionHash);
1027
+ const updatedTransaction = updated.find(({ hash }) => hash === originalTransaction.hash);
937
1028
  return updatedTransaction !== null && updatedTransaction !== void 0 ? updatedTransaction : originalTransaction;
938
1029
  }),
939
1030
  ];
@@ -945,11 +1036,11 @@ class TransactionController extends base_controller_1.BaseController {
945
1036
  this.update({ lastFetchedBlockNumbers });
946
1037
  this.hub.emit('incomingTransactionBlock', blockNumber);
947
1038
  }
948
- generateDappSuggestedGasFees(transaction, origin) {
1039
+ generateDappSuggestedGasFees(txParams, origin) {
949
1040
  if (!origin || origin === controller_utils_1.ORIGIN_METAMASK) {
950
1041
  return undefined;
951
1042
  }
952
- const { gasPrice, maxFeePerGas, maxPriorityFeePerGas, gas } = transaction;
1043
+ const { gasPrice, maxFeePerGas, maxPriorityFeePerGas, gas } = txParams;
953
1044
  if (gasPrice === undefined &&
954
1045
  maxFeePerGas === undefined &&
955
1046
  maxPriorityFeePerGas === undefined &&
@@ -976,16 +1067,22 @@ class TransactionController extends base_controller_1.BaseController {
976
1067
  * @param transactionMeta - Nominated external transaction to be added to state.
977
1068
  */
978
1069
  addExternalTransaction(transactionMeta) {
979
- var _a;
1070
+ var _a, _b;
980
1071
  return __awaiter(this, void 0, void 0, function* () {
981
- const { networkId, chainId } = this.getChainAndNetworkId();
1072
+ const chainId = this.getChainId();
982
1073
  const { transactions } = this.state;
983
- const fromAddress = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.transaction) === null || _a === void 0 ? void 0 : _a.from;
984
- const sameFromAndNetworkTransactions = transactions.filter((transaction) => transaction.transaction.from === fromAddress &&
985
- (0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
1074
+ const fromAddress = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.from;
1075
+ const sameFromAndNetworkTransactions = transactions.filter((transaction) => transaction.txParams.from === fromAddress &&
1076
+ transaction.chainId === chainId);
986
1077
  const confirmedTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.confirmed);
987
1078
  const pendingTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.submitted);
988
1079
  (0, external_transactions_1.validateConfirmedExternalTransaction)(transactionMeta, confirmedTxs, pendingTxs);
1080
+ // Make sure provided external transaction has non empty history array
1081
+ if (!((_b = transactionMeta.history) !== null && _b !== void 0 ? _b : []).length) {
1082
+ if (!this.isHistoryDisabled) {
1083
+ (0, history_1.addInitialHistorySnapshot)(transactionMeta);
1084
+ }
1085
+ }
989
1086
  const updatedTransactions = [...transactions, transactionMeta];
990
1087
  this.update({
991
1088
  transactions: this.trimTransactionsForState(updatedTransactions),
@@ -1000,13 +1097,13 @@ class TransactionController extends base_controller_1.BaseController {
1000
1097
  */
1001
1098
  markNonceDuplicatesDropped(transactionId) {
1002
1099
  var _a, _b;
1003
- const { networkId, chainId } = this.getChainAndNetworkId();
1100
+ const chainId = this.getChainId();
1004
1101
  const transactionMeta = this.getTransaction(transactionId);
1005
- const nonce = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.transaction) === null || _a === void 0 ? void 0 : _a.nonce;
1006
- const from = (_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.transaction) === null || _b === void 0 ? void 0 : _b.from;
1007
- const sameNonceTxs = this.state.transactions.filter((transaction) => transaction.transaction.from === from &&
1008
- transaction.transaction.nonce === nonce &&
1009
- (0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
1102
+ const nonce = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.nonce;
1103
+ const from = (_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.from;
1104
+ const sameNonceTxs = this.state.transactions.filter((transaction) => transaction.txParams.from === from &&
1105
+ transaction.txParams.nonce === nonce &&
1106
+ transaction.chainId === chainId);
1010
1107
  if (!sameNonceTxs.length) {
1011
1108
  return;
1012
1109
  }
@@ -1030,7 +1127,7 @@ class TransactionController extends base_controller_1.BaseController {
1030
1127
  */
1031
1128
  setTransactionStatusDropped(transactionMeta) {
1032
1129
  transactionMeta.status = types_1.TransactionStatus.dropped;
1033
- this.updateTransaction(transactionMeta);
1130
+ this.updateTransaction(transactionMeta, 'TransactionController#setTransactionStatusDropped - Transaction dropped');
1034
1131
  }
1035
1132
  /**
1036
1133
  * Get transaction with provided actionId.
@@ -1050,6 +1147,26 @@ class TransactionController extends base_controller_1.BaseController {
1050
1147
  });
1051
1148
  });
1052
1149
  }
1150
+ /**
1151
+ * Updates the r, s, and v properties of a TransactionMeta object
1152
+ * with values from a signed transaction.
1153
+ *
1154
+ * @param transactionMeta - The TransactionMeta object to update.
1155
+ * @param signedTx - The encompassing type for all transaction types containing r, s, and v values.
1156
+ */
1157
+ updateTransactionMetaRSV(transactionMeta, signedTx) {
1158
+ return __awaiter(this, void 0, void 0, function* () {
1159
+ if (signedTx.r) {
1160
+ transactionMeta.r = (0, ethereumjs_util_1.addHexPrefix)(signedTx.r.toString(16));
1161
+ }
1162
+ if (signedTx.s) {
1163
+ transactionMeta.s = (0, ethereumjs_util_1.addHexPrefix)(signedTx.s.toString(16));
1164
+ }
1165
+ if (signedTx.v) {
1166
+ transactionMeta.v = (0, ethereumjs_util_1.addHexPrefix)(signedTx.v.toString(16));
1167
+ }
1168
+ });
1169
+ }
1053
1170
  }
1054
1171
  exports.TransactionController = TransactionController;
1055
1172
  exports.default = TransactionController;