mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add support for EIP1559 transactions to transaction breakdown (#11622)
* Add support for EIP1559 transactions to transaction breakdown * Use userPreferencedCurrencyDisplay for effective gas price in transaction breakdown * Hide eip1559 gas properties in transaction breakdown on non-1559 networks * Add comment explaining gasPrice and effectiveGasPrice usage in transaction breakdown container.
This commit is contained in:
parent
52bac60a22
commit
aaa15cbe03
@ -812,7 +812,7 @@ export default class TransactionController extends EventEmitter {
|
|||||||
* @param {number} txId - The tx's ID
|
* @param {number} txId - The tx's ID
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async confirmTransaction(txId, txReceipt) {
|
async confirmTransaction(txId, txReceipt, baseFeePerGas) {
|
||||||
// get the txReceipt before marking the transaction confirmed
|
// get the txReceipt before marking the transaction confirmed
|
||||||
// to ensure the receipt is gotten before the ui revives the tx
|
// to ensure the receipt is gotten before the ui revives the tx
|
||||||
const txMeta = this.txStateManager.getTransaction(txId);
|
const txMeta = this.txStateManager.getTransaction(txId);
|
||||||
@ -833,6 +833,11 @@ export default class TransactionController extends EventEmitter {
|
|||||||
...txReceipt,
|
...txReceipt,
|
||||||
gasUsed,
|
gasUsed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (baseFeePerGas) {
|
||||||
|
txMeta.baseFeePerGas = baseFeePerGas;
|
||||||
|
}
|
||||||
|
|
||||||
this.txStateManager.setTxStatusConfirmed(txId);
|
this.txStateManager.setTxStatusConfirmed(txId);
|
||||||
this._markNonceDuplicatesDropped(txId);
|
this._markNonceDuplicatesDropped(txId);
|
||||||
|
|
||||||
@ -1011,8 +1016,10 @@ export default class TransactionController extends EventEmitter {
|
|||||||
this.pendingTxTracker.on('tx:failed', (txId, error) => {
|
this.pendingTxTracker.on('tx:failed', (txId, error) => {
|
||||||
this._failTransaction(txId, error);
|
this._failTransaction(txId, error);
|
||||||
});
|
});
|
||||||
this.pendingTxTracker.on('tx:confirmed', (txId, transactionReceipt) =>
|
this.pendingTxTracker.on(
|
||||||
this.confirmTransaction(txId, transactionReceipt),
|
'tx:confirmed',
|
||||||
|
(txId, transactionReceipt, baseFeePerGas) =>
|
||||||
|
this.confirmTransaction(txId, transactionReceipt, baseFeePerGas),
|
||||||
);
|
);
|
||||||
this.pendingTxTracker.on('tx:dropped', (txId) => {
|
this.pendingTxTracker.on('tx:dropped', (txId) => {
|
||||||
this._dropTransaction(txId);
|
this._dropTransaction(txId);
|
||||||
|
@ -193,7 +193,11 @@ export default class PendingTransactionTracker extends EventEmitter {
|
|||||||
try {
|
try {
|
||||||
const transactionReceipt = await this.query.getTransactionReceipt(txHash);
|
const transactionReceipt = await this.query.getTransactionReceipt(txHash);
|
||||||
if (transactionReceipt?.blockNumber) {
|
if (transactionReceipt?.blockNumber) {
|
||||||
this.emit('tx:confirmed', txId, transactionReceipt);
|
const { baseFeePerGas } = await this.query.getBlockByHash(
|
||||||
|
transactionReceipt?.blockHash,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
this.emit('tx:confirmed', txId, transactionReceipt, baseFeePerGas);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -4,7 +4,12 @@ import classnames from 'classnames';
|
|||||||
import CurrencyDisplay from '../../ui/currency-display';
|
import CurrencyDisplay from '../../ui/currency-display';
|
||||||
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display';
|
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display';
|
||||||
import HexToDecimal from '../../ui/hex-to-decimal';
|
import HexToDecimal from '../../ui/hex-to-decimal';
|
||||||
import { GWEI, PRIMARY, SECONDARY } from '../../../helpers/constants/common';
|
import {
|
||||||
|
GWEI,
|
||||||
|
PRIMARY,
|
||||||
|
SECONDARY,
|
||||||
|
ETH,
|
||||||
|
} from '../../../helpers/constants/common';
|
||||||
import TransactionBreakdownRow from './transaction-breakdown-row';
|
import TransactionBreakdownRow from './transaction-breakdown-row';
|
||||||
|
|
||||||
export default class TransactionBreakdown extends PureComponent {
|
export default class TransactionBreakdown extends PureComponent {
|
||||||
@ -25,7 +30,8 @@ export default class TransactionBreakdown extends PureComponent {
|
|||||||
totalInHex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
totalInHex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
baseFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
baseFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
priorityFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
priorityFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
effectiveGasPrice: PropTypes.number,
|
hexGasTotal: PropTypes.string,
|
||||||
|
supportsEIP1559: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -47,7 +53,8 @@ export default class TransactionBreakdown extends PureComponent {
|
|||||||
isTokenApprove,
|
isTokenApprove,
|
||||||
baseFee,
|
baseFee,
|
||||||
priorityFee,
|
priorityFee,
|
||||||
effectiveGasPrice,
|
hexGasTotal,
|
||||||
|
supportsEIP1559,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<div className={classnames('transaction-breakdown', className)}>
|
<div className={classnames('transaction-breakdown', className)}>
|
||||||
@ -91,7 +98,7 @@ export default class TransactionBreakdown extends PureComponent {
|
|||||||
/>
|
/>
|
||||||
</TransactionBreakdownRow>
|
</TransactionBreakdownRow>
|
||||||
)}
|
)}
|
||||||
{process.env.SHOW_EIP_1559_UI && (
|
{process.env.SHOW_EIP_1559_UI && supportsEIP1559 && (
|
||||||
<TransactionBreakdownRow title={t('transactionHistoryBaseFee')}>
|
<TransactionBreakdownRow title={t('transactionHistoryBaseFee')}>
|
||||||
{typeof baseFee === 'undefined' ? (
|
{typeof baseFee === 'undefined' ? (
|
||||||
'?'
|
'?'
|
||||||
@ -102,12 +109,13 @@ export default class TransactionBreakdown extends PureComponent {
|
|||||||
currency={nativeCurrency}
|
currency={nativeCurrency}
|
||||||
denomination={GWEI}
|
denomination={GWEI}
|
||||||
value={baseFee}
|
value={baseFee}
|
||||||
|
numberOfDecimals={10}
|
||||||
hideLabel
|
hideLabel
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</TransactionBreakdownRow>
|
</TransactionBreakdownRow>
|
||||||
)}
|
)}
|
||||||
{process.env.SHOW_EIP_1559_UI && (
|
{process.env.SHOW_EIP_1559_UI && supportsEIP1559 && (
|
||||||
<TransactionBreakdownRow title={t('transactionHistoryPriorityFee')}>
|
<TransactionBreakdownRow title={t('transactionHistoryPriorityFee')}>
|
||||||
{typeof priorityFee === 'undefined' ? (
|
{typeof priorityFee === 'undefined' ? (
|
||||||
'?'
|
'?'
|
||||||
@ -118,12 +126,13 @@ export default class TransactionBreakdown extends PureComponent {
|
|||||||
currency={nativeCurrency}
|
currency={nativeCurrency}
|
||||||
denomination={GWEI}
|
denomination={GWEI}
|
||||||
value={priorityFee}
|
value={priorityFee}
|
||||||
|
numberOfDecimals={10}
|
||||||
hideLabel
|
hideLabel
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</TransactionBreakdownRow>
|
</TransactionBreakdownRow>
|
||||||
)}
|
)}
|
||||||
{!process.env.SHOW_EIP_1559_UI && (
|
{(!process.env.SHOW_EIP_1559_UI || !supportsEIP1559) && (
|
||||||
<TransactionBreakdownRow title={t('advancedGasPriceTitle')}>
|
<TransactionBreakdownRow title={t('advancedGasPriceTitle')}>
|
||||||
{typeof gasPrice === 'undefined' ? (
|
{typeof gasPrice === 'undefined' ? (
|
||||||
'?'
|
'?'
|
||||||
@ -139,22 +148,28 @@ export default class TransactionBreakdown extends PureComponent {
|
|||||||
)}
|
)}
|
||||||
</TransactionBreakdownRow>
|
</TransactionBreakdownRow>
|
||||||
)}
|
)}
|
||||||
|
{process.env.SHOW_EIP_1559_UI && supportsEIP1559 && (
|
||||||
<TransactionBreakdownRow
|
<TransactionBreakdownRow
|
||||||
title={t('transactionHistoryEffectiveGasPrice')}
|
title={t('transactionHistoryEffectiveGasPrice')}
|
||||||
>
|
>
|
||||||
<UserPreferencedCurrencyDisplay
|
<UserPreferencedCurrencyDisplay
|
||||||
className="transaction-breakdown__value transaction-breakdown__value--effective-gas-price"
|
className="transaction-breakdown__value"
|
||||||
|
data-testid="transaction-breakdown__effective-gas-price"
|
||||||
|
currency={nativeCurrency}
|
||||||
|
denomination={ETH}
|
||||||
|
numberOfDecimals={6}
|
||||||
|
value={hexGasTotal}
|
||||||
type={PRIMARY}
|
type={PRIMARY}
|
||||||
value={effectiveGasPrice}
|
|
||||||
/>
|
/>
|
||||||
{showFiat && (
|
{showFiat && (
|
||||||
<UserPreferencedCurrencyDisplay
|
<UserPreferencedCurrencyDisplay
|
||||||
className="transaction-breakdown__value"
|
className="transaction-breakdown__value"
|
||||||
type={SECONDARY}
|
type={SECONDARY}
|
||||||
value={effectiveGasPrice}
|
value={hexGasTotal}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</TransactionBreakdownRow>
|
</TransactionBreakdownRow>
|
||||||
|
)}
|
||||||
<TransactionBreakdownRow title={t('total')}>
|
<TransactionBreakdownRow title={t('total')}>
|
||||||
<UserPreferencedCurrencyDisplay
|
<UserPreferencedCurrencyDisplay
|
||||||
className="transaction-breakdown__value transaction-breakdown__value--eth-total"
|
className="transaction-breakdown__value transaction-breakdown__value--eth-total"
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { getShouldShowFiat } from '../../../selectors';
|
import { getShouldShowFiat } from '../../../selectors';
|
||||||
import { getNativeCurrency } from '../../../ducks/metamask/metamask';
|
import {
|
||||||
|
getNativeCurrency,
|
||||||
|
isEIP1559Network,
|
||||||
|
} from '../../../ducks/metamask/metamask';
|
||||||
import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util';
|
import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util';
|
||||||
|
import { subtractHexes } from '../../../helpers/utils/conversions.util';
|
||||||
import { sumHexes } from '../../../helpers/utils/transactions.util';
|
import { sumHexes } from '../../../helpers/utils/transactions.util';
|
||||||
import TransactionBreakdown from './transaction-breakdown.component';
|
import TransactionBreakdown from './transaction-breakdown.component';
|
||||||
|
|
||||||
@ -9,15 +13,32 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
const { transaction, isTokenApprove } = ownProps;
|
const { transaction, isTokenApprove } = ownProps;
|
||||||
const {
|
const {
|
||||||
txParams: { gas, gasPrice, value } = {},
|
txParams: { gas, gasPrice, value } = {},
|
||||||
txReceipt: { gasUsed } = {},
|
txReceipt: { gasUsed, effectiveGasPrice } = {},
|
||||||
|
baseFeePerGas,
|
||||||
} = transaction;
|
} = transaction;
|
||||||
|
|
||||||
const gasLimit = typeof gasUsed === 'string' ? gasUsed : gas;
|
const gasLimit = typeof gasUsed === 'string' ? gasUsed : gas;
|
||||||
|
|
||||||
|
const priorityFee =
|
||||||
|
effectiveGasPrice &&
|
||||||
|
baseFeePerGas &&
|
||||||
|
subtractHexes(effectiveGasPrice, baseFeePerGas);
|
||||||
|
|
||||||
|
// To calculate the total cost of the transaction, we use gasPrice if it is in the txParam,
|
||||||
|
// which will only be the case on non-EIP1559 networks. If it is not in the params, we can
|
||||||
|
// use the effectiveGasPrice from the receipt, which will ultimately represent to true cost
|
||||||
|
// of the transaction. Either of these are used the same way with gasLimit to calculate total
|
||||||
|
// cost. effectiveGasPrice will be available on the txReciept for all EIP1559 networks
|
||||||
|
const usedGasPrice = gasPrice || effectiveGasPrice;
|
||||||
const hexGasTotal =
|
const hexGasTotal =
|
||||||
(gasLimit && gasPrice && getHexGasTotal({ gasLimit, gasPrice })) || '0x0';
|
(gasLimit &&
|
||||||
|
usedGasPrice &&
|
||||||
|
getHexGasTotal({ gasLimit, gasPrice: usedGasPrice })) ||
|
||||||
|
'0x0';
|
||||||
const totalInHex = sumHexes(hexGasTotal, value);
|
const totalInHex = sumHexes(hexGasTotal, value);
|
||||||
|
|
||||||
|
const supportsEIP1559 = isEIP1559Network(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nativeCurrency: getNativeCurrency(state),
|
nativeCurrency: getNativeCurrency(state),
|
||||||
showFiat: getShouldShowFiat(state),
|
showFiat: getShouldShowFiat(state),
|
||||||
@ -26,6 +47,11 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
gasPrice,
|
gasPrice,
|
||||||
gasUsed,
|
gasUsed,
|
||||||
isTokenApprove,
|
isTokenApprove,
|
||||||
|
effectiveGasPrice,
|
||||||
|
hexGasTotal,
|
||||||
|
priorityFee,
|
||||||
|
baseFee: baseFeePerGas,
|
||||||
|
supportsEIP1559,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,6 +171,15 @@ export function addHexes(aHexWEI, bHexWEI) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function subtractHexes(aHexWEI, bHexWEI) {
|
||||||
|
return addCurrencies(aHexWEI, bHexWEI, {
|
||||||
|
aBase: 16,
|
||||||
|
bBase: 16,
|
||||||
|
toNumericBase: 'hex',
|
||||||
|
numberOfDecimals: 6,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function sumHexWEIs(hexWEIs) {
|
export function sumHexWEIs(hexWEIs) {
|
||||||
return hexWEIs.filter(Boolean).reduce(addHexes);
|
return hexWEIs.filter(Boolean).reduce(addHexes);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user