mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Using EIP-1559 V2 for swaps (#12966)
This commit is contained in:
parent
2085352de8
commit
19c3d021ea
@ -2899,6 +2899,12 @@
|
|||||||
"swapSourceInfo": {
|
"swapSourceInfo": {
|
||||||
"message": "We search multiple liquidity sources (exchanges, aggregators and professional market makers) to find the best rates and lowest network fees."
|
"message": "We search multiple liquidity sources (exchanges, aggregators and professional market makers) to find the best rates and lowest network fees."
|
||||||
},
|
},
|
||||||
|
"swapSuggested": {
|
||||||
|
"message": "Swap suggested"
|
||||||
|
},
|
||||||
|
"swapSuggestedGasSettingToolTipMessage": {
|
||||||
|
"message": "Swaps are complex and time sensitive transactions. We recommend this gas fee for a good balance between cost and confidence of a successful Swap."
|
||||||
|
},
|
||||||
"swapSwapFrom": {
|
"swapSwapFrom": {
|
||||||
"message": "Swap from"
|
"message": "Swap from"
|
||||||
},
|
},
|
||||||
|
@ -258,8 +258,12 @@ export default class ConfirmPageContainer extends Component {
|
|||||||
transaction={currentTransaction}
|
transaction={currentTransaction}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<EditGasFeePopover />
|
{supportsEIP1559V2 && (
|
||||||
<AdvancedGasFeePopover />
|
<>
|
||||||
|
<EditGasFeePopover />
|
||||||
|
<AdvancedGasFeePopover />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</GasFeeContextProvider>
|
</GasFeeContextProvider>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { COLORS } from '../../../helpers/constants/design-system';
|
import {
|
||||||
|
EDIT_GAS_MODES,
|
||||||
|
PRIORITY_LEVELS,
|
||||||
|
} from '../../../../shared/constants/gas';
|
||||||
|
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system';
|
||||||
import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas';
|
import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas';
|
||||||
import { useGasFeeContext } from '../../../contexts/gasFee';
|
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
@ -12,6 +16,7 @@ import Typography from '../../ui/typography/typography';
|
|||||||
export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const {
|
const {
|
||||||
|
editGasMode,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
hasSimulationError,
|
hasSimulationError,
|
||||||
estimateUsed,
|
estimateUsed,
|
||||||
@ -28,13 +33,23 @@ export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let icon = estimateUsed;
|
||||||
|
let title = estimateUsed;
|
||||||
|
if (
|
||||||
|
estimateUsed === PRIORITY_LEVELS.HIGH &&
|
||||||
|
editGasMode === EDIT_GAS_MODES.SWAPS
|
||||||
|
) {
|
||||||
|
icon = 'swapSuggested';
|
||||||
|
title = 'swapSuggested';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="edit-gas-fee-button">
|
<div className="edit-gas-fee-button">
|
||||||
<button onClick={() => openModal('editGasFee')}>
|
<button onClick={() => openModal('editGasFee')}>
|
||||||
<span className="edit-gas-fee-button__icon">
|
<span className="edit-gas-fee-button__icon">
|
||||||
{`${PRIORITY_LEVEL_ICON_MAP[estimateUsed]} `}
|
{`${PRIORITY_LEVEL_ICON_MAP[icon]} `}
|
||||||
</span>
|
</span>
|
||||||
<span className="edit-gas-fee-button__label">{t(estimateUsed)}</span>
|
<span className="edit-gas-fee-button__label">{t(title)}</span>
|
||||||
<i className="fas fa-chevron-right asset-list-item__chevron-right" />
|
<i className="fas fa-chevron-right asset-list-item__chevron-right" />
|
||||||
</button>
|
</button>
|
||||||
{estimateUsed === 'custom' && (
|
{estimateUsed === 'custom' && (
|
||||||
@ -44,18 +59,18 @@ export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
|||||||
<InfoTooltip
|
<InfoTooltip
|
||||||
contentText={
|
contentText={
|
||||||
<div className="edit-gas-fee-button__tooltip">
|
<div className="edit-gas-fee-button__tooltip">
|
||||||
<Typography fontSize="12px" color={COLORS.GREY}>
|
<Typography variant={TYPOGRAPHY.H7} color={COLORS.GREY}>
|
||||||
{t('dappSuggestedTooltip', [transaction.origin])}
|
{t('dappSuggestedTooltip', [transaction.origin])}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography fontSize="12px">
|
<Typography variant={TYPOGRAPHY.H7}>
|
||||||
<b>{t('maxBaseFee')}</b>
|
<b>{t('maxBaseFee')}</b>
|
||||||
{maxFeePerGas}
|
{maxFeePerGas}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography fontSize="12px">
|
<Typography variant={TYPOGRAPHY.H7}>
|
||||||
<b>{t('maxPriorityFee')}</b>
|
<b>{t('maxPriorityFee')}</b>
|
||||||
{maxPriorityFeePerGas}
|
{maxPriorityFeePerGas}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography fontSize="12px">
|
<Typography variant={TYPOGRAPHY.H7}>
|
||||||
<b>{t('gasLimit')}</b>
|
<b>{t('gasLimit')}</b>
|
||||||
{gasLimit}
|
{gasLimit}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
EDIT_GAS_MODES,
|
||||||
GAS_ESTIMATE_TYPES,
|
GAS_ESTIMATE_TYPES,
|
||||||
PRIORITY_LEVELS,
|
PRIORITY_LEVELS,
|
||||||
} from '../../../../shared/constants/gas';
|
} from '../../../../shared/constants/gas';
|
||||||
@ -87,6 +88,17 @@ describe('EditGasFeeButton', () => {
|
|||||||
expect(document.getElementsByClassName('info-tooltip')).toHaveLength(1);
|
expect(document.getElementsByClassName('info-tooltip')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render edit link with text swap suggested if high gas estimates are selected for swaps', () => {
|
||||||
|
render({
|
||||||
|
contextProps: {
|
||||||
|
transaction: { userFeeLevel: 'high' },
|
||||||
|
editGasMode: EDIT_GAS_MODES.SWAPS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('🔄')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Swap suggested')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should render edit link with text advance if custom gas estimates are used', () => {
|
it('should render edit link with text advance if custom gas estimates are used', () => {
|
||||||
render({
|
render({
|
||||||
contextProps: {
|
contextProps: {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { PRIORITY_LEVELS } from '../../../../shared/constants/gas';
|
import {
|
||||||
|
EDIT_GAS_MODES,
|
||||||
|
PRIORITY_LEVELS,
|
||||||
|
} from '../../../../shared/constants/gas';
|
||||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
import { useTransactionModalContext } from '../../../contexts/transaction-modal';
|
import { useTransactionModalContext } from '../../../contexts/transaction-modal';
|
||||||
import ErrorMessage from '../../ui/error-message';
|
import ErrorMessage from '../../ui/error-message';
|
||||||
@ -15,7 +18,7 @@ import EditGasItem from './edit-gas-item';
|
|||||||
import NetworkStatistics from './network-statistics';
|
import NetworkStatistics from './network-statistics';
|
||||||
|
|
||||||
const EditGasFeePopover = () => {
|
const EditGasFeePopover = () => {
|
||||||
const { balanceError } = useGasFeeContext();
|
const { balanceError, editGasMode } = useGasFeeContext();
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const { closeModal, currentModal } = useTransactionModalContext();
|
const { closeModal, currentModal } = useTransactionModalContext();
|
||||||
|
|
||||||
@ -38,17 +41,23 @@ const EditGasFeePopover = () => {
|
|||||||
<I18nValue messageKey="gasOption" />
|
<I18nValue messageKey="gasOption" />
|
||||||
</span>
|
</span>
|
||||||
<span className="edit-gas-fee-popover__content__header-time">
|
<span className="edit-gas-fee-popover__content__header-time">
|
||||||
<I18nValue messageKey="time" />
|
{editGasMode !== EDIT_GAS_MODES.SWAPS && (
|
||||||
|
<I18nValue messageKey="time" />
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span className="edit-gas-fee-popover__content__header-max-fee">
|
<span className="edit-gas-fee-popover__content__header-max-fee">
|
||||||
<I18nValue messageKey="maxFee" />
|
<I18nValue messageKey="maxFee" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<EditGasItem priorityLevel={PRIORITY_LEVELS.LOW} />
|
{editGasMode !== EDIT_GAS_MODES.SWAPS && (
|
||||||
|
<EditGasItem priorityLevel={PRIORITY_LEVELS.LOW} />
|
||||||
|
)}
|
||||||
<EditGasItem priorityLevel={PRIORITY_LEVELS.MEDIUM} />
|
<EditGasItem priorityLevel={PRIORITY_LEVELS.MEDIUM} />
|
||||||
<EditGasItem priorityLevel={PRIORITY_LEVELS.HIGH} />
|
<EditGasItem priorityLevel={PRIORITY_LEVELS.HIGH} />
|
||||||
<div className="edit-gas-fee-popover__content__separator" />
|
<div className="edit-gas-fee-popover__content__separator" />
|
||||||
<EditGasItem priorityLevel={PRIORITY_LEVELS.DAPP_SUGGESTED} />
|
{editGasMode !== EDIT_GAS_MODES.SWAPS && (
|
||||||
|
<EditGasItem priorityLevel={PRIORITY_LEVELS.DAPP_SUGGESTED} />
|
||||||
|
)}
|
||||||
<EditGasItem priorityLevel={PRIORITY_LEVELS.CUSTOM} />
|
<EditGasItem priorityLevel={PRIORITY_LEVELS.CUSTOM} />
|
||||||
<NetworkStatistics />
|
<NetworkStatistics />
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { EDIT_GAS_MODES } from '../../../../shared/constants/gas';
|
||||||
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
||||||
import { ETH } from '../../../helpers/constants/common';
|
import { ETH } from '../../../helpers/constants/common';
|
||||||
import configureStore from '../../../store/store';
|
import configureStore from '../../../store/store';
|
||||||
@ -45,7 +46,7 @@ const MOCK_FEE_ESTIMATE = {
|
|||||||
estimatedBaseFee: '50',
|
estimatedBaseFee: '50',
|
||||||
};
|
};
|
||||||
|
|
||||||
const render = (txProps) => {
|
const render = ({ txProps, contextProps } = {}) => {
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
metamask: {
|
metamask: {
|
||||||
nativeCurrency: ETH,
|
nativeCurrency: ETH,
|
||||||
@ -66,6 +67,7 @@ const render = (txProps) => {
|
|||||||
return renderWithProvider(
|
return renderWithProvider(
|
||||||
<GasFeeContextProvider
|
<GasFeeContextProvider
|
||||||
transaction={{ txParams: { gas: '0x5208' }, ...txProps }}
|
transaction={{ txParams: { gas: '0x5208' }, ...txProps }}
|
||||||
|
{...contextProps}
|
||||||
>
|
>
|
||||||
<EditGasFeePopover />
|
<EditGasFeePopover />
|
||||||
</GasFeeContextProvider>,
|
</GasFeeContextProvider>,
|
||||||
@ -75,7 +77,7 @@ const render = (txProps) => {
|
|||||||
|
|
||||||
describe('EditGasFeePopover', () => {
|
describe('EditGasFeePopover', () => {
|
||||||
it('should renders low / medium / high options', () => {
|
it('should renders low / medium / high options', () => {
|
||||||
render({ dappSuggestedGasFees: {} });
|
render({ txProps: { dappSuggestedGasFees: {} } });
|
||||||
|
|
||||||
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
||||||
@ -103,12 +105,40 @@ describe('EditGasFeePopover', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not show insufficient balance message if transaction value is less than balance', () => {
|
it('should not show insufficient balance message if transaction value is less than balance', () => {
|
||||||
render({ userFeeLevel: 'high', txParams: { value: '0x64' } });
|
render({ txProps: { userFeeLevel: 'high', txParams: { value: '0x64' } } });
|
||||||
expect(screen.queryByText('Insufficient funds.')).not.toBeInTheDocument();
|
expect(screen.queryByText('Insufficient funds.')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show insufficient balance message if transaction value is more than balance', () => {
|
it('should show insufficient balance message if transaction value is more than balance', () => {
|
||||||
render({ userFeeLevel: 'high', txParams: { value: '0x5208' } });
|
render({
|
||||||
|
txProps: { userFeeLevel: 'high', txParams: { value: '0x5208' } },
|
||||||
|
});
|
||||||
expect(screen.queryByText('Insufficient funds.')).toBeInTheDocument();
|
expect(screen.queryByText('Insufficient funds.')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not show low, aggressive and dapp-suggested options for swap', () => {
|
||||||
|
render({
|
||||||
|
contextProps: { editGasMode: EDIT_GAS_MODES.SWAPS },
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('🐢')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('🦍')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('🌐')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('🔄')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('⚙')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Low')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Market')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Aggressive')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Site')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Swap suggested')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Advanced')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show time estimates for swaps', () => {
|
||||||
|
render({
|
||||||
|
contextProps: { editGasMode: EDIT_GAS_MODES.SWAPS },
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('Time')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Max fee')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,10 @@ import classNames from 'classnames';
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { getMaximumGasTotalInHexWei } from '../../../../../shared/modules/gas.utils';
|
import { getMaximumGasTotalInHexWei } from '../../../../../shared/modules/gas.utils';
|
||||||
import { PRIORITY_LEVELS } from '../../../../../shared/constants/gas';
|
import {
|
||||||
|
EDIT_GAS_MODES,
|
||||||
|
PRIORITY_LEVELS,
|
||||||
|
} from '../../../../../shared/constants/gas';
|
||||||
import { PRIORITY_LEVEL_ICON_MAP } from '../../../../helpers/constants/gas';
|
import { PRIORITY_LEVEL_ICON_MAP } from '../../../../helpers/constants/gas';
|
||||||
import { PRIMARY } from '../../../../helpers/constants/common';
|
import { PRIMARY } from '../../../../helpers/constants/common';
|
||||||
import {
|
import {
|
||||||
@ -27,17 +30,19 @@ import { useCustomTimeEstimate } from './useCustomTimeEstimate';
|
|||||||
|
|
||||||
const EditGasItem = ({ priorityLevel }) => {
|
const EditGasItem = ({ priorityLevel }) => {
|
||||||
const {
|
const {
|
||||||
|
editGasMode,
|
||||||
estimateUsed,
|
estimateUsed,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
maxFeePerGas: maxFeePerGasValue,
|
maxFeePerGas: maxFeePerGasValue,
|
||||||
maxPriorityFeePerGas: maxPriorityFeePerGasValue,
|
maxPriorityFeePerGas: maxPriorityFeePerGasValue,
|
||||||
updateTransactionUsingGasFeeEstimates,
|
updateTransactionUsingGasFeeEstimates,
|
||||||
transaction: { dappSuggestedGasFees },
|
transaction,
|
||||||
} = useGasFeeContext();
|
} = useGasFeeContext();
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const advancedGasFeeValues = useSelector(getAdvancedGasFeeValues);
|
const advancedGasFeeValues = useSelector(getAdvancedGasFeeValues);
|
||||||
const { closeModal, openModal } = useTransactionModalContext();
|
const { closeModal, openModal } = useTransactionModalContext();
|
||||||
|
const { dappSuggestedGasFees } = transaction;
|
||||||
|
|
||||||
let maxFeePerGas;
|
let maxFeePerGas;
|
||||||
let maxPriorityFeePerGas;
|
let maxPriorityFeePerGas;
|
||||||
@ -45,6 +50,8 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
|
|
||||||
if (gasFeeEstimates?.[priorityLevel]) {
|
if (gasFeeEstimates?.[priorityLevel]) {
|
||||||
maxFeePerGas = gasFeeEstimates[priorityLevel].suggestedMaxFeePerGas;
|
maxFeePerGas = gasFeeEstimates[priorityLevel].suggestedMaxFeePerGas;
|
||||||
|
maxPriorityFeePerGas =
|
||||||
|
gasFeeEstimates[priorityLevel].suggestedMaxPriorityFeePerGas;
|
||||||
} else if (
|
} else if (
|
||||||
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
||||||
dappSuggestedGasFees
|
dappSuggestedGasFees
|
||||||
@ -105,6 +112,18 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let icon = priorityLevel;
|
||||||
|
let title = priorityLevel;
|
||||||
|
if (priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED) {
|
||||||
|
title = 'dappSuggestedShortLabel';
|
||||||
|
} else if (
|
||||||
|
priorityLevel === PRIORITY_LEVELS.HIGH &&
|
||||||
|
editGasMode === EDIT_GAS_MODES.SWAPS
|
||||||
|
) {
|
||||||
|
icon = 'swapSuggested';
|
||||||
|
title = 'swapSuggested';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={classNames('edit-gas-item', {
|
className={classNames('edit-gas-item', {
|
||||||
@ -118,22 +137,15 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
<span
|
<span
|
||||||
className={`edit-gas-item__icon edit-gas-item__icon-${priorityLevel}`}
|
className={`edit-gas-item__icon edit-gas-item__icon-${priorityLevel}`}
|
||||||
>
|
>
|
||||||
{PRIORITY_LEVEL_ICON_MAP[priorityLevel]}
|
{PRIORITY_LEVEL_ICON_MAP[icon]}
|
||||||
</span>
|
</span>
|
||||||
<I18nValue
|
<I18nValue messageKey={title} />
|
||||||
messageKey={
|
|
||||||
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED
|
|
||||||
? 'dappSuggestedShortLabel'
|
|
||||||
: priorityLevel
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`edit-gas-item__time-estimate edit-gas-item__time-estimate-${priorityLevel}`}
|
className={`edit-gas-item__time-estimate edit-gas-item__time-estimate-${priorityLevel}`}
|
||||||
>
|
>
|
||||||
{minWaitTime
|
{editGasMode !== EDIT_GAS_MODES.SWAPS &&
|
||||||
? minWaitTime && toHumanReadableTime(t, minWaitTime)
|
(minWaitTime ? toHumanReadableTime(t, minWaitTime) : '--')}
|
||||||
: '--'}
|
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`edit-gas-item__fee-estimate edit-gas-item__fee-estimate-${priorityLevel}`}
|
className={`edit-gas-item__fee-estimate edit-gas-item__fee-estimate-${priorityLevel}`}
|
||||||
@ -159,6 +171,9 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
priorityLevel={priorityLevel}
|
priorityLevel={priorityLevel}
|
||||||
maxFeePerGas={maxFeePerGas}
|
maxFeePerGas={maxFeePerGas}
|
||||||
maxPriorityFeePerGas={maxPriorityFeePerGas}
|
maxPriorityFeePerGas={maxPriorityFeePerGas}
|
||||||
|
editGasMode={editGasMode}
|
||||||
|
gasLimit={gasLimit}
|
||||||
|
transaction={transaction}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
position="top"
|
position="top"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { EDIT_GAS_MODES } from '../../../../../shared/constants/gas';
|
||||||
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
|
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
|
||||||
import { ETH } from '../../../../helpers/constants/common';
|
import { ETH } from '../../../../helpers/constants/common';
|
||||||
import configureStore from '../../../../store/store';
|
import configureStore from '../../../../store/store';
|
||||||
@ -46,7 +47,11 @@ const DAPP_SUGGESTED_ESTIMATE = {
|
|||||||
maxPriorityFeePerGas: '0x59682f00',
|
maxPriorityFeePerGas: '0x59682f00',
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = (componentProps, transactionProps) => {
|
const renderComponent = ({
|
||||||
|
componentProps,
|
||||||
|
transactionProps,
|
||||||
|
contextProps,
|
||||||
|
} = {}) => {
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
metamask: {
|
metamask: {
|
||||||
nativeCurrency: ETH,
|
nativeCurrency: ETH,
|
||||||
@ -71,6 +76,7 @@ const renderComponent = (componentProps, transactionProps) => {
|
|||||||
return renderWithProvider(
|
return renderWithProvider(
|
||||||
<GasFeeContextProvider
|
<GasFeeContextProvider
|
||||||
transaction={{ txParams: { gas: '0x5208' }, ...transactionProps }}
|
transaction={{ txParams: { gas: '0x5208' }, ...transactionProps }}
|
||||||
|
{...contextProps}
|
||||||
>
|
>
|
||||||
<EditGasItem priorityLevel="low" {...componentProps} />
|
<EditGasItem priorityLevel="low" {...componentProps} />
|
||||||
</GasFeeContextProvider>,
|
</GasFeeContextProvider>,
|
||||||
@ -80,7 +86,7 @@ const renderComponent = (componentProps, transactionProps) => {
|
|||||||
|
|
||||||
describe('EditGasItem', () => {
|
describe('EditGasItem', () => {
|
||||||
it('should renders low gas estimate option for priorityLevel low', () => {
|
it('should renders low gas estimate option for priorityLevel low', () => {
|
||||||
renderComponent({ priorityLevel: 'low' });
|
renderComponent({ componentProps: { priorityLevel: 'low' } });
|
||||||
expect(screen.queryByRole('button', { name: 'low' })).toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'low' })).toBeInTheDocument();
|
||||||
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('Low')).toBeInTheDocument();
|
expect(screen.queryByText('Low')).toBeInTheDocument();
|
||||||
@ -89,7 +95,7 @@ describe('EditGasItem', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should renders market gas estimate option for priorityLevel medium', () => {
|
it('should renders market gas estimate option for priorityLevel medium', () => {
|
||||||
renderComponent({ priorityLevel: 'medium' });
|
renderComponent({ componentProps: { priorityLevel: 'medium' } });
|
||||||
expect(
|
expect(
|
||||||
screen.queryByRole('button', { name: 'medium' }),
|
screen.queryByRole('button', { name: 'medium' }),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
@ -100,7 +106,7 @@ describe('EditGasItem', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should renders aggressive gas estimate option for priorityLevel high', () => {
|
it('should renders aggressive gas estimate option for priorityLevel high', () => {
|
||||||
renderComponent({ priorityLevel: 'high' });
|
renderComponent({ componentProps: { priorityLevel: 'high' } });
|
||||||
expect(screen.queryByRole('button', { name: 'high' })).toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'high' })).toBeInTheDocument();
|
||||||
expect(screen.queryByText('🦍')).toBeInTheDocument();
|
expect(screen.queryByText('🦍')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('Aggressive')).toBeInTheDocument();
|
expect(screen.queryByText('Aggressive')).toBeInTheDocument();
|
||||||
@ -108,21 +114,33 @@ describe('EditGasItem', () => {
|
|||||||
expect(screen.queryByTitle('0.0021 ETH')).toBeInTheDocument();
|
expect(screen.queryByTitle('0.0021 ETH')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render priorityLevel high as "Swap suggested" for swaps', () => {
|
||||||
|
renderComponent({
|
||||||
|
componentProps: { priorityLevel: 'high' },
|
||||||
|
contextProps: { editGasMode: EDIT_GAS_MODES.SWAPS },
|
||||||
|
});
|
||||||
|
expect(screen.queryByRole('button', { name: 'high' })).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('🔄')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Swap suggested')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('15 sec')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByTitle('0.0021 ETH')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should highlight option is priorityLevel is currently selected', () => {
|
it('should highlight option is priorityLevel is currently selected', () => {
|
||||||
renderComponent({ priorityLevel: 'high' }, { userFeeLevel: 'high' });
|
renderComponent({
|
||||||
|
componentProps: { priorityLevel: 'high' },
|
||||||
|
transactionProps: { userFeeLevel: 'high' },
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
document.getElementsByClassName('edit-gas-item--selected'),
|
document.getElementsByClassName('edit-gas-item--selected'),
|
||||||
).toHaveLength(1);
|
).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should renders site gas estimate option for priorityLevel dappSuggested', () => {
|
it('should renders site gas estimate option for priorityLevel dappSuggested', () => {
|
||||||
renderComponent(
|
renderComponent({
|
||||||
{ priorityLevel: 'dappSuggested' },
|
componentProps: { priorityLevel: 'dappSuggested' },
|
||||||
{
|
transactionProps: { dappSuggestedGasFees: DAPP_SUGGESTED_ESTIMATE },
|
||||||
dappSuggestedGasFees: DAPP_SUGGESTED_ESTIMATE,
|
});
|
||||||
txParams: { gas: '0x5208', ...DAPP_SUGGESTED_ESTIMATE },
|
|
||||||
},
|
|
||||||
);
|
|
||||||
expect(
|
expect(
|
||||||
screen.queryByRole('button', { name: 'dappSuggested' }),
|
screen.queryByRole('button', { name: 'dappSuggested' }),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
@ -132,7 +150,10 @@ describe('EditGasItem', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should renders advance gas estimate option for priorityLevel custom', () => {
|
it('should renders advance gas estimate option for priorityLevel custom', () => {
|
||||||
renderComponent({ priorityLevel: 'custom' }, { userFeeLevel: 'high' });
|
renderComponent({
|
||||||
|
componentProps: { priorityLevel: 'custom' },
|
||||||
|
transactionProps: { userFeeLevel: 'high' },
|
||||||
|
});
|
||||||
expect(
|
expect(
|
||||||
screen.queryByRole('button', { name: 'custom' }),
|
screen.queryByRole('button', { name: 'custom' }),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
color: $ui-black;
|
color: $ui-black;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
white-space: nowrap;
|
||||||
width: 36%;
|
width: 36%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,30 +1,28 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { PRIORITY_LEVELS } from '../../../../../shared/constants/gas';
|
import {
|
||||||
|
EDIT_GAS_MODES,
|
||||||
|
PRIORITY_LEVELS,
|
||||||
|
} from '../../../../../shared/constants/gas';
|
||||||
import {
|
import {
|
||||||
COLORS,
|
COLORS,
|
||||||
FONT_WEIGHT,
|
FONT_WEIGHT,
|
||||||
TYPOGRAPHY,
|
TYPOGRAPHY,
|
||||||
} from '../../../../helpers/constants/design-system';
|
} from '../../../../helpers/constants/design-system';
|
||||||
import Typography from '../../../ui/typography';
|
import Typography from '../../../ui/typography';
|
||||||
import { useGasFeeContext } from '../../../../contexts/gasFee';
|
|
||||||
|
|
||||||
const EditGasToolTip = ({
|
const EditGasToolTip = ({
|
||||||
|
gasLimit,
|
||||||
priorityLevel,
|
priorityLevel,
|
||||||
// maxFeePerGas & maxPriorityFeePerGas are derived from conditional logic
|
// maxFeePerGas & maxPriorityFeePerGas are derived from conditional logic
|
||||||
// related to the source of the estimates. We pass these values from the
|
// related to the source of the estimates. We pass these values from the
|
||||||
// the parent component (edit-gas-item) rather than recalculate them
|
// the parent component (edit-gas-item) rather than recalculate them
|
||||||
maxFeePerGas,
|
maxFeePerGas,
|
||||||
maxPriorityFeePerGas,
|
maxPriorityFeePerGas,
|
||||||
|
editGasMode,
|
||||||
|
transaction,
|
||||||
t,
|
t,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
|
||||||
gasLimit,
|
|
||||||
maxFeePerGas: maxFeePerGasValue,
|
|
||||||
maxPriorityFeePerGas: maxPriorityFeePerGasValue,
|
|
||||||
transaction,
|
|
||||||
} = useGasFeeContext();
|
|
||||||
|
|
||||||
const toolTipMessage = () => {
|
const toolTipMessage = () => {
|
||||||
switch (priorityLevel) {
|
switch (priorityLevel) {
|
||||||
case PRIORITY_LEVELS.LOW:
|
case PRIORITY_LEVELS.LOW:
|
||||||
@ -40,6 +38,9 @@ const EditGasToolTip = ({
|
|||||||
</span>,
|
</span>,
|
||||||
]);
|
]);
|
||||||
case PRIORITY_LEVELS.HIGH:
|
case PRIORITY_LEVELS.HIGH:
|
||||||
|
if (editGasMode === EDIT_GAS_MODES.SWAPS) {
|
||||||
|
return t('swapSuggestedGasSettingToolTipMessage');
|
||||||
|
}
|
||||||
return t('highGasSettingToolTipMessage', [
|
return t('highGasSettingToolTipMessage', [
|
||||||
<span key={priorityLevel}>
|
<span key={priorityLevel}>
|
||||||
<b>{t('high')}</b>
|
<b>{t('high')}</b>
|
||||||
@ -64,10 +65,15 @@ const EditGasToolTip = ({
|
|||||||
return (
|
return (
|
||||||
<div className="edit-gas-tooltip__container">
|
<div className="edit-gas-tooltip__container">
|
||||||
{priorityLevel !== PRIORITY_LEVELS.CUSTOM &&
|
{priorityLevel !== PRIORITY_LEVELS.CUSTOM &&
|
||||||
priorityLevel !== PRIORITY_LEVELS.DAPP_SUGGESTED ? (
|
priorityLevel !== PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
||||||
|
!(
|
||||||
|
priorityLevel === PRIORITY_LEVELS.HIGH &&
|
||||||
|
editGasMode === EDIT_GAS_MODES.SWAPS
|
||||||
|
) ? (
|
||||||
<img alt="" src={`./images/curve-${priorityLevel}.svg`} />
|
<img alt="" src={`./images/curve-${priorityLevel}.svg`} />
|
||||||
) : null}
|
) : null}
|
||||||
{priorityLevel === PRIORITY_LEVELS.HIGH ? (
|
{priorityLevel === PRIORITY_LEVELS.HIGH &&
|
||||||
|
editGasMode !== EDIT_GAS_MODES.SWAPS ? (
|
||||||
<div className="edit-gas-tooltip__container__dialog">
|
<div className="edit-gas-tooltip__container__dialog">
|
||||||
<Typography variant={TYPOGRAPHY.H7} color={COLORS.WHITE}>
|
<Typography variant={TYPOGRAPHY.H7} color={COLORS.WHITE}>
|
||||||
{t('highGasSettingToolTipDialog')}
|
{t('highGasSettingToolTipDialog')}
|
||||||
@ -92,7 +98,7 @@ const EditGasToolTip = ({
|
|||||||
color={COLORS.NEUTRAL_GREY}
|
color={COLORS.NEUTRAL_GREY}
|
||||||
className="edit-gas-tooltip__container__value"
|
className="edit-gas-tooltip__container__value"
|
||||||
>
|
>
|
||||||
{maxFeePerGas ?? maxFeePerGasValue}
|
{maxFeePerGas}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -108,7 +114,7 @@ const EditGasToolTip = ({
|
|||||||
color={COLORS.NEUTRAL_GREY}
|
color={COLORS.NEUTRAL_GREY}
|
||||||
className="edit-gas-tooltip__container__value"
|
className="edit-gas-tooltip__container__value"
|
||||||
>
|
>
|
||||||
{maxPriorityFeePerGas ?? maxPriorityFeePerGasValue}
|
{maxPriorityFeePerGas}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -138,6 +144,9 @@ EditGasToolTip.propTypes = {
|
|||||||
maxFeePerGas: PropTypes.string,
|
maxFeePerGas: PropTypes.string,
|
||||||
maxPriorityFeePerGas: PropTypes.string,
|
maxPriorityFeePerGas: PropTypes.string,
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
|
editGasMode: PropTypes.string,
|
||||||
|
gasLimit: PropTypes.number,
|
||||||
|
transaction: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EditGasToolTip;
|
export default EditGasToolTip;
|
||||||
|
@ -30,7 +30,7 @@ const HIGH_GAS_OPTION = {
|
|||||||
maxPriorityFeePerGas: '2',
|
maxPriorityFeePerGas: '2',
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = (props, transactionProps, gasFeeContextProps) => {
|
const renderComponent = (componentProps) => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
provider: {},
|
provider: {},
|
||||||
@ -43,21 +43,14 @@ const renderComponent = (props, transactionProps, gasFeeContextProps) => {
|
|||||||
},
|
},
|
||||||
selectedAddress: '0xAddress',
|
selectedAddress: '0xAddress',
|
||||||
featureFlags: { advancedInlineGas: true },
|
featureFlags: { advancedInlineGas: true },
|
||||||
advancedGasFee: {
|
|
||||||
maxBaseFee: '1.5',
|
|
||||||
priorityFee: '2',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = configureStore(mockStore);
|
const store = configureStore(mockStore);
|
||||||
|
|
||||||
return renderWithProvider(
|
return renderWithProvider(
|
||||||
<GasFeeContextProvider
|
<GasFeeContextProvider transaction={{ txParams: { gas: '0x5208' } }}>
|
||||||
transaction={{ txParams: { gas: '0x5208' }, ...transactionProps }}
|
<EditGasToolTip {...componentProps} t={jest.fn()} gasLimit={21000} />
|
||||||
{...gasFeeContextProps}
|
|
||||||
>
|
|
||||||
<EditGasToolTip {...props} t={jest.fn()} />
|
|
||||||
</GasFeeContextProvider>,
|
</GasFeeContextProvider>,
|
||||||
store,
|
store,
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@ import TransactionDetailItem from '../transaction-detail-item/transaction-detail
|
|||||||
export default function TransactionDetail({
|
export default function TransactionDetail({
|
||||||
rows = [],
|
rows = [],
|
||||||
onEdit,
|
onEdit,
|
||||||
userAcknowledgedGasMissing,
|
userAcknowledgedGasMissing = false,
|
||||||
}) {
|
}) {
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const { supportsEIP1559V2 } = useGasFeeContext();
|
const { supportsEIP1559V2 } = useGasFeeContext();
|
||||||
@ -44,9 +44,5 @@ TransactionDetail.propTypes = {
|
|||||||
* onClick handler for the Edit link
|
* onClick handler for the Edit link
|
||||||
*/
|
*/
|
||||||
onEdit: PropTypes.func,
|
onEdit: PropTypes.func,
|
||||||
/**
|
userAcknowledgedGasMissing: PropTypes.bool,
|
||||||
* If there is a error in getting correct estimates we show a message to the user
|
|
||||||
* which they can acknowledge and proceed with their transaction
|
|
||||||
*/
|
|
||||||
userAcknowledgedGasMissing: PropTypes.bool.isRequired,
|
|
||||||
};
|
};
|
||||||
|
@ -37,5 +37,6 @@ export const PRIORITY_LEVEL_ICON_MAP = {
|
|||||||
medium: '🦊',
|
medium: '🦊',
|
||||||
high: '🦍',
|
high: '🦍',
|
||||||
dappSuggested: '🌐',
|
dappSuggested: '🌐',
|
||||||
|
swapSuggested: '🔄',
|
||||||
custom: '⚙',
|
custom: '⚙',
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,10 @@ import {
|
|||||||
import { ETH } from '../../helpers/constants/common';
|
import { ETH } from '../../helpers/constants/common';
|
||||||
|
|
||||||
import { useGasFeeEstimates } from '../useGasFeeEstimates';
|
import { useGasFeeEstimates } from '../useGasFeeEstimates';
|
||||||
|
import {
|
||||||
|
getCustomMaxFeePerGas,
|
||||||
|
getCustomMaxPriorityFeePerGas,
|
||||||
|
} from '../../ducks/swaps/swaps';
|
||||||
|
|
||||||
// Why this number?
|
// Why this number?
|
||||||
// 20 gwei * 21000 gasLimit = 420,000 gwei
|
// 20 gwei * 21000 gasLimit = 420,000 gwei
|
||||||
@ -122,6 +126,12 @@ export const generateUseSelectorRouter = ({
|
|||||||
balance: '0x440aa47cc2556',
|
balance: '0x440aa47cc2556',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (selector === getCustomMaxFeePerGas) {
|
||||||
|
return '0x5208';
|
||||||
|
}
|
||||||
|
if (selector === getCustomMaxPriorityFeePerGas) {
|
||||||
|
return '0x5208';
|
||||||
|
}
|
||||||
if (selector === checkNetworkAndAccountSupports1559) {
|
if (selector === checkNetworkAndAccountSupports1559) {
|
||||||
return checkNetworkAndAccountSupports1559Response;
|
return checkNetworkAndAccountSupports1559Response;
|
||||||
}
|
}
|
||||||
|
@ -170,12 +170,12 @@ export function useGasFeeInputs(
|
|||||||
maxFeePerGasFiat,
|
maxFeePerGasFiat,
|
||||||
setMaxFeePerGas,
|
setMaxFeePerGas,
|
||||||
} = useMaxFeePerGasInput({
|
} = useMaxFeePerGasInput({
|
||||||
supportsEIP1559V2,
|
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
gasEstimateType,
|
gasEstimateType,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
gasPrice,
|
gasPrice,
|
||||||
|
supportsEIP1559V2,
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -184,11 +184,11 @@ export function useGasFeeInputs(
|
|||||||
maxPriorityFeePerGasFiat,
|
maxPriorityFeePerGasFiat,
|
||||||
setMaxPriorityFeePerGas,
|
setMaxPriorityFeePerGas,
|
||||||
} = useMaxPriorityFeePerGasInput({
|
} = useMaxPriorityFeePerGasInput({
|
||||||
supportsEIP1559V2,
|
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
gasEstimateType,
|
gasEstimateType,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
|
supportsEIP1559V2,
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -248,6 +248,7 @@ export function useGasFeeInputs(
|
|||||||
updateTransactionUsingGasFeeEstimates,
|
updateTransactionUsingGasFeeEstimates,
|
||||||
} = useTransactionFunctions({
|
} = useTransactionFunctions({
|
||||||
defaultEstimateToUse,
|
defaultEstimateToUse,
|
||||||
|
editGasMode,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
transaction,
|
transaction,
|
||||||
@ -313,6 +314,7 @@ export function useGasFeeInputs(
|
|||||||
setGasPrice,
|
setGasPrice,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
setGasLimit,
|
setGasLimit,
|
||||||
|
editGasMode,
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
setEstimateToUse,
|
setEstimateToUse,
|
||||||
estimatedMinimumFiat,
|
estimatedMinimumFiat,
|
||||||
|
@ -4,6 +4,7 @@ import { TRANSACTION_ENVELOPE_TYPES } from '../../../shared/constants/transactio
|
|||||||
import {
|
import {
|
||||||
GAS_RECOMMENDATIONS,
|
GAS_RECOMMENDATIONS,
|
||||||
CUSTOM_GAS_ESTIMATE,
|
CUSTOM_GAS_ESTIMATE,
|
||||||
|
EDIT_GAS_MODES,
|
||||||
} from '../../../shared/constants/gas';
|
} from '../../../shared/constants/gas';
|
||||||
|
|
||||||
import { ETH, PRIMARY } from '../../helpers/constants/common';
|
import { ETH, PRIMARY } from '../../helpers/constants/common';
|
||||||
@ -350,4 +351,13 @@ describe('useGasFeeInputs', () => {
|
|||||||
expect(result.current.supportsEIP1559V2).toBe(false);
|
expect(result.current.supportsEIP1559V2).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('editGasMode', () => {
|
||||||
|
it('should return editGasMode passed', () => {
|
||||||
|
const { result } = renderHook(() =>
|
||||||
|
useGasFeeInputs(undefined, undefined, undefined, EDIT_GAS_MODES.SWAPS),
|
||||||
|
);
|
||||||
|
expect(result.current.editGasMode).toBe(EDIT_GAS_MODES.SWAPS);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -34,12 +34,12 @@ const getMaxFeePerGasFromTransaction = (transaction) => {
|
|||||||
* method to update the setMaxFeePerGas.
|
* method to update the setMaxFeePerGas.
|
||||||
*/
|
*/
|
||||||
export function useMaxFeePerGasInput({
|
export function useMaxFeePerGasInput({
|
||||||
supportsEIP1559V2,
|
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
gasEstimateType,
|
gasEstimateType,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
gasPrice,
|
gasPrice,
|
||||||
|
supportsEIP1559V2,
|
||||||
transaction,
|
transaction,
|
||||||
}) {
|
}) {
|
||||||
const supportsEIP1559 =
|
const supportsEIP1559 =
|
||||||
@ -53,7 +53,7 @@ export function useMaxFeePerGasInput({
|
|||||||
|
|
||||||
const showFiat = useSelector(getShouldShowFiat);
|
const showFiat = useSelector(getShouldShowFiat);
|
||||||
|
|
||||||
const maxFeePerGasFromTransaction = supportsEIP1559
|
const initialMaxFeePerGas = supportsEIP1559
|
||||||
? getMaxFeePerGasFromTransaction(transaction)
|
? getMaxFeePerGasFromTransaction(transaction)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
@ -61,16 +61,16 @@ export function useMaxFeePerGasInput({
|
|||||||
// 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(() => {
|
||||||
if (maxFeePerGasFromTransaction && feeParamsAreCustom(transaction))
|
if (initialMaxFeePerGas && feeParamsAreCustom(transaction))
|
||||||
return maxFeePerGasFromTransaction;
|
return initialMaxFeePerGas;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (supportsEIP1559V2) {
|
if (supportsEIP1559V2 && initialMaxFeePerGas) {
|
||||||
setMaxFeePerGas(maxFeePerGasFromTransaction);
|
setMaxFeePerGas(initialMaxFeePerGas);
|
||||||
}
|
}
|
||||||
}, [maxFeePerGasFromTransaction, setMaxFeePerGas, supportsEIP1559V2]);
|
}, [initialMaxFeePerGas, setMaxFeePerGas, supportsEIP1559V2]);
|
||||||
|
|
||||||
let gasSettings = {
|
let gasSettings = {
|
||||||
gasLimit: decimalToHex(gasLimit),
|
gasLimit: decimalToHex(gasLimit),
|
||||||
@ -117,7 +117,7 @@ export function useMaxFeePerGasInput({
|
|||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasEstimateType,
|
gasEstimateType,
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
maxFeePerGasFromTransaction,
|
initialMaxFeePerGas || 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -9,8 +9,8 @@ import {
|
|||||||
checkNetworkAndAccountSupports1559,
|
checkNetworkAndAccountSupports1559,
|
||||||
getShouldShowFiat,
|
getShouldShowFiat,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import { multiplyCurrencies } from '../../../shared/modules/conversion.utils';
|
|
||||||
import { isLegacyTransaction } from '../../helpers/utils/transactions.util';
|
import { isLegacyTransaction } from '../../helpers/utils/transactions.util';
|
||||||
|
import { multiplyCurrencies } from '../../../shared/modules/conversion.utils';
|
||||||
|
|
||||||
import { useCurrencyDisplay } from '../useCurrencyDisplay';
|
import { useCurrencyDisplay } from '../useCurrencyDisplay';
|
||||||
import { useUserPreferencedCurrency } from '../useUserPreferencedCurrency';
|
import { useUserPreferencedCurrency } from '../useUserPreferencedCurrency';
|
||||||
@ -34,11 +34,11 @@ const getMaxPriorityFeePerGasFromTransaction = (transaction) => {
|
|||||||
* method to update the maxPriorityFeePerGas.
|
* method to update the maxPriorityFeePerGas.
|
||||||
*/
|
*/
|
||||||
export function useMaxPriorityFeePerGasInput({
|
export function useMaxPriorityFeePerGasInput({
|
||||||
supportsEIP1559V2,
|
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
gasEstimateType,
|
gasEstimateType,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
|
supportsEIP1559V2,
|
||||||
transaction,
|
transaction,
|
||||||
}) {
|
}) {
|
||||||
const supportsEIP1559 =
|
const supportsEIP1559 =
|
||||||
@ -52,25 +52,21 @@ export function useMaxPriorityFeePerGasInput({
|
|||||||
|
|
||||||
const showFiat = useSelector(getShouldShowFiat);
|
const showFiat = useSelector(getShouldShowFiat);
|
||||||
|
|
||||||
const maxPriorityFeePerGasFromTransaction = supportsEIP1559
|
const initialMaxPriorityFeePerGas = supportsEIP1559
|
||||||
? getMaxPriorityFeePerGasFromTransaction(transaction)
|
? getMaxPriorityFeePerGasFromTransaction(transaction)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
const [maxPriorityFeePerGas, setMaxPriorityFeePerGas] = useState(() => {
|
const [maxPriorityFeePerGas, setMaxPriorityFeePerGas] = useState(() => {
|
||||||
if (maxPriorityFeePerGasFromTransaction && feeParamsAreCustom(transaction))
|
if (initialMaxPriorityFeePerGas && feeParamsAreCustom(transaction))
|
||||||
return maxPriorityFeePerGasFromTransaction;
|
return initialMaxPriorityFeePerGas;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (supportsEIP1559V2) {
|
if (supportsEIP1559V2 && initialMaxPriorityFeePerGas) {
|
||||||
setMaxPriorityFeePerGas(maxPriorityFeePerGasFromTransaction);
|
setMaxPriorityFeePerGas(initialMaxPriorityFeePerGas);
|
||||||
}
|
}
|
||||||
}, [
|
}, [initialMaxPriorityFeePerGas, setMaxPriorityFeePerGas, supportsEIP1559V2]);
|
||||||
maxPriorityFeePerGasFromTransaction,
|
|
||||||
setMaxPriorityFeePerGas,
|
|
||||||
supportsEIP1559V2,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const maxPriorityFeePerGasToUse =
|
const maxPriorityFeePerGasToUse =
|
||||||
maxPriorityFeePerGas ??
|
maxPriorityFeePerGas ??
|
||||||
@ -79,7 +75,7 @@ export function useMaxPriorityFeePerGasInput({
|
|||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasEstimateType,
|
gasEstimateType,
|
||||||
estimateToUse,
|
estimateToUse,
|
||||||
maxPriorityFeePerGasFromTransaction,
|
initialMaxPriorityFeePerGas || 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We need to display the estimated fiat currency impact of the
|
// We need to display the estimated fiat currency impact of the
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { PRIORITY_LEVELS } from '../../../shared/constants/gas';
|
import { EDIT_GAS_MODES, PRIORITY_LEVELS } from '../../../shared/constants/gas';
|
||||||
import {
|
import {
|
||||||
decimalToHex,
|
decimalToHex,
|
||||||
decGWEIToHexWEI,
|
decGWEIToHexWEI,
|
||||||
} from '../../helpers/utils/conversions.util';
|
} from '../../helpers/utils/conversions.util';
|
||||||
import { updateTransaction as updateTransactionFn } from '../../store/actions';
|
import {
|
||||||
|
updateCustomSwapsEIP1559GasParams,
|
||||||
|
updateSwapsUserFeeLevel,
|
||||||
|
updateTransaction as updateTransactionFn,
|
||||||
|
} from '../../store/actions';
|
||||||
|
|
||||||
export const useTransactionFunctions = ({
|
export const useTransactionFunctions = ({
|
||||||
defaultEstimateToUse,
|
defaultEstimateToUse,
|
||||||
|
editGasMode,
|
||||||
gasFeeEstimates,
|
gasFeeEstimates,
|
||||||
gasLimit: gasLimitInTransaction,
|
gasLimit: gasLimitInTransaction,
|
||||||
transaction,
|
transaction,
|
||||||
@ -38,16 +43,29 @@ export const useTransactionFunctions = ({
|
|||||||
|
|
||||||
const updatedTxMeta = {
|
const updatedTxMeta = {
|
||||||
...transaction,
|
...transaction,
|
||||||
userFeeLevel: estimateUsed || 'custom',
|
userFeeLevel: estimateUsed || PRIORITY_LEVELS.CUSTOM,
|
||||||
txParams: {
|
txParams: {
|
||||||
...transaction.txParams,
|
...transaction.txParams,
|
||||||
...newGasSettings,
|
...newGasSettings,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch(updateTransactionFn(updatedTxMeta));
|
if (editGasMode === EDIT_GAS_MODES.SWAPS) {
|
||||||
|
dispatch(
|
||||||
|
updateSwapsUserFeeLevel(estimateUsed || PRIORITY_LEVELS.CUSTOM),
|
||||||
|
);
|
||||||
|
dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings));
|
||||||
|
} else {
|
||||||
|
dispatch(updateTransactionFn(updatedTxMeta));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[defaultEstimateToUse, dispatch, gasLimitInTransaction, transaction],
|
[
|
||||||
|
defaultEstimateToUse,
|
||||||
|
dispatch,
|
||||||
|
editGasMode,
|
||||||
|
gasLimitInTransaction,
|
||||||
|
transaction,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateTransactionUsingGasFeeEstimates = useCallback(
|
const updateTransactionUsingGasFeeEstimates = useCallback(
|
||||||
|
@ -269,8 +269,12 @@ export default function ConfirmApprove() {
|
|||||||
transaction={transaction}
|
transaction={transaction}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<EditGasFeePopover />
|
{supportsEIP1559V2 && (
|
||||||
<AdvancedGasFeePopover />
|
<>
|
||||||
|
<EditGasFeePopover />
|
||||||
|
<AdvancedGasFeePopover />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</TransactionModalContextProvider>
|
</TransactionModalContextProvider>
|
||||||
}
|
}
|
||||||
hideSenderToRecipient
|
hideSenderToRecipient
|
||||||
|
@ -439,7 +439,6 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
key="gas_details"
|
key="gas_details"
|
||||||
hexMaximumTransactionFee={hexMaximumTransactionFee}
|
hexMaximumTransactionFee={hexMaximumTransactionFee}
|
||||||
hexMinimumTransactionFee={hexMinimumTransactionFee}
|
hexMinimumTransactionFee={hexMinimumTransactionFee}
|
||||||
isMainnet={isMainnet}
|
|
||||||
maxFeePerGas={maxFeePerGas}
|
maxFeePerGas={maxFeePerGas}
|
||||||
maxPriorityFeePerGas={maxPriorityFeePerGas}
|
maxPriorityFeePerGas={maxPriorityFeePerGas}
|
||||||
supportsEIP1559={supportsEIP1559}
|
supportsEIP1559={supportsEIP1559}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { TYPOGRAPHY } from '../../../../helpers/constants/design-system';
|
||||||
|
import { useI18nContext } from '../../../../hooks/useI18nContext';
|
||||||
|
import { getIsMainnet } from '../../../../selectors';
|
||||||
|
import Box from '../../../../components/ui/box';
|
||||||
|
import I18nValue from '../../../../components/ui/i18n-value';
|
||||||
|
import InfoTooltip from '../../../../components/ui/info-tooltip/info-tooltip';
|
||||||
|
import Typography from '../../../../components/ui/typography/typography';
|
||||||
|
|
||||||
|
const GasDetailsItemTitle = () => {
|
||||||
|
const t = useI18nContext();
|
||||||
|
const isMainnet = useSelector(getIsMainnet);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box display="flex">
|
||||||
|
<Box marginRight={1}>
|
||||||
|
<I18nValue messageKey="transactionDetailGasHeadingV2" />
|
||||||
|
</Box>
|
||||||
|
<span className="gas-details-item-title__estimate">
|
||||||
|
(<I18nValue messageKey="transactionDetailGasInfoV2" />)
|
||||||
|
</span>
|
||||||
|
<InfoTooltip
|
||||||
|
contentText={
|
||||||
|
<>
|
||||||
|
<Typography variant={TYPOGRAPHY.H7}>
|
||||||
|
{t('transactionDetailGasTooltipIntro', [
|
||||||
|
isMainnet ? t('networkNameEthereum') : '',
|
||||||
|
])}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant={TYPOGRAPHY.H7}>
|
||||||
|
{t('transactionDetailGasTooltipExplanation')}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant={TYPOGRAPHY.H7}>
|
||||||
|
<a
|
||||||
|
href="https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{t('transactionDetailGasTooltipConversion')}
|
||||||
|
</a>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
position="bottom"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GasDetailsItemTitle;
|
@ -0,0 +1,9 @@
|
|||||||
|
.gas-details-item-title {
|
||||||
|
&__estimate {
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $Grey-500;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { screen, waitFor } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { MAINNET_CHAIN_ID } from '../../../../../shared/constants/network';
|
||||||
|
import { GasFeeContextProvider } from '../../../../contexts/gasFee';
|
||||||
|
import { renderWithProvider } from '../../../../../test/jest';
|
||||||
|
import configureStore from '../../../../store/store';
|
||||||
|
|
||||||
|
import GasDetailsItemTitle from './gas-details-item-title';
|
||||||
|
|
||||||
|
jest.mock('../../../../store/actions', () => ({
|
||||||
|
disconnectGasFeeEstimatePoller: jest.fn(),
|
||||||
|
getGasFeeEstimatesAndStartPolling: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve()),
|
||||||
|
addPollingTokenToAppState: jest.fn(),
|
||||||
|
getGasFeeTimeEstimate: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
const store = configureStore({
|
||||||
|
metamask: {
|
||||||
|
provider: { chainId: MAINNET_CHAIN_ID },
|
||||||
|
cachedBalances: {},
|
||||||
|
accounts: {
|
||||||
|
'0xAddress': {
|
||||||
|
address: '0xAddress',
|
||||||
|
balance: '0x176e5b6f173ebe66',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectedAddress: '0xAddress',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return renderWithProvider(
|
||||||
|
<GasFeeContextProvider transaction={{ txParams: {} }}>
|
||||||
|
<GasDetailsItemTitle userAcknowledgedGasMissing={false} />
|
||||||
|
</GasFeeContextProvider>,
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('GasDetailsItem', () => {
|
||||||
|
it('should render label', async () => {
|
||||||
|
render();
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText('Gas')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('(estimated)')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1 @@
|
|||||||
|
export { default } from './gas-details-item-title';
|
@ -2,31 +2,27 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system';
|
import { COLORS } from '../../../helpers/constants/design-system';
|
||||||
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common';
|
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common';
|
||||||
import { hexWEIToDecGWEI } from '../../../helpers/utils/conversions.util';
|
import { hexWEIToDecGWEI } from '../../../helpers/utils/conversions.util';
|
||||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
|
||||||
|
|
||||||
import Box from '../../../components/ui/box';
|
import Box from '../../../components/ui/box';
|
||||||
import Typography from '../../../components/ui/typography/typography';
|
|
||||||
import GasTiming from '../../../components/app/gas-timing/gas-timing.component';
|
import GasTiming from '../../../components/app/gas-timing/gas-timing.component';
|
||||||
import I18nValue from '../../../components/ui/i18n-value';
|
import I18nValue from '../../../components/ui/i18n-value';
|
||||||
import InfoTooltip from '../../../components/ui/info-tooltip/info-tooltip';
|
|
||||||
import LoadingHeartBeat from '../../../components/ui/loading-heartbeat';
|
import LoadingHeartBeat from '../../../components/ui/loading-heartbeat';
|
||||||
import TransactionDetailItem from '../../../components/app/transaction-detail-item/transaction-detail-item.component';
|
import TransactionDetailItem from '../../../components/app/transaction-detail-item/transaction-detail-item.component';
|
||||||
import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display';
|
import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display';
|
||||||
import { useGasFeeContext } from '../../../contexts/gasFee';
|
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||||
|
import GasDetailsItemTitle from './gas-details-item-title';
|
||||||
|
|
||||||
const GasDetailsItem = ({
|
const GasDetailsItem = ({
|
||||||
hexMaximumTransactionFee,
|
hexMaximumTransactionFee,
|
||||||
hexMinimumTransactionFee,
|
hexMinimumTransactionFee,
|
||||||
isMainnet,
|
|
||||||
maxFeePerGas,
|
maxFeePerGas,
|
||||||
maxPriorityFeePerGas,
|
maxPriorityFeePerGas,
|
||||||
userAcknowledgedGasMissing,
|
userAcknowledgedGasMissing,
|
||||||
useNativeCurrencyAsPrimaryCurrency,
|
useNativeCurrencyAsPrimaryCurrency,
|
||||||
}) => {
|
}) => {
|
||||||
const t = useI18nContext();
|
|
||||||
const { estimateUsed, hasSimulationError, transaction } = useGasFeeContext();
|
const { estimateUsed, hasSimulationError, transaction } = useGasFeeContext();
|
||||||
|
|
||||||
if (hasSimulationError && !userAcknowledgedGasMissing) return null;
|
if (hasSimulationError && !userAcknowledgedGasMissing) return null;
|
||||||
@ -34,40 +30,7 @@ const GasDetailsItem = ({
|
|||||||
return (
|
return (
|
||||||
<TransactionDetailItem
|
<TransactionDetailItem
|
||||||
key="gas-item"
|
key="gas-item"
|
||||||
detailTitle={
|
detailTitle={<GasDetailsItemTitle />}
|
||||||
<Box display="flex">
|
|
||||||
<Box marginRight={1}>
|
|
||||||
<I18nValue messageKey="transactionDetailGasHeadingV2" />
|
|
||||||
</Box>
|
|
||||||
<span className="gas-details-item__estimate">
|
|
||||||
(<I18nValue messageKey="transactionDetailGasInfoV2" />)
|
|
||||||
</span>
|
|
||||||
<InfoTooltip
|
|
||||||
contentText={
|
|
||||||
<>
|
|
||||||
<Typography tag={TYPOGRAPHY.Paragraph} variant={TYPOGRAPHY.H7}>
|
|
||||||
{t('transactionDetailGasTooltipIntro', [
|
|
||||||
isMainnet ? t('networkNameEthereum') : '',
|
|
||||||
])}
|
|
||||||
</Typography>
|
|
||||||
<Typography tag={TYPOGRAPHY.Paragraph} variant={TYPOGRAPHY.H7}>
|
|
||||||
{t('transactionDetailGasTooltipExplanation')}
|
|
||||||
</Typography>
|
|
||||||
<Typography tag={TYPOGRAPHY.Paragraph} variant={TYPOGRAPHY.H7}>
|
|
||||||
<a
|
|
||||||
href="https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
{t('transactionDetailGasTooltipConversion')}
|
|
||||||
</a>
|
|
||||||
</Typography>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
position="bottom"
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
detailTitleColor={COLORS.BLACK}
|
detailTitleColor={COLORS.BLACK}
|
||||||
detailText={
|
detailText={
|
||||||
<div className="gas-details-item__currency-container">
|
<div className="gas-details-item__currency-container">
|
||||||
@ -137,7 +100,6 @@ const GasDetailsItem = ({
|
|||||||
GasDetailsItem.propTypes = {
|
GasDetailsItem.propTypes = {
|
||||||
hexMaximumTransactionFee: PropTypes.string,
|
hexMaximumTransactionFee: PropTypes.string,
|
||||||
hexMinimumTransactionFee: PropTypes.string,
|
hexMinimumTransactionFee: PropTypes.string,
|
||||||
isMainnet: PropTypes.bool,
|
|
||||||
maxFeePerGas: PropTypes.string,
|
maxFeePerGas: PropTypes.string,
|
||||||
maxPriorityFeePerGas: PropTypes.string,
|
maxPriorityFeePerGas: PropTypes.string,
|
||||||
userAcknowledgedGasMissing: PropTypes.bool.isRequired,
|
userAcknowledgedGasMissing: PropTypes.bool.isRequired,
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
.gas-details-item {
|
.gas-details-item {
|
||||||
&__estimate {
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 12px;
|
|
||||||
color: $Grey-500;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gas-fee-warning {
|
&__gas-fee-warning {
|
||||||
color: $secondary-1;
|
color: $secondary-1;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
@import 'confirm-decrypt-message/confirm-decrypt-message';
|
@import 'confirm-decrypt-message/confirm-decrypt-message';
|
||||||
@import 'confirm-encryption-public-key/confirm-encryption-public-key';
|
@import 'confirm-encryption-public-key/confirm-encryption-public-key';
|
||||||
@import 'confirm-transaction-base/gas-details-item/gas-details-item';
|
@import 'confirm-transaction-base/gas-details-item/gas-details-item';
|
||||||
|
@import 'confirm-transaction-base/gas-details-item/gas-details-item-title/gas-details-item-title';
|
||||||
@import 'confirm-transaction-base/transaction-alerts/transaction-alerts';
|
@import 'confirm-transaction-base/transaction-alerts/transaction-alerts';
|
||||||
@import 'confirmation/confirmation';
|
@import 'confirmation/confirmation';
|
||||||
@import 'connected-sites/index';
|
@import 'connected-sites/index';
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`FeeCard renders the component with EIP-1559 V2 enabled 1`] = `null`;
|
||||||
|
|
||||||
exports[`FeeCard renders the component with EIP-1559 enabled 1`] = `null`;
|
exports[`FeeCard renders the component with EIP-1559 enabled 1`] = `null`;
|
||||||
|
|
||||||
exports[`FeeCard renders the component with initial props 1`] = `null`;
|
exports[`FeeCard renders the component with initial props 1`] = `null`;
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
TYPOGRAPHY,
|
TYPOGRAPHY,
|
||||||
FONT_WEIGHT,
|
FONT_WEIGHT,
|
||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
|
import GasDetailsItemTitle from '../../confirm-transaction-base/gas-details-item/gas-details-item-title';
|
||||||
|
|
||||||
const GAS_FEES_LEARN_MORE_URL =
|
const GAS_FEES_LEARN_MORE_URL =
|
||||||
'https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172';
|
'https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172';
|
||||||
@ -34,6 +35,7 @@ export default function FeeCard({
|
|||||||
onQuotesClick,
|
onQuotesClick,
|
||||||
chainId,
|
chainId,
|
||||||
isBestQuote,
|
isBestQuote,
|
||||||
|
supportsEIP1559V2,
|
||||||
}) {
|
}) {
|
||||||
const t = useContext(I18nContext);
|
const t = useContext(I18nContext);
|
||||||
|
|
||||||
@ -73,42 +75,46 @@ export default function FeeCard({
|
|||||||
<TransactionDetailItem
|
<TransactionDetailItem
|
||||||
key="gas-item"
|
key="gas-item"
|
||||||
detailTitle={
|
detailTitle={
|
||||||
<>
|
supportsEIP1559V2 ? (
|
||||||
{t('transactionDetailGasHeading')}
|
<GasDetailsItemTitle />
|
||||||
<InfoTooltip
|
) : (
|
||||||
position="top"
|
<>
|
||||||
contentText={
|
{t('transactionDetailGasHeading')}
|
||||||
<>
|
<InfoTooltip
|
||||||
<p className="fee-card__info-tooltip-paragraph">
|
position="top"
|
||||||
{t('swapGasFeesSummary', [
|
contentText={
|
||||||
getTranslatedNetworkName(),
|
<>
|
||||||
])}
|
<p className="fee-card__info-tooltip-paragraph">
|
||||||
</p>
|
{t('swapGasFeesSummary', [
|
||||||
<p className="fee-card__info-tooltip-paragraph">
|
getTranslatedNetworkName(),
|
||||||
{t('swapGasFeesDetails')}
|
])}
|
||||||
</p>
|
</p>
|
||||||
<p className="fee-card__info-tooltip-paragraph">
|
<p className="fee-card__info-tooltip-paragraph">
|
||||||
<a
|
{t('swapGasFeesDetails')}
|
||||||
className="fee-card__link"
|
</p>
|
||||||
onClick={() => {
|
<p className="fee-card__info-tooltip-paragraph">
|
||||||
gasFeesLearnMoreLinkClickedEvent();
|
<a
|
||||||
global.platform.openTab({
|
className="fee-card__link"
|
||||||
url: GAS_FEES_LEARN_MORE_URL,
|
onClick={() => {
|
||||||
});
|
gasFeesLearnMoreLinkClickedEvent();
|
||||||
}}
|
global.platform.openTab({
|
||||||
target="_blank"
|
url: GAS_FEES_LEARN_MORE_URL,
|
||||||
rel="noopener noreferrer"
|
});
|
||||||
>
|
}}
|
||||||
{t('swapGasFeesLearnMore')}
|
target="_blank"
|
||||||
</a>
|
rel="noopener noreferrer"
|
||||||
</p>
|
>
|
||||||
</>
|
{t('swapGasFeesLearnMore')}
|
||||||
}
|
</a>
|
||||||
containerClassName="fee-card__info-tooltip-content-container"
|
</p>
|
||||||
wrapperClassName="fee-card__row-label fee-card__info-tooltip-container"
|
</>
|
||||||
wide
|
}
|
||||||
/>
|
containerClassName="fee-card__info-tooltip-content-container"
|
||||||
</>
|
wrapperClassName="fee-card__row-label fee-card__info-tooltip-container"
|
||||||
|
wide
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
detailText={primaryFee.fee}
|
detailText={primaryFee.fee}
|
||||||
detailTotal={secondaryFee.fee}
|
detailTotal={secondaryFee.fee}
|
||||||
@ -124,12 +130,14 @@ export default function FeeCard({
|
|||||||
{t('maxFee')}
|
{t('maxFee')}
|
||||||
</Typography>
|
</Typography>
|
||||||
{`: ${secondaryFee.maxFee}`}
|
{`: ${secondaryFee.maxFee}`}
|
||||||
<span
|
{!supportsEIP1559V2 && (
|
||||||
className="fee-card__edit-link"
|
<span
|
||||||
onClick={() => onFeeCardMaxRowClick()}
|
className="fee-card__edit-link"
|
||||||
>
|
onClick={() => onFeeCardMaxRowClick()}
|
||||||
{t('edit')}
|
>
|
||||||
</span>
|
{t('edit')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -203,4 +211,5 @@ FeeCard.propTypes = {
|
|||||||
numberOfQuotes: PropTypes.number.isRequired,
|
numberOfQuotes: PropTypes.number.isRequired,
|
||||||
chainId: PropTypes.string.isRequired,
|
chainId: PropTypes.string.isRequired,
|
||||||
isBestQuote: PropTypes.bool.isRequired,
|
isBestQuote: PropTypes.bool.isRequired,
|
||||||
|
supportsEIP1559V2: PropTypes.bool.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -3,25 +3,37 @@ import configureMockStore from 'redux-mock-store';
|
|||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { checkNetworkAndAccountSupports1559 } from '../../../selectors';
|
|
||||||
import {
|
|
||||||
getGasEstimateType,
|
|
||||||
getGasFeeEstimates,
|
|
||||||
getIsGasEstimatesLoading,
|
|
||||||
} from '../../../ducks/metamask/metamask';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
renderWithProvider,
|
renderWithProvider,
|
||||||
createSwapsMockStore,
|
createSwapsMockStore,
|
||||||
setBackgroundConnection,
|
setBackgroundConnection,
|
||||||
MOCKS,
|
MOCKS,
|
||||||
} from '../../../../test/jest';
|
} from '../../../../test/jest';
|
||||||
|
import { EDIT_GAS_MODES } from '../../../../shared/constants/gas';
|
||||||
import { MAINNET_CHAIN_ID } from '../../../../shared/constants/network';
|
import { MAINNET_CHAIN_ID } from '../../../../shared/constants/network';
|
||||||
|
|
||||||
|
import {
|
||||||
|
checkNetworkAndAccountSupports1559,
|
||||||
|
getPreferences,
|
||||||
|
getSelectedAccount,
|
||||||
|
} from '../../../selectors';
|
||||||
|
import {
|
||||||
|
getGasEstimateType,
|
||||||
|
getGasFeeEstimates,
|
||||||
|
getIsGasEstimatesLoading,
|
||||||
|
} from '../../../ducks/metamask/metamask';
|
||||||
|
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
||||||
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../helpers/constants/transactions';
|
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../helpers/constants/transactions';
|
||||||
|
import { useGasFeeEstimates } from '../../../hooks/useGasFeeEstimates';
|
||||||
|
|
||||||
import FeeCard from '.';
|
import FeeCard from '.';
|
||||||
|
|
||||||
const middleware = [thunk];
|
const middleware = [thunk];
|
||||||
|
|
||||||
|
jest.mock('../../../hooks/useGasFeeEstimates', () => ({
|
||||||
|
useGasFeeEstimates: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('react-redux', () => {
|
jest.mock('react-redux', () => {
|
||||||
const actual = jest.requireActual('react-redux');
|
const actual = jest.requireActual('react-redux');
|
||||||
|
|
||||||
@ -78,6 +90,7 @@ const createProps = (customProps = {}) => {
|
|||||||
tokenConversionRate: 0.015,
|
tokenConversionRate: 0.015,
|
||||||
chainId: MAINNET_CHAIN_ID,
|
chainId: MAINNET_CHAIN_ID,
|
||||||
networkAndAccountSupports1559: false,
|
networkAndAccountSupports1559: false,
|
||||||
|
supportsEIP1559V2: false,
|
||||||
...customProps,
|
...customProps,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -118,4 +131,55 @@ describe('FeeCard', () => {
|
|||||||
document.querySelector('.fee-card__top-bordered-row'),
|
document.querySelector('.fee-card__top-bordered-row'),
|
||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders the component with EIP-1559 V2 enabled', () => {
|
||||||
|
process.env.EIP_1559_V2 = true;
|
||||||
|
useGasFeeEstimates.mockImplementation(() => ({ gasFeeEstimates: {} }));
|
||||||
|
useSelector.mockImplementation((selector) => {
|
||||||
|
if (selector === getPreferences) {
|
||||||
|
return {
|
||||||
|
useNativeCurrencyAsPrimaryCurrency: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (selector === getSelectedAccount) {
|
||||||
|
return {
|
||||||
|
balance: '0x440aa47cc2556',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (selector === checkNetworkAndAccountSupports1559) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||||
|
const props = createProps({
|
||||||
|
networkAndAccountSupports1559: true,
|
||||||
|
maxPriorityFeePerGasDecGWEI: '3',
|
||||||
|
maxFeePerGasDecGWEI: '4',
|
||||||
|
supportsEIP1559V2: true,
|
||||||
|
});
|
||||||
|
const { getByText } = renderWithProvider(
|
||||||
|
<GasFeeContextProvider
|
||||||
|
transaction={{ txParams: {}, userFeeLevel: 'high' }}
|
||||||
|
editGasMode={EDIT_GAS_MODES.SWAPS}
|
||||||
|
>
|
||||||
|
<FeeCard {...props} />
|
||||||
|
</GasFeeContextProvider>,
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
expect(getByText('Best of 6 quotes.')).toBeInTheDocument();
|
||||||
|
expect(getByText('Gas')).toBeInTheDocument();
|
||||||
|
expect(getByText('(estimated)')).toBeInTheDocument();
|
||||||
|
expect(getByText('Swap suggested')).toBeInTheDocument();
|
||||||
|
expect(getByText('Max fee')).toBeInTheDocument();
|
||||||
|
expect(getByText(props.primaryFee.fee)).toBeInTheDocument();
|
||||||
|
expect(getByText(props.secondaryFee.fee)).toBeInTheDocument();
|
||||||
|
expect(getByText(`: ${props.secondaryFee.maxFee}`)).toBeInTheDocument();
|
||||||
|
expect(getByText('Includes a 0.875% MetaMask fee.')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
document.querySelector('.fee-card__top-bordered-row'),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
process.env.EIP_1559_V2 = false;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -81,6 +81,10 @@ import {
|
|||||||
decGWEIToHexWEI,
|
decGWEIToHexWEI,
|
||||||
addHexes,
|
addHexes,
|
||||||
} from '../../../helpers/utils/conversions.util';
|
} from '../../../helpers/utils/conversions.util';
|
||||||
|
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
||||||
|
import { TransactionModalContextProvider } from '../../../contexts/transaction-modal';
|
||||||
|
import AdvancedGasFeePopover from '../../../components/app/advanced-gas-fee-popover';
|
||||||
|
import EditGasFeePopover from '../../../components/app/edit-gas-fee-popover';
|
||||||
import MainQuoteSummary from '../main-quote-summary';
|
import MainQuoteSummary from '../main-quote-summary';
|
||||||
import { calcGasTotal } from '../../send/send.utils';
|
import { calcGasTotal } from '../../send/send.utils';
|
||||||
import { getCustomTxParamsData } from '../../confirm-approve/confirm-approve.util';
|
import { getCustomTxParamsData } from '../../confirm-approve/confirm-approve.util';
|
||||||
@ -99,6 +103,10 @@ import CountdownTimer from '../countdown-timer';
|
|||||||
import SwapsFooter from '../swaps-footer';
|
import SwapsFooter from '../swaps-footer';
|
||||||
import ViewQuotePriceDifference from './view-quote-price-difference';
|
import ViewQuotePriceDifference from './view-quote-price-difference';
|
||||||
|
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
const EIP_1559_V2_ENABLED =
|
||||||
|
process.env.EIP_1559_V2 === true || process.env.EIP_1559_V2 === 'true';
|
||||||
|
|
||||||
export default function ViewQuote() {
|
export default function ViewQuote() {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -672,93 +680,152 @@ export default function ViewQuote() {
|
|||||||
}
|
}
|
||||||
}, [dispatch, viewQuotePageLoadedEvent, reviewSwapClickedTimestamp]);
|
}, [dispatch, viewQuotePageLoadedEvent, reviewSwapClickedTimestamp]);
|
||||||
|
|
||||||
|
const transaction = {
|
||||||
|
userFeeLevel: swapsUserFeeLevel || GAS_RECOMMENDATIONS.HIGH,
|
||||||
|
txParams: {
|
||||||
|
maxFeePerGas,
|
||||||
|
maxPriorityFeePerGas,
|
||||||
|
gas: maxGasLimit,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const supportsEIP1559V2 =
|
||||||
|
EIP_1559_V2_ENABLED && networkAndAccountSupports1559;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="view-quote">
|
<GasFeeContextProvider
|
||||||
<div
|
editGasMode={EDIT_GAS_MODES.SWAPS}
|
||||||
className={classnames('view-quote__content', {
|
minimumGasLimit={usedGasLimit}
|
||||||
'view-quote__content_modal': disableSubmissionDueToPriceWarning,
|
transaction={transaction}
|
||||||
})}
|
>
|
||||||
>
|
<TransactionModalContextProvider captureEventEnabled={false}>
|
||||||
{selectQuotePopoverShown && (
|
<div className="view-quote">
|
||||||
<SelectQuotePopover
|
<div
|
||||||
quoteDataRows={renderablePopoverData}
|
className={classnames('view-quote__content', {
|
||||||
onClose={() => setSelectQuotePopoverShown(false)}
|
'view-quote__content_modal': disableSubmissionDueToPriceWarning,
|
||||||
onSubmit={(aggId) => dispatch(swapsQuoteSelected(aggId))}
|
})}
|
||||||
swapToSymbol={destinationTokenSymbol}
|
>
|
||||||
initialAggId={usedQuote.aggregator}
|
{selectQuotePopoverShown && (
|
||||||
onQuoteDetailsIsOpened={quoteDetailsOpened}
|
<SelectQuotePopover
|
||||||
/>
|
quoteDataRows={renderablePopoverData}
|
||||||
)}
|
onClose={() => setSelectQuotePopoverShown(false)}
|
||||||
|
onSubmit={(aggId) => dispatch(swapsQuoteSelected(aggId))}
|
||||||
|
swapToSymbol={destinationTokenSymbol}
|
||||||
|
initialAggId={usedQuote.aggregator}
|
||||||
|
onQuoteDetailsIsOpened={quoteDetailsOpened}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{showEditGasPopover && networkAndAccountSupports1559 && (
|
{!supportsEIP1559V2 &&
|
||||||
<EditGasPopover
|
showEditGasPopover &&
|
||||||
transaction={{
|
networkAndAccountSupports1559 && (
|
||||||
userFeeLevel: swapsUserFeeLevel || GAS_RECOMMENDATIONS.HIGH,
|
<EditGasPopover
|
||||||
txParams: {
|
transaction={transaction}
|
||||||
maxFeePerGas,
|
minimumGasLimit={usedGasLimit}
|
||||||
maxPriorityFeePerGas,
|
defaultEstimateToUse={GAS_RECOMMENDATIONS.HIGH}
|
||||||
gas: maxGasLimit,
|
mode={EDIT_GAS_MODES.SWAPS}
|
||||||
},
|
confirmButtonText={t('submit')}
|
||||||
}}
|
onClose={onCloseEditGasPopover}
|
||||||
minimumGasLimit={usedGasLimit}
|
/>
|
||||||
defaultEstimateToUse={GAS_RECOMMENDATIONS.HIGH}
|
)}
|
||||||
mode={EDIT_GAS_MODES.SWAPS}
|
{supportsEIP1559V2 && (
|
||||||
confirmButtonText={t('submit')}
|
<>
|
||||||
onClose={onCloseEditGasPopover}
|
<EditGasFeePopover />
|
||||||
/>
|
<AdvancedGasFeePopover />
|
||||||
)}
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={classnames('view-quote__warning-wrapper', {
|
className={classnames('view-quote__warning-wrapper', {
|
||||||
'view-quote__warning-wrapper--thin': !isShowingWarning,
|
'view-quote__warning-wrapper--thin': !isShowingWarning,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{viewQuotePriceDifferenceComponent}
|
{viewQuotePriceDifferenceComponent}
|
||||||
{(showInsufficientWarning || tokenBalanceUnavailable) && (
|
{(showInsufficientWarning || tokenBalanceUnavailable) && (
|
||||||
<ActionableMessage
|
<ActionableMessage
|
||||||
message={actionableBalanceErrorMessage}
|
message={actionableBalanceErrorMessage}
|
||||||
onClose={() => setWarningHidden(true)}
|
onClose={() => setWarningHidden(true)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="view-quote__countdown-timer-container">
|
||||||
|
<CountdownTimer
|
||||||
|
timeStarted={quotesLastFetched}
|
||||||
|
warningTime="0:30"
|
||||||
|
labelKey="swapNewQuoteIn"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<MainQuoteSummary
|
||||||
|
sourceValue={calcTokenValue(
|
||||||
|
sourceTokenValue,
|
||||||
|
sourceTokenDecimals,
|
||||||
|
)}
|
||||||
|
sourceDecimals={sourceTokenDecimals}
|
||||||
|
sourceSymbol={sourceTokenSymbol}
|
||||||
|
destinationValue={calcTokenValue(
|
||||||
|
destinationTokenValue,
|
||||||
|
destinationTokenDecimals,
|
||||||
|
)}
|
||||||
|
destinationDecimals={destinationTokenDecimals}
|
||||||
|
destinationSymbol={destinationTokenSymbol}
|
||||||
|
sourceIconUrl={sourceTokenIconUrl}
|
||||||
|
destinationIconUrl={destinationIconUrl}
|
||||||
/>
|
/>
|
||||||
)}
|
<div
|
||||||
</div>
|
className={classnames('view-quote__fee-card-container', {
|
||||||
<div className="view-quote__countdown-timer-container">
|
'view-quote__fee-card-container--three-rows':
|
||||||
<CountdownTimer
|
approveTxParams && (!balanceError || warningHidden),
|
||||||
timeStarted={quotesLastFetched}
|
})}
|
||||||
warningTime="0:30"
|
>
|
||||||
labelKey="swapNewQuoteIn"
|
<FeeCard
|
||||||
/>
|
primaryFee={{
|
||||||
</div>
|
fee: feeInEth,
|
||||||
<MainQuoteSummary
|
maxFee: maxFeeInEth,
|
||||||
sourceValue={calcTokenValue(sourceTokenValue, sourceTokenDecimals)}
|
}}
|
||||||
sourceDecimals={sourceTokenDecimals}
|
secondaryFee={{
|
||||||
sourceSymbol={sourceTokenSymbol}
|
fee: feeInFiat,
|
||||||
destinationValue={calcTokenValue(
|
maxFee: maxFeeInFiat,
|
||||||
destinationTokenValue,
|
}}
|
||||||
destinationTokenDecimals,
|
onFeeCardMaxRowClick={onFeeCardMaxRowClick}
|
||||||
)}
|
hideTokenApprovalRow={
|
||||||
destinationDecimals={destinationTokenDecimals}
|
!approveTxParams || (balanceError && !warningHidden)
|
||||||
destinationSymbol={destinationTokenSymbol}
|
}
|
||||||
sourceIconUrl={sourceTokenIconUrl}
|
tokenApprovalSourceTokenSymbol={sourceTokenSymbol}
|
||||||
destinationIconUrl={destinationIconUrl}
|
onTokenApprovalClick={onFeeCardTokenApprovalClick}
|
||||||
/>
|
metaMaskFee={String(metaMaskFee)}
|
||||||
<div
|
numberOfQuotes={Object.values(quotes).length}
|
||||||
className={classnames('view-quote__fee-card-container', {
|
onQuotesClick={() => {
|
||||||
'view-quote__fee-card-container--three-rows':
|
allAvailableQuotesOpened();
|
||||||
approveTxParams && (!balanceError || warningHidden),
|
setSelectQuotePopoverShown(true);
|
||||||
})}
|
}}
|
||||||
>
|
chainId={chainId}
|
||||||
<FeeCard
|
isBestQuote={isBestQuote}
|
||||||
primaryFee={{
|
supportsEIP1559V2={supportsEIP1559V2}
|
||||||
fee: feeInEth,
|
/>
|
||||||
maxFee: maxFeeInEth,
|
</div>
|
||||||
|
</div>
|
||||||
|
<SwapsFooter
|
||||||
|
onSubmit={() => {
|
||||||
|
setSubmitClicked(true);
|
||||||
|
if (!balanceError) {
|
||||||
|
dispatch(signAndSendTransactions(history, metaMetricsEvent));
|
||||||
|
} else if (destinationToken.symbol === defaultSwapsToken.symbol) {
|
||||||
|
history.push(DEFAULT_ROUTE);
|
||||||
|
} else {
|
||||||
|
history.push(`${ASSET_ROUTE}/${destinationToken.address}`);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
secondaryFee={{
|
submitText={t('swap')}
|
||||||
fee: feeInFiat,
|
hideCancel
|
||||||
maxFee: maxFeeInFiat,
|
disabled={
|
||||||
}}
|
submitClicked ||
|
||||||
onFeeCardMaxRowClick={onFeeCardMaxRowClick}
|
balanceError ||
|
||||||
hideTokenApprovalRow={
|
tokenBalanceUnavailable ||
|
||||||
!approveTxParams || (balanceError && !warningHidden)
|
disableSubmissionDueToPriceWarning ||
|
||||||
|
(networkAndAccountSupports1559 &&
|
||||||
|
baseAndPriorityFeePerGas === undefined) ||
|
||||||
|
(!networkAndAccountSupports1559 &&
|
||||||
|
(gasPrice === null || gasPrice === undefined))
|
||||||
}
|
}
|
||||||
tokenApprovalSourceTokenSymbol={sourceTokenSymbol}
|
tokenApprovalSourceTokenSymbol={sourceTokenSymbol}
|
||||||
onTokenApprovalClick={onFeeCardTokenApprovalClick}
|
onTokenApprovalClick={onFeeCardTokenApprovalClick}
|
||||||
@ -772,33 +839,7 @@ export default function ViewQuote() {
|
|||||||
isBestQuote={isBestQuote}
|
isBestQuote={isBestQuote}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TransactionModalContextProvider>
|
||||||
<SwapsFooter
|
</GasFeeContextProvider>
|
||||||
onSubmit={() => {
|
|
||||||
setSubmitClicked(true);
|
|
||||||
if (!balanceError) {
|
|
||||||
dispatch(signAndSendTransactions(history, metaMetricsEvent));
|
|
||||||
} else if (destinationToken.symbol === defaultSwapsToken.symbol) {
|
|
||||||
history.push(DEFAULT_ROUTE);
|
|
||||||
} else {
|
|
||||||
history.push(`${ASSET_ROUTE}/${destinationToken.address}`);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
submitText={t('swap')}
|
|
||||||
hideCancel
|
|
||||||
disabled={
|
|
||||||
submitClicked ||
|
|
||||||
balanceError ||
|
|
||||||
tokenBalanceUnavailable ||
|
|
||||||
disableSubmissionDueToPriceWarning ||
|
|
||||||
(networkAndAccountSupports1559 &&
|
|
||||||
baseAndPriorityFeePerGas === undefined) ||
|
|
||||||
(!networkAndAccountSupports1559 &&
|
|
||||||
(gasPrice === null || gasPrice === undefined))
|
|
||||||
}
|
|
||||||
className={isShowingWarning && 'view-quote__thin-swaps-footer'}
|
|
||||||
showTopBorder
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user