@@ -604,16 +625,10 @@ export default class ConfirmApproveContent extends Component {
render() {
const { t } = this.context;
const {
- decimals,
siteImage,
- tokenAmount,
- customTokenAmount,
origin,
tokenSymbol,
showCustomizeGasModal,
- showEditApprovalPermissionModal,
- setCustomAmount,
- tokenBalance,
useNonceField,
warning,
txData,
@@ -621,15 +636,15 @@ export default class ConfirmApproveContent extends Component {
toAddress,
chainId,
rpcPrefs,
- isContract,
assetStandard,
- userAddress,
tokenId,
tokenAddress,
assetName,
- isSetApproveForAll,
+ userAcknowledgedGasMissing,
+ setUserAcknowledgedGasMissing,
+ renderSimulationFailureWarning,
} = this.props;
- const { showFullTxDetails, setshowContractDetails } = this.state;
+ const { showFullTxDetails, setShowContractDetails } = this.state;
return (
- {assetStandard === TokenStandard.ERC20 ||
- (tokenSymbol && !tokenId && !isSetApproveForAll) ? (
-
+ {renderSimulationFailureWarning && (
+
+
+ setUserAcknowledgedGasMissing(true)
+ }
+ />
+
+ )}
{this.renderApproveContentCard({
symbol:
,
title: t('transactionFee'),
diff --git a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js
index 0d59cdf37..3962f345e 100644
--- a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js
+++ b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js
@@ -33,6 +33,10 @@ const props = {
useNonceField: true,
nextNonce: 1,
customNonceValue: '2',
+ txData: { simulationFails: null },
+ userAcknowledgedGasMissing: false,
+ setUserAcknowledgedGasMissing: jest.fn(),
+ renderSimulationFailureWarning: false,
showCustomizeNonceModal: jest.fn(),
chainId: '1337',
rpcPrefs: {},
@@ -54,7 +58,13 @@ describe('ConfirmApproveContent Component', () => {
'By granting permission, you are allowing the following contract to access your funds',
),
).toBeInTheDocument();
- expect(queryByText('0x9bc5...fef4')).toBeInTheDocument();
+ expect(queryByText('Verify contract details')).toBeInTheDocument();
+ expect(
+ queryByText(
+ 'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
+ ),
+ ).not.toBeInTheDocument();
+ expect(queryByText('I want to proceed anyway')).not.toBeInTheDocument();
expect(queryByText('View full transaction details')).toBeInTheDocument();
expect(queryByText('Edit permission')).toBeInTheDocument();
@@ -88,4 +98,124 @@ describe('ConfirmApproveContent Component', () => {
expect(getByText('Granted to:')).toBeInTheDocument();
expect(getByText('0x9bc5...fef4')).toBeInTheDocument();
});
+
+ it('should render Confirm approve page correctly and simulation error message without I want to procced anyway link', () => {
+ props.userAcknowledgedGasMissing = true;
+ props.renderSimulationFailureWarning = true;
+ const { queryByText, getByText, getAllByText, getByTestId } =
+ renderComponent(props);
+ expect(
+ queryByText('https://metamask.github.io/test-dapp/'),
+ ).toBeInTheDocument();
+ expect(getByTestId('confirm-approve-title').textContent).toStrictEqual(
+ ' Allow access to and transfer of your TestDappCollectibles (#1)? ',
+ );
+ expect(
+ queryByText(
+ 'This allows a third party to access and transfer the following NFTs without further notice until you revoke its access.',
+ ),
+ ).toBeInTheDocument();
+ expect(queryByText('Verify contract details')).toBeInTheDocument();
+ expect(
+ queryByText(
+ 'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
+ ),
+ ).toBeInTheDocument();
+ expect(queryByText('I want to proceed anyway')).not.toBeInTheDocument();
+ expect(queryByText('View full transaction details')).toBeInTheDocument();
+
+ const editButtons = getAllByText('Edit');
+
+ expect(queryByText('Transaction fee')).toBeInTheDocument();
+ expect(
+ queryByText('A fee is associated with this request.'),
+ ).toBeInTheDocument();
+ expect(queryByText(`${props.ethTransactionTotal} ETH`)).toBeInTheDocument();
+ fireEvent.click(editButtons[0]);
+ expect(props.showCustomizeGasModal).toHaveBeenCalledTimes(2);
+
+ expect(queryByText('Nonce')).toBeInTheDocument();
+ expect(queryByText('2')).toBeInTheDocument();
+ fireEvent.click(editButtons[1]);
+ expect(props.showCustomizeNonceModal).toHaveBeenCalledTimes(2);
+
+ const showViewTxDetails = getByText('View full transaction details');
+ expect(queryByText('Permission request')).not.toBeInTheDocument();
+ expect(queryByText('Approved asset:')).not.toBeInTheDocument();
+ expect(queryByText('Granted to:')).not.toBeInTheDocument();
+ expect(queryByText('Data')).not.toBeInTheDocument();
+ fireEvent.click(showViewTxDetails);
+ expect(getByText('Hide full transaction details')).toBeInTheDocument();
+ expect(getByText('Permission request')).toBeInTheDocument();
+ expect(getByText('Approved asset:')).toBeInTheDocument();
+ expect(getByText('Granted to:')).toBeInTheDocument();
+ expect(getByText('Contract (0x9bc5baF8...fEF4)')).toBeInTheDocument();
+ expect(getByText('Data')).toBeInTheDocument();
+ expect(getByText('Function: Approve')).toBeInTheDocument();
+ expect(
+ getByText(
+ '0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000011170',
+ ),
+ ).toBeInTheDocument();
+ });
+
+ it('should render Confirm approve page correctly and simulation error message with I want to procced anyway link', () => {
+ props.userAcknowledgedGasMissing = false;
+ props.renderSimulationFailureWarning = true;
+ const { queryByText, getByText, getAllByText, getByTestId } =
+ renderComponent(props);
+ expect(
+ queryByText('https://metamask.github.io/test-dapp/'),
+ ).toBeInTheDocument();
+ expect(getByTestId('confirm-approve-title').textContent).toStrictEqual(
+ ' Allow access to and transfer of your TestDappCollectibles (#1)? ',
+ );
+ expect(
+ queryByText(
+ 'This allows a third party to access and transfer the following NFTs without further notice until you revoke its access.',
+ ),
+ ).toBeInTheDocument();
+ expect(queryByText('Verify contract details')).toBeInTheDocument();
+ expect(
+ queryByText(
+ 'We were not able to estimate gas. There might be an error in the contract and this transaction may fail.',
+ ),
+ ).toBeInTheDocument();
+ expect(queryByText('I want to proceed anyway')).toBeInTheDocument();
+ expect(queryByText('View full transaction details')).toBeInTheDocument();
+
+ const editButtons = getAllByText('Edit');
+
+ expect(queryByText('Transaction fee')).toBeInTheDocument();
+ expect(
+ queryByText('A fee is associated with this request.'),
+ ).toBeInTheDocument();
+ expect(queryByText(`${props.ethTransactionTotal} ETH`)).toBeInTheDocument();
+ fireEvent.click(editButtons[0]);
+ expect(props.showCustomizeGasModal).toHaveBeenCalledTimes(3);
+
+ expect(queryByText('Nonce')).toBeInTheDocument();
+ expect(queryByText('2')).toBeInTheDocument();
+ fireEvent.click(editButtons[1]);
+ expect(props.showCustomizeNonceModal).toHaveBeenCalledTimes(3);
+
+ const showViewTxDetails = getByText('View full transaction details');
+ expect(queryByText('Permission request')).not.toBeInTheDocument();
+ expect(queryByText('Approved asset:')).not.toBeInTheDocument();
+ expect(queryByText('Granted to:')).not.toBeInTheDocument();
+ expect(queryByText('Data')).not.toBeInTheDocument();
+ fireEvent.click(showViewTxDetails);
+ expect(getByText('Hide full transaction details')).toBeInTheDocument();
+ expect(getByText('Permission request')).toBeInTheDocument();
+ expect(getByText('Approved asset:')).toBeInTheDocument();
+ expect(getByText('Granted to:')).toBeInTheDocument();
+ expect(getByText('Contract (0x9bc5baF8...fEF4)')).toBeInTheDocument();
+ expect(getByText('Data')).toBeInTheDocument();
+ expect(getByText('Function: Approve')).toBeInTheDocument();
+ expect(
+ getByText(
+ '0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000011170',
+ ),
+ ).toBeInTheDocument();
+ });
});
diff --git a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.stories.js b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.stories.js
index b472e0121..c3d867614 100644
--- a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.stories.js
+++ b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.stories.js
@@ -129,6 +129,7 @@ export default {
useNonceField: true,
nextNonce: 1,
customNonceValue: '2',
+ txData: { simulationFails: null },
chainId: '1337',
rpcPrefs: {},
isContract: true,
diff --git a/ui/pages/confirm-approve/confirm-approve.js b/ui/pages/confirm-approve/confirm-approve.js
index 14158d2fe..199ae07ac 100644
--- a/ui/pages/confirm-approve/confirm-approve.js
+++ b/ui/pages/confirm-approve/confirm-approve.js
@@ -30,6 +30,7 @@ import {
getIsImprovedTokenAllowanceEnabled,
} from '../../selectors';
import { useApproveTransaction } from '../../hooks/useApproveTransaction';
+import { useSimulationFailureWarning } from '../../hooks/useSimulationFailureWarning';
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';
@@ -84,6 +85,8 @@ export default function ConfirmApprove({
const [customPermissionAmount, setCustomPermissionAmount] = useState('');
const [submitWarning, setSubmitWarning] = useState('');
const [isContract, setIsContract] = useState(false);
+ const [userAcknowledgedGasMissing, setUserAcknowledgedGasMissing] =
+ useState(false);
const supportsEIP1559 = networkAndAccountSupports1559;
@@ -97,6 +100,9 @@ export default function ConfirmApprove({
showCustomizeGasPopover,
closeCustomizeGasPopover,
} = useApproveTransaction();
+ const renderSimulationFailureWarning = useSimulationFailureWarning(
+ userAcknowledgedGasMissing,
+ );
useEffect(() => {
if (customPermissionAmount && previousTokenAmount.current !== tokenAmount) {
@@ -284,6 +290,9 @@ export default function ConfirmApprove({
useNonceField={useNonceField}
nextNonce={nextNonce}
customNonceValue={customNonceValue}
+ userAcknowledgedGasMissing={userAcknowledgedGasMissing}
+ setUserAcknowledgedGasMissing={setUserAcknowledgedGasMissing}
+ renderSimulationFailureWarning={renderSimulationFailureWarning}
updateCustomNonce={(value) => {
dispatch(updateCustomNonce(value));
}}
diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
index 923c8b67e..a503ef430 100644
--- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
+++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
@@ -19,7 +19,7 @@ import CopyRawData from '../../components/app/transaction-decoding/components/ui
import { PRIMARY, SECONDARY } from '../../helpers/constants/common';
import TextField from '../../components/ui/text-field';
-import ActionableMessage from '../../components/ui/actionable-message';
+import SimulationErrorMessage from '../../components/ui/simulation-error-message';
import Disclosure from '../../components/ui/disclosure';
import { EVENT } from '../../../shared/constants/metametrics';
import {
@@ -586,18 +586,10 @@ export default class ConfirmTransactionBase extends Component {
const simulationFailureWarning = () => (
-
this.setUserAcknowledgedGasMissing(),
- }
+
+ this.setUserAcknowledgedGasMissing()
}
/>
diff --git a/ui/pages/token-allowance/token-allowance.js b/ui/pages/token-allowance/token-allowance.js
index 68b1eece1..05e5cd359 100644
--- a/ui/pages/token-allowance/token-allowance.js
+++ b/ui/pages/token-allowance/token-allowance.js
@@ -57,6 +57,8 @@ import {
NUM_W_OPT_DECIMAL_COMMA_OR_DOT_REGEX,
} from '../../../shared/constants/tokens';
import { ConfirmPageContainerNavigation } from '../../components/app/confirm-page-container';
+import { useSimulationFailureWarning } from '../../hooks/useSimulationFailureWarning';
+import SimulationErrorMessage from '../../components/ui/simulation-error-message';
export default function TokenAllowance({
origin,
@@ -93,7 +95,12 @@ export default function TokenAllowance({
dappProposedTokenAmount !== '0',
);
const [errorText, setErrorText] = useState('');
+ const [userAcknowledgedGasMissing, setUserAcknowledgedGasMissing] =
+ useState(false);
+ const renderSimulationFailureWarning = useSimulationFailureWarning(
+ userAcknowledgedGasMissing,
+ );
const currentAccount = useSelector(getCurrentAccountWithSendEtherInfo);
const networkIdentifier = useSelector(getNetworkIdentifier);
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
@@ -391,6 +398,21 @@ export default function TokenAllowance({
)}
{!isFirstPage && (
+ {renderSimulationFailureWarning && (
+
+
+ setUserAcknowledgedGasMissing(true)
+ }
+ />
+
+ )}
}
title={t('transactionFee')}
@@ -404,6 +426,8 @@ export default function TokenAllowance({
ethTransactionTotal={ethTransactionTotal}
nativeCurrency={nativeCurrency}
fullTxData={fullTxData}
+ userAcknowledgedGasMissing={userAcknowledgedGasMissing}
+ renderSimulationFailureWarning={renderSimulationFailureWarning}
hexTransactionTotal={hexTransactionTotal}
fiatTransactionTotal={fiatTransactionTotal}
currentCurrency={currentCurrency}
@@ -449,6 +473,9 @@ export default function TokenAllowance({
noBorder
supportsEIP1559={supportsEIP1559}
isSetApproveForAll={isSetApproveForAll}
+ fullTxData={fullTxData}
+ userAcknowledgedGasMissing={userAcknowledgedGasMissing}
+ renderSimulationFailureWarning={renderSimulationFailureWarning}
isApprovalOrRejection={isApprovalOrRejection}
data={customTxParamsData || data}
/>