From 2c6fb061142dcb8b9b8286136c97fbc424c04de3 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Fri, 19 Nov 2021 00:38:29 +0530 Subject: [PATCH] Edit gas fee modal more changes (#12660) --- app/_locales/en/messages.json | 6 +- shared/constants/gas.js | 11 ++ .../edit-gas-fee-popover.js | 25 +++- .../edit-gas-fee-popover.test.js | 8 +- .../edit-gas-item/edit-gas-item.js | 120 ++++++++++++++---- .../edit-gas-item/edit-gas-item.test.js | 73 +++++++++-- .../edit-gas-item/index.scss | 14 +- .../edit-gas-item/useCustomTimeEstimate.js | 83 ++++++++++++ .../app/edit-gas-fee-popover/index.scss | 5 + .../transaction-detail.component.js | 27 ++-- ui/contexts/gasFee.js | 2 +- ui/hooks/gasFeeInput/useGasFeeInputs.js | 19 ++- .../gasFeeInput/useTransactionFunctions.js | 47 +++++-- .../gas-details-item/gas-details-item.js | 20 ++- .../gas-details-item/gas-details-item.test.js | 29 +++-- 15 files changed, 380 insertions(+), 109 deletions(-) create mode 100644 ui/components/app/edit-gas-fee-popover/edit-gas-item/useCustomTimeEstimate.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7e65268e4..36654de69 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -581,6 +581,9 @@ "dappSuggested": { "message": "Site suggested" }, + "dappSuggestedShortLabel": { + "message": "Site" + }, "dappSuggestedTooltip": { "message": "$1 has recommended this price.", "description": "$1 represents the Dapp's origin" @@ -1035,9 +1038,6 @@ "gasPriceInfoTooltipContent": { "message": "Gas price specifies the amount of Ether you are willing to pay for each unit of gas." }, - "gasPriceLabel": { - "message": "Gas price" - }, "gasTimingHoursShort": { "message": "$1 hrs", "description": "$1 represents a number of hours" diff --git a/shared/constants/gas.js b/shared/constants/gas.js index 1c0bc8ae7..01d490960 100644 --- a/shared/constants/gas.js +++ b/shared/constants/gas.js @@ -30,6 +30,17 @@ export const GAS_RECOMMENDATIONS = { HIGH: 'high', }; +/** + * These represent types of gas estimation + */ +export const PRIORITY_LEVELS = { + LOW: 'low', + MEDIUM: 'medium', + HIGH: 'high', + CUSTOM: 'custom', + DAPP_SUGGESTED: 'dappSuggested', +}; + /** * Represents the user customizing their gas preference */ diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js index 84f31a256..afbaefc53 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { PRIORITY_LEVELS } from '../../../../shared/constants/gas'; import { useI18nContext } from '../../../hooks/useI18nContext'; import Popover from '../../ui/popover'; import I18nValue from '../../ui/i18n-value'; @@ -32,9 +33,27 @@ const EditGasFeePopover = ({ onClose }) => { - - - + + + +
+ +
diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js index cd4f772dc..2131e0205 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js @@ -71,16 +71,18 @@ describe('EditGasFeePopover', () => { expect(screen.queryByText('🐢')).toBeInTheDocument(); expect(screen.queryByText('🦊')).toBeInTheDocument(); expect(screen.queryByText('🦍')).toBeInTheDocument(); + expect(screen.queryByText('🌐')).toBeInTheDocument(); + expect(screen.queryByText('⚙')).toBeInTheDocument(); expect(screen.queryByText('Low')).toBeInTheDocument(); expect(screen.queryByText('Market')).toBeInTheDocument(); expect(screen.queryByText('Aggressive')).toBeInTheDocument(); + expect(screen.queryByText('Site')).toBeInTheDocument(); + expect(screen.queryByText('Advanced')).toBeInTheDocument(); }); it('should show time estimates', () => { renderComponent(); - console.log(document.body.innerHTML); - expect(screen.queryByText('6 min')).toBeInTheDocument(); - expect(screen.queryByText('30 sec')).toBeInTheDocument(); + expect(screen.queryAllByText('5 min')).toHaveLength(2); expect(screen.queryByText('15 sec')).toBeInTheDocument(); }); diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.js b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.js index 59cf3ac01..9fe5d5889 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.js @@ -1,14 +1,18 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import { useSelector } from 'react-redux'; import { getMaximumGasTotalInHexWei } from '../../../../../shared/modules/gas.utils'; +import { PRIORITY_LEVELS } from '../../../../../shared/constants/gas'; import { PRIORITY_LEVEL_ICON_MAP } from '../../../../helpers/constants/gas'; import { PRIMARY } from '../../../../helpers/constants/common'; import { decGWEIToHexWEI, decimalToHex, + hexWEIToDecGWEI, } from '../../../../helpers/utils/conversions.util'; +import { getAdvancedGasFeeValues } from '../../../../selectors'; import { toHumanReadableTime } from '../../../../helpers/utils/util'; import { useGasFeeContext } from '../../../../contexts/gasFee'; import { useI18nContext } from '../../../../hooks/useI18nContext'; @@ -16,59 +20,121 @@ import I18nValue from '../../../ui/i18n-value'; import InfoTooltip from '../../../ui/info-tooltip'; import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'; -const EditGasItem = ({ estimateType, onClose }) => { +import { useCustomTimeEstimate } from './useCustomTimeEstimate'; + +const EditGasItem = ({ priorityLevel, onClose }) => { const { estimateUsed, gasFeeEstimates, gasLimit, - setEstimateToUse, - updateTransaction, + maxFeePerGas: maxFeePerGasValue, + maxPriorityFeePerGas: maxPriorityFeePerGasValue, + updateTransactionUsingGasFeeEstimates, + transaction: { dappSuggestedGasFees }, } = useGasFeeContext(); const t = useI18nContext(); + const advancedGasFeeValues = useSelector(getAdvancedGasFeeValues); + let maxFeePerGas; + let maxPriorityFeePerGas; + let minWaitTime; - const { minWaitTimeEstimate, suggestedMaxFeePerGas } = - gasFeeEstimates[estimateType] || {}; - const hexMaximumTransactionFee = suggestedMaxFeePerGas + if (gasFeeEstimates[priorityLevel]) { + maxFeePerGas = gasFeeEstimates[priorityLevel].suggestedMaxFeePerGas; + } else if ( + priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED && + dappSuggestedGasFees + ) { + maxFeePerGas = hexWEIToDecGWEI(dappSuggestedGasFees.maxFeePerGas); + maxPriorityFeePerGas = hexWEIToDecGWEI( + dappSuggestedGasFees.maxPriorityFeePerGas, + ); + } else if (priorityLevel === PRIORITY_LEVELS.CUSTOM) { + if (estimateUsed === PRIORITY_LEVELS.CUSTOM) { + maxFeePerGas = maxFeePerGasValue; + maxPriorityFeePerGas = maxPriorityFeePerGasValue; + } else if (advancedGasFeeValues) { + maxFeePerGas = + gasFeeEstimates.estimatedBaseFee * + parseFloat(advancedGasFeeValues.maxBaseFee); + maxPriorityFeePerGas = advancedGasFeeValues.priorityFee; + } + } + + const { waitTimeEstimate } = useCustomTimeEstimate({ + gasFeeEstimates, + maxFeePerGas, + maxPriorityFeePerGas, + }); + + if (gasFeeEstimates[priorityLevel]) { + minWaitTime = + priorityLevel === PRIORITY_LEVELS.HIGH + ? gasFeeEstimates?.high.minWaitTimeEstimate + : gasFeeEstimates?.low.maxWaitTimeEstimate; + } else { + minWaitTime = waitTimeEstimate; + } + + const hexMaximumTransactionFee = maxFeePerGas ? getMaximumGasTotalInHexWei({ gasLimit: decimalToHex(gasLimit), - maxFeePerGas: decGWEIToHexWEI(suggestedMaxFeePerGas), + maxFeePerGas: decGWEIToHexWEI(maxFeePerGas), }) : null; const onOptionSelect = () => { - setEstimateToUse(estimateType); - updateTransaction(estimateType); + if (priorityLevel !== PRIORITY_LEVELS.CUSTOM) { + updateTransactionUsingGasFeeEstimates(priorityLevel); + } + // todo: open advance modal if priorityLevel is custom onClose(); }; return (
- - {PRIORITY_LEVEL_ICON_MAP[estimateType]} + + {PRIORITY_LEVEL_ICON_MAP[priorityLevel]} - - - - {minWaitTimeEstimate && toHumanReadableTime(t, minWaitTimeEstimate)} - - - + + {minWaitTime + ? minWaitTime && toHumanReadableTime(t, minWaitTime) + : '--'} + + + {hexMaximumTransactionFee ? ( + + ) : ( + '--' + )} + @@ -77,7 +143,7 @@ const EditGasItem = ({ estimateType, onClose }) => { }; EditGasItem.propTypes = { - estimateType: PropTypes.string, + priorityLevel: PropTypes.string, onClose: PropTypes.func, }; diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js index 4d8a40f88..30280fe11 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js @@ -14,6 +14,9 @@ jest.mock('../../../../store/actions', () => ({ .fn() .mockImplementation(() => Promise.resolve()), addPollingTokenToAppState: jest.fn(), + getGasFeeTimeEstimate: jest + .fn() + .mockImplementation(() => Promise.resolve('unknown')), })); const MOCK_FEE_ESTIMATE = { @@ -38,7 +41,12 @@ const MOCK_FEE_ESTIMATE = { estimatedBaseFee: '50', }; -const renderComponent = (props) => { +const DAPP_SUGGESTED_ESTIMATE = { + maxFeePerGas: '0x59682f10', + maxPriorityFeePerGas: '0x59682f00', +}; + +const renderComponent = (props, transactionProps, gasFeeContextProps) => { const store = configureStore({ metamask: { nativeCurrency: ETH, @@ -53,41 +61,78 @@ const renderComponent = (props) => { selectedAddress: '0xAddress', featureFlags: { advancedInlineGas: true }, gasFeeEstimates: MOCK_FEE_ESTIMATE, + advancedGasFee: { + maxBaseFee: '1.5', + priorityFee: '2', + }, }, }); return renderWithProvider( - - + + , store, ); }; describe('EditGasItem', () => { - it('should renders low gas estimate options for estimateType low', () => { - renderComponent({ estimateType: 'low' }); - + it('should renders low gas estimate option for priorityLevel low', () => { + renderComponent({ priorityLevel: 'low' }); expect(screen.queryByText('🐢')).toBeInTheDocument(); expect(screen.queryByText('Low')).toBeInTheDocument(); - expect(screen.queryByText('6 min')).toBeInTheDocument(); + expect(screen.queryByText('5 min')).toBeInTheDocument(); expect(screen.queryByTitle('0.001113 ETH')).toBeInTheDocument(); }); - it('should renders market gas estimate options for estimateType medium', () => { - renderComponent({ estimateType: 'medium' }); - + it('should renders market gas estimate option for priorityLevel medium', () => { + renderComponent({ priorityLevel: 'medium' }); expect(screen.queryByText('🦊')).toBeInTheDocument(); expect(screen.queryByText('Market')).toBeInTheDocument(); - expect(screen.queryByText('30 sec')).toBeInTheDocument(); + expect(screen.queryByText('5 min')).toBeInTheDocument(); expect(screen.queryByTitle('0.00147 ETH')).toBeInTheDocument(); }); - it('should renders aggressive gas estimate options for estimateType high', () => { - renderComponent({ estimateType: 'high' }); - + it('should renders aggressive gas estimate option for priorityLevel high', () => { + renderComponent({ priorityLevel: 'high' }); expect(screen.queryByText('🦍')).toBeInTheDocument(); + expect(screen.queryByText('Aggressive')).toBeInTheDocument(); expect(screen.queryByText('15 sec')).toBeInTheDocument(); expect(screen.queryByTitle('0.0021 ETH')).toBeInTheDocument(); }); + + it('should highlight option is priorityLevel is currently selected', () => { + renderComponent({ priorityLevel: 'high' }, { userFeeLevel: 'high' }); + expect( + document.getElementsByClassName('edit-gas-item-selected'), + ).toHaveLength(1); + }); + + it('should renders site gas estimate option for priorityLevel dappSuggested', () => { + renderComponent( + { priorityLevel: 'dappSuggested' }, + { dappSuggestedGasFees: DAPP_SUGGESTED_ESTIMATE }, + ); + expect(screen.queryByText('🌐')).toBeInTheDocument(); + expect(screen.queryByText('Site')).toBeInTheDocument(); + expect(screen.queryByTitle('0.0000315 ETH')).toBeInTheDocument(); + }); + + it('should disable site gas estimate option for is transaction does not have dappSuggestedGasFees', async () => { + renderComponent({ priorityLevel: 'dappSuggested' }); + expect( + document.getElementsByClassName('edit-gas-item-disabled'), + ).toHaveLength(1); + }); + + it('should renders advance gas estimate option for priorityLevel custom', () => { + renderComponent({ priorityLevel: 'custom' }); + expect(screen.queryByText('⚙')).toBeInTheDocument(); + expect(screen.queryByText('Advanced')).toBeInTheDocument(); + // below value of custom gas fee estimate is default obtained from state.metamask.advancedGasFee + expect(screen.queryByTitle('0.001575 ETH')).toBeInTheDocument(); + }); }); diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/index.scss b/ui/components/app/edit-gas-fee-popover/edit-gas-item/index.scss index 17072a813..95061e43a 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-item/index.scss +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/index.scss @@ -3,6 +3,8 @@ color: $ui-4; cursor: pointer; font-size: 12px; + display: flex; + align-items: center; margin: 12px 0; padding: 4px 12px; height: 32px; @@ -11,8 +13,13 @@ background-color: $ui-1; } + &-disabled { + cursor: default; + } + &__name { - display: inline-block; + display: inline-flex; + align-items: center; color: $ui-black; font-size: 12px; font-weight: bold; @@ -21,6 +28,11 @@ &__icon { margin-right: 4px; + + &-custom { + font-size: 20px; + line-height: 0; + } } &__time-estimate { diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/useCustomTimeEstimate.js b/ui/components/app/edit-gas-fee-popover/edit-gas-item/useCustomTimeEstimate.js new file mode 100644 index 000000000..41d6c59ed --- /dev/null +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/useCustomTimeEstimate.js @@ -0,0 +1,83 @@ +import { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import BigNumber from 'bignumber.js'; + +import { GAS_ESTIMATE_TYPES } from '../../../../../shared/constants/gas'; +import { + getGasEstimateType, + getIsGasEstimatesLoading, +} from '../../../../ducks/metamask/metamask'; +import { getGasFeeTimeEstimate } from '../../../../store/actions'; + +export const useCustomTimeEstimate = ({ + gasFeeEstimates, + maxFeePerGas, + maxPriorityFeePerGas, +}) => { + const gasEstimateType = useSelector(getGasEstimateType); + const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading); + + const [customEstimatedTime, setCustomEstimatedTime] = useState(null); + + const returnNoEstimates = + isGasEstimatesLoading || + gasEstimateType !== GAS_ESTIMATE_TYPES.FEE_MARKET || + !maxPriorityFeePerGas; + + // If the user has chosen a value lower than the low gas fee estimate, + // We'll need to use the useEffect hook below to make a call to calculate + // the time to show + const isUnknownLow = + gasFeeEstimates?.low && + Number(maxPriorityFeePerGas) < + Number(gasFeeEstimates.low.suggestedMaxPriorityFeePerGas); + + useEffect(() => { + if ( + isGasEstimatesLoading || + gasEstimateType !== GAS_ESTIMATE_TYPES.FEE_MARKET || + !maxPriorityFeePerGas + ) + return; + if (isUnknownLow) { + // getGasFeeTimeEstimate requires parameters in string format + getGasFeeTimeEstimate( + new BigNumber(maxPriorityFeePerGas, 10).toString(10), + new BigNumber(maxFeePerGas, 10).toString(10), + ).then((result) => { + setCustomEstimatedTime(result); + }); + } + }, [ + gasEstimateType, + isUnknownLow, + isGasEstimatesLoading, + maxFeePerGas, + maxPriorityFeePerGas, + returnNoEstimates, + ]); + + if (returnNoEstimates) { + return {}; + } + + const { low = {}, medium = {}, high = {} } = gasFeeEstimates; + let waitTimeEstimate = ''; + + if ( + isUnknownLow && + customEstimatedTime && + customEstimatedTime !== 'unknown' && + customEstimatedTime?.upperTimeBound !== 'unknown' + ) { + waitTimeEstimate = Number(customEstimatedTime?.upperTimeBound); + } else if ( + Number(maxPriorityFeePerGas) >= Number(medium.suggestedMaxPriorityFeePerGas) + ) { + waitTimeEstimate = high.minWaitTimeEstimate; + } else { + waitTimeEstimate = low.maxWaitTimeEstimate; + } + + return { waitTimeEstimate }; +}; diff --git a/ui/components/app/edit-gas-fee-popover/index.scss b/ui/components/app/edit-gas-fee-popover/index.scss index 0e149efbc..f892e8a71 100644 --- a/ui/components/app/edit-gas-fee-popover/index.scss +++ b/ui/components/app/edit-gas-fee-popover/index.scss @@ -31,5 +31,10 @@ width: 30%; } } + + &__separator { + border-top: 1px solid $ui-grey; + margin: 8px 12px; + } } } diff --git a/ui/components/app/transaction-detail/transaction-detail.component.js b/ui/components/app/transaction-detail/transaction-detail.component.js index 64677883a..2f000e59e 100644 --- a/ui/components/app/transaction-detail/transaction-detail.component.js +++ b/ui/components/app/transaction-detail/transaction-detail.component.js @@ -17,12 +17,10 @@ export default function TransactionDetail({ rows = [], onEdit }) { const t = useI18nContext(); const { gasLimit, - gasPrice, estimateUsed, maxFeePerGas, maxPriorityFeePerGas, transaction, - supportsEIP1559, } = useGasFeeContext(); if (EIP_1559_V2 && estimateUsed) { @@ -48,23 +46,14 @@ export default function TransactionDetail({ rows = [], onEdit }) { {t('dappSuggestedTooltip', [transaction.origin])} - {supportsEIP1559 ? ( - <> - - {t('maxBaseFee')} - {maxFeePerGas} - - - {t('maxPriorityFee')} - {maxPriorityFeePerGas} - - - ) : ( - - {t('gasPriceLabel')} - {gasPrice} - - )} + + {t('maxBaseFee')} + {maxFeePerGas} + + + {t('maxPriorityFee')} + {maxPriorityFeePerGas} + {t('gasLimit')} {gasLimit} diff --git a/ui/contexts/gasFee.js b/ui/contexts/gasFee.js index c7fe7f092..65242fe94 100644 --- a/ui/contexts/gasFee.js +++ b/ui/contexts/gasFee.js @@ -31,7 +31,7 @@ export function useGasFeeContext() { GasFeeContextProvider.propTypes = { children: PropTypes.node.isRequired, defaultEstimateToUse: PropTypes.string, - transaction: PropTypes.object.isRequired, + transaction: PropTypes.object, minimumGasLimit: PropTypes.string, editGasMode: PropTypes.string, }; diff --git a/ui/hooks/gasFeeInput/useGasFeeInputs.js b/ui/hooks/gasFeeInput/useGasFeeInputs.js index b7d457aa7..f65897c71 100644 --- a/ui/hooks/gasFeeInput/useGasFeeInputs.js +++ b/ui/hooks/gasFeeInput/useGasFeeInputs.js @@ -1,4 +1,4 @@ -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { @@ -108,6 +108,19 @@ export function useGasFeeInputs( return estimateToUse; }); + /** + * In EIP-1559 V2 designs change to gas estimate is always updated to transaction + * Thus callback setEstimateToUse can be deprecate in favour of this useEffect + * so that transaction is source of truth whenever possible. + */ + useEffect(() => { + if (areDappSuggestedAndTxParamGasFeesTheSame(transaction)) { + setEstimateUsed('dappSuggested'); + } else if (transaction?.userFeeLevel) { + setEstimateUsed(transaction?.userFeeLevel); + } + }, [setEstimateUsed, transaction]); + const [gasLimit, setGasLimit] = useState(() => Number(hexToDecimal(transaction?.txParams?.gas ?? '0x0')), ); @@ -198,7 +211,7 @@ export function useGasFeeInputs( } }, [minimumGasLimit, gasErrors.gasLimit, transaction]); - const { updateTransaction } = useTransactionFunctions({ + const { updateTransactionUsingGasFeeEstimates } = useTransactionFunctions({ defaultEstimateToUse, gasLimit, gasPrice, @@ -289,6 +302,6 @@ export function useGasFeeInputs( gasWarnings, hasGasErrors, supportsEIP1559, - updateTransaction, + updateTransactionUsingGasFeeEstimates, }; } diff --git a/ui/hooks/gasFeeInput/useTransactionFunctions.js b/ui/hooks/gasFeeInput/useTransactionFunctions.js index bc9068b9b..ea891869a 100644 --- a/ui/hooks/gasFeeInput/useTransactionFunctions.js +++ b/ui/hooks/gasFeeInput/useTransactionFunctions.js @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { useDispatch } from 'react-redux'; +import { PRIORITY_LEVELS } from '../../../shared/constants/gas'; import { decGWEIToHexWEI, decimalToHex, @@ -16,24 +17,19 @@ export const useTransactionFunctions = ({ const dispatch = useDispatch(); const updateTransaction = useCallback( - (estimateType) => { + (estimateUsed, maxFeePerGas, maxPriorityFeePerGas) => { const newGasSettings = { gas: decimalToHex(gasLimit), gasLimit: decimalToHex(gasLimit), estimateSuggested: defaultEstimateToUse, - estimateUsed: estimateType, + estimateUsed, + maxFeePerGas, + maxPriorityFeePerGas, }; - newGasSettings.maxFeePerGas = decGWEIToHexWEI( - gasFeeEstimates[estimateType].suggestedMaxFeePerGas, - ); - newGasSettings.maxPriorityFeePerGas = decGWEIToHexWEI( - gasFeeEstimates[estimateType].suggestedMaxPriorityFeePerGas, - ); - const updatedTxMeta = { ...transaction, - userFeeLevel: estimateType || 'custom', + userFeeLevel: estimateUsed || 'custom', txParams: { ...transaction.txParams, ...newGasSettings, @@ -42,8 +38,35 @@ export const useTransactionFunctions = ({ dispatch(updateTransactionFn(updatedTxMeta)); }, - [defaultEstimateToUse, dispatch, gasLimit, gasFeeEstimates, transaction], + [defaultEstimateToUse, dispatch, gasLimit, transaction], ); - return { updateTransaction }; + const updateTransactionUsingGasFeeEstimates = useCallback( + (gasFeeEstimateToUse) => { + if (gasFeeEstimateToUse === PRIORITY_LEVELS.DAPP_SUGGESTED) { + const { + maxFeePerGas, + maxPriorityFeePerGas, + } = transaction?.dappSuggestedGasFees; + updateTransaction( + PRIORITY_LEVELS.CUSTOM, + maxFeePerGas, + maxPriorityFeePerGas, + ); + } else { + const { + suggestedMaxFeePerGas, + suggestedMaxPriorityFeePerGas, + } = gasFeeEstimates[gasFeeEstimateToUse]; + updateTransaction( + gasFeeEstimateToUse, + decGWEIToHexWEI(suggestedMaxFeePerGas), + decGWEIToHexWEI(suggestedMaxPriorityFeePerGas), + ); + } + }, + [gasFeeEstimates, transaction?.dappSuggestedGasFees, updateTransaction], + ); + + return { updateTransactionUsingGasFeeEstimates }; }; diff --git a/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js b/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js index 6db82e185..86fa32f4c 100644 --- a/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js +++ b/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js @@ -26,7 +26,6 @@ const GasDetailsItem = ({ isMainnet, maxFeePerGas, maxPriorityFeePerGas, - supportsEIP1559, txData, useNativeCurrencyAsPrimaryCurrency, }) => { @@ -120,16 +119,14 @@ const GasDetailsItem = ({ , ])} subTitle={ - supportsEIP1559 && ( - - ) + } /> ); @@ -141,7 +138,6 @@ GasDetailsItem.propTypes = { isMainnet: PropTypes.bool, maxFeePerGas: PropTypes.string, maxPriorityFeePerGas: PropTypes.string, - supportsEIP1559: PropTypes.bool, txData: PropTypes.object, useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, }; diff --git a/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.test.js b/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.test.js index 2d8c97fab..2287db844 100644 --- a/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { screen } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import { ETH } from '../../../helpers/constants/common'; import { GasFeeContextProvider } from '../../../contexts/gasFee'; @@ -14,6 +14,7 @@ jest.mock('../../../store/actions', () => ({ .fn() .mockImplementation(() => Promise.resolve()), addPollingTokenToAppState: jest.fn(), + getGasFeeTimeEstimate: jest.fn().mockImplementation(() => Promise.resolve()), })); const render = (props) => { @@ -37,28 +38,34 @@ const render = (props) => { return renderWithProvider( - + , store, ); }; describe('GasDetailsItem', () => { - it('should render label', () => { + it('should render label', async () => { render(); - expect(screen.queryByText('Gas')).toBeInTheDocument(); - expect(screen.queryByText('(estimated)')).toBeInTheDocument(); - expect(screen.queryByText('Max fee:')).toBeInTheDocument(); - expect(screen.queryByText('ETH')).toBeInTheDocument(); + await waitFor(() => { + expect(screen.queryByText('Gas')).toBeInTheDocument(); + expect(screen.queryByText('(estimated)')).toBeInTheDocument(); + expect(screen.queryByText('Max fee:')).toBeInTheDocument(); + expect(screen.queryByText('ETH')).toBeInTheDocument(); + }); }); - it('should show warning icon if estimates are high', () => { + it('should show warning icon if estimates are high', async () => { render({ defaultEstimateToUse: 'high' }); - expect(screen.queryByText('⚠ Max fee:')).toBeInTheDocument(); + await waitFor(() => { + expect(screen.queryByText('⚠ Max fee:')).toBeInTheDocument(); + }); }); - it('should not show warning icon if estimates are not high', () => { + it('should not show warning icon if estimates are not high', async () => { render({ defaultEstimateToUse: 'low' }); - expect(screen.queryByText('Max fee:')).toBeInTheDocument(); + await waitFor(() => { + expect(screen.queryByText('Max fee:')).toBeInTheDocument(); + }); }); });