@metamask/transaction-controller 17.0.0 → 18.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.
- package/CHANGELOG.md +25 -1
- package/dist/TransactionController.d.ts +52 -13
- package/dist/TransactionController.d.ts.map +1 -1
- package/dist/TransactionController.js +242 -106
- package/dist/TransactionController.js.map +1 -1
- package/dist/helpers/PendingTransactionTracker.d.ts +1 -1
- package/dist/helpers/PendingTransactionTracker.d.ts.map +1 -1
- package/dist/helpers/PendingTransactionTracker.js.map +1 -1
- package/dist/types.d.ts +8 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/swaps.d.ts.map +1 -1
- package/dist/utils/swaps.js +13 -0
- package/dist/utils/swaps.js.map +1 -1
- package/dist/utils/utils.d.ts +10 -2
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +28 -3
- package/dist/utils/utils.js.map +1 -1
- package/package.json +11 -11
|
@@ -24,7 +24,7 @@ const eth_method_registry_1 = __importDefault(require("eth-method-registry"));
|
|
|
24
24
|
const ethereumjs_util_1 = require("ethereumjs-util");
|
|
25
25
|
const events_1 = require("events");
|
|
26
26
|
const lodash_1 = require("lodash");
|
|
27
|
-
const nonce_tracker_1 =
|
|
27
|
+
const nonce_tracker_1 = require("nonce-tracker");
|
|
28
28
|
const uuid_1 = require("uuid");
|
|
29
29
|
const EtherscanRemoteTransactionSource_1 = require("./helpers/EtherscanRemoteTransactionSource");
|
|
30
30
|
const IncomingTransactionHelper_1 = require("./helpers/IncomingTransactionHelper");
|
|
@@ -55,7 +55,7 @@ const controllerName = 'TransactionController';
|
|
|
55
55
|
/**
|
|
56
56
|
* Controller responsible for submitting and managing transactions.
|
|
57
57
|
*/
|
|
58
|
-
class TransactionController extends base_controller_1.
|
|
58
|
+
class TransactionController extends base_controller_1.BaseControllerV1 {
|
|
59
59
|
/**
|
|
60
60
|
* Creates a TransactionController instance.
|
|
61
61
|
*
|
|
@@ -123,7 +123,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
123
123
|
this.registry = new eth_method_registry_1.default({ provider });
|
|
124
124
|
this.getSavedGasFees = getSavedGasFees !== null && getSavedGasFees !== void 0 ? getSavedGasFees : ((_chainId) => undefined);
|
|
125
125
|
this.getCurrentAccountEIP1559Compatibility =
|
|
126
|
-
getCurrentAccountEIP1559Compatibility;
|
|
126
|
+
getCurrentAccountEIP1559Compatibility !== null && getCurrentAccountEIP1559Compatibility !== void 0 ? getCurrentAccountEIP1559Compatibility : (() => Promise.resolve(true));
|
|
127
127
|
this.getCurrentNetworkEIP1559Compatibility =
|
|
128
128
|
getCurrentNetworkEIP1559Compatibility;
|
|
129
129
|
this.getGasFeeEstimates =
|
|
@@ -140,11 +140,12 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
140
140
|
this.beforePublish = (_d = hooks === null || hooks === void 0 ? void 0 : hooks.beforePublish) !== null && _d !== void 0 ? _d : (() => true);
|
|
141
141
|
this.getAdditionalSignArguments =
|
|
142
142
|
(_e = hooks === null || hooks === void 0 ? void 0 : hooks.getAdditionalSignArguments) !== null && _e !== void 0 ? _e : (() => []);
|
|
143
|
-
this.nonceTracker = new nonce_tracker_1.
|
|
143
|
+
this.nonceTracker = new nonce_tracker_1.NonceTracker({
|
|
144
|
+
// @ts-expect-error provider types misaligned: SafeEventEmitterProvider vs Record<string,string>
|
|
144
145
|
provider,
|
|
145
146
|
blockTracker,
|
|
146
|
-
getPendingTransactions:
|
|
147
|
-
getConfirmedTransactions:
|
|
147
|
+
getPendingTransactions: this.getNonceTrackerTransactions.bind(this, types_1.TransactionStatus.submitted),
|
|
148
|
+
getConfirmedTransactions: this.getNonceTrackerTransactions.bind(this, types_1.TransactionStatus.confirmed),
|
|
148
149
|
});
|
|
149
150
|
this.incomingTransactionHelper = new IncomingTransactionHelper_1.IncomingTransactionHelper({
|
|
150
151
|
blockTracker,
|
|
@@ -192,6 +193,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
192
193
|
transactionMeta: newTransactionMeta,
|
|
193
194
|
});
|
|
194
195
|
this.updateTransaction(newTransactionMeta, 'TransactionController#failTransaction - Add error message and set status to failed');
|
|
196
|
+
this.onTransactionStatusChange(newTransactionMeta);
|
|
195
197
|
this.hub.emit(`${transactionMeta.id}:finished`, newTransactionMeta);
|
|
196
198
|
}
|
|
197
199
|
registryLookup(fourBytePrefix) {
|
|
@@ -249,7 +251,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
249
251
|
*/
|
|
250
252
|
addTransaction(txParams, { actionId, deviceConfirmedOn, method, origin, requireApproval, securityAlertResponse, sendFlowHistory, swaps = {}, type, } = {}) {
|
|
251
253
|
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
-
|
|
254
|
+
(0, logger_1.projectLogger)('Adding transaction', txParams);
|
|
253
255
|
txParams = (0, utils_1.normalizeTxParams)(txParams);
|
|
254
256
|
const isEIP1559Compatible = yield this.getEIP1559Compatibility();
|
|
255
257
|
(0, validation_1.validateTxParams)(txParams, isEIP1559Compatible);
|
|
@@ -259,6 +261,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
259
261
|
const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin);
|
|
260
262
|
const transactionType = type !== null && type !== void 0 ? type : (yield (0, transaction_type_1.determineTransactionType)(txParams, this.ethQuery)).type;
|
|
261
263
|
const existingTransactionMeta = this.getTransactionWithActionId(actionId);
|
|
264
|
+
const chainId = this.getChainId();
|
|
262
265
|
// If a request to add a transaction with the same actionId is submitted again, a new transaction will not be created for it.
|
|
263
266
|
const transactionMeta = existingTransactionMeta || {
|
|
264
267
|
// Add actionId to txMeta to check if same actionId is seen again
|
|
@@ -338,6 +341,8 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
338
341
|
return;
|
|
339
342
|
}
|
|
340
343
|
if (gasValues) {
|
|
344
|
+
// Not good practice to reassign a parameter but temporarily avoiding a larger refactor.
|
|
345
|
+
gasValues = (0, utils_1.normalizeGasFeeValues)(gasValues);
|
|
341
346
|
(0, utils_1.validateGasValues)(gasValues);
|
|
342
347
|
}
|
|
343
348
|
const transactionMeta = this.getTransaction(transactionId);
|
|
@@ -373,7 +378,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
373
378
|
gasLimit: transactionMeta.txParams.gas,
|
|
374
379
|
maxFeePerGas: newMaxFeePerGas,
|
|
375
380
|
maxPriorityFeePerGas: newMaxPriorityFeePerGas,
|
|
376
|
-
type:
|
|
381
|
+
type: types_1.TransactionEnvelopeType.feeMarket,
|
|
377
382
|
nonce: transactionMeta.txParams.nonce,
|
|
378
383
|
to: transactionMeta.txParams.from,
|
|
379
384
|
value: '0x0',
|
|
@@ -432,6 +437,8 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
432
437
|
return;
|
|
433
438
|
}
|
|
434
439
|
if (gasValues) {
|
|
440
|
+
// Not good practice to reassign a parameter but temporarily avoiding a larger refactor.
|
|
441
|
+
gasValues = (0, utils_1.normalizeGasFeeValues)(gasValues);
|
|
435
442
|
(0, utils_1.validateGasValues)(gasValues);
|
|
436
443
|
}
|
|
437
444
|
const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
|
|
@@ -464,7 +471,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
464
471
|
(0, utils_1.validateMinimumIncrease)(maxPriorityFeePerGasValues, minMaxPriorityFeePerGas)) ||
|
|
465
472
|
(existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
|
|
466
473
|
const txParams = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
467
|
-
? Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type:
|
|
474
|
+
? 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 });
|
|
468
475
|
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
469
476
|
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
|
|
470
477
|
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
@@ -606,29 +613,16 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
606
613
|
this.markNonceDuplicatesDropped(transactionId);
|
|
607
614
|
// Update external provided transaction with updated gas values and confirmed status.
|
|
608
615
|
this.updateTransaction(transactionMeta, 'TransactionController:confirmExternalTransaction - Add external transaction');
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
updateTransaction: this.updateTransaction.bind(this),
|
|
614
|
-
})
|
|
615
|
-
.then(({ updatedTransactionMeta, approvalTransactionMeta }) => {
|
|
616
|
-
this.hub.emit('post-transaction-balance-updated', {
|
|
617
|
-
transactionMeta: updatedTransactionMeta,
|
|
618
|
-
approvalTransactionMeta,
|
|
619
|
-
});
|
|
620
|
-
})
|
|
621
|
-
.catch((error) => {
|
|
622
|
-
/* istanbul ignore next */
|
|
623
|
-
(0, logger_1.projectLogger)('Error while updating post transaction balance', error);
|
|
624
|
-
});
|
|
625
|
-
}
|
|
616
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
617
|
+
// Intentional given potential duration of process.
|
|
618
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
619
|
+
this.updatePostBalance(transactionMeta);
|
|
626
620
|
this.hub.emit('transaction-confirmed', {
|
|
627
621
|
transactionMeta,
|
|
628
622
|
});
|
|
629
623
|
}
|
|
630
624
|
catch (error) {
|
|
631
|
-
console.error(error);
|
|
625
|
+
console.error('Failed to confirm external transaction', error);
|
|
632
626
|
}
|
|
633
627
|
});
|
|
634
628
|
}
|
|
@@ -749,6 +743,44 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
749
743
|
return this.nonceTracker.getNonceLock(address);
|
|
750
744
|
});
|
|
751
745
|
}
|
|
746
|
+
/**
|
|
747
|
+
* Updates the editable parameters of a transaction.
|
|
748
|
+
*
|
|
749
|
+
* @param txId - The ID of the transaction to update.
|
|
750
|
+
* @param params - The editable parameters to update.
|
|
751
|
+
* @param params.data - Data to pass with the transaction.
|
|
752
|
+
* @param params.gas - Maximum number of units of gas to use for the transaction.
|
|
753
|
+
* @param params.gasPrice - Price per gas for legacy transactions.
|
|
754
|
+
* @param params.from - Address to send the transaction from.
|
|
755
|
+
* @param params.to - Address to send the transaction to.
|
|
756
|
+
* @param params.value - Value associated with the transaction.
|
|
757
|
+
* @returns The updated transaction metadata.
|
|
758
|
+
*/
|
|
759
|
+
updateEditableParams(txId, { data, gas, gasPrice, from, to, value, }) {
|
|
760
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
761
|
+
const transactionMeta = this.getTransaction(txId);
|
|
762
|
+
if (!transactionMeta) {
|
|
763
|
+
throw new Error(`Cannot update editable params as no transaction metadata found`);
|
|
764
|
+
}
|
|
765
|
+
(0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updateEditableParams');
|
|
766
|
+
const editableParams = {
|
|
767
|
+
txParams: {
|
|
768
|
+
data,
|
|
769
|
+
from,
|
|
770
|
+
to,
|
|
771
|
+
value,
|
|
772
|
+
gas,
|
|
773
|
+
gasPrice,
|
|
774
|
+
},
|
|
775
|
+
};
|
|
776
|
+
editableParams.txParams = (0, lodash_1.pickBy)(editableParams.txParams);
|
|
777
|
+
const updatedTransaction = (0, lodash_1.merge)(transactionMeta, editableParams);
|
|
778
|
+
const { type } = yield (0, transaction_type_1.determineTransactionType)(updatedTransaction.txParams, this.ethQuery);
|
|
779
|
+
updatedTransaction.type = type;
|
|
780
|
+
this.updateTransaction(updatedTransaction, `Update Editable Params for ${txId}`);
|
|
781
|
+
return this.getTransaction(txId);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
752
784
|
/**
|
|
753
785
|
* Signs and returns the raw transaction data for provided transaction params list.
|
|
754
786
|
*
|
|
@@ -801,14 +833,12 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
801
833
|
*
|
|
802
834
|
* @param transactionId - The ID of the transaction to update.
|
|
803
835
|
* @param options - The custodial transaction options to update.
|
|
804
|
-
* @param options.custodyStatus - The new custody status value to be assigned.
|
|
805
836
|
* @param options.errorMessage - The error message to be assigned in case transaction status update to failed.
|
|
806
837
|
* @param options.hash - The new hash value to be assigned.
|
|
807
838
|
* @param options.status - The new status value to be assigned.
|
|
808
839
|
*/
|
|
809
|
-
updateCustodialTransaction(transactionId, {
|
|
810
|
-
|
|
811
|
-
transactionMeta = this.getTransaction(transactionId);
|
|
840
|
+
updateCustodialTransaction(transactionId, { errorMessage, hash, status, }) {
|
|
841
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
812
842
|
if (!transactionMeta) {
|
|
813
843
|
throw new Error(`Cannot update custodial transaction as no transaction metadata found`);
|
|
814
844
|
}
|
|
@@ -823,23 +853,112 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
823
853
|
].includes(status)) {
|
|
824
854
|
throw new Error(`Cannot update custodial transaction with status: ${status}`);
|
|
825
855
|
}
|
|
826
|
-
|
|
827
|
-
transactionMeta.status = status;
|
|
828
|
-
}
|
|
856
|
+
const updatedTransactionMeta = (0, lodash_1.merge)(transactionMeta, (0, lodash_1.pickBy)({ hash, status }));
|
|
829
857
|
if (status === types_1.TransactionStatus.submitted) {
|
|
830
|
-
|
|
831
|
-
transactionMeta.status = status;
|
|
858
|
+
updatedTransactionMeta.submittedTime = new Date().getTime();
|
|
832
859
|
}
|
|
833
860
|
if (status === types_1.TransactionStatus.failed) {
|
|
834
|
-
|
|
861
|
+
updatedTransactionMeta.error = (0, utils_1.normalizeTxError)(new Error(errorMessage));
|
|
835
862
|
}
|
|
836
|
-
|
|
837
|
-
|
|
863
|
+
this.updateTransaction(updatedTransactionMeta, `TransactionController:updateCustodialTransaction - Custodial transaction updated`);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Creates approvals for all unapproved transactions persisted.
|
|
867
|
+
*/
|
|
868
|
+
initApprovals() {
|
|
869
|
+
const chainId = this.getChainId();
|
|
870
|
+
const unapprovedTxs = this.state.transactions.filter((transaction) => transaction.status === types_1.TransactionStatus.unapproved &&
|
|
871
|
+
transaction.chainId === chainId);
|
|
872
|
+
for (const txMeta of unapprovedTxs) {
|
|
873
|
+
this.processApproval(txMeta, {
|
|
874
|
+
shouldShowRequest: false,
|
|
875
|
+
}).catch((error) => {
|
|
876
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === rpc_errors_1.errorCodes.provider.userRejectedRequest) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
console.error('Error during persisted transaction approval', error);
|
|
880
|
+
});
|
|
838
881
|
}
|
|
839
|
-
|
|
840
|
-
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Search transaction metadata for matching entries.
|
|
885
|
+
*
|
|
886
|
+
* @param opts - Options bag.
|
|
887
|
+
* @param opts.searchCriteria - An object containing values or functions for transaction properties to filter transactions with.
|
|
888
|
+
* @param opts.initialList - The transactions to search. Defaults to the current state.
|
|
889
|
+
* @param opts.filterToCurrentNetwork - Whether to filter the results to the current network. Defaults to true.
|
|
890
|
+
* @param opts.limit - The maximum number of transactions to return. No limit by default.
|
|
891
|
+
* @returns An array of transactions matching the provided options.
|
|
892
|
+
*/
|
|
893
|
+
getTransactions({ searchCriteria = {}, initialList, filterToCurrentNetwork = true, limit, } = {}) {
|
|
894
|
+
const chainId = this.getChainId();
|
|
895
|
+
// searchCriteria is an object that might have values that aren't predicate
|
|
896
|
+
// methods. When providing any other value type (string, number, etc), we
|
|
897
|
+
// consider this shorthand for "check the value at key for strict equality
|
|
898
|
+
// with the provided value". To conform this object to be only methods, we
|
|
899
|
+
// mapValues (lodash) such that every value on the object is a method that
|
|
900
|
+
// returns a boolean.
|
|
901
|
+
const predicateMethods = (0, lodash_1.mapValues)(searchCriteria, (predicate) => {
|
|
902
|
+
return typeof predicate === 'function'
|
|
903
|
+
? predicate
|
|
904
|
+
: (v) => v === predicate;
|
|
905
|
+
});
|
|
906
|
+
const transactionsToFilter = initialList !== null && initialList !== void 0 ? initialList : this.state.transactions;
|
|
907
|
+
// Combine sortBy and pickBy to transform our state object into an array of
|
|
908
|
+
// matching transactions that are sorted by time.
|
|
909
|
+
const filteredTransactions = (0, lodash_1.sortBy)((0, lodash_1.pickBy)(transactionsToFilter, (transaction) => {
|
|
910
|
+
if (filterToCurrentNetwork && transaction.chainId !== chainId) {
|
|
911
|
+
return false;
|
|
912
|
+
}
|
|
913
|
+
// iterate over the predicateMethods keys to check if the transaction
|
|
914
|
+
// matches the searchCriteria
|
|
915
|
+
for (const [key, predicate] of Object.entries(predicateMethods)) {
|
|
916
|
+
// We return false early as soon as we know that one of the specified
|
|
917
|
+
// search criteria do not match the transaction. This prevents
|
|
918
|
+
// needlessly checking all criteria when we already know the criteria
|
|
919
|
+
// are not fully satisfied. We check both txParams and the base
|
|
920
|
+
// object as predicate keys can be either.
|
|
921
|
+
if (key in transaction.txParams) {
|
|
922
|
+
if (predicate(transaction.txParams[key]) === false) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
else if (predicate(transaction[key]) === false) {
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return true;
|
|
931
|
+
}), 'time');
|
|
932
|
+
if (limit !== undefined) {
|
|
933
|
+
// We need to have all transactions of a given nonce in order to display
|
|
934
|
+
// necessary details in the UI. We use the size of this set to determine
|
|
935
|
+
// whether we have reached the limit provided, thus ensuring that all
|
|
936
|
+
// transactions of nonces we include will be sent to the UI.
|
|
937
|
+
const nonces = new Set();
|
|
938
|
+
const txs = [];
|
|
939
|
+
// By default, the transaction list we filter from is sorted by time ASC.
|
|
940
|
+
// To ensure that filtered results prefers the newest transactions we
|
|
941
|
+
// iterate from right to left, inserting transactions into front of a new
|
|
942
|
+
// array. The original order is preserved, but we ensure that newest txs
|
|
943
|
+
// are preferred.
|
|
944
|
+
for (let i = filteredTransactions.length - 1; i > -1; i--) {
|
|
945
|
+
const txMeta = filteredTransactions[i];
|
|
946
|
+
const { nonce } = txMeta.txParams;
|
|
947
|
+
if (!nonces.has(nonce)) {
|
|
948
|
+
if (nonces.size < limit) {
|
|
949
|
+
nonces.add(nonce);
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
// Push transaction into the beginning of our array to ensure the
|
|
956
|
+
// original order is preserved.
|
|
957
|
+
txs.unshift(txMeta);
|
|
958
|
+
}
|
|
959
|
+
return txs;
|
|
841
960
|
}
|
|
842
|
-
|
|
961
|
+
return filteredTransactions;
|
|
843
962
|
}
|
|
844
963
|
signExternalTransaction(transactionParams) {
|
|
845
964
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -874,7 +993,8 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
874
993
|
}
|
|
875
994
|
updateGasProperties(transactionMeta) {
|
|
876
995
|
return __awaiter(this, void 0, void 0, function* () {
|
|
877
|
-
const isEIP1559Compatible = yield this.getEIP1559Compatibility()
|
|
996
|
+
const isEIP1559Compatible = (yield this.getEIP1559Compatibility()) &&
|
|
997
|
+
transactionMeta.txParams.type !== types_1.TransactionEnvelopeType.legacy;
|
|
878
998
|
const chainId = this.getChainId();
|
|
879
999
|
yield (0, gas_1.updateGas)({
|
|
880
1000
|
ethQuery: this.ethQuery,
|
|
@@ -895,8 +1015,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
895
1015
|
return this.state.transactions.filter((transaction) => transaction.status === status && transaction.chainId === chainId);
|
|
896
1016
|
}
|
|
897
1017
|
onBootCleanup() {
|
|
898
|
-
this.createApprovalsForUnapprovedTransactions();
|
|
899
|
-
this.loadGasValuesForUnapprovedTransactions();
|
|
900
1018
|
this.submitApprovedTransactions();
|
|
901
1019
|
}
|
|
902
1020
|
/**
|
|
@@ -916,26 +1034,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
916
1034
|
});
|
|
917
1035
|
}
|
|
918
1036
|
}
|
|
919
|
-
/**
|
|
920
|
-
* Update the gas values of all unapproved transactions on current chain.
|
|
921
|
-
*/
|
|
922
|
-
loadGasValuesForUnapprovedTransactions() {
|
|
923
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
924
|
-
const unapprovedTransactions = this.getCurrentChainTransactionsByStatus(types_1.TransactionStatus.unapproved);
|
|
925
|
-
const results = yield Promise.allSettled(unapprovedTransactions.map((transactionMeta) => __awaiter(this, void 0, void 0, function* () {
|
|
926
|
-
yield this.updateGasProperties(transactionMeta);
|
|
927
|
-
this.updateTransaction(transactionMeta, 'TransactionController:loadGasValuesForUnapprovedTransactions - Gas values updated');
|
|
928
|
-
})));
|
|
929
|
-
for (const [index, result] of results.entries()) {
|
|
930
|
-
if (result.status === 'rejected') {
|
|
931
|
-
const transactionMeta = unapprovedTransactions[index];
|
|
932
|
-
this.failTransaction(transactionMeta, result.reason);
|
|
933
|
-
/* istanbul ignore next */
|
|
934
|
-
console.error('Error while loading gas values for persisted transaction id: ', transactionMeta.id, result.reason);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
1037
|
/**
|
|
940
1038
|
* Force to submit approved transactions on current chain.
|
|
941
1039
|
*/
|
|
@@ -965,6 +1063,13 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
965
1063
|
shouldShowRequest,
|
|
966
1064
|
});
|
|
967
1065
|
resultCallbacks = acceptResult.resultCallbacks;
|
|
1066
|
+
if (resultCallbacks) {
|
|
1067
|
+
this.hub.once(`${transactionId}:publish-skip`, () => {
|
|
1068
|
+
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
|
|
1069
|
+
// Remove the reference to prevent additional reports once submitted.
|
|
1070
|
+
resultCallbacks = undefined;
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
968
1073
|
}
|
|
969
1074
|
const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
|
|
970
1075
|
if (!isTxCompleted) {
|
|
@@ -1036,7 +1141,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1036
1141
|
(0, logger_1.projectLogger)('Skipping approval as signing in progress', transactionId);
|
|
1037
1142
|
return;
|
|
1038
1143
|
}
|
|
1039
|
-
const { approved: status } = types_1.TransactionStatus;
|
|
1040
1144
|
let nonceToUse = nonce;
|
|
1041
1145
|
// if a nonce already exists on the transactionMeta it means this is a speedup or cancel transaction
|
|
1042
1146
|
// so we want to reuse that nonce and hope that it beats the previous attempt to chain. Otherwise use a new locked nonce
|
|
@@ -1044,23 +1148,19 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1044
1148
|
nonceLock = yield this.nonceTracker.getNonceLock(from);
|
|
1045
1149
|
nonceToUse = (0, ethereumjs_util_1.addHexPrefix)(nonceLock.nextNonce.toString(16));
|
|
1046
1150
|
}
|
|
1047
|
-
transactionMeta.status =
|
|
1151
|
+
transactionMeta.status = types_1.TransactionStatus.approved;
|
|
1048
1152
|
transactionMeta.txParams.nonce = nonceToUse;
|
|
1049
1153
|
transactionMeta.txParams.chainId = chainId;
|
|
1050
1154
|
const baseTxParams = Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas });
|
|
1051
1155
|
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction approved');
|
|
1156
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1052
1157
|
const isEIP1559 = (0, utils_1.isEIP1559Transaction)(transactionMeta.txParams);
|
|
1053
1158
|
const txParams = isEIP1559
|
|
1054
|
-
? Object.assign(Object.assign({}, baseTxParams), {
|
|
1055
|
-
|
|
1056
|
-
type: '2' }) : baseTxParams;
|
|
1057
|
-
// delete gasPrice if maxFeePerGas and maxPriorityFeePerGas are set
|
|
1058
|
-
if (isEIP1559) {
|
|
1059
|
-
delete txParams.gasPrice;
|
|
1060
|
-
}
|
|
1061
|
-
const rawTx = yield this.signTransaction(transactionMeta);
|
|
1159
|
+
? Object.assign(Object.assign({}, baseTxParams), { estimatedBaseFee: transactionMeta.txParams.estimatedBaseFee, type: types_1.TransactionEnvelopeType.feeMarket }) : baseTxParams;
|
|
1160
|
+
const rawTx = yield this.signTransaction(transactionMeta, txParams);
|
|
1062
1161
|
if (!this.beforePublish(transactionMeta)) {
|
|
1063
1162
|
(0, logger_1.projectLogger)('Skipping publishing transaction based on hook');
|
|
1163
|
+
this.hub.emit(`${transactionMeta.id}:publish-skip`, transactionMeta);
|
|
1064
1164
|
return;
|
|
1065
1165
|
}
|
|
1066
1166
|
if (!rawTx) {
|
|
@@ -1070,11 +1170,12 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1070
1170
|
transactionMeta.hash = hash;
|
|
1071
1171
|
transactionMeta.status = types_1.TransactionStatus.submitted;
|
|
1072
1172
|
transactionMeta.submittedTime = new Date().getTime();
|
|
1173
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
|
|
1073
1174
|
this.hub.emit('transaction-submitted', {
|
|
1074
1175
|
transactionMeta,
|
|
1075
1176
|
});
|
|
1076
|
-
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
|
|
1077
1177
|
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
1178
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1078
1179
|
}
|
|
1079
1180
|
catch (error) {
|
|
1080
1181
|
this.failTransaction(transactionMeta, error);
|
|
@@ -1107,13 +1208,14 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1107
1208
|
return;
|
|
1108
1209
|
}
|
|
1109
1210
|
transactionMeta.status = types_1.TransactionStatus.rejected;
|
|
1211
|
+
const transactions = this.state.transactions.filter(({ id }) => id !== transactionId);
|
|
1212
|
+
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
1110
1213
|
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
1111
1214
|
this.hub.emit('transaction-rejected', {
|
|
1112
1215
|
transactionMeta,
|
|
1113
1216
|
actionId,
|
|
1114
1217
|
});
|
|
1115
|
-
|
|
1116
|
-
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
1218
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1117
1219
|
}
|
|
1118
1220
|
/**
|
|
1119
1221
|
* Trim the amount of transactions that are set on the state. Checks
|
|
@@ -1124,7 +1226,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1124
1226
|
* representation, this function will not break apart transactions with the
|
|
1125
1227
|
* same nonce, created on the same day, per network. Not accounting for transactions of the same
|
|
1126
1228
|
* nonce, same day and network combo can result in confusing or broken experiences
|
|
1127
|
-
* in the UI. The transactions are then updated using the
|
|
1229
|
+
* in the UI. The transactions are then updated using the BaseControllerV1 update.
|
|
1128
1230
|
*
|
|
1129
1231
|
* @param transactions - The transactions to be applied to the state.
|
|
1130
1232
|
* @returns The trimmed list of transactions.
|
|
@@ -1288,25 +1390,23 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1288
1390
|
*/
|
|
1289
1391
|
addExternalTransaction(transactionMeta) {
|
|
1290
1392
|
var _a, _b;
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
if (!
|
|
1302
|
-
|
|
1303
|
-
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
1304
|
-
}
|
|
1393
|
+
const chainId = this.getChainId();
|
|
1394
|
+
const { transactions } = this.state;
|
|
1395
|
+
const fromAddress = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.from;
|
|
1396
|
+
const sameFromAndNetworkTransactions = transactions.filter((transaction) => transaction.txParams.from === fromAddress &&
|
|
1397
|
+
transaction.chainId === chainId);
|
|
1398
|
+
const confirmedTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.confirmed);
|
|
1399
|
+
const pendingTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.submitted);
|
|
1400
|
+
(0, external_transactions_1.validateConfirmedExternalTransaction)(transactionMeta, confirmedTxs, pendingTxs);
|
|
1401
|
+
// Make sure provided external transaction has non empty history array
|
|
1402
|
+
if (!((_b = transactionMeta.history) !== null && _b !== void 0 ? _b : []).length) {
|
|
1403
|
+
if (!this.isHistoryDisabled) {
|
|
1404
|
+
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
1305
1405
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1406
|
+
}
|
|
1407
|
+
const updatedTransactions = [...transactions, transactionMeta];
|
|
1408
|
+
this.update({
|
|
1409
|
+
transactions: this.trimTransactionsForState(updatedTransactions),
|
|
1310
1410
|
});
|
|
1311
1411
|
}
|
|
1312
1412
|
/**
|
|
@@ -1351,6 +1451,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1351
1451
|
transactionMeta,
|
|
1352
1452
|
});
|
|
1353
1453
|
this.updateTransaction(transactionMeta, 'TransactionController#setTransactionStatusDropped - Transaction dropped');
|
|
1454
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1354
1455
|
}
|
|
1355
1456
|
/**
|
|
1356
1457
|
* Get transaction with provided actionId.
|
|
@@ -1391,26 +1492,22 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1391
1492
|
});
|
|
1392
1493
|
}
|
|
1393
1494
|
getEIP1559Compatibility() {
|
|
1394
|
-
var _a, _b;
|
|
1395
1495
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1396
1496
|
const currentNetworkIsEIP1559Compatible = yield this.getCurrentNetworkEIP1559Compatibility();
|
|
1397
|
-
const currentAccountIsEIP1559Compatible =
|
|
1497
|
+
const currentAccountIsEIP1559Compatible = yield this.getCurrentAccountEIP1559Compatibility();
|
|
1398
1498
|
return (currentNetworkIsEIP1559Compatible && currentAccountIsEIP1559Compatible);
|
|
1399
1499
|
});
|
|
1400
1500
|
}
|
|
1401
1501
|
addPendingTransactionTrackerListeners() {
|
|
1402
|
-
this.pendingTransactionTracker.hub.on('transaction-confirmed', (
|
|
1403
|
-
this.hub.emit('transaction-confirmed', { transactionMeta });
|
|
1404
|
-
this.hub.emit(`${transactionMeta.id}:confirmed`, transactionMeta);
|
|
1405
|
-
});
|
|
1502
|
+
this.pendingTransactionTracker.hub.on('transaction-confirmed', this.onConfirmedTransaction.bind(this));
|
|
1406
1503
|
this.pendingTransactionTracker.hub.on('transaction-dropped', this.setTransactionStatusDropped.bind(this));
|
|
1407
1504
|
this.pendingTransactionTracker.hub.on('transaction-failed', this.failTransaction.bind(this));
|
|
1408
1505
|
this.pendingTransactionTracker.hub.on('transaction-updated', this.updateTransaction.bind(this));
|
|
1409
1506
|
}
|
|
1410
|
-
signTransaction(transactionMeta) {
|
|
1507
|
+
signTransaction(transactionMeta, txParams) {
|
|
1411
1508
|
var _a;
|
|
1412
1509
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1413
|
-
|
|
1510
|
+
(0, logger_1.projectLogger)('Signing transaction', txParams);
|
|
1414
1511
|
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
1415
1512
|
this.inProcessOfSigning.add(transactionMeta.id);
|
|
1416
1513
|
const signedTx = yield ((_a = this.sign) === null || _a === void 0 ? void 0 : _a.call(this, unsignedEthTx, txParams.from, ...this.getAdditionalSignArguments(transactionMeta)));
|
|
@@ -1419,19 +1516,58 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1419
1516
|
return undefined;
|
|
1420
1517
|
}
|
|
1421
1518
|
if (!this.afterSign(transactionMeta, signedTx)) {
|
|
1519
|
+
this.updateTransaction(transactionMeta, 'TransactionController#signTransaction - Update after sign');
|
|
1422
1520
|
(0, logger_1.projectLogger)('Skipping signed status based on hook');
|
|
1423
1521
|
return undefined;
|
|
1424
1522
|
}
|
|
1425
1523
|
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
1426
1524
|
transactionMeta.status = types_1.TransactionStatus.signed;
|
|
1427
1525
|
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction signed');
|
|
1526
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1428
1527
|
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
1429
1528
|
transactionMeta.rawTx = rawTx;
|
|
1430
1529
|
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - RawTransaction added');
|
|
1431
1530
|
return rawTx;
|
|
1432
1531
|
});
|
|
1433
1532
|
}
|
|
1533
|
+
onTransactionStatusChange(transactionMeta) {
|
|
1534
|
+
this.hub.emit('transaction-status-update', { transactionMeta });
|
|
1535
|
+
}
|
|
1536
|
+
getNonceTrackerTransactions(status, address) {
|
|
1537
|
+
const currentChainId = this.getChainId();
|
|
1538
|
+
return (0, utils_1.getAndFormatTransactionsForNonceTracker)(currentChainId, address, status, this.state.transactions);
|
|
1539
|
+
}
|
|
1540
|
+
onConfirmedTransaction(transactionMeta) {
|
|
1541
|
+
(0, logger_1.projectLogger)('Processing confirmed transaction', transactionMeta.id);
|
|
1542
|
+
this.hub.emit('transaction-confirmed', { transactionMeta });
|
|
1543
|
+
this.hub.emit(`${transactionMeta.id}:confirmed`, transactionMeta);
|
|
1544
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1545
|
+
// Intentional given potential duration of process.
|
|
1546
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1547
|
+
this.updatePostBalance(transactionMeta);
|
|
1548
|
+
}
|
|
1549
|
+
updatePostBalance(transactionMeta) {
|
|
1550
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1551
|
+
try {
|
|
1552
|
+
if (transactionMeta.type !== types_1.TransactionType.swap) {
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
const { updatedTransactionMeta, approvalTransactionMeta } = yield (0, swaps_1.updatePostTransactionBalance)(transactionMeta, {
|
|
1556
|
+
ethQuery: this.ethQuery,
|
|
1557
|
+
getTransaction: this.getTransaction.bind(this),
|
|
1558
|
+
updateTransaction: this.updateTransaction.bind(this),
|
|
1559
|
+
});
|
|
1560
|
+
this.hub.emit('post-transaction-balance-updated', {
|
|
1561
|
+
transactionMeta: updatedTransactionMeta,
|
|
1562
|
+
approvalTransactionMeta,
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
catch (error) {
|
|
1566
|
+
/* istanbul ignore next */
|
|
1567
|
+
(0, logger_1.projectLogger)('Error while updating post transaction balance', error);
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1434
1571
|
}
|
|
1435
1572
|
exports.TransactionController = TransactionController;
|
|
1436
|
-
exports.default = TransactionController;
|
|
1437
1573
|
//# sourceMappingURL=TransactionController.js.map
|