mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Eip1559 v2 12593 (#12719)
This commit is contained in:
parent
582882b3ed
commit
f65063ac6c
@ -404,6 +404,9 @@
|
|||||||
"cancelPopoverTitle": {
|
"cancelPopoverTitle": {
|
||||||
"message": "Cancel transaction"
|
"message": "Cancel transaction"
|
||||||
},
|
},
|
||||||
|
"cancelSpeedUp": {
|
||||||
|
"message": "cancel or speed up a tranaction."
|
||||||
|
},
|
||||||
"cancellationGasFee": {
|
"cancellationGasFee": {
|
||||||
"message": "Cancellation Gas Fee"
|
"message": "Cancellation Gas Fee"
|
||||||
},
|
},
|
||||||
@ -1378,6 +1381,9 @@
|
|||||||
"learmMoreAboutGas": {
|
"learmMoreAboutGas": {
|
||||||
"message": "Want to $1 about gas?"
|
"message": "Want to $1 about gas?"
|
||||||
},
|
},
|
||||||
|
"learnCancelSpeeedup": {
|
||||||
|
"message": "Learn how to $1"
|
||||||
|
},
|
||||||
"learnMore": {
|
"learnMore": {
|
||||||
"message": "learn more"
|
"message": "learn more"
|
||||||
},
|
},
|
||||||
@ -1963,6 +1969,12 @@
|
|||||||
"pending": {
|
"pending": {
|
||||||
"message": "Pending"
|
"message": "Pending"
|
||||||
},
|
},
|
||||||
|
"pendingTransaction": {
|
||||||
|
"message": "You have ($1) pending transaction(s)."
|
||||||
|
},
|
||||||
|
"pendingTransactionInfo": {
|
||||||
|
"message": "This transaction will not process until that one is complete."
|
||||||
|
},
|
||||||
"permissionCheckedIconDescription": {
|
"permissionCheckedIconDescription": {
|
||||||
"message": "You have approved this permission"
|
"message": "You have approved this permission"
|
||||||
},
|
},
|
||||||
|
@ -7,6 +7,9 @@ import ActionableMessage from '../../../ui/actionable-message/actionable-message
|
|||||||
import { PageContainerFooter } from '../../../ui/page-container';
|
import { PageContainerFooter } from '../../../ui/page-container';
|
||||||
import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.';
|
import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.';
|
||||||
|
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
const EIP_1559_V2 = process.env.EIP_1559_V2;
|
||||||
|
|
||||||
export default class ConfirmPageContainerContent extends Component {
|
export default class ConfirmPageContainerContent extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
t: PropTypes.func.isRequired,
|
t: PropTypes.func.isRequired,
|
||||||
@ -138,7 +141,7 @@ export default class ConfirmPageContainerContent extends Component {
|
|||||||
hideTitle={hideTitle}
|
hideTitle={hideTitle}
|
||||||
/>
|
/>
|
||||||
{this.renderContent()}
|
{this.renderContent()}
|
||||||
{(errorKey || errorMessage) && !hasSimulationError && (
|
{!EIP_1559_V2 && !hasSimulationError && (errorKey || errorMessage) && (
|
||||||
<div className="confirm-page-container-content__error-container">
|
<div className="confirm-page-container-content__error-container">
|
||||||
<ErrorMessage errorMessage={errorMessage} errorKey={errorKey} />
|
<ErrorMessage errorMessage={errorMessage} errorKey={errorKey} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,6 +4,9 @@ import PropTypes from 'prop-types';
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Identicon from '../../../../ui/identicon';
|
import Identicon from '../../../../ui/identicon';
|
||||||
|
|
||||||
|
// eslint-disable-next-line prefer-destructuring
|
||||||
|
const EIP_1559_V2 = process.env.EIP_1559_V2;
|
||||||
|
|
||||||
const ConfirmPageContainerSummary = (props) => {
|
const ConfirmPageContainerSummary = (props) => {
|
||||||
const {
|
const {
|
||||||
action,
|
action,
|
||||||
@ -45,7 +48,7 @@ const ConfirmPageContainerSummary = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{hideSubtitle || (
|
{!hideSubtitle && !EIP_1559_V2 && (
|
||||||
<div className="confirm-page-container-summary__subtitle">
|
<div className="confirm-page-container-summary__subtitle">
|
||||||
{subtitleComponent}
|
{subtitleComponent}
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,17 +3,20 @@ import React from 'react';
|
|||||||
import { PRIORITY_LEVELS } from '../../../../shared/constants/gas';
|
import { 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 I18nValue from '../../ui/i18n-value';
|
import I18nValue from '../../ui/i18n-value';
|
||||||
import LoadingHeartBeat from '../../ui/loading-heartbeat';
|
import LoadingHeartBeat from '../../ui/loading-heartbeat';
|
||||||
import Popover from '../../ui/popover';
|
import Popover from '../../ui/popover';
|
||||||
import Typography from '../../ui/typography/typography';
|
import Typography from '../../ui/typography/typography';
|
||||||
|
|
||||||
import { COLORS } from '../../../helpers/constants/design-system';
|
import { COLORS } from '../../../helpers/constants/design-system';
|
||||||
|
import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../helpers/constants/error-keys';
|
||||||
|
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||||
import EditGasItem from './edit-gas-item';
|
import EditGasItem from './edit-gas-item';
|
||||||
import NetworkStatus from './network-status';
|
import NetworkStatus from './network-status';
|
||||||
|
|
||||||
const EditGasFeePopover = () => {
|
const EditGasFeePopover = () => {
|
||||||
|
const { balanceError } = useGasFeeContext();
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const { closeModal, currentModal } = useTransactionModalContext();
|
const { closeModal, currentModal } = useTransactionModalContext();
|
||||||
|
|
||||||
@ -29,6 +32,9 @@ const EditGasFeePopover = () => {
|
|||||||
{process.env.IN_TEST === 'true' ? null : <LoadingHeartBeat />}
|
{process.env.IN_TEST === 'true' ? null : <LoadingHeartBeat />}
|
||||||
<div className="edit-gas-fee-popover__wrapper">
|
<div className="edit-gas-fee-popover__wrapper">
|
||||||
<div className="edit-gas-fee-popover__content">
|
<div className="edit-gas-fee-popover__content">
|
||||||
|
{balanceError && (
|
||||||
|
<ErrorMessage errorKey={INSUFFICIENT_FUNDS_ERROR_KEY} />
|
||||||
|
)}
|
||||||
<div className="edit-gas-fee-popover__content__header">
|
<div className="edit-gas-fee-popover__content__header">
|
||||||
<span className="edit-gas-fee-popover__content__header-option">
|
<span className="edit-gas-fee-popover__content__header-option">
|
||||||
<I18nValue messageKey="gasOption" />
|
<I18nValue messageKey="gasOption" />
|
||||||
|
@ -45,7 +45,7 @@ const MOCK_FEE_ESTIMATE = {
|
|||||||
estimatedBaseFee: '50',
|
estimatedBaseFee: '50',
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = () => {
|
const render = (txProps) => {
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
metamask: {
|
metamask: {
|
||||||
nativeCurrency: ETH,
|
nativeCurrency: ETH,
|
||||||
@ -54,7 +54,7 @@ const renderComponent = () => {
|
|||||||
accounts: {
|
accounts: {
|
||||||
'0xAddress': {
|
'0xAddress': {
|
||||||
address: '0xAddress',
|
address: '0xAddress',
|
||||||
balance: '0x176e5b6f173ebe66',
|
balance: '0x1F4',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
selectedAddress: '0xAddress',
|
selectedAddress: '0xAddress',
|
||||||
@ -64,7 +64,9 @@ const renderComponent = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return renderWithProvider(
|
return renderWithProvider(
|
||||||
<GasFeeContextProvider transaction={{ txParams: { gas: '0x5208' } }}>
|
<GasFeeContextProvider
|
||||||
|
transaction={{ txParams: { gas: '0x5208' }, ...txProps }}
|
||||||
|
>
|
||||||
<EditGasFeePopover />
|
<EditGasFeePopover />
|
||||||
</GasFeeContextProvider>,
|
</GasFeeContextProvider>,
|
||||||
store,
|
store,
|
||||||
@ -73,7 +75,7 @@ const renderComponent = () => {
|
|||||||
|
|
||||||
describe('EditGasFeePopover', () => {
|
describe('EditGasFeePopover', () => {
|
||||||
it('should renders low / medium / high options', () => {
|
it('should renders low / medium / high options', () => {
|
||||||
renderComponent();
|
render();
|
||||||
|
|
||||||
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
||||||
@ -88,15 +90,25 @@ describe('EditGasFeePopover', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show time estimates', () => {
|
it('should show time estimates', () => {
|
||||||
renderComponent();
|
render();
|
||||||
expect(screen.queryAllByText('5 min')).toHaveLength(2);
|
expect(screen.queryAllByText('5 min')).toHaveLength(2);
|
||||||
expect(screen.queryByText('15 sec')).toBeInTheDocument();
|
expect(screen.queryByText('15 sec')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show gas fee estimates', () => {
|
it('should show gas fee estimates', () => {
|
||||||
renderComponent();
|
render();
|
||||||
expect(screen.queryByTitle('0.001113 ETH')).toBeInTheDocument();
|
expect(screen.queryByTitle('0.001113 ETH')).toBeInTheDocument();
|
||||||
expect(screen.queryByTitle('0.00147 ETH')).toBeInTheDocument();
|
expect(screen.queryByTitle('0.00147 ETH')).toBeInTheDocument();
|
||||||
expect(screen.queryByTitle('0.0021 ETH')).toBeInTheDocument();
|
expect(screen.queryByTitle('0.0021 ETH')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not show insufficient balance message if transaction value is less than balance', () => {
|
||||||
|
render({ userFeeLevel: 'high', txParams: { value: '0x64' } });
|
||||||
|
expect(screen.queryByText('Insufficient funds.')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show insufficient balance message if transaction value is more than balance', () => {
|
||||||
|
render({ userFeeLevel: 'high', txParams: { value: '0x5208' } });
|
||||||
|
expect(screen.queryByText('Insufficient funds.')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -41,7 +41,7 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
let maxPriorityFeePerGas;
|
let maxPriorityFeePerGas;
|
||||||
let minWaitTime;
|
let minWaitTime;
|
||||||
|
|
||||||
if (gasFeeEstimates[priorityLevel]) {
|
if (gasFeeEstimates?.[priorityLevel]) {
|
||||||
maxFeePerGas = gasFeeEstimates[priorityLevel].suggestedMaxFeePerGas;
|
maxFeePerGas = gasFeeEstimates[priorityLevel].suggestedMaxFeePerGas;
|
||||||
} else if (
|
} else if (
|
||||||
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
||||||
@ -95,15 +95,20 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<button
|
||||||
className={classNames('edit-gas-item', {
|
className={classNames('edit-gas-item', {
|
||||||
'edit-gas-item-selected': priorityLevel === estimateUsed,
|
'edit-gas-item-selected': priorityLevel === estimateUsed,
|
||||||
'edit-gas-item-disabled':
|
'edit-gas-item-disabled':
|
||||||
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
||||||
!dappSuggestedGasFees,
|
!dappSuggestedGasFees,
|
||||||
})}
|
})}
|
||||||
role="button"
|
disabled={
|
||||||
|
priorityLevel === PRIORITY_LEVELS.DAPP_SUGGESTED &&
|
||||||
|
!dappSuggestedGasFees
|
||||||
|
}
|
||||||
onClick={onOptionSelect}
|
onClick={onOptionSelect}
|
||||||
|
aria-label={priorityLevel}
|
||||||
|
autoFocus={priorityLevel === estimateUsed}
|
||||||
>
|
>
|
||||||
<span className="edit-gas-item__name">
|
<span className="edit-gas-item__name">
|
||||||
<span
|
<span
|
||||||
@ -142,7 +147,7 @@ const EditGasItem = ({ priorityLevel }) => {
|
|||||||
<span className="edit-gas-item__tooltip">
|
<span className="edit-gas-item__tooltip">
|
||||||
<InfoTooltip position="top" />
|
<InfoTooltip position="top" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,6 +82,7 @@ const renderComponent = (props, transactionProps, gasFeeContextProps) => {
|
|||||||
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({ priorityLevel: 'low' });
|
||||||
|
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();
|
||||||
expect(screen.queryByText('5 min')).toBeInTheDocument();
|
expect(screen.queryByText('5 min')).toBeInTheDocument();
|
||||||
@ -90,6 +91,9 @@ 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({ priorityLevel: 'medium' });
|
||||||
|
expect(
|
||||||
|
screen.queryByRole('button', { name: 'medium' }),
|
||||||
|
).toBeInTheDocument();
|
||||||
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('Market')).toBeInTheDocument();
|
expect(screen.queryByText('Market')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('5 min')).toBeInTheDocument();
|
expect(screen.queryByText('5 min')).toBeInTheDocument();
|
||||||
@ -98,6 +102,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({ priorityLevel: 'high' });
|
||||||
|
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();
|
||||||
expect(screen.queryByText('15 sec')).toBeInTheDocument();
|
expect(screen.queryByText('15 sec')).toBeInTheDocument();
|
||||||
@ -116,6 +121,9 @@ describe('EditGasItem', () => {
|
|||||||
{ priorityLevel: 'dappSuggested' },
|
{ priorityLevel: 'dappSuggested' },
|
||||||
{ dappSuggestedGasFees: DAPP_SUGGESTED_ESTIMATE },
|
{ dappSuggestedGasFees: DAPP_SUGGESTED_ESTIMATE },
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
screen.queryByRole('button', { name: 'dappSuggested' }),
|
||||||
|
).toBeInTheDocument();
|
||||||
expect(screen.queryByText('🌐')).toBeInTheDocument();
|
expect(screen.queryByText('🌐')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('Site')).toBeInTheDocument();
|
expect(screen.queryByText('Site')).toBeInTheDocument();
|
||||||
expect(screen.queryByTitle('0.0000315 ETH')).toBeInTheDocument();
|
expect(screen.queryByTitle('0.0000315 ETH')).toBeInTheDocument();
|
||||||
@ -130,6 +138,9 @@ 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' });
|
renderComponent({ priorityLevel: 'custom' });
|
||||||
|
expect(
|
||||||
|
screen.queryByRole('button', { name: 'custom' }),
|
||||||
|
).toBeInTheDocument();
|
||||||
expect(screen.queryByText('⚙')).toBeInTheDocument();
|
expect(screen.queryByText('⚙')).toBeInTheDocument();
|
||||||
expect(screen.queryByText('Advanced')).toBeInTheDocument();
|
expect(screen.queryByText('Advanced')).toBeInTheDocument();
|
||||||
// below value of custom gas fee estimate is default obtained from state.metamask.advancedGasFee
|
// below value of custom gas fee estimate is default obtained from state.metamask.advancedGasFee
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.edit-gas-item {
|
.edit-gas-item {
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
|
background: white;
|
||||||
color: $ui-4;
|
color: $ui-4;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -8,6 +9,7 @@
|
|||||||
margin: 12px 0;
|
margin: 12px 0;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&--selected {
|
&--selected {
|
||||||
background-color: $ui-1;
|
background-color: $ui-1;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.edit-gas-fee-popover {
|
.edit-gas-fee-popover {
|
||||||
height: 500px;
|
height: 540px;
|
||||||
|
|
||||||
&__wrapper {
|
&__wrapper {
|
||||||
border-top: 1px solid $ui-grey;
|
border-top: 1px solid $ui-grey;
|
||||||
@ -8,6 +8,11 @@
|
|||||||
&__content {
|
&__content {
|
||||||
padding: 16px 12px;
|
padding: 16px 12px;
|
||||||
|
|
||||||
|
& .error-message {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
color: $ui-4;
|
color: $ui-4;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 65%;
|
width: 55%;
|
||||||
|
|
||||||
&__line {
|
&__line {
|
||||||
background-image: linear-gradient(to right, #037dd6, #d73a49);
|
background-image: linear-gradient(to right, #037dd6, #d73a49);
|
||||||
|
@ -54,7 +54,7 @@ import Typography from '../../components/ui/typography/typography';
|
|||||||
import { MIN_GAS_LIMIT_DEC } from '../send/send.constants';
|
import { MIN_GAS_LIMIT_DEC } from '../send/send.constants';
|
||||||
|
|
||||||
import GasDetailsItem from './gas-details-item';
|
import GasDetailsItem from './gas-details-item';
|
||||||
import LowPriorityMessage from './low-priority-message';
|
import TransactionAlerts from './transaction-alerts';
|
||||||
|
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
const EIP_1559_V2 = process.env.EIP_1559_V2;
|
const EIP_1559_V2 = process.env.EIP_1559_V2;
|
||||||
@ -569,7 +569,7 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="confirm-page-container-content__details">
|
<div className="confirm-page-container-content__details">
|
||||||
{EIP_1559_V2 && <LowPriorityMessage />}
|
{EIP_1559_V2 && <TransactionAlerts />}
|
||||||
<TransactionDetail
|
<TransactionDetail
|
||||||
disabled={isDisabled()}
|
disabled={isDisabled()}
|
||||||
onEdit={
|
onEdit={
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { default } from './low-priority-message';
|
|
@ -1,24 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import ActionableMessage from '../../../components/ui/actionable-message/actionable-message';
|
|
||||||
import { useGasFeeContext } from '../../../contexts/gasFee';
|
|
||||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
|
||||||
|
|
||||||
const LowPriorityMessage = () => {
|
|
||||||
const { estimateUsed } = useGasFeeContext();
|
|
||||||
const t = useI18nContext();
|
|
||||||
|
|
||||||
if (estimateUsed !== 'low') return null;
|
|
||||||
return (
|
|
||||||
<div className="low-priority-message">
|
|
||||||
<ActionableMessage
|
|
||||||
className="actionable-message--warning"
|
|
||||||
message={t('lowPriorityMessage')}
|
|
||||||
useIcon
|
|
||||||
iconFillColor="#f8c000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LowPriorityMessage;
|
|
@ -1,3 +0,0 @@
|
|||||||
.low-priority-message {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
|
||||||
import { ETH } from '../../../helpers/constants/common';
|
|
||||||
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
|
||||||
import configureStore from '../../../store/store';
|
|
||||||
|
|
||||||
import LowPriorityMessage from './low-priority-message';
|
|
||||||
|
|
||||||
jest.mock('../../../store/actions', () => ({
|
|
||||||
disconnectGasFeeEstimatePoller: jest.fn(),
|
|
||||||
getGasFeeEstimatesAndStartPolling: jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementation(() => Promise.resolve()),
|
|
||||||
addPollingTokenToAppState: jest.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const render = (props) => {
|
|
||||||
const store = configureStore({
|
|
||||||
metamask: {
|
|
||||||
nativeCurrency: ETH,
|
|
||||||
preferences: {
|
|
||||||
useNativeCurrencyAsPrimaryCurrency: true,
|
|
||||||
},
|
|
||||||
provider: {},
|
|
||||||
cachedBalances: {},
|
|
||||||
accounts: {
|
|
||||||
'0xAddress': {
|
|
||||||
address: '0xAddress',
|
|
||||||
balance: '0x176e5b6f173ebe66',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selectedAddress: '0xAddress',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return renderWithProvider(
|
|
||||||
<GasFeeContextProvider {...props}>
|
|
||||||
<LowPriorityMessage />
|
|
||||||
</GasFeeContextProvider>,
|
|
||||||
store,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('LowPriorityMessage', () => {
|
|
||||||
it('should returning warning message for low gas estimate', () => {
|
|
||||||
render({ transaction: { userFeeLevel: 'low' } });
|
|
||||||
expect(
|
|
||||||
document.getElementsByClassName('actionable-message--warning'),
|
|
||||||
).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null for gas estimate other than low', () => {
|
|
||||||
render({ transaction: { userFeeLevel: 'high' } });
|
|
||||||
expect(
|
|
||||||
document.getElementsByClassName('actionable-message--warning'),
|
|
||||||
).toHaveLength(0);
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1 @@
|
|||||||
|
export { default } from './transaction-alerts';
|
@ -0,0 +1,73 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../helpers/constants/error-keys';
|
||||||
|
import { submittedPendingTransactionsSelector } from '../../../selectors/transactions';
|
||||||
|
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||||
|
import ActionableMessage from '../../../components/ui/actionable-message/actionable-message';
|
||||||
|
import ErrorMessage from '../../../components/ui/error-message';
|
||||||
|
import I18nValue from '../../../components/ui/i18n-value';
|
||||||
|
|
||||||
|
const TransactionAlerts = () => {
|
||||||
|
const { balanceError, estimateUsed } = useGasFeeContext();
|
||||||
|
const pendingTransactions = useSelector(submittedPendingTransactionsSelector);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="transaction-alerts">
|
||||||
|
{pendingTransactions?.length > 0 && (
|
||||||
|
<ActionableMessage
|
||||||
|
message={
|
||||||
|
<div className="transaction-alerts__pending-transactions">
|
||||||
|
<strong>
|
||||||
|
<I18nValue
|
||||||
|
messageKey="pendingTransaction"
|
||||||
|
options={[pendingTransactions?.length]}
|
||||||
|
/>
|
||||||
|
</strong>{' '}
|
||||||
|
<I18nValue messageKey="pendingTransactionInfo" />{' '}
|
||||||
|
<I18nValue
|
||||||
|
messageKey="learnCancelSpeeedup"
|
||||||
|
options={[
|
||||||
|
<a
|
||||||
|
key="cancelSpeedUpInfo"
|
||||||
|
href="https://metamask.zendesk.com/hc/en-us/articles/360015489251-How-to-speed-up-or-cancel-a-pending-transaction"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<I18nValue messageKey="cancelSpeedUp" />
|
||||||
|
</a>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
useIcon
|
||||||
|
iconFillColor="#f8c000"
|
||||||
|
type="warning"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{balanceError && (
|
||||||
|
<>
|
||||||
|
{pendingTransactions?.length > 0 && (
|
||||||
|
<div className="transaction-alerts--separator" />
|
||||||
|
)}
|
||||||
|
<ErrorMessage errorKey={INSUFFICIENT_FUNDS_ERROR_KEY} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{estimateUsed === 'low' && (
|
||||||
|
<>
|
||||||
|
{balanceError && (
|
||||||
|
<div className="transaction-alerts-message--separator" />
|
||||||
|
)}
|
||||||
|
<ActionableMessage
|
||||||
|
message={<I18nValue messageKey="lowPriorityMessage" />}
|
||||||
|
useIcon
|
||||||
|
iconFillColor="#f8c000"
|
||||||
|
type="warning"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TransactionAlerts;
|
@ -0,0 +1,17 @@
|
|||||||
|
.transaction-alerts {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
&--separator {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__pending-transactions {
|
||||||
|
& a {
|
||||||
|
color: $primary-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { ETH } from '../../../helpers/constants/common';
|
||||||
|
import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
|
||||||
|
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
||||||
|
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
||||||
|
import configureStore from '../../../store/store';
|
||||||
|
|
||||||
|
import TransactionAlerts from './transaction-alerts';
|
||||||
|
|
||||||
|
jest.mock('../../../store/actions', () => ({
|
||||||
|
disconnectGasFeeEstimatePoller: jest.fn(),
|
||||||
|
getGasFeeEstimatesAndStartPolling: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve()),
|
||||||
|
addPollingTokenToAppState: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const render = ({ props, state }) => {
|
||||||
|
const store = configureStore({
|
||||||
|
metamask: {
|
||||||
|
nativeCurrency: ETH,
|
||||||
|
preferences: {
|
||||||
|
useNativeCurrencyAsPrimaryCurrency: true,
|
||||||
|
},
|
||||||
|
provider: {},
|
||||||
|
cachedBalances: {},
|
||||||
|
accounts: {
|
||||||
|
'0xAddress': {
|
||||||
|
address: '0xAddress',
|
||||||
|
balance: '0x1F4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectedAddress: '0xAddress',
|
||||||
|
...state,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return renderWithProvider(
|
||||||
|
<GasFeeContextProvider {...props}>
|
||||||
|
<TransactionAlerts />
|
||||||
|
</GasFeeContextProvider>,
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('TransactionAlerts', () => {
|
||||||
|
it('should returning warning message for low gas estimate', () => {
|
||||||
|
render({ props: { transaction: { userFeeLevel: 'low' } } });
|
||||||
|
expect(
|
||||||
|
document.getElementsByClassName('actionable-message--warning'),
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null for gas estimate other than low', () => {
|
||||||
|
render({ props: { transaction: { userFeeLevel: 'high' } } });
|
||||||
|
expect(
|
||||||
|
document.getElementsByClassName('actionable-message--warning'),
|
||||||
|
).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show insufficient balance message if transaction value is less than balance', () => {
|
||||||
|
render({
|
||||||
|
props: {
|
||||||
|
transaction: { userFeeLevel: 'high', txParams: { value: '0x64' } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('Insufficient funds.')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show insufficient balance message if transaction value is more than balance', () => {
|
||||||
|
render({
|
||||||
|
props: {
|
||||||
|
transaction: { userFeeLevel: 'high', txParams: { value: '0x5208' } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('Insufficient funds.')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show pending transaction message if there are >= 1 pending transactions', () => {
|
||||||
|
render({
|
||||||
|
state: {
|
||||||
|
currentNetworkTxList: [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
time: 0,
|
||||||
|
txParams: {
|
||||||
|
from: '0xAddress',
|
||||||
|
to: '0xRecipient',
|
||||||
|
},
|
||||||
|
status: TRANSACTION_STATUSES.SUBMITTED,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
screen.queryByText('You have (1) pending transaction(s).'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -6,7 +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/low-priority-message/low-priority-message';
|
@import 'confirm-transaction-base/transaction-alerts/transaction-alerts';
|
||||||
@import 'confirmation/confirmation';
|
@import 'confirmation/confirmation';
|
||||||
@import 'connected-sites/index';
|
@import 'connected-sites/index';
|
||||||
@import 'connected-accounts/index';
|
@import 'connected-accounts/index';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user