1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Ensure transaction activity log supports EIP-1559 (#11794)

* Ensure transaction activity log supports EIP-1559

* unit test fix

* Add estimated base fee to swaps txMeta

* fix lint and tests

* Improve activity log copy
This commit is contained in:
Dan J Miller 2021-08-06 19:48:53 -02:30 committed by GitHub
parent 1216dc95c0
commit e6543a83ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 103 additions and 19 deletions

View File

@ -2499,7 +2499,7 @@
"message": "transaction" "message": "transaction"
}, },
"transactionCancelAttempted": { "transactionCancelAttempted": {
"message": "Transaction cancel attempted with gas fee of $1 at $2" "message": "Transaction cancel attempted with estimated gas fee of $1 at $2"
}, },
"transactionCancelSuccess": { "transactionCancelSuccess": {
"message": "Transaction successfully cancelled at $2" "message": "Transaction successfully cancelled at $2"
@ -2557,10 +2557,10 @@
"message": "Total Gas Fee" "message": "Total Gas Fee"
}, },
"transactionResubmitted": { "transactionResubmitted": {
"message": "Transaction resubmitted with gas fee increased to $1 at $2" "message": "Transaction resubmitted with estimated gas fee increased to $1 at $2"
}, },
"transactionSubmitted": { "transactionSubmitted": {
"message": "Transaction submitted with gas fee of $1 at $2." "message": "Transaction submitted with estimated gas fee of $1 at $2."
}, },
"transactionUpdated": { "transactionUpdated": {
"message": "Transaction updated at $2." "message": "Transaction updated at $2."

View File

@ -693,7 +693,11 @@ export default class TransactionController extends EventEmitter {
* params instead of allowing this method to generate them * params instead of allowing this method to generate them
* @returns {txMeta} * @returns {txMeta}
*/ */
async createCancelTransaction(originalTxId, customGasSettings) { async createCancelTransaction(
originalTxId,
customGasSettings,
{ estimatedBaseFee } = {},
) {
const originalTxMeta = this.txStateManager.getTransaction(originalTxId); const originalTxMeta = this.txStateManager.getTransaction(originalTxId);
const { txParams } = originalTxMeta; const { txParams } = originalTxMeta;
const { from, nonce } = txParams; const { from, nonce } = txParams;
@ -723,6 +727,10 @@ export default class TransactionController extends EventEmitter {
type: TRANSACTION_TYPES.CANCEL, type: TRANSACTION_TYPES.CANCEL,
}); });
if (estimatedBaseFee) {
newTxMeta.estimatedBaseFee = estimatedBaseFee;
}
this.addTransaction(newTxMeta); this.addTransaction(newTxMeta);
await this.approveTransaction(newTxMeta.id); await this.approveTransaction(newTxMeta.id);
return newTxMeta; return newTxMeta;
@ -738,7 +746,11 @@ export default class TransactionController extends EventEmitter {
* params instead of allowing this method to generate them * params instead of allowing this method to generate them
* @returns {txMeta} * @returns {txMeta}
*/ */
async createSpeedUpTransaction(originalTxId, customGasSettings) { async createSpeedUpTransaction(
originalTxId,
customGasSettings,
{ estimatedBaseFee } = {},
) {
const originalTxMeta = this.txStateManager.getTransaction(originalTxId); const originalTxMeta = this.txStateManager.getTransaction(originalTxId);
const { txParams } = originalTxMeta; const { txParams } = originalTxMeta;
@ -758,6 +770,10 @@ export default class TransactionController extends EventEmitter {
type: TRANSACTION_TYPES.RETRY, type: TRANSACTION_TYPES.RETRY,
}); });
if (estimatedBaseFee) {
newTxMeta.estimatedBaseFee = estimatedBaseFee;
}
this.addTransaction(newTxMeta); this.addTransaction(newTxMeta);
await this.approveTransaction(newTxMeta.id); await this.approveTransaction(newTxMeta.id);
return newTxMeta; return newTxMeta;

View File

@ -2099,10 +2099,15 @@ export default class MetamaskController extends EventEmitter {
* instead of allowing this method to generate them * instead of allowing this method to generate them
* @returns {Object} MetaMask state * @returns {Object} MetaMask state
*/ */
async createCancelTransaction(originalTxId, customGasSettings) { async createCancelTransaction(
originalTxId,
customGasSettings,
newTxMetaProps,
) {
await this.txController.createCancelTransaction( await this.txController.createCancelTransaction(
originalTxId, originalTxId,
customGasSettings, customGasSettings,
newTxMetaProps,
); );
const state = await this.getState(); const state = await this.getState();
return state; return state;
@ -2119,10 +2124,15 @@ export default class MetamaskController extends EventEmitter {
* instead of allowing this method to generate them * instead of allowing this method to generate them
* @returns {Object} MetaMask state * @returns {Object} MetaMask state
*/ */
async createSpeedUpTransaction(originalTxId, customGasSettings) { async createSpeedUpTransaction(
originalTxId,
customGasSettings,
newTxMetaProps,
) {
await this.txController.createSpeedUpTransaction( await this.txController.createSpeedUpTransaction(
originalTxId, originalTxId,
customGasSettings, customGasSettings,
newTxMetaProps,
); );
const state = await this.getState(); const state = await this.getState();
return state; return state;

View File

@ -90,6 +90,7 @@ export default function EditGasPopover({
onManualChange, onManualChange,
balanceError, balanceError,
estimatesUnavailableWarning, estimatesUnavailableWarning,
estimatedBaseFee,
} = useGasFeeInputs(defaultEstimateToUse, transaction, minimumGasLimit, mode); } = useGasFeeInputs(defaultEstimateToUse, transaction, minimumGasLimit, mode);
/** /**
@ -139,10 +140,18 @@ export default function EditGasPopover({
switch (mode) { switch (mode) {
case EDIT_GAS_MODES.CANCEL: case EDIT_GAS_MODES.CANCEL:
dispatch(createCancelTransaction(transaction.id, newGasSettings)); dispatch(
createCancelTransaction(transaction.id, newGasSettings, {
estimatedBaseFee,
}),
);
break; break;
case EDIT_GAS_MODES.SPEED_UP: case EDIT_GAS_MODES.SPEED_UP:
dispatch(createSpeedUpTransaction(transaction.id, newGasSettings)); dispatch(
createSpeedUpTransaction(transaction.id, newGasSettings, {
estimatedBaseFee,
}),
);
break; break;
case EDIT_GAS_MODES.MODIFY_IN_PLACE: case EDIT_GAS_MODES.MODIFY_IN_PLACE:
dispatch(updateTransaction(updatedTxMeta)); dispatch(updateTransaction(updatedTxMeta));
@ -170,6 +179,7 @@ export default function EditGasPopover({
maxPriorityFeePerGas, maxPriorityFeePerGas,
networkAndAccountSupport1559, networkAndAccountSupport1559,
estimateToUse, estimateToUse,
estimatedBaseFee,
]); ]);
let title = t('editGasTitle'); let title = t('editGasTitle');

View File

@ -1,5 +1,6 @@
import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction'; import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction';
import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util'; import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util';
import { sumHexes } from '../../../helpers/utils/transactions.util';
import { import {
// event constants // event constants
@ -22,6 +23,7 @@ import {
const STATUS_PATH = '/status'; const STATUS_PATH = '/status';
const GAS_PRICE_PATH = '/txParams/gasPrice'; const GAS_PRICE_PATH = '/txParams/gasPrice';
const GAS_LIMIT_PATH = '/txParams/gas'; const GAS_LIMIT_PATH = '/txParams/gas';
const ESTIMATE_BASE_FEE_PATH = '/estimatedBaseFee';
// op constants // op constants
const REPLACE_OP = 'replace'; const REPLACE_OP = 'replace';
@ -53,11 +55,20 @@ export function getActivities(transaction, isFirstTransaction = false) {
metamaskNetworkId, metamaskNetworkId,
hash, hash,
history = [], history = [],
txParams: { gas: paramsGasLimit, gasPrice: paramsGasPrice }, txParams: {
xReceipt: { status } = {}, gas: paramsGasLimit,
gasPrice: paramsGasPrice,
maxPriorityFeePerGas: paramsMaxPriorityFeePerGas,
},
txReceipt: { status } = {},
type, type,
estimatedBaseFee: paramsEstimatedBaseFee,
} = transaction; } = transaction;
const paramsEip1559Price =
paramsEstimatedBaseFee &&
paramsMaxPriorityFeePerGas &&
sumHexes(paramsEstimatedBaseFee, paramsMaxPriorityFeePerGas);
let cachedGasLimit = '0x0'; let cachedGasLimit = '0x0';
let cachedGasPrice = '0x0'; let cachedGasPrice = '0x0';
@ -66,13 +77,19 @@ export function getActivities(transaction, isFirstTransaction = false) {
if (index === 0 && !Array.isArray(base) && base.txParams) { if (index === 0 && !Array.isArray(base) && base.txParams) {
const { const {
time: timestamp, time: timestamp,
txParams: { value, gas = '0x0', gasPrice = '0x0' } = {}, estimatedBaseFee,
txParams: { value, gas = '0x0', gasPrice, maxPriorityFeePerGas } = {},
} = base; } = base;
const eip1559Price =
estimatedBaseFee &&
maxPriorityFeePerGas &&
sumHexes(estimatedBaseFee, maxPriorityFeePerGas);
// The cached gas limit and gas price are used to display the gas fee in the activity log. We // The cached gas limit and gas price are used to display the gas fee in the activity log. We
// need to cache these values because the status update history events don't provide us with // need to cache these values because the status update history events don't provide us with
// the latest gas limit and gas price. // the latest gas limit and gas price.
cachedGasLimit = gas; cachedGasLimit = gas;
cachedGasPrice = gasPrice; cachedGasPrice = eip1559Price || gasPrice || '0x0';
if (isFirstTransaction) { if (isFirstTransaction) {
return acc.concat({ return acc.concat({
@ -95,14 +112,16 @@ export function getActivities(transaction, isFirstTransaction = false) {
// timestamp, the first sub-entry in a history entry should. // timestamp, the first sub-entry in a history entry should.
const timestamp = entryTimestamp || (base[0] && base[0].timestamp); const timestamp = entryTimestamp || (base[0] && base[0].timestamp);
if (path in eventPathsHash && op === REPLACE_OP) { const isAddBaseFee = path === ESTIMATE_BASE_FEE_PATH && op === 'add';
if ((path in eventPathsHash && op === REPLACE_OP) || isAddBaseFee) {
switch (path) { switch (path) {
case STATUS_PATH: { case STATUS_PATH: {
const gasFee = const gasFee =
cachedGasLimit === '0x0' && cachedGasPrice === '0x0' cachedGasLimit === '0x0' && cachedGasPrice === '0x0'
? getHexGasTotal({ ? getHexGasTotal({
gasLimit: paramsGasLimit, gasLimit: paramsGasLimit,
gasPrice: paramsGasPrice, gasPrice: paramsEip1559Price || paramsGasPrice,
}) })
: getHexGasTotal({ : getHexGasTotal({
gasLimit: cachedGasLimit, gasLimit: cachedGasLimit,
@ -144,7 +163,8 @@ export function getActivities(transaction, isFirstTransaction = false) {
// previously submitted event. These events happen when the gas limit and gas price is // previously submitted event. These events happen when the gas limit and gas price is
// changed at the confirm screen. // changed at the confirm screen.
case GAS_PRICE_PATH: case GAS_PRICE_PATH:
case GAS_LIMIT_PATH: { case GAS_LIMIT_PATH:
case ESTIMATE_BASE_FEE_PATH: {
const lastEvent = events[events.length - 1] || {}; const lastEvent = events[events.length - 1] || {};
const { lastEventKey } = lastEvent; const { lastEventKey } = lastEvent;
@ -152,6 +172,12 @@ export function getActivities(transaction, isFirstTransaction = false) {
cachedGasLimit = value; cachedGasLimit = value;
} else if (path === GAS_PRICE_PATH) { } else if (path === GAS_PRICE_PATH) {
cachedGasPrice = value; cachedGasPrice = value;
} else if (path === ESTIMATE_BASE_FEE_PATH) {
cachedGasPrice = paramsEip1559Price || base?.txParams?.gasPrice;
lastEvent.value = getHexGasTotal({
gasLimit: paramsGasLimit,
gasPrice: cachedGasPrice,
});
} }
if ( if (

View File

@ -674,19 +674,21 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => {
let maxFeePerGas; let maxFeePerGas;
let maxPriorityFeePerGas; let maxPriorityFeePerGas;
let baseAndPriorityFeePerGas; let baseAndPriorityFeePerGas;
let decEstimatedBaseFee;
if (networkAndAccountSupports1559) { if (networkAndAccountSupports1559) {
const { const {
high: { suggestedMaxFeePerGas, suggestedMaxPriorityFeePerGas }, high: { suggestedMaxFeePerGas, suggestedMaxPriorityFeePerGas },
estimatedBaseFee = '0', estimatedBaseFee = '0',
} = getGasFeeEstimates(state); } = getGasFeeEstimates(state);
decEstimatedBaseFee = decGWEIToHexWEI(estimatedBaseFee);
maxFeePerGas = maxFeePerGas =
customMaxFeePerGas || decGWEIToHexWEI(suggestedMaxFeePerGas); customMaxFeePerGas || decGWEIToHexWEI(suggestedMaxFeePerGas);
maxPriorityFeePerGas = maxPriorityFeePerGas =
customMaxPriorityFeePerGas || customMaxPriorityFeePerGas ||
decGWEIToHexWEI(suggestedMaxPriorityFeePerGas); decGWEIToHexWEI(suggestedMaxPriorityFeePerGas);
baseAndPriorityFeePerGas = addHexes( baseAndPriorityFeePerGas = addHexes(
decGWEIToHexWEI(estimatedBaseFee), decEstimatedBaseFee,
maxPriorityFeePerGas, maxPriorityFeePerGas,
); );
} }
@ -816,6 +818,7 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => {
updateTransaction( updateTransaction(
{ {
...approveTxMeta, ...approveTxMeta,
estimatedBaseFee: decEstimatedBaseFee,
type: TRANSACTION_TYPES.SWAP_APPROVAL, type: TRANSACTION_TYPES.SWAP_APPROVAL,
sourceTokenSymbol: sourceTokenInfo.symbol, sourceTokenSymbol: sourceTokenInfo.symbol,
}, },
@ -855,6 +858,7 @@ export const signAndSendTransactions = (history, metaMetricsEvent) => {
updateTransaction( updateTransaction(
{ {
...tradeTxMeta, ...tradeTxMeta,
estimatedBaseFee: decEstimatedBaseFee,
sourceTokenSymbol: sourceTokenInfo.symbol, sourceTokenSymbol: sourceTokenInfo.symbol,
destinationTokenSymbol: destinationTokenInfo.symbol, destinationTokenSymbol: destinationTokenInfo.symbol,
type: TRANSACTION_TYPES.SWAP, type: TRANSACTION_TYPES.SWAP,

View File

@ -544,5 +544,6 @@ export function useGasFeeInputs(
}, },
balanceError, balanceError,
estimatesUnavailableWarning, estimatesUnavailableWarning,
estimatedBaseFee: gasSettings.baseFeePerGas,
}; };
} }

View File

@ -111,6 +111,7 @@ export default class ConfirmTransactionBase extends Component {
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
maxFeePerGas: PropTypes.string, maxFeePerGas: PropTypes.string,
maxPriorityFeePerGas: PropTypes.string, maxPriorityFeePerGas: PropTypes.string,
baseFeePerGas: PropTypes.string,
}; };
state = { state = {
@ -612,6 +613,7 @@ export default class ConfirmTransactionBase extends Component {
updateCustomNonce, updateCustomNonce,
maxFeePerGas, maxFeePerGas,
maxPriorityFeePerGas, maxPriorityFeePerGas,
baseFeePerGas,
} = this.props; } = this.props;
const { submitting } = this.state; const { submitting } = this.state;
@ -619,6 +621,10 @@ export default class ConfirmTransactionBase extends Component {
return; return;
} }
if (baseFeePerGas) {
txData.estimatedBaseFee = baseFeePerGas;
}
if (maxFeePerGas) { if (maxFeePerGas) {
txData.txParams = { txData.txParams = {
...txData.txParams, ...txData.txParams,

View File

@ -200,6 +200,7 @@ const mapStateToProps = (state, ownProps) => {
useNativeCurrencyAsPrimaryCurrency, useNativeCurrencyAsPrimaryCurrency,
maxFeePerGas: gasEstimationObject.maxFeePerGas, maxFeePerGas: gasEstimationObject.maxFeePerGas,
maxPriorityFeePerGas: gasEstimationObject.maxPriorityFeePerGas, maxPriorityFeePerGas: gasEstimationObject.maxPriorityFeePerGas,
baseFeePerGas: gasEstimationObject.baseFeePerGas,
}; };
}; };

View File

@ -1340,7 +1340,11 @@ export function clearPendingTokens() {
}; };
} }
export function createCancelTransaction(txId, customGasSettings) { export function createCancelTransaction(
txId,
customGasSettings,
newTxMetaProps,
) {
log.debug('background.cancelTransaction'); log.debug('background.cancelTransaction');
let newTxId; let newTxId;
@ -1349,6 +1353,7 @@ export function createCancelTransaction(txId, customGasSettings) {
background.createCancelTransaction( background.createCancelTransaction(
txId, txId,
customGasSettings, customGasSettings,
newTxMetaProps,
(err, newState) => { (err, newState) => {
if (err) { if (err) {
dispatch(displayWarning(err.message)); dispatch(displayWarning(err.message));
@ -1368,7 +1373,11 @@ export function createCancelTransaction(txId, customGasSettings) {
}; };
} }
export function createSpeedUpTransaction(txId, customGasSettings) { export function createSpeedUpTransaction(
txId,
customGasSettings,
newTxMetaProps,
) {
log.debug('background.createSpeedUpTransaction'); log.debug('background.createSpeedUpTransaction');
let newTx; let newTx;
@ -1377,6 +1386,7 @@ export function createSpeedUpTransaction(txId, customGasSettings) {
background.createSpeedUpTransaction( background.createSpeedUpTransaction(
txId, txId,
customGasSettings, customGasSettings,
newTxMetaProps,
(err, newState) => { (err, newState) => {
if (err) { if (err) {
dispatch(displayWarning(err.message)); dispatch(displayWarning(err.message));