import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import copyToClipboard from 'copy-to-clipboard'; import { getTokenTrackerLink, getAccountLink } from '@metamask/etherscan-link'; import UrlIcon from '../../../components/ui/url-icon'; import { addressSummary, getURLHostName } from '../../../helpers/utils/util'; import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; import { isBeta } from '../../../helpers/utils/build-types'; import { ellipsify } from '../../send/send.utils'; import Typography from '../../../components/ui/typography'; import Box from '../../../components/ui/box'; import Button from '../../../components/ui/button'; import EditGasFeeButton from '../../../components/app/edit-gas-fee-button'; import MetaFoxLogo from '../../../components/ui/metafox-logo'; import Identicon from '../../../components/ui/identicon'; import MultiLayerFeeMessage from '../../../components/app/multilayer-fee-message'; import CopyIcon from '../../../components/ui/icon/copy-icon.component'; import { TYPOGRAPHY, FONT_WEIGHT, BLOCK_SIZES, JUSTIFY_CONTENT, COLORS, DISPLAY, } from '../../../helpers/constants/design-system'; import { SECOND } from '../../../../shared/constants/time'; import { ConfirmPageContainerWarning } from '../../../components/app/confirm-page-container/confirm-page-container-content'; import GasDetailsItem from '../../../components/app/gas-details-item'; import LedgerInstructionField from '../../../components/app/ledger-instruction-field'; import { ERC1155, ERC20, ERC721 } from '../../../helpers/constants/common'; export default class ConfirmApproveContent extends Component { static contextTypes = { t: PropTypes.func, }; static propTypes = { decimals: PropTypes.number, tokenAmount: PropTypes.string, customTokenAmount: PropTypes.string, tokenSymbol: PropTypes.string, siteImage: PropTypes.string, showCustomizeGasModal: PropTypes.func, showEditApprovalPermissionModal: PropTypes.func, origin: PropTypes.string, setCustomAmount: PropTypes.func, tokenBalance: PropTypes.string, data: PropTypes.string, toAddress: PropTypes.string, currentCurrency: PropTypes.string, nativeCurrency: PropTypes.string, fiatTransactionTotal: PropTypes.string, ethTransactionTotal: PropTypes.string, useNonceField: PropTypes.bool, customNonceValue: PropTypes.string, updateCustomNonce: PropTypes.func, getNextNonce: PropTypes.func, nextNonce: PropTypes.number, showCustomizeNonceModal: PropTypes.func, warning: PropTypes.string, txData: PropTypes.object, fromAddressIsLedger: PropTypes.bool, chainId: PropTypes.string, rpcPrefs: PropTypes.object, isContract: PropTypes.bool, hexTransactionTotal: PropTypes.string, isMultiLayerFeeNetwork: PropTypes.bool, supportsEIP1559V2: PropTypes.bool, assetName: PropTypes.string, tokenId: PropTypes.string, assetStandard: PropTypes.string, }; state = { showFullTxDetails: true, copied: false, }; renderApproveContentCard({ showHeader = true, symbol, title, showEdit, showAdvanceGasFeeOptions = false, onEditClick, content, footer, noBorder, }) { const { supportsEIP1559V2 } = this.props; const { t } = this.context; return (
{showHeader && (
{!supportsEIP1559V2 && ( <>
{symbol}
{title}
)} {showEdit && (!showAdvanceGasFeeOptions || !supportsEIP1559V2) && ( )} {showEdit && showAdvanceGasFeeOptions && supportsEIP1559V2 && ( )}
)}
{content}
{footer}
); } // TODO: Add "Learn Why" with link to the feeAssociatedRequest text renderTransactionDetailsContent() { const { t } = this.context; const { currentCurrency, nativeCurrency, ethTransactionTotal, fiatTransactionTotal, hexTransactionTotal, txData, isMultiLayerFeeNetwork, supportsEIP1559V2, } = this.props; if (!isMultiLayerFeeNetwork && supportsEIP1559V2) { return ; } return (
{isMultiLayerFeeNetwork ? (
{t('transactionDetailLayer2GasHeading')} {`${ethTransactionTotal} ${nativeCurrency}`}
) : ( <>
{t('feeAssociatedRequest')}
{formatCurrency(fiatTransactionTotal, currentCurrency)}
{`${ethTransactionTotal} ${nativeCurrency}`}
)}
); } renderERC721OrERC1155PermissionContent() { const { t } = this.context; const { origin, toAddress, isContract, assetName, tokenId } = this.props; const displayedAddress = isContract ? `${t('contract')} (${addressSummary(toAddress)})` : addressSummary(toAddress); return (
{t('accessAndSpendNoticeNFT', [origin])}
{t('approvedAsset')}:
{`${assetName} #${tokenId}`}
{t('grantedToWithColon')}
{displayedAddress}
); } renderERC20PermissionContent() { const { t } = this.context; const { customTokenAmount, tokenAmount, tokenSymbol, origin, toAddress, isContract, } = this.props; const displayedAddress = isContract ? `${t('contract')} (${addressSummary(toAddress)})` : addressSummary(toAddress); return (
{t('accessAndSpendNotice', [origin])}
{t('approvedAmountWithColon')}
{`${Number(customTokenAmount || tokenAmount)} ${tokenSymbol}`}
{t('grantedToWithColon')}
{`${displayedAddress}`}
); } renderDataContent() { const { t } = this.context; const { data } = this.props; return (
{t('functionApprove')}
{data}
); } renderFullDetails() { const { t } = this.context; const { assetStandard, showEditApprovalPermissionModal, customTokenAmount, tokenAmount, decimals, origin, setCustomAmount, tokenSymbol, tokenBalance, } = this.props; if (assetStandard === ERC20) { return (
{this.renderApproveContentCard({ symbol: , title: t('permissionRequest'), content: this.renderERC20PermissionContent(), showEdit: true, onEditClick: () => showEditApprovalPermissionModal({ customTokenAmount, decimals, origin, setCustomAmount, tokenAmount, tokenSymbol, tokenBalance, }), })}
{this.renderApproveContentCard({ symbol: , title: 'Data', content: this.renderDataContent(), noBorder: true, })}
); } else if (assetStandard === ERC721 || assetStandard === ERC1155) { return (
{this.renderApproveContentCard({ symbol: , title: t('permissionRequest'), content: this.renderERC721OrERC1155PermissionContent(), showEdit: false, })}
{this.renderApproveContentCard({ symbol: , title: t('data'), content: this.renderDataContent(), noBorder: true, })}
); } return null; } renderCustomNonceContent() { const { t } = this.context; const { useNonceField, customNonceValue, updateCustomNonce, getNextNonce, nextNonce, showCustomizeNonceModal, } = this.props; return ( <> {useNonceField && (
{t('nonce')} {customNonceValue || nextNonce}
)} ); } render() { const { t } = this.context; const { decimals, siteImage, tokenAmount, customTokenAmount, origin, tokenSymbol, showCustomizeGasModal, showEditApprovalPermissionModal, setCustomAmount, tokenBalance, useNonceField, warning, txData, fromAddressIsLedger, toAddress, chainId, rpcPrefs, isContract, assetStandard, tokenId, assetName, } = this.props; const { showFullTxDetails } = this.state; return (
{warning && (
)} {getURLHostName(origin)}
{t('allowSpendToken', [ assetStandard === ERC20 ? tokenSymbol : `${assetName} (#${tokenId})`, ])}
{t('trustSiteApprovePermission', [ isContract ? t('contract').toLowerCase() : t('account').toLowerCase(), ])}
{ellipsify(toAddress)} {assetStandard === ERC20 ? (
showEditApprovalPermissionModal({ customTokenAmount, decimals, origin, setCustomAmount, tokenAmount, tokenSymbol, tokenBalance, }) } > {t('editPermission')}
) : null}
{this.renderApproveContentCard({ symbol: , title: t('transactionFee'), showEdit: true, showAdvanceGasFeeOptions: true, onEditClick: showCustomizeGasModal, content: this.renderTransactionDetailsContent(), noBorder: useNonceField || !showFullTxDetails, footer: !useNonceField && (
this.setState({ showFullTxDetails: !this.state.showFullTxDetails, }) } >
{this.state.showFullTxDetails ? t('hideFullTransactionDetails') : t('viewFullTransactionDetails')}
), })} {useNonceField && this.renderApproveContentCard({ showHeader: false, content: this.renderCustomNonceContent(), useNonceField, noBorder: !showFullTxDetails, footer: (
this.setState({ showFullTxDetails: !this.state.showFullTxDetails, }) } >
{this.state.showFullTxDetails ? t('hideFullTransactionDetails') : t('viewFullTransactionDetails')}
), })}
{fromAddressIsLedger ? (
) : null} {showFullTxDetails ? this.renderFullDetails() : null}
); } }