EIP-1559 - Elevate gas properties to the Popover, disable submission if errors (#11510)

feature/default_network_editable
David Walsh 3 years ago committed by GitHub
parent 91e744a705
commit a294f02b1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      shared/constants/gas.js
  2. 169
      ui/components/app/edit-gas-display/edit-gas-display.component.js
  3. 172
      ui/components/app/edit-gas-popover/edit-gas-popover.component.js
  4. 8
      ui/components/app/transaction-list-item/transaction-list-item.component.js

@ -29,3 +29,12 @@ export const GAS_RECOMMENDATIONS = {
MEDIUM: 'medium',
HIGH: 'high',
};
/**
* These represent the different edit modes presented in the UI
*/
export const EDIT_GAS_MODES = {
SPEED_UP: 'speed-up',
CANCEL: 'cancel',
MODIFY_IN_PLACE: 'modify-in-place',
};

@ -1,7 +1,10 @@
import React, { useState, useContext } from 'react';
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { GAS_RECOMMENDATIONS } from '../../../../shared/constants/gas';
import {
GAS_RECOMMENDATIONS,
EDIT_GAS_MODES,
} from '../../../../shared/constants/gas';
import Button from '../../ui/button';
import Typography from '../../ui/typography/typography';
@ -19,55 +22,48 @@ import AdvancedGasControls from '../advanced-gas-controls/advanced-gas-controls.
import ActionableMessage from '../../ui/actionable-message/actionable-message';
import { I18nContext } from '../../../contexts/i18n';
import { useGasFeeInputs } from '../../../hooks/useGasFeeInputs';
export default function EditGasDisplay({
alwaysShowForm,
type,
showEducationButton,
mode = EDIT_GAS_MODES.MODIFY_IN_PLACE,
alwaysShowForm = false,
showEducationButton = false,
onEducationClick,
dappSuggestedGasFee,
dappOrigin,
defaultEstimateToUse = 'medium',
dappSuggestedGasFee = 0,
dappOrigin = '',
defaultEstimateToUse,
maxPriorityFeePerGas,
setMaxPriorityFeePerGas,
maxPriorityFeePerGasFiat,
maxFeePerGas,
setMaxFeePerGas,
maxFeePerGasFiat,
estimatedMaximumNative,
isGasEstimatesLoading,
gasFeeEstimates,
gasEstimateType,
gasPrice,
setGasPrice,
gasLimit,
setGasLimit,
estimateToUse,
setEstimateToUse,
estimatedMinimumFiat,
estimatedMaximumFiat,
isMaxFeeError,
isMaxPriorityFeeError,
isGasTooLow,
dappSuggestedGasFeeAcknowledged,
setDappSuggestedGasFeeAcknowledged,
showAdvancedForm,
setShowAdvancedForm,
warning,
}) {
const t = useContext(I18nContext);
const [warning] = useState(null);
const [showAdvancedForm, setShowAdvancedForm] = useState(false);
const [
dappSuggestedGasFeeAcknowledged,
setDappSuggestedGasFeeAcknowledged,
] = useState(false);
const requireDappAcknowledgement = Boolean(
dappSuggestedGasFee && !dappSuggestedGasFeeAcknowledged,
);
const {
maxPriorityFeePerGas,
setMaxPriorityFeePerGas,
maxPriorityFeePerGasFiat,
maxFeePerGas,
setMaxFeePerGas,
maxFeePerGasFiat,
estimatedMaximumNative,
isGasEstimatesLoading,
gasFeeEstimates,
gasEstimateType,
gasPrice,
setGasPrice,
gasLimit,
setGasLimit,
estimateToUse,
setEstimateToUse,
estimatedMinimumFiat,
estimatedMaximumFiat,
isMaxFeeError,
isMaxPriorityFeeError,
isGasTooLow,
} = useGasFeeInputs(defaultEstimateToUse);
return (
<div className="edit-gas-display">
<div className="edit-gas-display__content">
@ -88,7 +84,7 @@ export default function EditGasDisplay({
/>
</div>
)}
{type === 'speed-up' && (
{mode === EDIT_GAS_MODES.SPEED_UP && (
<div className="edit-gas-display__top-tooltip">
<Typography
color={COLORS.BLACK}
@ -141,31 +137,33 @@ export default function EditGasDisplay({
</Typography>
</div>
)}
{!requireDappAcknowledgement && (
<RadioGroup
name="gas-recommendation"
options={[
{
value: GAS_RECOMMENDATIONS.LOW,
label: t('editGasLow'),
recommended: defaultEstimateToUse === GAS_RECOMMENDATIONS.LOW,
},
{
value: GAS_RECOMMENDATIONS.MEDIUM,
label: t('editGasMedium'),
recommended:
defaultEstimateToUse === GAS_RECOMMENDATIONS.MEDIUM,
},
{
value: GAS_RECOMMENDATIONS.HIGH,
label: t('editGasHigh'),
recommended: defaultEstimateToUse === GAS_RECOMMENDATIONS.HIGH,
},
]}
selectedValue={estimateToUse}
onChange={setEstimateToUse}
/>
)}
{!requireDappAcknowledgement &&
![EDIT_GAS_MODES.SPEED_UP, EDIT_GAS_MODES.CANCEL].includes(mode) && (
<RadioGroup
name="gas-recommendation"
options={[
{
value: GAS_RECOMMENDATIONS.LOW,
label: t('editGasLow'),
recommended: defaultEstimateToUse === GAS_RECOMMENDATIONS.LOW,
},
{
value: GAS_RECOMMENDATIONS.MEDIUM,
label: t('editGasMedium'),
recommended:
defaultEstimateToUse === GAS_RECOMMENDATIONS.MEDIUM,
},
{
value: GAS_RECOMMENDATIONS.HIGH,
label: t('editGasHigh'),
recommended:
defaultEstimateToUse === GAS_RECOMMENDATIONS.HIGH,
},
]}
selectedValue={estimateToUse}
onChange={setEstimateToUse}
/>
)}
{!alwaysShowForm && (
<button
className="edit-gas-display__advanced-button"
@ -216,19 +214,36 @@ export default function EditGasDisplay({
EditGasDisplay.propTypes = {
alwaysShowForm: PropTypes.bool,
type: PropTypes.oneOf(['customize-gas', 'speed-up']),
mode: PropTypes.oneOf(Object.values(EDIT_GAS_MODES)),
showEducationButton: PropTypes.bool,
onEducationClick: PropTypes.func,
dappSuggestedGasFee: PropTypes.number,
dappOrigin: PropTypes.string,
defaultEstimateToUse: PropTypes.oneOf(Object.values(GAS_RECOMMENDATIONS)),
};
EditGasDisplay.defaultProps = {
alwaysShowForm: false,
type: 'customize-gas',
showEducationButton: false,
onEducationClick: undefined,
dappSuggestedGasFee: 0,
dappOrigin: '',
maxPriorityFeePerGas: PropTypes.string,
setMaxPriorityFeePerGas: PropTypes.func,
maxPriorityFeePerGasFiat: PropTypes.string,
maxFeePerGas: PropTypes.string,
setMaxFeePerGas: PropTypes.func,
maxFeePerGasFiat: PropTypes.string,
estimatedMaximumNative: PropTypes.string,
isGasEstimatesLoading: PropTypes.boolean,
gasFeeEstimates: PropTypes.object,
gasEstimateType: PropTypes.string,
gasPrice: PropTypes.string,
setGasPrice: PropTypes.func,
gasLimit: PropTypes.number,
setGasLimit: PropTypes.func,
estimateToUse: PropTypes.string,
setEstimateToUse: PropTypes.func,
estimatedMinimumFiat: PropTypes.string,
estimatedMaximumFiat: PropTypes.string,
isMaxFeeError: PropTypes.boolean,
isMaxPriorityFeeError: PropTypes.boolean,
isGasTooLow: PropTypes.boolean,
dappSuggestedGasFeeAcknowledged: PropTypes.boolean,
setDappSuggestedGasFeeAcknowledged: PropTypes.func,
showAdvancedForm: PropTypes.bool,
setShowAdvancedForm: PropTypes.func,
warning: PropTypes.string,
};

@ -2,6 +2,18 @@ import React, { useCallback, useContext, useState } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useGasFeeInputs } from '../../../hooks/useGasFeeInputs';
import {
GAS_ESTIMATE_TYPES,
EDIT_GAS_MODES,
} from '../../../../shared/constants/gas';
import {
decGWEIToHexWEI,
decimalToHex,
} from '../../../helpers/utils/conversions.util';
import Popover from '../../ui/popover';
import Button from '../../ui/button';
import EditGasDisplay from '../edit-gas-display';
@ -16,16 +28,11 @@ import {
updateTransaction,
} from '../../../store/actions';
export const EDIT_GAS_MODE = {
SPEED_UP: 'speed-up',
CANCEL: 'cancel',
MODIFY_IN_PLACE: 'modify-in-place',
};
export default function EditGasPopover({
popoverTitle,
confirmButtonText,
editGasDisplayProps,
popoverTitle = '',
confirmButtonText = '',
editGasDisplayProps = {},
defaultEstimateToUse = 'medium',
transaction,
mode,
onClose,
@ -33,8 +40,42 @@ export default function EditGasPopover({
const t = useContext(I18nContext);
const dispatch = useDispatch();
const showSidebar = useSelector((state) => state.appState.sidebar.isOpen);
const showEducationButton = mode === EDIT_GAS_MODES.MODIFY_IN_PLACE;
const [showEducationContent, setShowEducationContent] = useState(false);
const [warning] = useState(null);
const [showAdvancedForm, setShowAdvancedForm] = useState(false);
const [
dappSuggestedGasFeeAcknowledged,
setDappSuggestedGasFeeAcknowledged,
] = useState(false);
const {
maxPriorityFeePerGas,
setMaxPriorityFeePerGas,
maxPriorityFeePerGasFiat,
maxFeePerGas,
setMaxFeePerGas,
maxFeePerGasFiat,
estimatedMaximumNative,
isGasEstimatesLoading,
gasFeeEstimates,
gasEstimateType,
gasPrice,
setGasPrice,
gasLimit,
setGasLimit,
estimateToUse,
setEstimateToUse,
estimatedMinimumFiat,
estimatedMaximumFiat,
isMaxFeeError,
isMaxPriorityFeeError,
isGasTooLow,
} = useGasFeeInputs(defaultEstimateToUse);
/**
* Temporary placeholder, this should be managed by the parent component but
* we will be extracting this component from the hard to maintain modal/
@ -55,26 +96,36 @@ export default function EditGasPopover({
if (!transaction || !mode) {
closePopover();
}
const newGasSettings =
gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET
? {
gas: decimalToHex(gasLimit),
gasLimit: decimalToHex(gasLimit),
maxFeePerGas: decGWEIToHexWEI(maxFeePerGas),
maxPriorityFeePerGas: decGWEIToHexWEI(maxPriorityFeePerGas),
}
: {
gas: decimalToHex(gasLimit),
gasLimit: decimalToHex(gasLimit),
gasPrice: decGWEIToHexWEI(gasPrice),
};
switch (mode) {
case EDIT_GAS_MODE.CANCEL:
dispatch(
createCancelTransaction(transaction.id, {
/** new gas settings */
}),
);
case EDIT_GAS_MODES.CANCEL:
dispatch(createCancelTransaction(transaction.id, newGasSettings));
break;
case EDIT_GAS_MODE.SPEED_UP:
dispatch(
createSpeedUpTransaction(transaction.id, {
/** new gas settings */
}),
);
case EDIT_GAS_MODES.SPEED_UP:
dispatch(createSpeedUpTransaction(transaction.id, newGasSettings));
break;
case EDIT_GAS_MODE.MODIFY_IN_PLACE:
case EDIT_GAS_MODES.MODIFY_IN_PLACE:
dispatch(
updateTransaction({
...transaction,
txParams: { ...transaction.txParams /** ...newGasSettings */ },
txParams: {
...transaction.txParams,
...newGasSettings,
},
}),
);
break;
@ -83,11 +134,29 @@ export default function EditGasPopover({
}
closePopover();
}, [transaction, mode, dispatch, closePopover]);
}, [
transaction,
mode,
dispatch,
closePopover,
gasLimit,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
gasEstimateType,
]);
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 title = showEducationContent
? t('editGasEducationModalTitle')
: popoverTitle || t('editGasTitle');
const footerButtonText = confirmButtonText || t('save');
return (
@ -99,7 +168,11 @@ export default function EditGasPopover({
}
footer={
<>
<Button type="primary" onClick={onSubmit}>
<Button
type="primary"
onClick={onSubmit}
disabled={isMaxFeeError || isMaxPriorityFeeError || isGasTooLow}
>
{footerButtonText}
</Button>
</>
@ -110,8 +183,38 @@ export default function EditGasPopover({
<EditGasDisplayEducation />
) : (
<EditGasDisplay
{...editGasDisplayProps}
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}
isMaxFeeError={isMaxFeeError}
isMaxPriorityFeeError={isMaxPriorityFeeError}
isGasTooLow={isGasTooLow}
onEducationClick={() => setShowEducationContent(true)}
mode={mode}
{...editGasDisplayProps}
/>
)}
</div>
@ -123,15 +226,8 @@ EditGasPopover.propTypes = {
popoverTitle: PropTypes.string,
editGasDisplayProps: PropTypes.object,
confirmButtonText: PropTypes.string,
showEducationButton: PropTypes.bool,
onClose: PropTypes.func,
transaction: PropTypes.object,
mode: PropTypes.oneOf(Object.values(EDIT_GAS_MODE)),
};
EditGasPopover.defaultProps = {
popoverTitle: '',
editGasDisplayProps: {},
confirmButtonText: '',
showEducationButton: false,
mode: PropTypes.oneOf(Object.values(EDIT_GAS_MODES)),
defaultEstimateToUse: PropTypes.string,
};

@ -18,8 +18,8 @@ import {
TRANSACTION_GROUP_CATEGORIES,
TRANSACTION_STATUSES,
} from '../../../../shared/constants/transaction';
import { EDIT_GAS_MODES } from '../../../../shared/constants/gas';
import EditGasPopover from '../edit-gas-popover';
import { EDIT_GAS_MODE } from '../edit-gas-popover/edit-gas-popover.component';
export default function TransactionListItem({
transactionGroup,
@ -212,17 +212,15 @@ export default function TransactionListItem({
)}
{process.env.SHOW_EIP_1559_UI && showRetryEditGasPopover && (
<EditGasPopover
popoverTitle={t('cancelPopoverTitle')}
onClose={closeRetryEditGasPopover}
mode={EDIT_GAS_MODE.SPEED_UP}
mode={EDIT_GAS_MODES.SPEED_UP}
transaction={transactionGroup.primaryTransaction}
/>
)}
{process.env.SHOW_EIP_1559_UI && showCancelEditGasPopover && (
<EditGasPopover
popoverTitle={t('speedUpPopoverTitle')}
onClose={closeCancelEditGasPopover}
mode={EDIT_GAS_MODE.CANCEL}
mode={EDIT_GAS_MODES.CANCEL}
transaction={transactionGroup.primaryTransaction}
/>
)}

Loading…
Cancel
Save