mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Using EIP-1559 V2 for approve transaction flow (#12906)
This commit is contained in:
parent
a6bb503e52
commit
6fc9b6b7a2
@ -13,6 +13,7 @@
|
|||||||
@import 'connected-status-indicator/index';
|
@import 'connected-status-indicator/index';
|
||||||
@import 'edit-gas-display/index';
|
@import 'edit-gas-display/index';
|
||||||
@import 'edit-gas-display-education/index';
|
@import 'edit-gas-display-education/index';
|
||||||
|
@import 'edit-gas-fee-button/index';
|
||||||
@import 'edit-gas-fee-popover/index';
|
@import 'edit-gas-fee-popover/index';
|
||||||
@import 'edit-gas-fee-popover/edit-gas-item/index';
|
@import 'edit-gas-fee-popover/edit-gas-item/index';
|
||||||
@import 'edit-gas-fee-popover/network-statistics/index';
|
@import 'edit-gas-fee-popover/network-statistics/index';
|
||||||
|
73
ui/components/app/edit-gas-fee-button/edit-gas-fee-button.js
Normal file
73
ui/components/app/edit-gas-fee-button/edit-gas-fee-button.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { COLORS } from '../../../helpers/constants/design-system';
|
||||||
|
import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas';
|
||||||
|
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||||
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
|
import { useTransactionModalContext } from '../../../contexts/transaction-modal';
|
||||||
|
import InfoTooltip from '../../ui/info-tooltip/info-tooltip';
|
||||||
|
import Typography from '../../ui/typography/typography';
|
||||||
|
|
||||||
|
export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
||||||
|
const t = useI18nContext();
|
||||||
|
const {
|
||||||
|
gasLimit,
|
||||||
|
hasSimulationError,
|
||||||
|
estimateUsed,
|
||||||
|
maxFeePerGas,
|
||||||
|
maxPriorityFeePerGas,
|
||||||
|
supportsEIP1559V2,
|
||||||
|
transaction,
|
||||||
|
} = useGasFeeContext();
|
||||||
|
const { openModal } = useTransactionModalContext();
|
||||||
|
const editEnabled =
|
||||||
|
!hasSimulationError || userAcknowledgedGasMissing === true;
|
||||||
|
|
||||||
|
if (!supportsEIP1559V2 || !estimateUsed || !editEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="edit-gas-fee-button">
|
||||||
|
<button onClick={() => openModal('editGasFee')}>
|
||||||
|
<span className="edit-gas-fee-button__icon">
|
||||||
|
{`${PRIORITY_LEVEL_ICON_MAP[estimateUsed]} `}
|
||||||
|
</span>
|
||||||
|
<span className="edit-gas-fee-button__label">{t(estimateUsed)}</span>
|
||||||
|
<i className="fas fa-chevron-right asset-list-item__chevron-right" />
|
||||||
|
</button>
|
||||||
|
{estimateUsed === 'custom' && (
|
||||||
|
<button onClick={() => openModal('advancedGasFee')}>{t('edit')}</button>
|
||||||
|
)}
|
||||||
|
{estimateUsed === 'dappSuggested' && (
|
||||||
|
<InfoTooltip
|
||||||
|
contentText={
|
||||||
|
<div className="edit-gas-fee-button__tooltip">
|
||||||
|
<Typography fontSize="12px" color={COLORS.GREY}>
|
||||||
|
{t('dappSuggestedTooltip', [transaction.origin])}
|
||||||
|
</Typography>
|
||||||
|
<Typography fontSize="12px">
|
||||||
|
<b>{t('maxBaseFee')}</b>
|
||||||
|
{maxFeePerGas}
|
||||||
|
</Typography>
|
||||||
|
<Typography fontSize="12px">
|
||||||
|
<b>{t('maxPriorityFee')}</b>
|
||||||
|
{maxPriorityFeePerGas}
|
||||||
|
</Typography>
|
||||||
|
<Typography fontSize="12px">
|
||||||
|
<b>{t('gasLimit')}</b>
|
||||||
|
{gasLimit}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
position="top"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditGasFeeButton.propTypes = {
|
||||||
|
userAcknowledgedGasMissing: PropTypes.bool,
|
||||||
|
};
|
@ -0,0 +1,140 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
GAS_ESTIMATE_TYPES,
|
||||||
|
PRIORITY_LEVELS,
|
||||||
|
} from '../../../../shared/constants/gas';
|
||||||
|
import { TRANSACTION_ENVELOPE_TYPES } from '../../../../shared/constants/transaction';
|
||||||
|
|
||||||
|
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
||||||
|
import { renderWithProvider } from '../../../../test/jest';
|
||||||
|
import mockEstimates from '../../../../test/data/mock-estimates.json';
|
||||||
|
import mockState from '../../../../test/data/mock-state.json';
|
||||||
|
import configureStore from '../../../store/store';
|
||||||
|
|
||||||
|
import EditGasFeeButton from './edit-gas-fee-button';
|
||||||
|
|
||||||
|
jest.mock('../../../store/actions', () => ({
|
||||||
|
disconnectGasFeeEstimatePoller: jest.fn(),
|
||||||
|
getGasFeeEstimatesAndStartPolling: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve()),
|
||||||
|
addPollingTokenToAppState: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const render = ({ componentProps, contextProps } = {}) => {
|
||||||
|
const store = configureStore({
|
||||||
|
metamask: {
|
||||||
|
...mockState.metamask,
|
||||||
|
accounts: {
|
||||||
|
[mockState.metamask.selectedAddress]: {
|
||||||
|
address: mockState.metamask.selectedAddress,
|
||||||
|
balance: '0x1F4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gasFeeEstimates: mockEstimates[GAS_ESTIMATE_TYPES.FEE_MARKET],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return renderWithProvider(
|
||||||
|
<GasFeeContextProvider {...contextProps}>
|
||||||
|
<EditGasFeeButton {...componentProps} />
|
||||||
|
</GasFeeContextProvider>,
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('EditGasFeeButton', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
process.env.EIP_1559_V2 = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
process.env.EIP_1559_V2 = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edit link with text low if low gas estimates are selected', () => {
|
||||||
|
render({ contextProps: { transaction: { userFeeLevel: 'low' } } });
|
||||||
|
expect(screen.queryByText('🐢')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Low')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edit link with text market if medium gas estimates are selected', () => {
|
||||||
|
render({ contextProps: { transaction: { userFeeLevel: 'medium' } } });
|
||||||
|
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Market')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edit link with text agressive if high gas estimates are selected', () => {
|
||||||
|
render({ contextProps: { transaction: { userFeeLevel: 'high' } } });
|
||||||
|
expect(screen.queryByText('🦍')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Aggressive')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edit link with text Site suggested if site suggested estimated are used', () => {
|
||||||
|
render({
|
||||||
|
contextProps: {
|
||||||
|
transaction: {
|
||||||
|
userFeeLevel: PRIORITY_LEVELS.DAPP_SUGGESTED,
|
||||||
|
dappSuggestedGasFees: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 },
|
||||||
|
txParams: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('🌐')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Site suggested')).toBeInTheDocument();
|
||||||
|
expect(document.getElementsByClassName('info-tooltip')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edit link with text advance if custom gas estimates are used', () => {
|
||||||
|
render({
|
||||||
|
contextProps: {
|
||||||
|
defaultEstimateToUse: 'custom',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(screen.queryByText('⚙')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Advanced')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Edit')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render edit link if transaction has simulation error and prop userAcknowledgedGasMissing is false', () => {
|
||||||
|
render({
|
||||||
|
contextProps: {
|
||||||
|
transaction: {
|
||||||
|
simulationFails: true,
|
||||||
|
userFeeLevel: 'low',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
componentProps: { userAcknowledgedGasMissing: false },
|
||||||
|
});
|
||||||
|
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Low')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render edit link if userAcknowledgedGasMissing is true even if transaction has simulation error', () => {
|
||||||
|
render({
|
||||||
|
contextProps: {
|
||||||
|
transaction: {
|
||||||
|
simulationFails: true,
|
||||||
|
userFeeLevel: 'low',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
componentProps: { userAcknowledgedGasMissing: true },
|
||||||
|
});
|
||||||
|
expect(screen.queryByRole('button')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Low')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render null for legacy transactions', () => {
|
||||||
|
const { container } = render({
|
||||||
|
contextProps: {
|
||||||
|
transaction: {
|
||||||
|
userFeeLevel: 'low',
|
||||||
|
txParams: { type: TRANSACTION_ENVELOPE_TYPES.LEGACY },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
1
ui/components/app/edit-gas-fee-button/index.js
Normal file
1
ui/components/app/edit-gas-fee-button/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './edit-gas-fee-button';
|
48
ui/components/app/edit-gas-fee-button/index.scss
Normal file
48
ui/components/app/edit-gas-fee-button/index.scss
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
.edit-gas-fee-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include H7;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
color: $primary-1;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
padding-inline-end: 0;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: $primary-1;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-tooltip {
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tooltip {
|
||||||
|
p {
|
||||||
|
color: $Grey-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
color: $neutral-black;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -44,15 +44,15 @@ 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
|
||||||
) {
|
) {
|
||||||
maxFeePerGas = hexWEIToDecGWEI(dappSuggestedGasFees.maxFeePerGas);
|
maxFeePerGas = hexWEIToDecGWEI(
|
||||||
|
dappSuggestedGasFees.maxFeePerGas || dappSuggestedGasFees.gasPrice,
|
||||||
|
);
|
||||||
maxPriorityFeePerGas = hexWEIToDecGWEI(
|
maxPriorityFeePerGas = hexWEIToDecGWEI(
|
||||||
dappSuggestedGasFees.maxPriorityFeePerGas,
|
dappSuggestedGasFees.maxPriorityFeePerGas || maxFeePerGas,
|
||||||
);
|
);
|
||||||
} else if (priorityLevel === PRIORITY_LEVELS.CUSTOM) {
|
} else if (priorityLevel === PRIORITY_LEVELS.CUSTOM) {
|
||||||
if (estimateUsed === PRIORITY_LEVELS.CUSTOM) {
|
if (estimateUsed === PRIORITY_LEVELS.CUSTOM) {
|
||||||
|
@ -118,7 +118,10 @@ describe('EditGasItem', () => {
|
|||||||
it('should renders site gas estimate option for priorityLevel dappSuggested', () => {
|
it('should renders site gas estimate option for priorityLevel dappSuggested', () => {
|
||||||
renderComponent(
|
renderComponent(
|
||||||
{ priorityLevel: 'dappSuggested' },
|
{ priorityLevel: 'dappSuggested' },
|
||||||
{ 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' }),
|
||||||
|
@ -16,72 +16,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-edit-V2 {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding-top: 20px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
@include H7;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
color: $primary-1;
|
|
||||||
background: transparent;
|
|
||||||
border: 0;
|
|
||||||
padding-inline-end: 0;
|
|
||||||
position: relative;
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__edit-button {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
color: $primary-1;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
|
||||||
@include Paragraph;
|
|
||||||
|
|
||||||
line-height: 1;
|
|
||||||
position: absolute;
|
|
||||||
left: -16px;
|
|
||||||
top: 0;
|
|
||||||
|
|
||||||
&-custom {
|
|
||||||
font-size: 1.35rem;
|
|
||||||
left: -12px;
|
|
||||||
top: -2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__label {
|
|
||||||
font-size: 12px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-tooltip {
|
|
||||||
align-self: center;
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__tooltip {
|
|
||||||
p {
|
|
||||||
color: $Grey-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
b {
|
|
||||||
color: $neutral-black;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 60%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-rows {
|
&-rows {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,11 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { useGasFeeContext } from '../../../contexts/gasFee';
|
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||||
import { useTransactionModalContext } from '../../../contexts/transaction-modal';
|
|
||||||
import InfoTooltip from '../../ui/info-tooltip/info-tooltip';
|
|
||||||
import Typography from '../../ui/typography/typography';
|
|
||||||
|
|
||||||
import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component';
|
|
||||||
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system';
|
|
||||||
import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas';
|
|
||||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
|
import Box from '../../ui/box';
|
||||||
|
|
||||||
|
import EditGasFeeButton from '../edit-gas-fee-button';
|
||||||
|
import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component';
|
||||||
|
|
||||||
export default function TransactionDetail({
|
export default function TransactionDetail({
|
||||||
rows = [],
|
rows = [],
|
||||||
@ -17,89 +14,18 @@ export default function TransactionDetail({
|
|||||||
userAcknowledgedGasMissing,
|
userAcknowledgedGasMissing,
|
||||||
}) {
|
}) {
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
const {
|
const { supportsEIP1559V2 } = useGasFeeContext();
|
||||||
gasLimit,
|
|
||||||
hasSimulationError,
|
|
||||||
estimateUsed,
|
|
||||||
maxFeePerGas,
|
|
||||||
maxPriorityFeePerGas,
|
|
||||||
supportsEIP1559V2,
|
|
||||||
transaction,
|
|
||||||
} = useGasFeeContext();
|
|
||||||
const { openModal } = useTransactionModalContext();
|
|
||||||
|
|
||||||
if (supportsEIP1559V2 && estimateUsed) {
|
|
||||||
const editEnabled = !hasSimulationError || userAcknowledgedGasMissing;
|
|
||||||
if (!editEnabled) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="transaction-detail">
|
<div className="transaction-detail">
|
||||||
<div className="transaction-detail-edit-V2">
|
{supportsEIP1559V2 && (
|
||||||
<button onClick={() => openModal('editGasFee')}>
|
<Box display="flex" justifyContent="flex-end" paddingTop={5}>
|
||||||
<span
|
<EditGasFeeButton
|
||||||
className={`transaction-detail-edit-V2__icon transaction-detail-edit-V2__icon-${estimateUsed}`}
|
userAcknowledgedGasMissing={userAcknowledgedGasMissing}
|
||||||
>
|
|
||||||
{`${PRIORITY_LEVEL_ICON_MAP[estimateUsed]} `}
|
|
||||||
</span>
|
|
||||||
<span className="transaction-detail-edit-V2__label">
|
|
||||||
{t(estimateUsed)}
|
|
||||||
</span>
|
|
||||||
<i className="fas fa-chevron-right asset-list-item__chevron-right" />
|
|
||||||
</button>
|
|
||||||
{estimateUsed === 'custom' && (
|
|
||||||
<button
|
|
||||||
onClick={() => openModal('advancedGasFee')}
|
|
||||||
className="transaction-detail__edit-button"
|
|
||||||
>
|
|
||||||
{t('edit')}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{estimateUsed === 'dappSuggested' && (
|
|
||||||
<InfoTooltip
|
|
||||||
contentText={
|
|
||||||
<div className="transaction-detail-edit-V2__tooltip">
|
|
||||||
<Typography
|
|
||||||
tag={TYPOGRAPHY.Paragraph}
|
|
||||||
variant={TYPOGRAPHY.H7}
|
|
||||||
color={COLORS.GREY}
|
|
||||||
>
|
|
||||||
{t('dappSuggestedTooltip', [transaction.origin])}
|
|
||||||
</Typography>
|
|
||||||
<Typography
|
|
||||||
tag={TYPOGRAPHY.Paragraph}
|
|
||||||
variant={TYPOGRAPHY.H7}
|
|
||||||
>
|
|
||||||
<strong>{t('maxBaseFee')}</strong>
|
|
||||||
{maxFeePerGas}
|
|
||||||
</Typography>
|
|
||||||
<Typography
|
|
||||||
tag={TYPOGRAPHY.Paragraph}
|
|
||||||
variant={TYPOGRAPHY.H7}
|
|
||||||
>
|
|
||||||
<strong>{t('maxPriorityFee')}</strong>
|
|
||||||
{maxPriorityFeePerGas}
|
|
||||||
</Typography>
|
|
||||||
<Typography
|
|
||||||
tag={TYPOGRAPHY.Paragraph}
|
|
||||||
variant={TYPOGRAPHY.H7}
|
|
||||||
>
|
|
||||||
<strong>{t('gasLimit')}</strong>
|
|
||||||
{gasLimit}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
position="top"
|
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</div>
|
{!supportsEIP1559V2 && onEdit && (
|
||||||
<div className="transaction-detail-rows">{rows}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="transaction-detail">
|
|
||||||
{onEdit && (
|
|
||||||
<div className="transaction-detail-edit">
|
<div className="transaction-detail-edit">
|
||||||
<button onClick={onEdit}>{t('edit')}</button>
|
<button onClick={onEdit}>{t('edit')}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
|
|
||||||
import {
|
import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas';
|
||||||
GAS_ESTIMATE_TYPES,
|
|
||||||
PRIORITY_LEVELS,
|
|
||||||
} from '../../../../shared/constants/gas';
|
|
||||||
import { TRANSACTION_ENVELOPE_TYPES } from '../../../../shared/constants/transaction';
|
import { TRANSACTION_ENVELOPE_TYPES } from '../../../../shared/constants/transaction';
|
||||||
|
|
||||||
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
import { GasFeeContextProvider } from '../../../contexts/gasFee';
|
||||||
@ -67,72 +64,6 @@ describe('TransactionDetail', () => {
|
|||||||
expect(screen.queryByText('Low')).toBeInTheDocument();
|
expect(screen.queryByText('Low')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render edit link with text markey if medium gas estimates are selected', () => {
|
|
||||||
render({ contextProps: { transaction: { userFeeLevel: 'medium' } } });
|
|
||||||
expect(screen.queryByText('🦊')).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Market')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render edit link with text agressive if high gas estimates are selected', () => {
|
|
||||||
render({ contextProps: { transaction: { userFeeLevel: 'high' } } });
|
|
||||||
expect(screen.queryByText('🦍')).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Aggressive')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render edit link with text Site suggested if site suggested estimated are used', () => {
|
|
||||||
render({
|
|
||||||
contextProps: {
|
|
||||||
transaction: {
|
|
||||||
userFeeLevel: PRIORITY_LEVELS.DAPP_SUGGESTED,
|
|
||||||
dappSuggestedGasFees: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 },
|
|
||||||
txParams: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(screen.queryByText('🌐')).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Site suggested')).toBeInTheDocument();
|
|
||||||
expect(document.getElementsByClassName('info-tooltip')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render edit link with text advance if custom gas estimates are used', () => {
|
|
||||||
render({
|
|
||||||
contextProps: {
|
|
||||||
defaultEstimateToUse: 'custom',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(screen.queryByText('⚙')).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Advanced')).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Edit')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not render edit link if transaction has simulation error and prop userAcknowledgedGasMissing is false', () => {
|
|
||||||
render({
|
|
||||||
contextProps: {
|
|
||||||
transaction: {
|
|
||||||
simulationFails: true,
|
|
||||||
userFeeLevel: 'low',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
componentProps: { userAcknowledgedGasMissing: false },
|
|
||||||
});
|
|
||||||
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Low')).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render edit link if userAcknowledgedGasMissing is true even if transaction has simulation error', () => {
|
|
||||||
render({
|
|
||||||
contextProps: {
|
|
||||||
transaction: {
|
|
||||||
simulationFails: true,
|
|
||||||
userFeeLevel: 'low',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
componentProps: { userAcknowledgedGasMissing: true },
|
|
||||||
});
|
|
||||||
expect(screen.queryByRole('button')).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Low')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render edit link with text edit for legacy transactions', () => {
|
it('should render edit link with text edit for legacy transactions', () => {
|
||||||
render({
|
render({
|
||||||
contextProps: {
|
contextProps: {
|
||||||
|
@ -12,6 +12,7 @@ export const TransactionModalContextProvider = ({
|
|||||||
actionKey,
|
actionKey,
|
||||||
children,
|
children,
|
||||||
methodData,
|
methodData,
|
||||||
|
captureEventEnabled = true,
|
||||||
}) => {
|
}) => {
|
||||||
const [openModals, setOpenModals] = useState([]);
|
const [openModals, setOpenModals] = useState([]);
|
||||||
const metricsEvent = useMetaMetricsContext();
|
const metricsEvent = useMetaMetricsContext();
|
||||||
@ -28,7 +29,7 @@ export const TransactionModalContextProvider = ({
|
|||||||
recipientKnown: null,
|
recipientKnown: null,
|
||||||
functionType:
|
functionType:
|
||||||
actionKey ||
|
actionKey ||
|
||||||
getMethodName(methodData.name) ||
|
getMethodName(methodData?.name) ||
|
||||||
TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
||||||
origin,
|
origin,
|
||||||
},
|
},
|
||||||
@ -49,7 +50,7 @@ export const TransactionModalContextProvider = ({
|
|||||||
|
|
||||||
const openModal = (modalName) => {
|
const openModal = (modalName) => {
|
||||||
if (openModals.includes(modalName)) return;
|
if (openModals.includes(modalName)) return;
|
||||||
captureEvent();
|
captureEventEnabled && captureEvent();
|
||||||
const modals = [...openModals];
|
const modals = [...openModals];
|
||||||
modals.push(modalName);
|
modals.push(modalName);
|
||||||
setOpenModals(modals);
|
setOpenModals(modals);
|
||||||
@ -77,4 +78,5 @@ TransactionModalContextProvider.propTypes = {
|
|||||||
actionKey: PropTypes.string,
|
actionKey: PropTypes.string,
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node.isRequired,
|
||||||
methodData: PropTypes.object,
|
methodData: PropTypes.object,
|
||||||
|
captureEventEnabled: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,7 @@ import { ellipsify } from '../../send/send.utils';
|
|||||||
import Typography from '../../../components/ui/typography';
|
import Typography from '../../../components/ui/typography';
|
||||||
import Box from '../../../components/ui/box';
|
import Box from '../../../components/ui/box';
|
||||||
import Button from '../../../components/ui/button';
|
import Button from '../../../components/ui/button';
|
||||||
|
import EditGasFeeButton from '../../../components/app/edit-gas-fee-button';
|
||||||
import MetaFoxLogo from '../../../components/ui/metafox-logo';
|
import MetaFoxLogo from '../../../components/ui/metafox-logo';
|
||||||
import Identicon from '../../../components/ui/identicon';
|
import Identicon from '../../../components/ui/identicon';
|
||||||
import MultiLayerFeeMessage from '../../../components/app/multilayer-fee-message';
|
import MultiLayerFeeMessage from '../../../components/app/multilayer-fee-message';
|
||||||
@ -64,6 +65,7 @@ export default class ConfirmApproveContent extends Component {
|
|||||||
isContract: PropTypes.bool,
|
isContract: PropTypes.bool,
|
||||||
hexTransactionTotal: PropTypes.string,
|
hexTransactionTotal: PropTypes.string,
|
||||||
isMultiLayerFeeNetwork: PropTypes.bool,
|
isMultiLayerFeeNetwork: PropTypes.bool,
|
||||||
|
supportsEIP1559V2: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -76,11 +78,13 @@ export default class ConfirmApproveContent extends Component {
|
|||||||
symbol,
|
symbol,
|
||||||
title,
|
title,
|
||||||
showEdit,
|
showEdit,
|
||||||
|
showAdvanceGasFeeOptions = false,
|
||||||
onEditClick,
|
onEditClick,
|
||||||
content,
|
content,
|
||||||
footer,
|
footer,
|
||||||
noBorder,
|
noBorder,
|
||||||
}) {
|
}) {
|
||||||
|
const { supportsEIP1559V2 } = this.props;
|
||||||
const { t } = this.context;
|
const { t } = this.context;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -97,7 +101,7 @@ export default class ConfirmApproveContent extends Component {
|
|||||||
<div className="confirm-approve-content__card-header__title">
|
<div className="confirm-approve-content__card-header__title">
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
{showEdit && (
|
{showEdit && (!showAdvanceGasFeeOptions || !supportsEIP1559V2) && (
|
||||||
<Box width={BLOCK_SIZES.ONE_SIXTH}>
|
<Box width={BLOCK_SIZES.ONE_SIXTH}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
@ -108,6 +112,9 @@ export default class ConfirmApproveContent extends Component {
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
{showEdit && showAdvanceGasFeeOptions && supportsEIP1559V2 && (
|
||||||
|
<EditGasFeeButton />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="confirm-approve-content__card-content">{content}</div>
|
<div className="confirm-approve-content__card-content">{content}</div>
|
||||||
@ -445,6 +452,7 @@ export default class ConfirmApproveContent extends Component {
|
|||||||
symbol: <i className="fa fa-tag" />,
|
symbol: <i className="fa fa-tag" />,
|
||||||
title: t('transactionFee'),
|
title: t('transactionFee'),
|
||||||
showEdit: true,
|
showEdit: true,
|
||||||
|
showAdvanceGasFeeOptions: true,
|
||||||
onEditClick: showCustomizeGasModal,
|
onEditClick: showCustomizeGasModal,
|
||||||
content: this.renderTransactionDetailsContent(),
|
content: this.renderTransactionDetailsContent(),
|
||||||
noBorder: useNonceField || !showFullTxDetails,
|
noBorder: useNonceField || !showFullTxDetails,
|
||||||
|
@ -15,6 +15,8 @@ import {
|
|||||||
getTokenValueParam,
|
getTokenValueParam,
|
||||||
} from '../../helpers/utils/token-util';
|
} from '../../helpers/utils/token-util';
|
||||||
import { readAddressAsContract } from '../../../shared/modules/contract-utils';
|
import { readAddressAsContract } from '../../../shared/modules/contract-utils';
|
||||||
|
import { GasFeeContextProvider } from '../../contexts/gasFee';
|
||||||
|
import { TransactionModalContextProvider } from '../../contexts/transaction-modal';
|
||||||
import { useTokenTracker } from '../../hooks/useTokenTracker';
|
import { useTokenTracker } from '../../hooks/useTokenTracker';
|
||||||
import {
|
import {
|
||||||
getTokens,
|
getTokens,
|
||||||
@ -32,13 +34,14 @@ import {
|
|||||||
getCurrentChainId,
|
getCurrentChainId,
|
||||||
getRpcPrefsForCurrentProvider,
|
getRpcPrefsForCurrentProvider,
|
||||||
getIsMultiLayerFeeNetwork,
|
getIsMultiLayerFeeNetwork,
|
||||||
|
checkNetworkAndAccountSupports1559,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
|
|
||||||
import { useApproveTransaction } from '../../hooks/useApproveTransaction';
|
import { useApproveTransaction } from '../../hooks/useApproveTransaction';
|
||||||
|
|
||||||
import { currentNetworkTxListSelector } from '../../selectors/transactions';
|
import { currentNetworkTxListSelector } from '../../selectors/transactions';
|
||||||
import Loading from '../../components/ui/loading-screen';
|
import AdvancedGasFeePopover from '../../components/app/advanced-gas-fee-popover';
|
||||||
|
import EditGasFeePopover from '../../components/app/edit-gas-fee-popover';
|
||||||
import EditGasPopover from '../../components/app/edit-gas-popover/edit-gas-popover.component';
|
import EditGasPopover from '../../components/app/edit-gas-popover/edit-gas-popover.component';
|
||||||
|
import Loading from '../../components/ui/loading-screen';
|
||||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||||
import { getCustomTxParamsData } from './confirm-approve.util';
|
import { getCustomTxParamsData } from './confirm-approve.util';
|
||||||
import ConfirmApproveContent from './confirm-approve-content';
|
import ConfirmApproveContent from './confirm-approve-content';
|
||||||
@ -47,6 +50,10 @@ const isAddressLedgerByFromAddress = (address) => (state) => {
|
|||||||
return isAddressLedger(state, address);
|
return isAddressLedger(state, address);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 ConfirmApprove() {
|
export default function ConfirmApprove() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { id: paramsTransactionId } = useParams();
|
const { id: paramsTransactionId } = useParams();
|
||||||
@ -66,6 +73,9 @@ export default function ConfirmApprove() {
|
|||||||
const chainId = useSelector(getCurrentChainId);
|
const chainId = useSelector(getCurrentChainId);
|
||||||
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
|
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
|
||||||
const isMultiLayerFeeNetwork = useSelector(getIsMultiLayerFeeNetwork);
|
const isMultiLayerFeeNetwork = useSelector(getIsMultiLayerFeeNetwork);
|
||||||
|
const networkAndAccountSupports1559 = useSelector(
|
||||||
|
checkNetworkAndAccountSupports1559,
|
||||||
|
);
|
||||||
|
|
||||||
const fromAddressIsLedger = useSelector(isAddressLedgerByFromAddress(from));
|
const fromAddressIsLedger = useSelector(isAddressLedgerByFromAddress(from));
|
||||||
|
|
||||||
@ -79,6 +89,9 @@ export default function ConfirmApprove() {
|
|||||||
hexTransactionTotal,
|
hexTransactionTotal,
|
||||||
} = useSelector((state) => transactionFeeSelector(state, transaction));
|
} = useSelector((state) => transactionFeeSelector(state, transaction));
|
||||||
|
|
||||||
|
const supportsEIP1559V2 =
|
||||||
|
EIP_1559_V2_ENABLED && networkAndAccountSupports1559;
|
||||||
|
|
||||||
const currentToken = (tokens &&
|
const currentToken = (tokens &&
|
||||||
tokens.find(({ address }) =>
|
tokens.find(({ address }) =>
|
||||||
isEqualCaseInsensitive(tokenAddress, address),
|
isEqualCaseInsensitive(tokenAddress, address),
|
||||||
@ -163,13 +176,14 @@ export default function ConfirmApprove() {
|
|||||||
return tokenSymbol === undefined ? (
|
return tokenSymbol === undefined ? (
|
||||||
<Loading />
|
<Loading />
|
||||||
) : (
|
) : (
|
||||||
|
<GasFeeContextProvider transaction={transaction}>
|
||||||
<ConfirmTransactionBase
|
<ConfirmTransactionBase
|
||||||
toAddress={toAddress}
|
toAddress={toAddress}
|
||||||
identiconAddress={tokenAddress}
|
identiconAddress={tokenAddress}
|
||||||
showAccountInHeader
|
showAccountInHeader
|
||||||
title={tokensText}
|
title={tokensText}
|
||||||
contentComponent={
|
contentComponent={
|
||||||
<>
|
<TransactionModalContextProvider captureEventEnabled={false}>
|
||||||
<ConfirmApproveContent
|
<ConfirmApproveContent
|
||||||
decimals={decimals}
|
decimals={decimals}
|
||||||
siteImage={siteImage}
|
siteImage={siteImage}
|
||||||
@ -246,18 +260,22 @@ export default function ConfirmApprove() {
|
|||||||
rpcPrefs={rpcPrefs}
|
rpcPrefs={rpcPrefs}
|
||||||
isContract={isContract}
|
isContract={isContract}
|
||||||
isMultiLayerFeeNetwork={isMultiLayerFeeNetwork}
|
isMultiLayerFeeNetwork={isMultiLayerFeeNetwork}
|
||||||
|
supportsEIP1559V2={supportsEIP1559V2}
|
||||||
/>
|
/>
|
||||||
{showCustomizeGasPopover && (
|
{showCustomizeGasPopover && !supportsEIP1559V2 && (
|
||||||
<EditGasPopover
|
<EditGasPopover
|
||||||
onClose={closeCustomizeGasPopover}
|
onClose={closeCustomizeGasPopover}
|
||||||
mode={EDIT_GAS_MODES.MODIFY_IN_PLACE}
|
mode={EDIT_GAS_MODES.MODIFY_IN_PLACE}
|
||||||
transaction={transaction}
|
transaction={transaction}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
<EditGasFeePopover />
|
||||||
|
<AdvancedGasFeePopover />
|
||||||
|
</TransactionModalContextProvider>
|
||||||
}
|
}
|
||||||
hideSenderToRecipient
|
hideSenderToRecipient
|
||||||
customTxParamsData={customData}
|
customTxParamsData={customData}
|
||||||
/>
|
/>
|
||||||
|
</GasFeeContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user