import React, { useContext } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { I18nContext } from '../../../contexts/i18n'; import { useGasFeeContext } from '../../../contexts/gasFee'; import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display'; import GasTiming from '../../../components/app/gas-timing'; import InfoTooltip from '../../../components/ui/info-tooltip'; import Typography from '../../../components/ui/typography'; import Button from '../../../components/ui/button'; import Box from '../../../components/ui/box'; import { TypographyVariant, DISPLAY, FLEX_DIRECTION, BLOCK_SIZES, Color, FONT_STYLE, FONT_WEIGHT, } from '../../../helpers/constants/design-system'; import { TokenStandard } from '../../../../shared/constants/transaction'; import LoadingHeartBeat from '../../../components/ui/loading-heartbeat'; import TransactionDetailItem from '../../../components/app/transaction-detail-item'; import { NETWORK_TO_NAME_MAP } from '../../../../shared/constants/network'; import TransactionDetail from '../../../components/app/transaction-detail'; import ActionableMessage from '../../../components/ui/actionable-message'; import { getProvider, getPreferences, getIsBuyableChain, transactionFeeSelector, getIsMainnet, getIsTestnet, getUseCurrencyRateCheck, } from '../../../selectors'; import { INSUFFICIENT_TOKENS_ERROR } from '../send.constants'; import { getCurrentDraftTransaction } from '../../../ducks/send'; import { getNativeCurrency } from '../../../ducks/metamask/metamask'; import { showModal } from '../../../store/actions'; import { addHexes, hexWEIToDecETH, hexWEIToDecGWEI, } from '../../../../shared/modules/conversion.utils'; import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import useRamps from '../../../hooks/experiences/useRamps'; export default function GasDisplay({ gasError }) { const t = useContext(I18nContext); const dispatch = useDispatch(); const { estimateUsed } = useGasFeeContext(); const trackEvent = useContext(MetaMetricsContext); const { openBuyCryptoInPdapp } = useRamps(); const currentProvider = useSelector(getProvider); const isMainnet = useSelector(getIsMainnet); const isTestnet = useSelector(getIsTestnet); const isBuyableChain = useSelector(getIsBuyableChain); const draftTransaction = useSelector(getCurrentDraftTransaction); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); const { showFiatInTestnets, useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const { provider, unapprovedTxs } = useSelector((state) => state.metamask); const nativeCurrency = useSelector(getNativeCurrency); const { chainId } = provider; const networkName = NETWORK_TO_NAME_MAP[chainId]; const isInsufficientTokenError = draftTransaction?.amount.error === INSUFFICIENT_TOKENS_ERROR; const editingTransaction = unapprovedTxs[draftTransaction.id]; const currentNetworkName = networkName || currentProvider.nickname; const transactionData = { txParams: { gasPrice: draftTransaction.gas?.gasPrice, gas: editingTransaction?.userEditedGasLimit ? editingTransaction?.txParams?.gas : draftTransaction.gas?.gasLimit, maxFeePerGas: editingTransaction?.txParams?.maxFeePerGas ? editingTransaction?.txParams?.maxFeePerGas : draftTransaction.gas?.maxFeePerGas, maxPriorityFeePerGas: editingTransaction?.txParams?.maxPriorityFeePerGas ? editingTransaction?.txParams?.maxPriorityFeePerGas : draftTransaction.gas?.maxPriorityFeePerGas, value: draftTransaction.amount?.value, type: draftTransaction.transactionType, }, userFeeLevel: editingTransaction?.userFeeLevel, }; const { hexMinimumTransactionFee, hexMaximumTransactionFee, hexTransactionTotal, } = useSelector((state) => transactionFeeSelector(state, transactionData)); let title; if ( draftTransaction?.asset.details?.standard === TokenStandard.ERC721 || draftTransaction?.asset.details?.standard === TokenStandard.ERC1155 ) { title = draftTransaction?.asset.details?.name; } else if ( draftTransaction?.asset.details?.standard === TokenStandard.ERC20 ) { title = `${hexWEIToDecETH(draftTransaction.amount.value)} ${ draftTransaction?.asset.details?.symbol }`; } const ethTransactionTotalMaxAmount = Number( hexWEIToDecETH(hexMaximumTransactionFee), ); const primaryTotalTextOverrideMaxAmount = `${title} + ${ethTransactionTotalMaxAmount} ${nativeCurrency}`; const showCurrencyRateCheck = useCurrencyRateCheck && (!isTestnet || showFiatInTestnets); let detailTotal, maxAmount; if (draftTransaction?.asset.type === 'NATIVE') { detailTotal = ( ); maxAmount = ( ); } else if (useNativeCurrencyAsPrimaryCurrency) { detailTotal = primaryTotalTextOverrideMaxAmount; maxAmount = primaryTotalTextOverrideMaxAmount; } return ( <> {t('gas')} ({t('transactionDetailGasInfoV2')}) {t('transactionDetailGasTooltipIntro', [ isMainnet ? t('networkNameEthereum') : '', ])} {t('transactionDetailGasTooltipExplanation')} {t('transactionDetailGasTooltipConversion')} } position="right" /> } detailTitleColor={Color.textDefault} detailText={ showCurrencyRateCheck && ( ) } detailTotal={ } subText={ <> {estimateUsed === 'high' && '⚠ '} {t('editGasSubTextFeeLabel')} } subTitle={ } />, (gasError || isInsufficientTokenError) && ( ) } detailTotal={detailTotal} subTitle={t('transactionDetailGasTotalSubtitle')} subText={ {t('editGasSubTextAmountLabel')} {' '} {maxAmount} } /> ), ]} /> {(gasError || isInsufficientTokenError) && currentNetworkName && ( {t('insufficientCurrencyBuyOrReceive', [ nativeCurrency, currentNetworkName, , , ])} ) : ( {t('insufficientCurrencyBuyOrReceive', [ nativeCurrency, currentNetworkName, `${t('buyAsset', [nativeCurrency])}`, , ])} ) } useIcon iconFillColor="var(--color-error-default)" type="danger" /> )} ); } GasDisplay.propTypes = { gasError: PropTypes.string, };