@metamask-previews/transaction-controller 9.2.0-preview.f71e42f → 10.0.0-preview.2f7e793

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.
@@ -58,7 +58,8 @@ class TransactionController extends base_controller_1.BaseController {
58
58
  * @param options.incomingTransactions.apiKey - An optional API key to use when fetching remote transaction data.
59
59
  * @param options.incomingTransactions.includeTokenTransfers - Whether or not to include ERC20 token transfers.
60
60
  * @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.
61
+ * @param options.incomingTransactions.queryEntireHistory - Whether to initially query the entire transaction history or only recent blocks.
62
+ * @param options.incomingTransactions.updateTransactions - Whether to update local transactions using remote transaction data.
62
63
  * @param options.messenger - The controller messenger.
63
64
  * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
64
65
  * @param options.provider - The provider used to create the underlying EthQuery instance.
@@ -100,8 +101,10 @@ class TransactionController extends base_controller_1.BaseController {
100
101
  this.incomingTransactionHelper = new IncomingTransactionHelper_1.IncomingTransactionHelper({
101
102
  blockTracker,
102
103
  getCurrentAccount: getSelectedAddress,
104
+ getLastFetchedBlockNumbers: () => this.state.lastFetchedBlockNumbers,
103
105
  getNetworkState,
104
106
  isEnabled: incomingTransactions.isEnabled,
107
+ queryEntireHistory: incomingTransactions.queryEntireHistory,
105
108
  remoteTransactionSource: new EtherscanRemoteTransactionSource_1.EtherscanRemoteTransactionSource({
106
109
  apiKey: incomingTransactions.apiKey,
107
110
  includeTokenTransfers: incomingTransactions.includeTokenTransfers,
@@ -186,7 +189,7 @@ class TransactionController extends base_controller_1.BaseController {
186
189
  */
187
190
  addTransaction(transaction, { actionId, deviceConfirmedOn, origin, requireApproval, securityAlertResponse, } = {}) {
188
191
  return __awaiter(this, void 0, void 0, function* () {
189
- const chainId = this.getChainId();
192
+ const { chainId, networkId } = this.getChainAndNetworkId();
190
193
  const { transactions } = this.state;
191
194
  transaction = (0, utils_1.normalizeTransaction)(transaction);
192
195
  (0, utils_1.validateTransaction)(transaction);
@@ -195,6 +198,7 @@ class TransactionController extends base_controller_1.BaseController {
195
198
  // If a request to add a transaction with the same actionId is submitted again, a new transaction will not be created for it.
196
199
  const transactionMeta = existingTransactionMeta || {
197
200
  id: (0, uuid_1.v1)(),
201
+ networkID: networkId !== null && networkId !== void 0 ? networkId : undefined,
198
202
  chainId,
199
203
  origin,
200
204
  status: types_1.TransactionStatus.unapproved,
@@ -211,6 +215,7 @@ class TransactionController extends base_controller_1.BaseController {
211
215
  const { gas, estimateGasError } = yield this.estimateGas(transaction);
212
216
  transaction.gas = gas;
213
217
  transaction.estimateGasError = estimateGasError;
218
+ transactionMeta.originalGasEstimate = gas;
214
219
  }
215
220
  catch (error) {
216
221
  this.failTransaction(transactionMeta, error);
@@ -248,9 +253,9 @@ class TransactionController extends base_controller_1.BaseController {
248
253
  * Creates approvals for all unapproved transactions persisted.
249
254
  */
250
255
  initApprovals() {
251
- const chainId = this.getChainId();
256
+ const { networkId, chainId } = this.getChainAndNetworkId();
252
257
  const unapprovedTxs = this.state.transactions.filter((transaction) => transaction.status === types_1.TransactionStatus.unapproved &&
253
- (0, utils_1.transactionMatchesChainId)(transaction, chainId));
258
+ (0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
254
259
  for (const txMeta of unapprovedTxs) {
255
260
  this.processApproval(txMeta, {
256
261
  shouldShowRequest: false,
@@ -384,11 +389,9 @@ class TransactionController extends base_controller_1.BaseController {
384
389
  const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
385
390
  const signedTx = yield this.sign(unsignedEthTx, transactionMeta.transaction.from);
386
391
  const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
387
- const transactionHash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [
388
- rawTx,
389
- ]);
390
- const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), transactionHash,
391
- actionId });
392
+ const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
393
+ const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), hash,
394
+ actionId, originalGasEstimate: transactionMeta.transaction.gas });
392
395
  const newTransactionMeta = newMaxFeePerGas && newMaxPriorityFeePerGas
393
396
  ? 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 }) });
394
397
  transactions.push(newTransactionMeta);
@@ -420,7 +423,7 @@ class TransactionController extends base_controller_1.BaseController {
420
423
  false,
421
424
  ]);
422
425
  // 2. If to is not defined or this is not a contract address, and there is no data use 0x5208 / 21000.
423
- // If the newtwork is a custom network then bypass this check and fetch 'estimateGas'.
426
+ // If the network is a custom network then bypass this check and fetch 'estimateGas'.
424
427
  /* istanbul ignore next */
425
428
  const code = to ? yield (0, controller_utils_1.query)(this.ethQuery, 'getCode', [to]) : undefined;
426
429
  /* istanbul ignore next */
@@ -474,11 +477,14 @@ class TransactionController extends base_controller_1.BaseController {
474
477
  queryTransactionStatuses() {
475
478
  return __awaiter(this, void 0, void 0, function* () {
476
479
  const { transactions } = this.state;
477
- const currentChainId = this.getChainId();
480
+ const { chainId: currentChainId, networkId: currentNetworkID } = this.getChainAndNetworkId();
478
481
  let gotUpdates = false;
479
482
  yield (0, controller_utils_1.safelyExecute)(() => Promise.all(transactions.map((meta, index) => __awaiter(this, void 0, void 0, function* () {
480
- if (!meta.verifiedOnBlockchain &&
481
- (0, utils_1.transactionMatchesChainId)(meta, currentChainId)) {
483
+ // Using fallback to networkID only when there is no chainId present.
484
+ // Should be removed when networkID is completely removed.
485
+ const txBelongsToCurrentChain = meta.chainId === currentChainId ||
486
+ (!meta.chainId && meta.networkID === currentNetworkID);
487
+ if (!meta.verifiedOnBlockchain && txBelongsToCurrentChain) {
482
488
  const [reconciledTx, updateRequired] = yield this.blockchainTransactionStateReconciler(meta);
483
489
  if (updateRequired) {
484
490
  transactions[index] = reconciledTx;
@@ -521,10 +527,13 @@ class TransactionController extends base_controller_1.BaseController {
521
527
  this.update({ transactions: [] });
522
528
  return;
523
529
  }
524
- const currentChainId = this.getChainId();
525
- const newTransactions = this.state.transactions.filter(({ chainId, transaction }) => {
530
+ const { chainId: currentChainId, networkId: currentNetworkID } = this.getChainAndNetworkId();
531
+ const newTransactions = this.state.transactions.filter(({ networkID, chainId, transaction }) => {
526
532
  var _a;
527
- const isMatchingNetwork = ignoreNetwork || chainId === currentChainId;
533
+ // Using fallback to networkID only when there is no chainId present. Should be removed when networkID is completely removed.
534
+ const isMatchingNetwork = ignoreNetwork ||
535
+ chainId === currentChainId ||
536
+ (!chainId && networkID === currentNetworkID);
528
537
  if (!isMatchingNetwork) {
529
538
  return true;
530
539
  }
@@ -615,7 +624,7 @@ class TransactionController extends base_controller_1.BaseController {
615
624
  throw cancelError;
616
625
  case types_1.TransactionStatus.submitted:
617
626
  resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
618
- return finalMeta.transactionHash;
627
+ return finalMeta.hash;
619
628
  default:
620
629
  const internalError = eth_rpc_errors_1.ethErrors.rpc.internal(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finalMeta || transactionId)}`);
621
630
  resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.error(internalError);
@@ -635,7 +644,7 @@ class TransactionController extends base_controller_1.BaseController {
635
644
  return __awaiter(this, void 0, void 0, function* () {
636
645
  const { transactions } = this.state;
637
646
  const releaseLock = yield this.mutex.acquire();
638
- const chainId = this.getChainId();
647
+ const { chainId } = this.getChainAndNetworkId();
639
648
  const index = transactions.findIndex(({ id }) => transactionID === id);
640
649
  const transactionMeta = transactions[index];
641
650
  const { transaction: { nonce, from }, } = transactionMeta;
@@ -679,10 +688,8 @@ class TransactionController extends base_controller_1.BaseController {
679
688
  const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
680
689
  transactionMeta.rawTx = rawTx;
681
690
  this.updateTransaction(transactionMeta);
682
- const transactionHash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [
683
- rawTx,
684
- ]);
685
- transactionMeta.transactionHash = transactionHash;
691
+ const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
692
+ transactionMeta.hash = hash;
686
693
  transactionMeta.status = types_1.TransactionStatus.submitted;
687
694
  transactionMeta.submittedTime = new Date().getTime();
688
695
  this.updateTransaction(transactionMeta);
@@ -732,10 +739,12 @@ class TransactionController extends base_controller_1.BaseController {
732
739
  */
733
740
  trimTransactionsForState(transactions) {
734
741
  const nonceNetworkSet = new Set();
735
- const txsToKeep = transactions.reverse().filter((tx) => {
736
- const { chainId, status, transaction, time } = tx;
742
+ const txsToKeep = transactions
743
+ .sort((a, b) => (a.time > b.time ? -1 : 1)) // Descending time order
744
+ .filter((tx) => {
745
+ const { chainId, networkID, status, transaction, time } = tx;
737
746
  if (transaction) {
738
- const key = `${transaction.nonce}-${chainId}-${new Date(time).toDateString()}`;
747
+ const key = `${transaction.nonce}-${chainId ? (0, controller_utils_1.convertHexToDecimal)(chainId) : networkID}-${new Date(time).toDateString()}`;
739
748
  if (nonceNetworkSet.has(key)) {
740
749
  return true;
741
750
  }
@@ -747,7 +756,7 @@ class TransactionController extends base_controller_1.BaseController {
747
756
  }
748
757
  return false;
749
758
  });
750
- txsToKeep.reverse();
759
+ txsToKeep.reverse(); // Ascending time order
751
760
  return txsToKeep;
752
761
  }
753
762
  /**
@@ -785,11 +794,11 @@ class TransactionController extends base_controller_1.BaseController {
785
794
  */
786
795
  blockchainTransactionStateReconciler(meta) {
787
796
  return __awaiter(this, void 0, void 0, function* () {
788
- const { status, transactionHash } = meta;
797
+ const { status, hash } = meta;
789
798
  switch (status) {
790
799
  case types_1.TransactionStatus.confirmed:
791
800
  const txReceipt = yield (0, controller_utils_1.query)(this.ethQuery, 'getTransactionReceipt', [
792
- transactionHash,
801
+ hash,
793
802
  ]);
794
803
  if (!txReceipt) {
795
804
  return [meta, false];
@@ -812,10 +821,10 @@ class TransactionController extends base_controller_1.BaseController {
812
821
  return [meta, true];
813
822
  case types_1.TransactionStatus.submitted:
814
823
  const txObj = yield (0, controller_utils_1.query)(this.ethQuery, 'getTransactionByHash', [
815
- transactionHash,
824
+ hash,
816
825
  ]);
817
826
  if (!txObj) {
818
- const receiptShowsFailedStatus = yield this.checkTxReceiptStatusIsFailed(transactionHash);
827
+ const receiptShowsFailedStatus = yield this.checkTxReceiptStatusIsFailed(hash);
819
828
  // Case the txObj is evaluated as false, a second check will
820
829
  // determine if the tx failed or it is pending or confirmed
821
830
  if (receiptShowsFailedStatus) {
@@ -886,9 +895,10 @@ class TransactionController extends base_controller_1.BaseController {
886
895
  const isCompleted = this.isLocalFinalState(transaction.status);
887
896
  return { meta: transaction, isCompleted };
888
897
  }
889
- getChainId() {
890
- const { providerConfig } = this.getNetworkState();
891
- return providerConfig.chainId;
898
+ getChainAndNetworkId() {
899
+ const { networkId, providerConfig } = this.getNetworkState();
900
+ const chainId = providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.chainId;
901
+ return { networkId, chainId };
892
902
  }
893
903
  prepareUnsignedEthTx(txParams) {
894
904
  return tx_1.TransactionFactory.fromTxData(txParams, {
@@ -906,7 +916,7 @@ class TransactionController extends base_controller_1.BaseController {
906
916
  * @returns common configuration object
907
917
  */
908
918
  getCommonConfiguration() {
909
- const { providerConfig: { type: chain, chainId, nickname: name }, } = this.getNetworkState();
919
+ const { networkId, providerConfig: { type: chain, chainId, nickname: name }, } = this.getNetworkState();
910
920
  if (chain !== controller_utils_1.RPC &&
911
921
  chain !== controller_utils_1.NetworkType['linea-goerli'] &&
912
922
  chain !== controller_utils_1.NetworkType['linea-mainnet']) {
@@ -915,6 +925,7 @@ class TransactionController extends base_controller_1.BaseController {
915
925
  const customChainParams = {
916
926
  name,
917
927
  chainId: parseInt(chainId, 16),
928
+ networkId: networkId === null ? NaN : parseInt(networkId, undefined),
918
929
  defaultHardfork: exports.HARDFORK,
919
930
  };
920
931
  return common_1.Common.custom(customChainParams);
@@ -924,7 +935,7 @@ class TransactionController extends base_controller_1.BaseController {
924
935
  const updatedTransactions = [
925
936
  ...added,
926
937
  ...currentTransactions.map((originalTransaction) => {
927
- const updatedTransaction = updated.find(({ transactionHash }) => transactionHash === originalTransaction.transactionHash);
938
+ const updatedTransaction = updated.find(({ hash }) => hash === originalTransaction.hash);
928
939
  return updatedTransaction !== null && updatedTransaction !== void 0 ? updatedTransaction : originalTransaction;
929
940
  }),
930
941
  ];
@@ -969,11 +980,11 @@ class TransactionController extends base_controller_1.BaseController {
969
980
  addExternalTransaction(transactionMeta) {
970
981
  var _a;
971
982
  return __awaiter(this, void 0, void 0, function* () {
972
- const chainId = this.getChainId();
983
+ const { networkId, chainId } = this.getChainAndNetworkId();
973
984
  const { transactions } = this.state;
974
985
  const fromAddress = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.transaction) === null || _a === void 0 ? void 0 : _a.from;
975
986
  const sameFromAndNetworkTransactions = transactions.filter((transaction) => transaction.transaction.from === fromAddress &&
976
- (0, utils_1.transactionMatchesChainId)(transaction, chainId));
987
+ (0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
977
988
  const confirmedTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.confirmed);
978
989
  const pendingTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.submitted);
979
990
  (0, external_transactions_1.validateConfirmedExternalTransaction)(transactionMeta, confirmedTxs, pendingTxs);
@@ -991,13 +1002,13 @@ class TransactionController extends base_controller_1.BaseController {
991
1002
  */
992
1003
  markNonceDuplicatesDropped(transactionId) {
993
1004
  var _a, _b;
994
- const chainId = this.getChainId();
1005
+ const { networkId, chainId } = this.getChainAndNetworkId();
995
1006
  const transactionMeta = this.getTransaction(transactionId);
996
1007
  const nonce = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.transaction) === null || _a === void 0 ? void 0 : _a.nonce;
997
1008
  const from = (_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.transaction) === null || _b === void 0 ? void 0 : _b.from;
998
1009
  const sameNonceTxs = this.state.transactions.filter((transaction) => transaction.transaction.from === from &&
999
1010
  transaction.transaction.nonce === nonce &&
1000
- (0, utils_1.transactionMatchesChainId)(transaction, chainId));
1011
+ (0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
1001
1012
  if (!sameNonceTxs.length) {
1002
1013
  return;
1003
1014
  }