A Metamask fork with Infura removed and default networks editable
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ciphermask/ui/components/app/edit-gas-popover/edit-gas-popover.component.js

263 lines
7.9 KiB

import React, { useCallback, useContext, useState } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { isEIP1559Network } from '../../../ducks/metamask/metamask';
import { useGasFeeInputs } from '../../../hooks/useGasFeeInputs';
import { useShouldAnimateGasEstimations } from '../../../hooks/useShouldAnimateGasEstimations';
import { EDIT_GAS_MODES, GAS_LIMITS } from '../../../../shared/constants/gas';
import {
decGWEIToHexWEI,
decimalToHex,
hexToDecimal,
} from '../../../helpers/utils/conversions.util';
import Popover from '../../ui/popover';
import Button from '../../ui/button';
import EditGasDisplay from '../edit-gas-display';
import EditGasDisplayEducation from '../edit-gas-display-education';
import { I18nContext } from '../../../contexts/i18n';
import {
createCancelTransaction,
createSpeedUpTransaction,
hideModal,
hideSidebar,
updateTransaction,
updateCustomSwapsEIP1559GasParams,
} from '../../../store/actions';
import LoadingHeartBeat from '../../ui/loading-heartbeat';
export default function EditGasPopover({
popoverTitle = '',
confirmButtonText = '',
editGasDisplayProps = {},
defaultEstimateToUse = 'medium',
transaction,
mode,
onClose,
minimumGasLimit = GAS_LIMITS.SIMPLE,
}) {
const t = useContext(I18nContext);
const dispatch = useDispatch();
const showSidebar = useSelector((state) => state.appState.sidebar.isOpen);
const networkSupports1559 = useSelector(isEIP1559Network);
const shouldAnimate = useShouldAnimateGasEstimations();
const showEducationButton =
mode === EDIT_GAS_MODES.MODIFY_IN_PLACE && networkSupports1559;
const [showEducationContent, setShowEducationContent] = useState(false);
const [warning] = useState(null);
const [
dappSuggestedGasFeeAcknowledged,
setDappSuggestedGasFeeAcknowledged,
] = useState(false);
const minimumGasLimitDec = hexToDecimal(minimumGasLimit);
const {
maxPriorityFeePerGas,
setMaxPriorityFeePerGas,
maxPriorityFeePerGasFiat,
maxFeePerGas,
setMaxFeePerGas,
maxFeePerGasFiat,
estimatedMaximumNative,
isGasEstimatesLoading,
gasFeeEstimates,
gasEstimateType,
gasPrice,
setGasPrice,
gasLimit,
setGasLimit,
estimateToUse,
setEstimateToUse,
estimatedMinimumFiat,
estimatedMaximumFiat,
hasGasErrors,
gasErrors,
onManualChange,
balanceError,
} = useGasFeeInputs(defaultEstimateToUse, transaction, minimumGasLimit, mode);
const [showAdvancedForm, setShowAdvancedForm] = useState(
!estimateToUse || hasGasErrors,
);
/**
* Temporary placeholder, this should be managed by the parent component but
* we will be extracting this component from the hard to maintain modal/
* sidebar component. For now this is just to be able to appropriately close
* the modal in testing
*/
const closePopover = useCallback(() => {
if (onClose) {
onClose();
} else if (showSidebar) {
dispatch(hideSidebar());
} else {
dispatch(hideModal());
}
}, [showSidebar, onClose, dispatch]);
const onSubmit = useCallback(() => {
if (!transaction || !mode) {
closePopover();
}
const newGasSettings = networkSupports1559
? {
gas: decimalToHex(gasLimit),
gasLimit: decimalToHex(gasLimit),
maxFeePerGas: decGWEIToHexWEI(maxFeePerGas ?? gasPrice),
maxPriorityFeePerGas: decGWEIToHexWEI(
maxPriorityFeePerGas ?? maxFeePerGas ?? gasPrice,
),
}
: {
gas: decimalToHex(gasLimit),
gasLimit: decimalToHex(gasLimit),
gasPrice: decGWEIToHexWEI(gasPrice),
};
switch (mode) {
case EDIT_GAS_MODES.CANCEL:
dispatch(createCancelTransaction(transaction.id, newGasSettings));
break;
case EDIT_GAS_MODES.SPEED_UP:
dispatch(createSpeedUpTransaction(transaction.id, newGasSettings));
break;
case EDIT_GAS_MODES.MODIFY_IN_PLACE:
dispatch(
updateTransaction({
...transaction,
txParams: {
...transaction.txParams,
...newGasSettings,
},
}),
);
break;
case EDIT_GAS_MODES.SWAPS:
// This popover component should only be used for the "FEE_MARKET" type in Swaps.
if (networkSupports1559) {
dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings));
}
break;
default:
break;
}
closePopover();
}, [
transaction,
mode,
dispatch,
closePopover,
gasLimit,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
networkSupports1559,
]);
let title = t('editGasTitle');
if (popoverTitle) {
title = popoverTitle;
} else if (showEducationContent) {
title = t('editGasEducationModalTitle');
} else if (mode === EDIT_GAS_MODES.SPEED_UP) {
title = t('speedUpPopoverTitle');
} else if (mode === EDIT_GAS_MODES.CANCEL) {
title = t('cancelPopoverTitle');
}
const footerButtonText = confirmButtonText || t('save');
return (
<Popover
title={title}
onClose={closePopover}
className="edit-gas-popover__wrapper"
onBack={
showEducationContent ? () => setShowEducationContent(false) : undefined
}
footer={
showEducationContent ? null : (
<>
<Button
type="primary"
onClick={onSubmit}
disabled={hasGasErrors || isGasEstimatesLoading || balanceError}
>
{footerButtonText}
</Button>
</>
)
}
>
<div style={{ padding: '0 20px 20px 20px', position: 'relative' }}>
{showEducationContent ? (
<EditGasDisplayEducation />
) : (
<>
{process.env.IN_TEST === 'true' ? null : (
<LoadingHeartBeat active={shouldAnimate} />
)}
<EditGasDisplay
showEducationButton={showEducationButton}
warning={warning}
showAdvancedForm={showAdvancedForm}
setShowAdvancedForm={setShowAdvancedForm}
dappSuggestedGasFeeAcknowledged={dappSuggestedGasFeeAcknowledged}
setDappSuggestedGasFeeAcknowledged={
setDappSuggestedGasFeeAcknowledged
}
maxPriorityFeePerGas={maxPriorityFeePerGas}
setMaxPriorityFeePerGas={setMaxPriorityFeePerGas}
maxPriorityFeePerGasFiat={maxPriorityFeePerGasFiat}
maxFeePerGas={maxFeePerGas}
setMaxFeePerGas={setMaxFeePerGas}
maxFeePerGasFiat={maxFeePerGasFiat}
estimatedMaximumNative={estimatedMaximumNative}
isGasEstimatesLoading={isGasEstimatesLoading}
gasFeeEstimates={gasFeeEstimates}
gasEstimateType={gasEstimateType}
gasPrice={gasPrice}
setGasPrice={setGasPrice}
gasLimit={gasLimit}
setGasLimit={setGasLimit}
estimateToUse={estimateToUse}
setEstimateToUse={setEstimateToUse}
estimatedMinimumFiat={estimatedMinimumFiat}
estimatedMaximumFiat={estimatedMaximumFiat}
onEducationClick={() => setShowEducationContent(true)}
mode={mode}
transaction={transaction}
gasErrors={gasErrors}
onManualChange={onManualChange}
minimumGasLimit={minimumGasLimitDec}
balanceError={balanceError}
{...editGasDisplayProps}
/>
</>
)}
</div>
</Popover>
);
}
EditGasPopover.propTypes = {
popoverTitle: PropTypes.string,
editGasDisplayProps: PropTypes.object,
confirmButtonText: PropTypes.string,
onClose: PropTypes.func,
transaction: PropTypes.object,
mode: PropTypes.oneOf(Object.values(EDIT_GAS_MODES)),
defaultEstimateToUse: PropTypes.string,
minimumGasLimit: PropTypes.string,
};