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

Fixes updates on the confirm screen. (#11788)

* Fixes updates on the confirm screen.

* Better handling of internal send transactions

* maxFee -> maxFeePerGas property name fix

* Remove redundant setEstimateToUse call in onManualChange

* Fix unit tests

* rebase error fix

* Fixes to speedup loading and transaction breakdown priority fee

* Fix lint and unit tests

* Ensure gas price based transaction that have been customized (e.g. speed up and retry) are properly initialized in useGasFeeInputs

* Clean up

* Link fix
This commit is contained in:
Dan J Miller 2021-08-06 17:01:30 -02:30 committed by GitHub
parent 827e6a6efc
commit bfde5a1d77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 156 additions and 111 deletions

View File

@ -73,6 +73,7 @@ const initialState = {
customGasPrice: null, customGasPrice: null,
customMaxFeePerGas: null, customMaxFeePerGas: null,
customMaxPriorityFeePerGas: null, customMaxPriorityFeePerGas: null,
swapsUserFeeLevel: '',
selectedAggId: null, selectedAggId: null,
customApproveTxData: '', customApproveTxData: '',
errorKey: '', errorKey: '',
@ -456,6 +457,13 @@ export default class SwapsController {
}); });
} }
setSwapsUserFeeLevel(swapsUserFeeLevel) {
const { swapsState } = this.store.getState();
this.store.updateState({
swapsState: { ...swapsState, swapsUserFeeLevel },
});
}
setSwapsTxMaxFeePriorityPerGas(maxPriorityFeePerGas) { setSwapsTxMaxFeePriorityPerGas(maxPriorityFeePerGas) {
const { swapsState } = this.store.getState(); const { swapsState } = this.store.getState();
this.store.updateState({ this.store.updateState({

View File

@ -133,6 +133,7 @@ const EMPTY_INIT_STATE = {
swapsFeatureIsLive: true, swapsFeatureIsLive: true,
useNewSwapsApi: false, useNewSwapsApi: false,
swapsQuoteRefreshTime: 60000, swapsQuoteRefreshTime: 60000,
swapsUserFeeLevel: '',
}, },
}; };

View File

@ -433,7 +433,20 @@ export default class TransactionController extends EventEmitter {
) { ) {
txMeta.txParams.maxFeePerGas = txMeta.txParams.gasPrice; txMeta.txParams.maxFeePerGas = txMeta.txParams.gasPrice;
txMeta.txParams.maxPriorityFeePerGas = txMeta.txParams.gasPrice; txMeta.txParams.maxPriorityFeePerGas = txMeta.txParams.gasPrice;
txMeta.userFeeLevel = 'custom';
} else { } else {
if (
(defaultMaxFeePerGas &&
defaultMaxPriorityFeePerGas &&
!txMeta.txParams.maxFeePerGas &&
!txMeta.txParams.maxPriorityFeePerGas) ||
txMeta.origin === 'metamask'
) {
txMeta.userFeeLevel = 'medium';
} else {
txMeta.userFeeLevel = 'custom';
}
if (defaultMaxFeePerGas && !txMeta.txParams.maxFeePerGas) { if (defaultMaxFeePerGas && !txMeta.txParams.maxFeePerGas) {
// If the dapp has not set the gasPrice or the maxFeePerGas, then we set maxFeePerGas // If the dapp has not set the gasPrice or the maxFeePerGas, then we set maxFeePerGas
// with the one returned by the gasFeeController, if that is available. // with the one returned by the gasFeeController, if that is available.

View File

@ -1089,6 +1089,10 @@ export default class MetamaskController extends EventEmitter {
swapsController.setSwapsLiveness, swapsController.setSwapsLiveness,
swapsController, swapsController,
), ),
setSwapsUserFeeLevel: nodeify(
swapsController.setSwapsUserFeeLevel,
swapsController,
),
// MetaMetrics // MetaMetrics
trackMetaMetricsEvent: nodeify( trackMetaMetricsEvent: nodeify(

View File

@ -40,7 +40,8 @@ export default function AdvancedGasControls({
const showFeeMarketFields = const showFeeMarketFields =
networkAndAccountSupport1559 && networkAndAccountSupport1559 &&
(gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET || (gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET ||
gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE); gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE ||
isGasEstimatesLoading);
return ( return (
<div className="advanced-gas-controls"> <div className="advanced-gas-controls">

View File

@ -77,7 +77,9 @@ export default function EditGasDisplay({
); );
const [showAdvancedForm, setShowAdvancedForm] = useState( const [showAdvancedForm, setShowAdvancedForm] = useState(
!estimateToUse || !networkAndAccountSupport1559, !estimateToUse ||
estimateToUse === 'custom' ||
!networkAndAccountSupport1559,
); );
const [hideRadioButtons, setHideRadioButtons] = useState( const [hideRadioButtons, setHideRadioButtons] = useState(
showAdvancedInlineGasIfPossible, showAdvancedInlineGasIfPossible,
@ -110,7 +112,7 @@ export default function EditGasDisplay({
return ( return (
<div className="edit-gas-display"> <div className="edit-gas-display">
<div className="edit-gas-display__content"> <div className="edit-gas-display__content">
{warning && ( {warning && !isGasEstimatesLoading && (
<div className="edit-gas-display__warning"> <div className="edit-gas-display__warning">
<ActionableMessage <ActionableMessage
className="actionable-message--warning" className="actionable-message--warning"
@ -118,12 +120,12 @@ export default function EditGasDisplay({
/> />
</div> </div>
)} )}
{showTopError && ( {showTopError && !isGasEstimatesLoading && (
<div className="edit-gas-display__warning"> <div className="edit-gas-display__warning">
<ErrorMessage errorKey={errorKey} /> <ErrorMessage errorKey={errorKey} />
</div> </div>
)} )}
{requireDappAcknowledgement && ( {requireDappAcknowledgement && !isGasEstimatesLoading && (
<div className="edit-gas-display__dapp-acknowledgement-warning"> <div className="edit-gas-display__dapp-acknowledgement-warning">
<ActionableMessage <ActionableMessage
className="actionable-message--warning" className="actionable-message--warning"

View File

@ -25,6 +25,7 @@ import {
hideSidebar, hideSidebar,
updateTransaction, updateTransaction,
updateCustomSwapsEIP1559GasParams, updateCustomSwapsEIP1559GasParams,
updateSwapsUserFeeLevel,
} from '../../../store/actions'; } from '../../../store/actions';
import LoadingHeartBeat from '../../ui/loading-heartbeat'; import LoadingHeartBeat from '../../ui/loading-heartbeat';
import { checkNetworkAndAccountSupports1559 } from '../../../selectors'; import { checkNetworkAndAccountSupports1559 } from '../../../selectors';
@ -126,6 +127,15 @@ export default function EditGasPopover({
gasPrice: decGWEIToHexWEI(gasPrice), gasPrice: decGWEIToHexWEI(gasPrice),
}; };
const updatedTxMeta = {
...transaction,
userFeeLevel: estimateToUse || 'custom',
txParams: {
...transaction.txParams,
...newGasSettings,
},
};
switch (mode) { switch (mode) {
case EDIT_GAS_MODES.CANCEL: case EDIT_GAS_MODES.CANCEL:
dispatch(createCancelTransaction(transaction.id, newGasSettings)); dispatch(createCancelTransaction(transaction.id, newGasSettings));
@ -134,19 +144,12 @@ export default function EditGasPopover({
dispatch(createSpeedUpTransaction(transaction.id, newGasSettings)); dispatch(createSpeedUpTransaction(transaction.id, newGasSettings));
break; break;
case EDIT_GAS_MODES.MODIFY_IN_PLACE: case EDIT_GAS_MODES.MODIFY_IN_PLACE:
dispatch( dispatch(updateTransaction(updatedTxMeta));
updateTransaction({
...transaction,
txParams: {
...transaction.txParams,
...newGasSettings,
},
}),
);
break; break;
case EDIT_GAS_MODES.SWAPS: case EDIT_GAS_MODES.SWAPS:
// This popover component should only be used for the "FEE_MARKET" type in Swaps. // This popover component should only be used for the "FEE_MARKET" type in Swaps.
if (networkAndAccountSupport1559) { if (networkAndAccountSupport1559) {
dispatch(updateSwapsUserFeeLevel(estimateToUse || 'custom'));
dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings)); dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings));
} }
break; break;
@ -165,6 +168,7 @@ export default function EditGasPopover({
maxFeePerGas, maxFeePerGas,
maxPriorityFeePerGas, maxPriorityFeePerGas,
networkAndAccountSupport1559, networkAndAccountSupport1559,
estimateToUse,
]); ]);
let title = t('editGasTitle'); let title = t('editGasTitle');

View File

@ -220,6 +220,7 @@ export default function TransactionListItem({
mode={EDIT_GAS_MODES.SPEED_UP} mode={EDIT_GAS_MODES.SPEED_UP}
transaction={{ transaction={{
...transactionGroup.primaryTransaction, ...transactionGroup.primaryTransaction,
userFeeLevel: 'custom',
txParams: { txParams: {
...transactionGroup.primaryTransaction?.txParams, ...transactionGroup.primaryTransaction?.txParams,
...customRetryGasSettings, ...customRetryGasSettings,
@ -233,6 +234,7 @@ export default function TransactionListItem({
mode={EDIT_GAS_MODES.CANCEL} mode={EDIT_GAS_MODES.CANCEL}
transaction={{ transaction={{
...transactionGroup.primaryTransaction, ...transactionGroup.primaryTransaction,
userFeeLevel: 'custom',
txParams: { txParams: {
...transactionGroup.primaryTransaction?.txParams, ...transactionGroup.primaryTransaction?.txParams,
...customCancelGasSettings, ...customCancelGasSettings,

View File

@ -251,6 +251,9 @@ export const getCustomMaxFeePerGas = (state) =>
export const getCustomMaxPriorityFeePerGas = (state) => export const getCustomMaxPriorityFeePerGas = (state) =>
state.metamask.swapsState.customMaxPriorityFeePerGas; state.metamask.swapsState.customMaxPriorityFeePerGas;
export const getSwapsUserFeeLevel = (state) =>
state.metamask.swapsState.swapsUserFeeLevel;
export const getFetchParams = (state) => state.metamask.swapsState.fetchParams; export const getFetchParams = (state) => state.metamask.swapsState.fetchParams;
export const getQuotes = (state) => state.metamask.swapsState.quotes; export const getQuotes = (state) => state.metamask.swapsState.quotes;

View File

@ -172,7 +172,7 @@ export function addHexes(aHexWEI, bHexWEI) {
} }
export function subtractHexes(aHexWEI, bHexWEI) { export function subtractHexes(aHexWEI, bHexWEI) {
return addCurrencies(aHexWEI, bHexWEI, { return subtractCurrencies(aHexWEI, bHexWEI, {
aBase: 16, aBase: 16,
bBase: 16, bBase: 16,
toNumericBase: 'hex', toNumericBase: 'hex',

View File

@ -1,7 +1,7 @@
import { addHexPrefix } from 'ethereumjs-util'; import { addHexPrefix } from 'ethereumjs-util';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { findKey, isEqual } from 'lodash'; import { isEqual } from 'lodash';
import { import {
GAS_ESTIMATE_TYPES, GAS_ESTIMATE_TYPES,
EDIT_GAS_MODES, EDIT_GAS_MODES,
@ -103,32 +103,6 @@ function getGasFeeEstimate(
return String(fallback); return String(fallback);
} }
/**
* This method tries to determine if any estimate level matches the
* current maxFeePerGas and maxPriorityFeePerGas values. If we find
* a match, we can pre-select a radio button in the RadioGroup
*/
function getMatchingEstimateFromGasFees(
gasFeeEstimates,
maxFeePerGas,
maxPriorityFeePerGas,
gasPrice,
networkAndAccountSupports1559,
) {
return (
findKey(gasFeeEstimates, (estimate) => {
if (networkAndAccountSupports1559) {
return (
Number(estimate?.suggestedMaxPriorityFeePerGas) ===
Number(maxPriorityFeePerGas) &&
Number(estimate?.suggestedMaxFeePerGas) === Number(maxFeePerGas)
);
}
return estimate?.gasPrice === gasPrice;
}) || null
);
}
/** /**
* @typedef {Object} GasFeeInputReturnType * @typedef {Object} GasFeeInputReturnType
* @property {DecGweiString} [maxFeePerGas] - the maxFeePerGas input value. * @property {DecGweiString} [maxFeePerGas] - the maxFeePerGas input value.
@ -229,33 +203,30 @@ export function useGasFeeInputs(
); );
const [initialMatchingEstimateLevel] = useState( const [initialMatchingEstimateLevel] = useState(
getMatchingEstimateFromGasFees( transaction?.userFeeLevel || null,
gasFeeEstimates,
initialMaxFeePerGas,
initialMaxPriorityFeePerGas,
initialGasPrice,
networkAndAccountSupports1559,
),
); );
const initialFeeParamsAreCustom =
initialMatchingEstimateLevel === 'custom' ||
initialMatchingEstimateLevel === null;
// This hook keeps track of a few pieces of transitional state. It is // This hook keeps track of a few pieces of transitional state. It is
// transitional because it is only used to modify a transaction in the // transitional because it is only used to modify a transaction in the
// metamask (background) state tree. // metamask (background) state tree.
const [maxFeePerGas, setMaxFeePerGas] = useState( const [maxFeePerGas, setMaxFeePerGas] = useState(
initialMaxFeePerGas && !initialMatchingEstimateLevel initialMaxFeePerGas && initialFeeParamsAreCustom
? initialMaxFeePerGas ? initialMaxFeePerGas
: null, : null,
); );
const [maxPriorityFeePerGas, setMaxPriorityFeePerGas] = useState( const [maxPriorityFeePerGas, setMaxPriorityFeePerGas] = useState(
initialMaxPriorityFeePerGas && !initialMatchingEstimateLevel initialMaxPriorityFeePerGas && initialFeeParamsAreCustom
? initialMaxPriorityFeePerGas ? initialMaxPriorityFeePerGas
: null, : null,
); );
const [gasPriceHasBeenManuallySet, setGasPriceHasBeenManuallySet] = useState( const [gasPriceHasBeenManuallySet, setGasPriceHasBeenManuallySet] = useState(
false, initialMatchingEstimateLevel === 'custom',
); );
const [gasPrice, setGasPrice] = useState( const [gasPrice, setGasPrice] = useState(
initialGasPrice && !initialMatchingEstimateLevel ? initialGasPrice : null, initialGasPrice && initialFeeParamsAreCustom ? initialGasPrice : null,
); );
const [gasLimit, setGasLimit] = useState( const [gasLimit, setGasLimit] = useState(
Number(hexToDecimal(transaction?.txParams?.gas ?? minimumGasLimit)), Number(hexToDecimal(transaction?.txParams?.gas ?? minimumGasLimit)),
@ -265,7 +236,7 @@ export function useGasFeeInputs(
const dontDefaultToAnEstimateLevel = const dontDefaultToAnEstimateLevel =
userPrefersAdvancedGas && userPrefersAdvancedGas &&
transaction?.txParams?.maxPriorityFeePerGas && transaction?.txParams?.maxPriorityFeePerGas &&
transaction?.txParams?.gasPrice; transaction?.txParams?.maxFeePerGas;
const initialEstimateToUse = transaction const initialEstimateToUse = transaction
? initialMatchingEstimateLevel ? initialMatchingEstimateLevel
@ -514,28 +485,28 @@ export function useGasFeeInputs(
{ value: ethBalance, fromNumericBase: 'hex' }, { value: ethBalance, fromNumericBase: 'hex' },
); );
// When a user selects an estimate level, it will wipe out what they have const handleGasLimitOutOfBoundError = useCallback(() => {
// previously put in the inputs. This returns the inputs to the estimated
// values at the level specified.
const setEstimateToUse = useCallback(
(estimateLevel) => {
setInternalEstimateToUse(estimateLevel);
if (gasErrors.gasLimit === GAS_FORM_ERRORS.GAS_LIMIT_OUT_OF_BOUNDS) { if (gasErrors.gasLimit === GAS_FORM_ERRORS.GAS_LIMIT_OUT_OF_BOUNDS) {
const transactionGasLimit = hexToDecimal(transaction?.txParams?.gas); const transactionGasLimitDec = hexToDecimal(transaction?.txParams?.gas);
const minimumGasLimitDec = hexToDecimal(minimumGasLimit); const minimumGasLimitDec = hexToDecimal(minimumGasLimit);
setGasLimit( setGasLimit(
transactionGasLimit > minimumGasLimitDec transactionGasLimitDec > minimumGasLimitDec
? transactionGasLimit ? transactionGasLimitDec
: minimumGasLimitDec, : minimumGasLimitDec,
); );
} }
}, [minimumGasLimit, gasErrors.gasLimit, transaction]);
// When a user selects an estimate level, it will wipe out what they have
// previously put in the inputs. This returns the inputs to the estimated
// values at the level specified.
const setEstimateToUse = (estimateLevel) => {
setInternalEstimateToUse(estimateLevel);
handleGasLimitOutOfBoundError();
setMaxFeePerGas(null); setMaxFeePerGas(null);
setMaxPriorityFeePerGas(null); setMaxPriorityFeePerGas(null);
setGasPrice(null); setGasPrice(null);
setGasPriceHasBeenManuallySet(false); setGasPriceHasBeenManuallySet(false);
}, };
[minimumGasLimit, gasErrors.gasLimit, transaction],
);
return { return {
maxFeePerGas: maxFeePerGasToUse, maxFeePerGas: maxFeePerGasToUse,
@ -561,7 +532,8 @@ export function useGasFeeInputs(
gasErrors: errorsAndWarnings, gasErrors: errorsAndWarnings,
hasGasErrors: hasBlockingGasErrors, hasGasErrors: hasBlockingGasErrors,
onManualChange: () => { onManualChange: () => {
setEstimateToUse(null); setInternalEstimateToUse('custom');
handleGasLimitOutOfBoundError();
// Restore existing values // Restore existing values
setGasPrice(gasPriceToUse); setGasPrice(gasPriceToUse);
setGasLimit(gasLimit); setGasLimit(gasLimit);

View File

@ -13,7 +13,6 @@ import {
getTokenValueParam, getTokenValueParam,
} from '../../helpers/utils/token-util'; } from '../../helpers/utils/token-util';
import { hexWEIToDecETH } from '../../helpers/utils/conversions.util'; import { hexWEIToDecETH } from '../../helpers/utils/conversions.util';
import { getHexGasTotal } from '../../helpers/utils/confirm-tx.util';
import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component'; import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component';
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
@ -34,32 +33,28 @@ const mapStateToProps = (state, ownProps) => {
const { const {
txData: { txData: {
id: transactionId, id: transactionId,
txParams: { to: tokenAddress, data, maxFeePerGas, gasPrice, gas } = {}, txParams: { to: tokenAddress, data } = {},
} = {}, } = {},
} = confirmTransaction; } = confirmTransaction;
const ethTransactionTotalMaxAmount = Number(
hexWEIToDecETH(
getHexGasTotal({
gasPrice: maxFeePerGas ?? gasPrice,
gasLimit: gas,
}),
),
).toFixed(6);
const transaction = const transaction =
currentNetworkTxList.find( currentNetworkTxList.find(
({ id }) => id === (Number(paramsTransactionId) || transactionId), ({ id }) => id === (Number(paramsTransactionId) || transactionId),
) || {}; ) || {};
const { ethTransactionTotal, fiatTransactionTotal } = transactionFeeSelector( const {
state, ethTransactionTotal,
transaction, fiatTransactionTotal,
); hexMaximumTransactionFee,
} = transactionFeeSelector(state, transaction);
const tokens = getTokens(state); const tokens = getTokens(state);
const currentToken = tokens?.find(({ address }) => tokenAddress === address); const currentToken = tokens?.find(({ address }) => tokenAddress === address);
const { decimals, symbol: tokenSymbol } = currentToken || {}; const { decimals, symbol: tokenSymbol } = currentToken || {};
const ethTransactionTotalMaxAmount = Number(
hexWEIToDecETH(hexMaximumTransactionFee),
).toFixed(6);
const tokenData = getTokenData(data); const tokenData = getTokenData(data);
const tokenValue = getTokenValueParam(tokenData); const tokenValue = getTokenValueParam(tokenData);
const toAddress = getTokenAddressParam(tokenData); const toAddress = getTokenAddressParam(tokenData);

View File

@ -4,7 +4,6 @@ import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../shared/constants/app';
import { getEnvironmentType } from '../../../app/scripts/lib/util'; import { getEnvironmentType } from '../../../app/scripts/lib/util';
import ConfirmPageContainer from '../../components/app/confirm-page-container'; import ConfirmPageContainer from '../../components/app/confirm-page-container';
import { isBalanceSufficient } from '../send/send.utils'; import { isBalanceSufficient } from '../send/send.utils';
import { getHexGasTotal } from '../../helpers/utils/confirm-tx.util';
import { import {
addHexes, addHexes,
hexToDecimal, hexToDecimal,
@ -110,6 +109,8 @@ export default class ConfirmTransactionBase extends Component {
gasIsLoading: PropTypes.bool, gasIsLoading: PropTypes.bool,
primaryTotalTextOverrideMaxAmount: PropTypes.string, primaryTotalTextOverrideMaxAmount: PropTypes.string,
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
maxFeePerGas: PropTypes.string,
maxPriorityFeePerGas: PropTypes.string,
}; };
state = { state = {
@ -275,6 +276,7 @@ export default class ConfirmTransactionBase extends Component {
primaryTotalTextOverride, primaryTotalTextOverride,
secondaryTotalTextOverride, secondaryTotalTextOverride,
hexMinimumTransactionFee, hexMinimumTransactionFee,
hexMaximumTransactionFee,
hexTransactionTotal, hexTransactionTotal,
useNonceField, useNonceField,
customNonceValue, customNonceValue,
@ -283,8 +285,9 @@ export default class ConfirmTransactionBase extends Component {
getNextNonce, getNextNonce,
txData, txData,
useNativeCurrencyAsPrimaryCurrency, useNativeCurrencyAsPrimaryCurrency,
hexMaximumTransactionFee,
primaryTotalTextOverrideMaxAmount, primaryTotalTextOverrideMaxAmount,
maxFeePerGas,
maxPriorityFeePerGas,
} = this.props; } = this.props;
const { t } = this.context; const { t } = this.context;
@ -305,14 +308,7 @@ export default class ConfirmTransactionBase extends Component {
return ( return (
<UserPreferencedCurrencyDisplay <UserPreferencedCurrencyDisplay
type={PRIMARY} type={PRIMARY}
value={addHexes( value={addHexes(txData.txParams.value, hexMaximumTransactionFee)}
txData.txParams.value,
getHexGasTotal({
gasPrice:
txData.txParams.maxFeePerGas ?? txData.txParams.gasPrice,
gasLimit: txData.txParams.gas,
}),
)}
hideLabel={!useNativeCurrencyAsPrimaryCurrency} hideLabel={!useNativeCurrencyAsPrimaryCurrency}
/> />
); );
@ -467,9 +463,12 @@ export default class ConfirmTransactionBase extends Component {
subTitle={ subTitle={
<GasTiming <GasTiming
maxPriorityFeePerGas={hexWEIToDecGWEI( maxPriorityFeePerGas={hexWEIToDecGWEI(
maxPriorityFeePerGas ||
txData.txParams.maxPriorityFeePerGas, txData.txParams.maxPriorityFeePerGas,
)} )}
maxFeePerGas={hexWEIToDecGWEI(txData.txParams.maxFeePerGas)} maxFeePerGas={hexWEIToDecGWEI(
maxFeePerGas || txData.txParams.maxFeePerGas,
)}
/> />
} }
/>, />,
@ -611,6 +610,8 @@ export default class ConfirmTransactionBase extends Component {
history, history,
mostRecentOverviewPage, mostRecentOverviewPage,
updateCustomNonce, updateCustomNonce,
maxFeePerGas,
maxPriorityFeePerGas,
} = this.props; } = this.props;
const { submitting } = this.state; const { submitting } = this.state;
@ -618,6 +619,20 @@ export default class ConfirmTransactionBase extends Component {
return; return;
} }
if (maxFeePerGas) {
txData.txParams = {
...txData.txParams,
maxFeePerGas,
};
}
if (maxPriorityFeePerGas) {
txData.txParams = {
...txData.txParams,
maxPriorityFeePerGas,
};
}
this.setState( this.setState(
{ {
submitting: true, submitting: true,

View File

@ -118,6 +118,7 @@ const mapStateToProps = (state, ownProps) => {
hexMinimumTransactionFee, hexMinimumTransactionFee,
hexMaximumTransactionFee, hexMaximumTransactionFee,
hexTransactionTotal, hexTransactionTotal,
gasEstimationObject,
} = transactionFeeSelector(state, transaction); } = transactionFeeSelector(state, transaction);
if (transaction && transaction.simulationFails) { if (transaction && transaction.simulationFails) {
@ -152,8 +153,9 @@ const mapStateToProps = (state, ownProps) => {
} }
customNonceValue = getCustomNonceValue(state); customNonceValue = getCustomNonceValue(state);
const isEthGasPrice = getIsEthGasPriceFetched(state); const isEthGasPrice = getIsEthGasPriceFetched(state);
const noGasPrice = getNoGasPriceFetched(state); const noGasPrice = !supportsEIP1599 && getNoGasPriceFetched(state);
const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
return { return {
balance, balance,
fromAddress, fromAddress,
@ -196,6 +198,8 @@ const mapStateToProps = (state, ownProps) => {
supportsEIP1599, supportsEIP1599,
gasIsLoading: isGasEstimatesLoading || gasLoadingAnimationIsShowing, gasIsLoading: isGasEstimatesLoading || gasLoadingAnimationIsShowing,
useNativeCurrencyAsPrimaryCurrency, useNativeCurrencyAsPrimaryCurrency,
maxFeePerGas: gasEstimationObject.maxFeePerGas,
maxPriorityFeePerGas: gasEstimationObject.maxPriorityFeePerGas,
}; };
}; };

View File

@ -26,6 +26,7 @@ import {
getCustomSwapsGas, // Gas limit. getCustomSwapsGas, // Gas limit.
getCustomMaxFeePerGas, getCustomMaxFeePerGas,
getCustomMaxPriorityFeePerGas, getCustomMaxPriorityFeePerGas,
getSwapsUserFeeLevel,
getDestinationTokenInfo, getDestinationTokenInfo,
getUsedSwapsGasPrice, getUsedSwapsGasPrice,
getTopQuote, getTopQuote,
@ -128,6 +129,7 @@ export default function ViewQuote() {
const customMaxGas = useSelector(getCustomSwapsGas); const customMaxGas = useSelector(getCustomSwapsGas);
const customMaxFeePerGas = useSelector(getCustomMaxFeePerGas); const customMaxFeePerGas = useSelector(getCustomMaxFeePerGas);
const customMaxPriorityFeePerGas = useSelector(getCustomMaxPriorityFeePerGas); const customMaxPriorityFeePerGas = useSelector(getCustomMaxPriorityFeePerGas);
const swapsUserFeeLevel = useSelector(getSwapsUserFeeLevel);
const tokenConversionRates = useSelector(getTokenExchangeRates); const tokenConversionRates = useSelector(getTokenExchangeRates);
const memoizedTokenConversionRates = useEqualityCheck(tokenConversionRates); const memoizedTokenConversionRates = useEqualityCheck(tokenConversionRates);
const { balance: ethBalance } = useSelector(getSelectedAccount); const { balance: ethBalance } = useSelector(getSelectedAccount);
@ -153,7 +155,9 @@ export default function ViewQuote() {
if (networkAndAccountSupports1559) { if (networkAndAccountSupports1559) {
// For Swaps we want to get 'high' estimations by default. // For Swaps we want to get 'high' estimations by default.
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
gasFeeInputs = useGasFeeInputs('high'); gasFeeInputs = useGasFeeInputs('high', {
userFeeLevel: swapsUserFeeLevel || 'high',
});
} }
const { isBestQuote } = usedQuote; const { isBestQuote } = usedQuote;
@ -670,6 +674,7 @@ export default function ViewQuote() {
{showEditGasPopover && networkAndAccountSupports1559 && ( {showEditGasPopover && networkAndAccountSupports1559 && (
<EditGasPopover <EditGasPopover
transaction={{ transaction={{
userFeeLevel: swapsUserFeeLevel || 'high',
txParams: { txParams: {
maxFeePerGas, maxFeePerGas,
maxPriorityFeePerGas, maxPriorityFeePerGas,

View File

@ -240,20 +240,28 @@ export const transactionFeeSelector = function (state, txData) {
}; };
if (networkAndAccountSupportsEIP1559) { if (networkAndAccountSupportsEIP1559) {
const { medium = {}, gasPrice = '0' } = gasFeeEstimates; const { gasPrice = '0' } = gasFeeEstimates;
const selectedGasEstimates = gasFeeEstimates[txData.userFeeLevel] || {};
if (txData.txParams?.type === TRANSACTION_ENVELOPE_TYPES.LEGACY) { if (txData.txParams?.type === TRANSACTION_ENVELOPE_TYPES.LEGACY) {
gasEstimationObject.gasPrice = gasEstimationObject.gasPrice =
txData.txParams?.gasPrice ?? decGWEIToHexWEI(gasPrice); txData.txParams?.gasPrice ?? decGWEIToHexWEI(gasPrice);
} else { } else {
const { suggestedMaxPriorityFeePerGas, suggestedMaxFeePerGas } = medium; const {
suggestedMaxPriorityFeePerGas,
suggestedMaxFeePerGas,
} = selectedGasEstimates;
gasEstimationObject.maxFeePerGas = gasEstimationObject.maxFeePerGas =
txData.txParams?.maxFeePerGas ?? txData.txParams?.maxFeePerGas &&
decGWEIToHexWEI(suggestedMaxFeePerGas || gasPrice); (txData.userFeeLevel === 'custom' || !suggestedMaxFeePerGas)
? txData.txParams?.maxFeePerGas
: decGWEIToHexWEI(suggestedMaxFeePerGas || gasPrice);
gasEstimationObject.maxPriorityFeePerGas = gasEstimationObject.maxPriorityFeePerGas =
txData.txParams?.maxPriorityFeePerGas ?? txData.txParams?.maxPriorityFeePerGas &&
((suggestedMaxPriorityFeePerGas && (txData.userFeeLevel === 'custom' || !suggestedMaxPriorityFeePerGas)
? txData.txParams?.maxPriorityFeePerGas
: (suggestedMaxPriorityFeePerGas &&
decGWEIToHexWEI(suggestedMaxPriorityFeePerGas)) || decGWEIToHexWEI(suggestedMaxPriorityFeePerGas)) ||
gasEstimationObject.maxFeePerGas); gasEstimationObject.maxFeePerGas;
gasEstimationObject.baseFeePerGas = decGWEIToHexWEI( gasEstimationObject.baseFeePerGas = decGWEIToHexWEI(
gasFeeEstimates.estimatedBaseFee, gasFeeEstimates.estimatedBaseFee,
); );
@ -346,5 +354,6 @@ export const transactionFeeSelector = function (state, txData) {
fiatTransactionTotal, fiatTransactionTotal,
ethTransactionTotal, ethTransactionTotal,
hexTransactionTotal, hexTransactionTotal,
gasEstimationObject,
}; };
}; };

View File

@ -2215,6 +2215,13 @@ export function updateCustomSwapsEIP1559GasParams({
}; };
} }
export function updateSwapsUserFeeLevel(swapsCustomUserFeeLevel) {
return async (dispatch) => {
await promisifiedBackground.setSwapsUserFeeLevel(swapsCustomUserFeeLevel);
await forceUpdateMetamaskState(dispatch);
};
}
export function customSwapsGasParamsUpdated(gasLimit, gasPrice) { export function customSwapsGasParamsUpdated(gasLimit, gasPrice) {
return async (dispatch) => { return async (dispatch) => {
await promisifiedBackground.setSwapsTxGasPrice(gasPrice); await promisifiedBackground.setSwapsTxGasPrice(gasPrice);