Remove the SHOW_EIP_1559_UI environment variable, replace with network detection where appropriate (#11694)

Fixing up tests and add back old custom gas modal for non-eip1559 compliant networks

Remove unnecessary props from send-gas-row.component

fix breaking test

Fix primary and secondary title overrides

fix rebase issue

Fix rebase conflict

Co-authored-by: David Walsh <davidwalsh83@gmail.com>
feature/default_network_editable
Alex Donesky 3 years ago committed by GitHub
parent e0953d9f68
commit 8a42258e10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      app/_locales/en/messages.json
  2. 3
      app/scripts/controllers/network/network.js
  3. 3
      development/build/scripts.js
  4. 60
      test/e2e/metamask-ui.spec.js
  5. 25
      test/e2e/tests/send-eth.spec.js
  6. 8
      ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js
  7. 15
      ui/components/app/edit-gas-popover/edit-gas-popover.component.js
  8. 35
      ui/components/app/modals/modal.js
  9. 12
      ui/components/app/transaction-breakdown/transaction-breakdown.component.js
  10. 11
      ui/components/app/transaction-breakdown/transaction-breakdown.container.js
  11. 4
      ui/components/app/transaction-detail/transaction-detail.component.js
  12. 4
      ui/components/app/transaction-list-item/transaction-list-item.component.js
  13. 62
      ui/hooks/useCancelTransaction.js
  14. 73
      ui/hooks/useCancelTransaction.test.js
  15. 5
      ui/hooks/useGasFeeInputs.js
  16. 44
      ui/hooks/useRetryTransaction.js
  17. 72
      ui/hooks/useRetryTransaction.test.js
  18. 11
      ui/pages/confirm-approve/confirm-approve.js
  19. 352
      ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
  20. 6
      ui/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.js
  21. 6
      ui/pages/send/send-content/send-content.component.js
  22. 16
      ui/pages/send/send-content/send-content.component.test.js
  23. 3
      ui/pages/send/send-content/send-content.container.js
  24. 8
      ui/pages/send/send-content/send-gas-row/send-gas-row.component.js
  25. 12
      ui/pages/send/send-content/send-gas-row/send-gas-row.component.test.js
  26. 4
      ui/pages/send/send-content/send-gas-row/send-gas-row.container.js
  27. 6
      ui/pages/send/send-content/send-gas-row/send-gas-row.container.test.js

@ -156,9 +156,6 @@
"amount": { "amount": {
"message": "Amount" "message": "Amount"
}, },
"amountGasFee": {
"message": "Amount + Gas Fee"
},
"amountWithColon": { "amountWithColon": {
"message": "Amount:" "message": "Amount:"
}, },

@ -162,9 +162,6 @@ export default class NetworkController extends EventEmitter {
*/ */
async getEIP1559Compatibility() { async getEIP1559Compatibility() {
const { EIPS } = this.networkDetails.getState(); const { EIPS } = this.networkDetails.getState();
if (process.env.SHOW_EIP_1559_UI === false) {
return false;
}
if (EIPS[1559] !== undefined) { if (EIPS[1559] !== undefined) {
return EIPS[1559]; return EIPS[1559];
} }

@ -528,9 +528,6 @@ function getEnvironmentVariables({ devMode, testing }) {
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '', PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '',
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '', PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '',
CONF: devMode ? metamaskrc : {}, CONF: devMode ? metamaskrc : {},
SHOW_EIP_1559_UI:
process.env.SHOW_EIP_1559_UI === '1' ||
metamaskrc.SHOW_EIP_1559_UI === '1',
SENTRY_DSN: process.env.SENTRY_DSN, SENTRY_DSN: process.env.SENTRY_DSN,
SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV, SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV,
INFURA_PROJECT_ID: testing INFURA_PROJECT_ID: testing

@ -487,23 +487,17 @@ describe('MetaMask', function () {
const popup = windowHandles[2]; const popup = windowHandles[2];
await driver.switchToWindow(popup); await driver.switchToWindow(popup);
await driver.delay(regularDelayMs); await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Edit', tag: 'button' }, 10000);
await driver.clickElement('.confirm-detail-row__header-text--edit'); const inputs = await driver.findElements('input[type="number"]');
await driver.delay(regularDelayMs); const gasLimitInput = inputs[0];
const gasPriceInput = inputs[1];
await driver.clickElement({ text: 'Advanced', tag: 'button' }); await gasLimitInput.fill('4700000');
await driver.delay(tinyDelayMs); await gasPriceInput.fill('20');
await driver.delay(1000);
const [gasPriceInput, gasLimitInput] = await driver.findElements( await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
'.advanced-gas-inputs__gas-edit-row__input', await driver.clickElement({ text: 'Confirm', tag: 'button' }, 10000);
);
assert(gasPriceInput.getAttribute('value'), 20);
assert(gasLimitInput.getAttribute('value'), 4700000);
await driver.clickElement({ text: 'Save', tag: 'button' });
await driver.delay(regularDelayMs);
await driver.clickElement({ text: 'Confirm', tag: 'button' });
await driver.delay(regularDelayMs); await driver.delay(regularDelayMs);
await driver.switchToWindow(dapp); await driver.switchToWindow(dapp);
@ -675,35 +669,21 @@ describe('MetaMask', function () {
}); });
it('customizes gas', async function () { it('customizes gas', async function () {
// Set the gas limit await driver.clickElement({ text: 'Edit', tag: 'button' });
await driver.clickElement('.confirm-detail-row__header-text--edit');
await driver.delay(regularDelayMs);
// wait for gas modal to be visible
const gasModal = await driver.findVisibleElement('span .modal');
await driver.clickElement('.page-container__tab:nth-of-type(2)');
await driver.delay(regularDelayMs); await driver.delay(regularDelayMs);
await driver.clickElement(
const [gasPriceInput, gasLimitInput] = await driver.findElements( { text: 'Edit suggested gas fee', tag: 'button' },
'.advanced-gas-inputs__gas-edit-row__input', 10000,
); );
await driver.delay(1000);
await gasPriceInput.fill('10'); const inputs = await driver.findElements('input[type="number"]');
await driver.delay(50); const gasLimitInput = inputs[0];
const gasPriceInput = inputs[1];
await gasLimitInput.fill('60000'); await gasLimitInput.fill('60000');
await gasPriceInput.fill('10');
await driver.delay(1000); await driver.delay(1000);
await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
await driver.clickElement('.page-container__footer-button'); await driver.findElement({ tag: 'span', text: '0.0006' });
// wait for gas modal to be removed from DOM.
await gasModal.waitForElementState('hidden');
const gasFeeInputs = await driver.findElements(
'.confirm-detail-row__primary',
);
const renderedGasFee = await gasFeeInputs[0].getText();
assert.equal(renderedGasFee, '0.0006');
}); });
it('submits the transaction', async function () { it('submits the transaction', async function () {

@ -232,6 +232,7 @@ describe('Send ETH from dapp using advanced gas controls', function () {
}, },
], ],
}; };
it('should display the correct gas price on the transaction', async function () { it('should display the correct gas price on the transaction', async function () {
await withFixtures( await withFixtures(
{ {
@ -293,18 +294,18 @@ describe('Send ETH from dapp using advanced gas controls', function () {
windowHandles, windowHandles,
); );
await driver.assertElementNotPresent({ text: 'Data', tag: 'li' }); await driver.assertElementNotPresent({ text: 'Data', tag: 'li' });
const [gasPriceInput, gasLimitInput] = await driver.findElements( await driver.clickElement({ text: 'Edit', tag: 'button' });
'.advanced-gas-inputs__gas-edit-row__input', await driver.delay(1000);
await driver.clickElement(
{ text: 'Edit suggested gas fee', tag: 'button' },
10000,
); );
await gasPriceInput.clear();
await driver.delay(50);
await gasPriceInput.fill('10');
await driver.delay(50);
await driver.delay(50);
await gasLimitInput.fill('');
await driver.delay(50);
await gasLimitInput.fill('25000');
await driver.delay(1000); await driver.delay(1000);
const inputs = await driver.findElements('input[type="number"]');
const gasPriceInput = inputs[1];
await gasPriceInput.fill('100');
await driver.delay(1000);
await driver.clickElement({ text: 'Save', tag: 'button' }, 10000);
await driver.clickElement({ text: 'Confirm', tag: 'button' }, 10000); await driver.clickElement({ text: 'Confirm', tag: 'button' }, 10000);
await driver.waitUntilXWindowHandles(2); await driver.waitUntilXWindowHandles(2);
await driver.switchToWindow(extension); await driver.switchToWindow(extension);
@ -327,9 +328,9 @@ describe('Send ETH from dapp using advanced gas controls', function () {
await txValue.click(); await txValue.click();
const gasPrice = await driver.waitForSelector({ const gasPrice = await driver.waitForSelector({
css: '[data-testid="transaction-breakdown__gas-price"]', css: '[data-testid="transaction-breakdown__gas-price"]',
text: '10', text: '100',
}); });
assert.equal(await gasPrice.getText(), '10'); assert.equal(await gasPrice.getText(), '100');
}, },
); );
}); });

@ -1,6 +1,8 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { isEIP1559Network } from '../../../ducks/metamask/metamask';
import { I18nContext } from '../../../contexts/i18n'; import { I18nContext } from '../../../contexts/i18n';
import Typography from '../../ui/typography/typography'; import Typography from '../../ui/typography/typography';
import { import {
@ -37,6 +39,7 @@ export default function AdvancedGasControls({
networkSupportsEIP1559, networkSupportsEIP1559,
}) { }) {
const t = useContext(I18nContext); const t = useContext(I18nContext);
const networkSupports1559 = useSelector(isEIP1559Network);
const suggestedValues = {}; const suggestedValues = {};
@ -60,7 +63,10 @@ export default function AdvancedGasControls({
} }
} }
const showFeeMarketFields = networkSupportsEIP1559; const showFeeMarketFields =
networkSupports1559 &&
(gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET ||
gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE);
return ( return (
<div className="advanced-gas-controls"> <div className="advanced-gas-controls">

@ -42,12 +42,12 @@ export default function EditGasPopover({
const t = useContext(I18nContext); const t = useContext(I18nContext);
const dispatch = useDispatch(); const dispatch = useDispatch();
const showSidebar = useSelector((state) => state.appState.sidebar.isOpen); const showSidebar = useSelector((state) => state.appState.sidebar.isOpen);
const supportsEIP1559 = useSelector(isEIP1559Network); const networkSupports1559 = useSelector(isEIP1559Network);
const shouldAnimate = useShouldAnimateGasEstimations(); const shouldAnimate = useShouldAnimateGasEstimations();
const showEducationButton = const showEducationButton =
mode === EDIT_GAS_MODES.MODIFY_IN_PLACE && process.env.SHOW_EIP_1559_UI; mode === EDIT_GAS_MODES.MODIFY_IN_PLACE && networkSupports1559;
const [showEducationContent, setShowEducationContent] = useState(false); const [showEducationContent, setShowEducationContent] = useState(false);
const [warning] = useState(null); const [warning] = useState(null);
@ -109,7 +109,7 @@ export default function EditGasPopover({
closePopover(); closePopover();
} }
const newGasSettings = supportsEIP1559 const newGasSettings = networkSupports1559
? { ? {
gas: decimalToHex(gasLimit), gas: decimalToHex(gasLimit),
gasLimit: decimalToHex(gasLimit), gasLimit: decimalToHex(gasLimit),
@ -144,7 +144,7 @@ export default function EditGasPopover({
break; break;
case EDIT_GAS_MODES.SWAPS: case EDIT_GAS_MODES.SWAPS:
// This popover component should only be used for the "FEE_MARKET" type in Swaps. // This popover component should only be used for the "FEE_MARKET" type in Swaps.
if (supportsEIP1559) { if (networkSupports1559) {
dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings)); dispatch(updateCustomSwapsEIP1559GasParams(newGasSettings));
} }
break; break;
@ -162,7 +162,7 @@ export default function EditGasPopover({
gasPrice, gasPrice,
maxFeePerGas, maxFeePerGas,
maxPriorityFeePerGas, maxPriorityFeePerGas,
supportsEIP1559, networkSupports1559,
]); ]);
let title = t('editGasTitle'); let title = t('editGasTitle');
@ -177,7 +177,6 @@ export default function EditGasPopover({
} }
const footerButtonText = confirmButtonText || t('save'); const footerButtonText = confirmButtonText || t('save');
return ( return (
<Popover <Popover
title={title} title={title}
@ -205,7 +204,9 @@ export default function EditGasPopover({
<EditGasDisplayEducation /> <EditGasDisplayEducation />
) : ( ) : (
<> <>
<LoadingHeartBeat active={shouldAnimate} /> {process.env.IN_TEST === 'true' ? null : (
<LoadingHeartBeat active={shouldAnimate} />
)}
<EditGasDisplay <EditGasDisplay
showEducationButton={showEducationButton} showEducationButton={showEducationButton}
warning={warning} warning={warning}

@ -247,11 +247,36 @@ const MODALS = {
}, },
CUSTOMIZE_GAS: { CUSTOMIZE_GAS: {
contents: process.env.SHOW_EIP_1559_UI ? ( contents: <EditGasPopover />,
<EditGasPopover /> mobileModalStyle: {
) : ( width: '100vw',
<ConfirmCustomizeGasModal /> height: '100vh',
), top: '0',
transform: 'none',
left: '0',
right: '0',
margin: '0 auto',
},
laptopModalStyle: {
width: 'auto',
height: '0px',
top: '80px',
left: '0px',
transform: 'none',
margin: '0 auto',
position: 'relative',
},
contentStyle: {
borderRadius: '8px',
},
customOnHideOpts: {
action: resetCustomGasData,
args: [],
},
},
LEGACY_CUSTOMIZE_GAS: {
contents: <ConfirmCustomizeGasModal />,
mobileModalStyle: { mobileModalStyle: {
width: '100vw', width: '100vw',
height: '100vh', height: '100vh',

@ -31,7 +31,7 @@ export default class TransactionBreakdown extends PureComponent {
baseFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), baseFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
priorityFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), priorityFee: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
hexGasTotal: PropTypes.string, hexGasTotal: PropTypes.string,
supportsEIP1559: PropTypes.bool, isEIP1559Transaction: PropTypes.bool,
}; };
static defaultProps = { static defaultProps = {
@ -54,7 +54,7 @@ export default class TransactionBreakdown extends PureComponent {
baseFee, baseFee,
priorityFee, priorityFee,
hexGasTotal, hexGasTotal,
supportsEIP1559, isEIP1559Transaction,
} = this.props; } = this.props;
return ( return (
<div className={classnames('transaction-breakdown', className)}> <div className={classnames('transaction-breakdown', className)}>
@ -98,7 +98,7 @@ export default class TransactionBreakdown extends PureComponent {
/> />
</TransactionBreakdownRow> </TransactionBreakdownRow>
)} )}
{process.env.SHOW_EIP_1559_UI && supportsEIP1559 && ( {isEIP1559Transaction && (
<TransactionBreakdownRow title={t('transactionHistoryBaseFee')}> <TransactionBreakdownRow title={t('transactionHistoryBaseFee')}>
{typeof baseFee === 'undefined' ? ( {typeof baseFee === 'undefined' ? (
'?' '?'
@ -115,7 +115,7 @@ export default class TransactionBreakdown extends PureComponent {
)} )}
</TransactionBreakdownRow> </TransactionBreakdownRow>
)} )}
{process.env.SHOW_EIP_1559_UI && supportsEIP1559 && ( {isEIP1559Transaction && (
<TransactionBreakdownRow title={t('transactionHistoryPriorityFee')}> <TransactionBreakdownRow title={t('transactionHistoryPriorityFee')}>
{typeof priorityFee === 'undefined' ? ( {typeof priorityFee === 'undefined' ? (
'?' '?'
@ -132,7 +132,7 @@ export default class TransactionBreakdown extends PureComponent {
)} )}
</TransactionBreakdownRow> </TransactionBreakdownRow>
)} )}
{(!process.env.SHOW_EIP_1559_UI || !supportsEIP1559) && ( {!isEIP1559Transaction && (
<TransactionBreakdownRow title={t('advancedGasPriceTitle')}> <TransactionBreakdownRow title={t('advancedGasPriceTitle')}>
{typeof gasPrice === 'undefined' ? ( {typeof gasPrice === 'undefined' ? (
'?' '?'
@ -148,7 +148,7 @@ export default class TransactionBreakdown extends PureComponent {
)} )}
</TransactionBreakdownRow> </TransactionBreakdownRow>
)} )}
{process.env.SHOW_EIP_1559_UI && supportsEIP1559 && ( {isEIP1559Transaction && (
<TransactionBreakdownRow <TransactionBreakdownRow
title={t('transactionHistoryEffectiveGasPrice')} title={t('transactionHistoryEffectiveGasPrice')}
> >

@ -1,12 +1,10 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getShouldShowFiat } from '../../../selectors'; import { getShouldShowFiat } from '../../../selectors';
import { import { getNativeCurrency } from '../../../ducks/metamask/metamask';
getNativeCurrency,
isEIP1559Network,
} from '../../../ducks/metamask/metamask';
import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util'; import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util';
import { subtractHexes } from '../../../helpers/utils/conversions.util'; import { subtractHexes } from '../../../helpers/utils/conversions.util';
import { sumHexes } from '../../../helpers/utils/transactions.util'; import { sumHexes } from '../../../helpers/utils/transactions.util';
import { isEIP1559Transaction } from '../../../../shared/modules/transaction.utils';
import TransactionBreakdown from './transaction-breakdown.component'; import TransactionBreakdown from './transaction-breakdown.component';
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
@ -37,8 +35,6 @@ const mapStateToProps = (state, ownProps) => {
'0x0'; '0x0';
const totalInHex = sumHexes(hexGasTotal, value); const totalInHex = sumHexes(hexGasTotal, value);
const supportsEIP1559 = isEIP1559Network(state);
return { return {
nativeCurrency: getNativeCurrency(state), nativeCurrency: getNativeCurrency(state),
showFiat: getShouldShowFiat(state), showFiat: getShouldShowFiat(state),
@ -47,11 +43,10 @@ const mapStateToProps = (state, ownProps) => {
gasPrice, gasPrice,
gasUsed, gasUsed,
isTokenApprove, isTokenApprove,
effectiveGasPrice,
hexGasTotal, hexGasTotal,
priorityFee, priorityFee,
baseFee: baseFeePerGas, baseFee: baseFeePerGas,
supportsEIP1559, isEIP1559Transaction: isEIP1559Transaction(transaction),
}; };
}; };

@ -13,7 +13,9 @@ export default function TransactionDetail({ rows = [], onEdit }) {
return ( return (
<div className="transaction-detail"> <div className="transaction-detail">
<LoadingHeartBeat active={shouldAnimate} /> {process.env.IN_TEST === 'true' ? null : (
<LoadingHeartBeat active={shouldAnimate} />
)}
{onEdit && ( {onEdit && (
<div className="transaction-detail-edit"> <div className="transaction-detail-edit">
<button onClick={onEdit}>{t('edit')}</button> <button onClick={onEdit}>{t('edit')}</button>

@ -210,14 +210,14 @@ export default function TransactionListItem({
cancelDisabled={!cancelEnabled} cancelDisabled={!cancelEnabled}
/> />
)} )}
{process.env.SHOW_EIP_1559_UI && showRetryEditGasPopover && ( {showRetryEditGasPopover && (
<EditGasPopover <EditGasPopover
onClose={closeRetryEditGasPopover} onClose={closeRetryEditGasPopover}
mode={EDIT_GAS_MODES.SPEED_UP} mode={EDIT_GAS_MODES.SPEED_UP}
transaction={transactionGroup.primaryTransaction} transaction={transactionGroup.primaryTransaction}
/> />
)} )}
{process.env.SHOW_EIP_1559_UI && showCancelEditGasPopover && ( {showCancelEditGasPopover && (
<EditGasPopover <EditGasPopover
onClose={closeCancelEditGasPopover} onClose={closeCancelEditGasPopover}
mode={EDIT_GAS_MODES.CANCEL} mode={EDIT_GAS_MODES.CANCEL}

@ -1,13 +1,9 @@
import { useDispatch, useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { showModal, showSidebar } from '../store/actions';
import { isBalanceSufficient } from '../pages/send/send.utils'; import { isBalanceSufficient } from '../pages/send/send.utils';
import { getSelectedAccount, getIsMainnet } from '../selectors'; import { getSelectedAccount } from '../selectors';
import { getConversionRate } from '../ducks/metamask/metamask'; import { getConversionRate } from '../ducks/metamask/metamask';
import { setCustomGasLimit, setCustomGasPrice } from '../ducks/gas/gas.duck';
import { GAS_LIMITS } from '../../shared/constants/gas';
import { isLegacyTransaction } from '../../shared/modules/transaction.utils';
import { getMaximumGasTotalInHexWei } from '../../shared/modules/gas.utils'; import { getMaximumGasTotalInHexWei } from '../../shared/modules/gas.utils';
import { useIncrementedGasFees } from './useIncrementedGasFees'; import { useIncrementedGasFees } from './useIncrementedGasFees';
@ -26,11 +22,8 @@ export function useCancelTransaction(transactionGroup) {
const customGasSettings = useIncrementedGasFees(transactionGroup); const customGasSettings = useIncrementedGasFees(transactionGroup);
const dispatch = useDispatch();
const selectedAccount = useSelector(getSelectedAccount); const selectedAccount = useSelector(getSelectedAccount);
const conversionRate = useSelector(getConversionRate); const conversionRate = useSelector(getConversionRate);
const isMainnet = useSelector(getIsMainnet);
const hideBasic = !(isMainnet || process.env.IN_TEST);
const [showCancelEditGasPopover, setShowCancelEditGasPopover] = useState( const [showCancelEditGasPopover, setShowCancelEditGasPopover] = useState(
false, false,
@ -38,53 +31,10 @@ export function useCancelTransaction(transactionGroup) {
const closeCancelEditGasPopover = () => setShowCancelEditGasPopover(false); const closeCancelEditGasPopover = () => setShowCancelEditGasPopover(false);
const cancelTransaction = useCallback( const cancelTransaction = useCallback((event) => {
(event) => { event.stopPropagation();
event.stopPropagation(); return setShowCancelEditGasPopover(true);
if (process.env.SHOW_EIP_1559_UI) { }, []);
return setShowCancelEditGasPopover(true);
}
if (isLegacyTransaction(primaryTransaction)) {
// To support the current process of cancelling or speeding up
// a transaction, we have to inform the custom gas state of the new
// gasPrice/gasLimit to start at.
dispatch(setCustomGasPrice(customGasSettings.gasPrice));
dispatch(setCustomGasLimit(GAS_LIMITS.SIMPLE));
}
const tx = {
...primaryTransaction,
txParams: {
...primaryTransaction.txParams,
gas: GAS_LIMITS.SIMPLE,
value: '0x0',
},
};
return dispatch(
showSidebar({
transitionName: 'sidebar-left',
type: 'customize-gas',
props: {
hideBasic,
transaction: tx,
onSubmit: (newGasSettings) => {
const userCustomizedGasTotal = getMaximumGasTotalInHexWei(
newGasSettings,
);
dispatch(
showModal({
name: 'CANCEL_TRANSACTION',
newGasFee: userCustomizedGasTotal,
transactionId: primaryTransaction.id,
customGasSettings: newGasSettings,
}),
);
},
},
}),
);
},
[dispatch, primaryTransaction, customGasSettings, hideBasic],
);
const hasEnoughCancelGas = const hasEnoughCancelGas =
primaryTransaction.txParams && primaryTransaction.txParams &&

@ -3,10 +3,7 @@ import { renderHook } from '@testing-library/react-hooks';
import sinon from 'sinon'; import sinon from 'sinon';
import transactions from '../../test/data/transaction-data.json'; import transactions from '../../test/data/transaction-data.json';
import { getConversionRate, getSelectedAccount } from '../selectors'; import { getConversionRate, getSelectedAccount } from '../selectors';
import { showModal } from '../store/actions';
import { increaseLastGasPrice } from '../helpers/utils/confirm-tx.util'; import { increaseLastGasPrice } from '../helpers/utils/confirm-tx.util';
import * as actionConstants from '../store/actionConstants';
import { GAS_LIMITS } from '../../shared/constants/gas';
import { useCancelTransaction } from './useCancelTransaction'; import { useCancelTransaction } from './useCancelTransaction';
describe('useCancelTransaction', function () { describe('useCancelTransaction', function () {
@ -61,42 +58,6 @@ describe('useCancelTransaction', function () {
expect(typeof result.current[1].cancelTransaction).toStrictEqual( expect(typeof result.current[1].cancelTransaction).toStrictEqual(
'function', 'function',
); );
result.current[1].cancelTransaction({
preventDefault: () => undefined,
stopPropagation: () => undefined,
});
const dispatchAction = dispatch.args;
// calls customize-gas sidebar
// also check type= customize-gas
expect(dispatchAction[dispatchAction.length - 1][0].type).toStrictEqual(
actionConstants.SIDEBAR_OPEN,
);
expect(
dispatchAction[dispatchAction.length - 1][0].value.props.transaction
.id,
).toStrictEqual(transactionId);
// call onSubmit myself
dispatchAction[dispatchAction.length - 1][0].value.props.onSubmit({
gasLimit: GAS_LIMITS.SIMPLE,
gasPrice: '0x1',
});
expect(
dispatch.calledWith(
showModal({
name: 'CANCEL_TRANSACTION',
transactionId,
newGasFee: GAS_LIMITS.SIMPLE,
customGasSettings: {
gasPrice: '0x1',
gasLimit: GAS_LIMITS.SIMPLE,
},
}),
),
).toStrictEqual(true);
}); });
}); });
}); });
@ -132,45 +93,13 @@ describe('useCancelTransaction', function () {
); );
expect(result.current[0]).toStrictEqual(true); expect(result.current[0]).toStrictEqual(true);
}); });
it(`should return a function that opens the gas sidebar onsubmit kicks off cancellation for id ${transactionId}`, function () { it(`should return a function that opens the gas popover onsubmit kicks off cancellation for id ${transactionId}`, function () {
const { result } = renderHook(() => const { result } = renderHook(() =>
useCancelTransaction(transactionGroup), useCancelTransaction(transactionGroup),
); );
expect(typeof result.current[1].cancelTransaction).toStrictEqual( expect(typeof result.current[1].cancelTransaction).toStrictEqual(
'function', 'function',
); );
result.current[1].cancelTransaction({
preventDefault: () => undefined,
stopPropagation: () => undefined,
});
const dispatchAction = dispatch.args;
expect(dispatchAction[dispatchAction.length - 1][0].type).toStrictEqual(
actionConstants.SIDEBAR_OPEN,
);
expect(
dispatchAction[dispatchAction.length - 1][0].value.props.transaction
.id,
).toStrictEqual(transactionId);
dispatchAction[dispatchAction.length - 1][0].value.props.onSubmit({
gasLimit: GAS_LIMITS.SIMPLE,
gasPrice: '0x1',
});
expect(
dispatch.calledWith(
showModal({
name: 'CANCEL_TRANSACTION',
transactionId,
newGasFee: GAS_LIMITS.SIMPLE,
customGasSettings: {
gasPrice: '0x1',
gasLimit: GAS_LIMITS.SIMPLE,
},
}),
),
).toStrictEqual(true);
}); });
}); });
}); });

@ -107,10 +107,11 @@ function getMatchingEstimateFromGasFees(
maxFeePerGas, maxFeePerGas,
maxPriorityFeePerGas, maxPriorityFeePerGas,
gasPrice, gasPrice,
supportsEIP1559,
) { ) {
return ( return (
findKey(gasFeeEstimates, (estimate) => { findKey(gasFeeEstimates, (estimate) => {
if (process.env.SHOW_EIP_1559_UI) { if (supportsEIP1559) {
return ( return (
Number(estimate?.suggestedMaxPriorityFeePerGas) === Number(estimate?.suggestedMaxPriorityFeePerGas) ===
Number(maxPriorityFeePerGas) && Number(maxPriorityFeePerGas) &&
@ -180,6 +181,7 @@ export function useGasFeeInputs(
// default our fiat values to empty strings if showing fiat is not wanted or // default our fiat values to empty strings if showing fiat is not wanted or
// possible. // possible.
const showFiat = useSelector(getShouldShowFiat); const showFiat = useSelector(getShouldShowFiat);
const supportsEIP1559 = useSelector(isEIP1559Network);
// We need to know the current network's currency and its decimal precision // We need to know the current network's currency and its decimal precision
// to calculate the amount to display to the user. // to calculate the amount to display to the user.
@ -235,6 +237,7 @@ export function useGasFeeInputs(
maxFeePerGas, maxFeePerGas,
maxPriorityFeePerGas, maxPriorityFeePerGas,
gasPrice, gasPrice,
supportsEIP1559,
) )
: defaultEstimateToUse, : defaultEstimateToUse,
); );

@ -1,12 +1,5 @@
import { useDispatch, useSelector } from 'react-redux';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { showSidebar } from '../store/actions';
import { setCustomGasLimit, setCustomGasPrice } from '../ducks/gas/gas.duck';
import { getIsMainnet } from '../selectors';
import { isLegacyTransaction } from '../../shared/modules/transaction.utils';
import { useMetricEvent } from './useMetricEvent'; import { useMetricEvent } from './useMetricEvent';
import { useIncrementedGasFees } from './useIncrementedGasFees';
/** /**
* @typedef {Object} RetryTransactionReturnValue * @typedef {Object} RetryTransactionReturnValue
@ -22,12 +15,7 @@ import { useIncrementedGasFees } from './useIncrementedGasFees';
* @param {Object} transactionGroup - the transaction group * @param {Object} transactionGroup - the transaction group
* @return {RetryTransactionReturnValue} * @return {RetryTransactionReturnValue}
*/ */
export function useRetryTransaction(transactionGroup) { export function useRetryTransaction() {
const { primaryTransaction } = transactionGroup;
const isMainnet = useSelector(getIsMainnet);
const hideBasic = !(isMainnet || process.env.IN_TEST);
const customGasSettings = useIncrementedGasFees(transactionGroup);
const trackMetricsEvent = useMetricEvent({ const trackMetricsEvent = useMetricEvent({
eventOpts: { eventOpts: {
category: 'Navigation', category: 'Navigation',
@ -35,7 +23,6 @@ export function useRetryTransaction(transactionGroup) {
name: 'Clicked "Speed Up"', name: 'Clicked "Speed Up"',
}, },
}); });
const dispatch = useDispatch();
const [showRetryEditGasPopover, setShowRetryEditGasPopover] = useState(false); const [showRetryEditGasPopover, setShowRetryEditGasPopover] = useState(false);
const closeRetryEditGasPopover = () => setShowRetryEditGasPopover(false); const closeRetryEditGasPopover = () => setShowRetryEditGasPopover(false);
@ -43,35 +30,10 @@ export function useRetryTransaction(transactionGroup) {
const retryTransaction = useCallback( const retryTransaction = useCallback(
async (event) => { async (event) => {
event.stopPropagation(); event.stopPropagation();
setShowRetryEditGasPopover(true);
trackMetricsEvent(); trackMetricsEvent();
if (process.env.SHOW_EIP_1559_UI) {
setShowRetryEditGasPopover(true);
} else {
if (isLegacyTransaction(primaryTransaction)) {
// To support the current process of cancelling or speeding up
// a transaction, we have to inform the custom gas state of the new
// gasPrice to start at.
dispatch(setCustomGasPrice(customGasSettings.gasPrice));
dispatch(setCustomGasLimit(primaryTransaction.txParams.gas));
}
dispatch(
showSidebar({
transitionName: 'sidebar-left',
type: 'customize-gas',
props: { transaction: primaryTransaction, hideBasic },
}),
);
}
}, },
[ [trackMetricsEvent],
dispatch,
trackMetricsEvent,
customGasSettings,
primaryTransaction,
hideBasic,
],
); );
return { return {

@ -1,8 +1,7 @@
import * as reactRedux from 'react-redux'; import * as reactRedux from 'react-redux';
import { renderHook } from '@testing-library/react-hooks'; import { renderHook, act } from '@testing-library/react-hooks';
import sinon from 'sinon'; import sinon from 'sinon';
import transactions from '../../test/data/transaction-data.json'; import transactions from '../../test/data/transaction-data.json';
import { showSidebar } from '../store/actions';
import { getIsMainnet } from '../selectors'; import { getIsMainnet } from '../selectors';
import * as methodDataHook from './useMethodData'; import * as methodDataHook from './useMethodData';
import * as metricEventHook from './useMetricEvent'; import * as metricEventHook from './useMetricEvent';
@ -58,74 +57,21 @@ describe('useRetryTransaction', () => {
useRetryTransaction(retryEnabledTransaction, true), useRetryTransaction(retryEnabledTransaction, true),
); );
const { retryTransaction } = result.current; const { retryTransaction } = result.current;
retryTransaction(event); act(() => {
retryTransaction(event);
});
expect(trackEvent.calledOnce).toStrictEqual(true); expect(trackEvent.calledOnce).toStrictEqual(true);
}); });
it('retryTransaction function should show retry sidebar', async () => { it('retryTransaction function should show retry popover', async () => {
const { result } = renderHook(() => const { result } = renderHook(() =>
useRetryTransaction(retryEnabledTransaction, true), useRetryTransaction(retryEnabledTransaction, true),
); );
const { retryTransaction } = result.current; const { retryTransaction } = result.current;
await retryTransaction(event); await act(async () => {
expect( await retryTransaction(event);
dispatch.calledWith( });
showSidebar({ expect(result.current.showRetryEditGasPopover).toStrictEqual(true);
transitionName: 'sidebar-left',
type: 'customize-gas',
props: {
transaction: retryEnabledTransaction.initialTransaction,
hideBasic: false,
},
}),
),
).toStrictEqual(true);
});
it('should handle cancelled or multiple speedup transactions', async () => {
const cancelledTransaction = {
initialTransaction: {
...transactions[0].initialTransaction,
txParams: {
...transactions[0].initialTransaction.txParams,
},
},
primaryTransaction: {
...transactions[0].primaryTransaction,
txParams: {
from: '0xee014609ef9e09776ac5fe00bdbfef57bcdefebb',
gas: '0x5308',
gasPrice: '0x77359400',
nonce: '0x3',
to: '0xabca64466f257793eaa52fcfff5066894b76a149',
value: '0x0',
},
},
transactions: [
{
submittedTime: new Date() - 5001,
},
],
hasRetried: false,
};
const { result } = renderHook(() =>
useRetryTransaction(cancelledTransaction, true),
);
const { retryTransaction } = result.current;
await retryTransaction(event);
expect(
dispatch.calledWith(
showSidebar({
transitionName: 'sidebar-left',
type: 'customize-gas',
props: {
transaction: cancelledTransaction.primaryTransaction,
hideBasic: false,
},
}),
),
).toStrictEqual(true);
}); });
}); });
}); });

@ -14,7 +14,11 @@ import {
getTokenValueParam, getTokenValueParam,
} from '../../helpers/utils/token-util'; } from '../../helpers/utils/token-util';
import { useTokenTracker } from '../../hooks/useTokenTracker'; import { useTokenTracker } from '../../hooks/useTokenTracker';
import { getTokens, getNativeCurrency } from '../../ducks/metamask/metamask'; import {
getTokens,
getNativeCurrency,
isEIP1559Network,
} from '../../ducks/metamask/metamask';
import { import {
transactionFeeSelector, transactionFeeSelector,
txDataSelector, txDataSelector,
@ -49,6 +53,7 @@ export default function ConfirmApprove() {
const useNonceField = useSelector(getUseNonceField); const useNonceField = useSelector(getUseNonceField);
const nextNonce = useSelector(getNextSuggestedNonce); const nextNonce = useSelector(getNextSuggestedNonce);
const customNonceValue = useSelector(getCustomNonceValue); const customNonceValue = useSelector(getCustomNonceValue);
const onEIP1559Network = useSelector(isEIP1559Network);
const transaction = const transaction =
currentNetworkTxList.find( currentNetworkTxList.find(
@ -145,7 +150,9 @@ export default function ConfirmApprove() {
showCustomizeGasModal={() => showCustomizeGasModal={() =>
dispatch( dispatch(
showModal({ showModal({
name: 'CUSTOMIZE_GAS', name: onEIP1559Network
? 'CUSTOMIZE_GAS'
: 'LEGACY_CUSTOMIZE_GAS',
txData, txData,
hideBasic, hideBasic,
}), }),

@ -2,9 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../shared/constants/app'; import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../shared/constants/app';
import { getEnvironmentType } from '../../../app/scripts/lib/util'; import { getEnvironmentType } from '../../../app/scripts/lib/util';
import ConfirmPageContainer, { import ConfirmPageContainer from '../../components/app/confirm-page-container';
ConfirmDetailRow,
} from '../../components/app/confirm-page-container';
import { isBalanceSufficient } from '../send/send.utils'; import { isBalanceSufficient } from '../send/send.utils';
import { getHexGasTotal } from '../../helpers/utils/confirm-tx.util'; import { getHexGasTotal } from '../../helpers/utils/confirm-tx.util';
import { addHexes, hexToDecimal } from '../../helpers/utils/conversions.util'; import { addHexes, hexToDecimal } from '../../helpers/utils/conversions.util';
@ -22,15 +20,12 @@ import {
import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display'; import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display';
import { PRIMARY, SECONDARY } from '../../helpers/constants/common'; import { PRIMARY, SECONDARY } from '../../helpers/constants/common';
import AdvancedGasInputs from '../../components/app/gas-customization/advanced-gas-inputs';
import TextField from '../../components/ui/text-field'; import TextField from '../../components/ui/text-field';
import AdvancedGasControls from '../../components/app/advanced-gas-controls';
import { import {
TRANSACTION_TYPES, TRANSACTION_TYPES,
TRANSACTION_STATUSES, TRANSACTION_STATUSES,
} from '../../../shared/constants/transaction'; } from '../../../shared/constants/transaction';
import { getTransactionTypeTitle } from '../../helpers/utils/transactions.util'; import { getTransactionTypeTitle } from '../../helpers/utils/transactions.util';
import ErrorMessage from '../../components/ui/error-message';
import { toBuffer } from '../../../shared/modules/buffer-utils'; import { toBuffer } from '../../../shared/modules/buffer-utils';
import TransactionDetail from '../../components/app/transaction-detail/transaction-detail.component'; import TransactionDetail from '../../components/app/transaction-detail/transaction-detail.component';
@ -72,7 +67,6 @@ export default class ConfirmTransactionBase extends Component {
updateCustomNonce: PropTypes.func, updateCustomNonce: PropTypes.func,
assetImage: PropTypes.string, assetImage: PropTypes.string,
sendTransaction: PropTypes.func, sendTransaction: PropTypes.func,
showCustomizeGasModal: PropTypes.func,
showTransactionConfirmedModal: PropTypes.func, showTransactionConfirmedModal: PropTypes.func,
showRejectTransactionsConfirmationModal: PropTypes.func, showRejectTransactionsConfirmationModal: PropTypes.func,
toAddress: PropTypes.string, toAddress: PropTypes.string,
@ -85,26 +79,17 @@ export default class ConfirmTransactionBase extends Component {
txData: PropTypes.object, txData: PropTypes.object,
unapprovedTxCount: PropTypes.number, unapprovedTxCount: PropTypes.number,
currentNetworkUnapprovedTxs: PropTypes.object, currentNetworkUnapprovedTxs: PropTypes.object,
updateGasAndCalculate: PropTypes.func,
customGas: PropTypes.object, customGas: PropTypes.object,
// Component props // Component props
actionKey: PropTypes.string, actionKey: PropTypes.string,
contentComponent: PropTypes.node, contentComponent: PropTypes.node,
dataComponent: PropTypes.node, dataComponent: PropTypes.node,
primaryTotalTextOverride: PropTypes.oneOfType([
PropTypes.string,
PropTypes.node,
]),
secondaryTotalTextOverride: PropTypes.string,
hideData: PropTypes.bool, hideData: PropTypes.bool,
hideSubtitle: PropTypes.bool, hideSubtitle: PropTypes.bool,
identiconAddress: PropTypes.string, identiconAddress: PropTypes.string,
onEdit: PropTypes.func, onEdit: PropTypes.func,
subtitleComponent: PropTypes.node, subtitleComponent: PropTypes.node,
title: PropTypes.string, title: PropTypes.string,
advancedInlineGasShown: PropTypes.bool,
insufficientBalance: PropTypes.bool,
hideFiatConversion: PropTypes.bool,
type: PropTypes.string, type: PropTypes.string,
getNextNonce: PropTypes.func, getNextNonce: PropTypes.func,
nextNonce: PropTypes.number, nextNonce: PropTypes.number,
@ -112,10 +97,11 @@ export default class ConfirmTransactionBase extends Component {
hideSenderToRecipient: PropTypes.bool, hideSenderToRecipient: PropTypes.bool,
showAccountInHeader: PropTypes.bool, showAccountInHeader: PropTypes.bool,
mostRecentOverviewPage: PropTypes.string.isRequired, mostRecentOverviewPage: PropTypes.string.isRequired,
isMainnet: PropTypes.bool,
isEthGasPrice: PropTypes.bool, isEthGasPrice: PropTypes.bool,
noGasPrice: PropTypes.bool, noGasPrice: PropTypes.bool,
setDefaultHomeActiveTabName: PropTypes.func, setDefaultHomeActiveTabName: PropTypes.func,
primaryTotalTextOverride: PropTypes.string,
secondaryTotalTextOverride: PropTypes.string,
}; };
state = { state = {
@ -248,7 +234,6 @@ export default class ConfirmTransactionBase extends Component {
handleEditGas() { handleEditGas() {
const { const {
showCustomizeGasModal,
actionKey, actionKey,
txData: { origin }, txData: { origin },
methodData = {}, methodData = {},
@ -270,16 +255,10 @@ export default class ConfirmTransactionBase extends Component {
}, },
}); });
if (process.env.SHOW_EIP_1559_UI) { this.setState({ editingGas: true });
this.setState({ editingGas: true });
} else {
showCustomizeGasModal();
}
} }
// TODO: rename this 'handleCloseEditGas' later when we remove the handleCloseEditGas() {
// SHOW_EIP_1559_UI flag/branch
handleCloseNewGasPopover() {
this.setState({ editingGas: false }); this.setState({ editingGas: false });
} }
@ -292,16 +271,8 @@ export default class ConfirmTransactionBase extends Component {
useNonceField, useNonceField,
customNonceValue, customNonceValue,
updateCustomNonce, updateCustomNonce,
advancedInlineGasShown,
customGas,
insufficientBalance,
updateGasAndCalculate,
hideFiatConversion,
nextNonce, nextNonce,
getNextNonce, getNextNonce,
isMainnet,
isEthGasPrice,
noGasPrice,
txData, txData,
} = this.props; } = this.props;
const { t } = this.context; const { t } = this.context;
@ -314,27 +285,6 @@ export default class ConfirmTransactionBase extends Component {
} }
}; };
const notMainnetOrTest = !(isMainnet || process.env.IN_TEST);
const gasPriceFetchFailure = isEthGasPrice || noGasPrice;
const inlineGasControls = process.env.SHOW_EIP_1559_UI ? (
<AdvancedGasControls />
) : (
<AdvancedGasInputs
updateCustomGasPrice={(newGasPrice) =>
updateGasAndCalculate({ ...customGas, gasPrice: newGasPrice })
}
updateCustomGasLimit={(newGasLimit) =>
updateGasAndCalculate({ ...customGas, gasLimit: newGasLimit })
}
customGasPrice={customGas.gasPrice}
customGasLimit={customGas.gasLimit}
insufficientBalance={insufficientBalance}
customPriceIsSafe
isSpeedUp={false}
/>
);
const nonceField = useNonceField ? ( const nonceField = useNonceField ? (
<div> <div>
<div className="confirm-detail-row"> <div className="confirm-detail-row">
@ -365,180 +315,126 @@ export default class ConfirmTransactionBase extends Component {
</div> </div>
) : null; ) : null;
const showInlineControls = process.env.SHOW_EIP_1559_UI
? advancedInlineGasShown
: advancedInlineGasShown || notMainnetOrTest || gasPriceFetchFailure;
const showGasEditButton = process.env.SHOW_EIP_1559_UI
? !showInlineControls
: !(notMainnetOrTest || gasPriceFetchFailure);
if (process.env.SHOW_EIP_1559_UI) {
return (
<div className="confirm-page-container-content__details">
<TransactionDetail
onEdit={() => this.handleEditGas()}
rows={[
<TransactionDetailItem
key="gas-item"
detailTitle={
txData.dappSuggestedGasFees ? (
<>
{t('transactionDetailDappGasHeading', [
getRequestingOrigin(),
])}
<InfoTooltip
contentText={t('transactionDetailDappGasTooltip')}
position="top"
iconFillColor="#f66a0a"
>
<i className="fa fa-info-circle" />
</InfoTooltip>
</>
) : (
<>
{t('transactionDetailGasHeading')}
<InfoTooltip
contentText={
<>
<p>{t('transactionDetailGasTooltipIntro')}</p>
<p>{t('transactionDetailGasTooltipExplanation')}</p>
<p>
<a
href="https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172"
target="_blank"
rel="noopener noreferrer"
>
{t('transactionDetailGasTooltipConversion')}
</a>
</p>
</>
}
position="top"
>
<i className="fa fa-info-circle" />
</InfoTooltip>
</>
)
}
detailTitleColor={
txData.dappSuggestedGasFees ? COLORS.SECONDARY1 : COLORS.BLACK
}
detailText={
<UserPreferencedCurrencyDisplay
type={PRIMARY}
value={hexMinimumTransactionFee}
hideLabel={false}
/>
}
detailTotal={
<UserPreferencedCurrencyDisplay
type={SECONDARY}
value={hexMinimumTransactionFee}
hideLabel
/>
}
subText={t('editGasSubTextFee', [
<UserPreferencedCurrencyDisplay
key="gas-subtext"
type={SECONDARY}
value={getHexGasTotal({
gasPrice: txData.txParams.maxFeePerGas,
gasLimit: txData.txParams.gas,
})}
hideLabel
/>,
])}
subTitle={
<GasTiming
maxPriorityFeePerGas={txData.txParams.maxPriorityFeePerGas}
maxFeePerGas={txData.txParams.maxFeePerGas}
/>
}
/>,
<TransactionDetailItem
key="total-item"
detailTitle={t('total')}
detailText={
<UserPreferencedCurrencyDisplay
type={PRIMARY}
value={hexTransactionTotal}
hideLabel={false}
/>
}
detailTotal={
<UserPreferencedCurrencyDisplay
type={SECONDARY}
value={hexTransactionTotal}
hideLabel
/>
}
subTitle={t('transactionDetailGasTotalSubtitle')}
subText={t('editGasSubTextAmount', [
<UserPreferencedCurrencyDisplay
key="gas-total-subtext"
type={SECONDARY}
value={addHexes(
txData.txParams.value,
getHexGasTotal({
gasPrice: txData.txParams.maxFeePerGas,
gasLimit: txData.txParams.gas,
}),
)}
hideLabel
/>,
])}
/>,
]}
/>
{nonceField}
</div>
);
}
return ( return (
<div className="confirm-page-container-content__details"> <div className="confirm-page-container-content__details">
<div className="confirm-page-container-content__gas-fee"> <TransactionDetail
<ConfirmDetailRow onEdit={() => this.handleEditGas()}
label={t('gasFee')} rows={[
value={hexMinimumTransactionFee} <TransactionDetailItem
headerText={showGasEditButton ? t('edit') : ''} key="gas-item"
headerTextClassName={ detailTitle={
showGasEditButton ? 'confirm-detail-row__header-text--edit' : '' txData.dappSuggestedGasFees ? (
} <>
onHeaderClick={ {t('transactionDetailDappGasHeading', [
showGasEditButton ? () => this.handleEditGas() : null getRequestingOrigin(),
} ])}
secondaryText={ <InfoTooltip
hideFiatConversion ? t('noConversionRateAvailable') : '' contentText={t('transactionDetailDappGasTooltip')}
} position="top"
/> iconFillColor="#f66a0a"
{showInlineControls ? inlineGasControls : null} >
{noGasPrice ? ( <i className="fa fa-info-circle" />
<div className="confirm-page-container-content__error-container"> </InfoTooltip>
<ErrorMessage errorKey={GAS_PRICE_FETCH_FAILURE_ERROR_KEY} /> </>
</div> ) : (
) : null} <>
</div> {t('transactionDetailGasHeading')}
<div <InfoTooltip
className={ contentText={
useNonceField ? 'confirm-page-container-content__gas-fee' : null <>
} <p>{t('transactionDetailGasTooltipIntro')}</p>
> <p>{t('transactionDetailGasTooltipExplanation')}</p>
<ConfirmDetailRow <p>
label={t('total')} <a
value={hexTransactionTotal} href="https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172"
primaryText={primaryTotalTextOverride} target="_blank"
secondaryText={ rel="noopener noreferrer"
hideFiatConversion >
? t('noConversionRateAvailable') {t('transactionDetailGasTooltipConversion')}
: secondaryTotalTextOverride </a>
} </p>
headerText={t('amountGasFee')} </>
headerTextClassName="confirm-detail-row__header-text--total" }
primaryValueTextColor="#2f9ae0" position="top"
/> >
</div> <i className="fa fa-info-circle" />
</InfoTooltip>
</>
)
}
detailTitleColor={
txData.dappSuggestedGasFees ? COLORS.SECONDARY1 : COLORS.BLACK
}
detailText={
<UserPreferencedCurrencyDisplay
type={PRIMARY}
value={hexMinimumTransactionFee}
hideLabel={false}
/>
}
detailTotal={
<UserPreferencedCurrencyDisplay
type={SECONDARY}
value={hexMinimumTransactionFee}
hideLabel
/>
}
subText={t('editGasSubTextFee', [
<UserPreferencedCurrencyDisplay
key="gas-subtext"
type={SECONDARY}
value={getHexGasTotal({
gasPrice: txData.txParams.maxFeePerGas,
gasLimit: txData.txParams.gas,
})}
hideLabel
/>,
])}
subTitle={
<GasTiming
maxPriorityFeePerGas={txData.txParams.maxPriorityFeePerGas}
maxFeePerGas={txData.txParams.maxFeePerGas}
/>
}
/>,
<TransactionDetailItem
key="total-item"
detailTitle={primaryTotalTextOverride || t('total')}
detailText={
<UserPreferencedCurrencyDisplay
type={PRIMARY}
value={hexTransactionTotal}
hideLabel={false}
/>
}
detailTotal={
<UserPreferencedCurrencyDisplay
type={SECONDARY}
value={hexTransactionTotal}
hideLabel
/>
}
subTitle={
secondaryTotalTextOverride ||
t('transactionDetailGasTotalSubtitle')
}
subText={t('editGasSubTextAmount', [
<UserPreferencedCurrencyDisplay
key="gas-total-subtext"
type={SECONDARY}
value={addHexes(
txData.txParams.value,
getHexGasTotal({
gasPrice: txData.txParams.maxFeePerGas,
gasLimit: txData.txParams.gas,
}),
)}
hideLabel
/>,
])}
/>,
]}
/>
{nonceField} {nonceField}
</div> </div>
); );
@ -924,7 +820,7 @@ export default class ConfirmTransactionBase extends Component {
origin={txData.origin} origin={txData.origin}
ethGasPriceWarning={ethGasPriceWarning} ethGasPriceWarning={ethGasPriceWarning}
editingGas={editingGas} editingGas={editingGas}
handleCloseEditGas={() => this.handleCloseNewGasPopover()} handleCloseEditGas={() => this.handleCloseEditGas()}
currentTransaction={txData} currentTransaction={txData}
/> />
); );

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { getBasicGasEstimateLoadingStatus } from '../../../../../selectors';
import { import {
getSendMaxModeState, getSendMaxModeState,
isSendFormInvalid, isSendFormInvalid,
@ -11,7 +10,6 @@ import { useI18nContext } from '../../../../../hooks/useI18nContext';
import { useMetricEvent } from '../../../../../hooks/useMetricEvent'; import { useMetricEvent } from '../../../../../hooks/useMetricEvent';
export default function AmountMaxButton() { export default function AmountMaxButton() {
const buttonDataLoading = useSelector(getBasicGasEstimateLoadingStatus);
const isDraftTransactionInvalid = useSelector(isSendFormInvalid); const isDraftTransactionInvalid = useSelector(isSendFormInvalid);
const maxModeOn = useSelector(getSendMaxModeState); const maxModeOn = useSelector(getSendMaxModeState);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -29,9 +27,7 @@ export default function AmountMaxButton() {
dispatch(toggleSendMaxMode()); dispatch(toggleSendMaxMode());
}; };
const disabled = process.env.SHOW_EIP_1559_UI const disabled = isDraftTransactionInvalid;
? isDraftTransactionInvalid
: buttonDataLoading || isDraftTransactionInvalid;
return ( return (
<button <button

@ -9,9 +9,9 @@ import {
UNSENDABLE_ASSET_ERROR_KEY, UNSENDABLE_ASSET_ERROR_KEY,
} from '../../../helpers/constants/error-keys'; } from '../../../helpers/constants/error-keys';
import SendAmountRow from './send-amount-row'; import SendAmountRow from './send-amount-row';
import SendGasRow from './send-gas-row';
import SendHexDataRow from './send-hex-data-row'; import SendHexDataRow from './send-hex-data-row';
import SendAssetRow from './send-asset-row'; import SendAssetRow from './send-asset-row';
import SendGasRow from './send-gas-row';
export default class SendContent extends Component { export default class SendContent extends Component {
static contextTypes = { static contextTypes = {
@ -29,6 +29,7 @@ export default class SendContent extends Component {
gasIsExcessive: PropTypes.bool.isRequired, gasIsExcessive: PropTypes.bool.isRequired,
isEthGasPrice: PropTypes.bool, isEthGasPrice: PropTypes.bool,
noGasPrice: PropTypes.bool, noGasPrice: PropTypes.bool,
isEIP1559Network: PropTypes.bool,
}; };
render() { render() {
@ -39,6 +40,7 @@ export default class SendContent extends Component {
isEthGasPrice, isEthGasPrice,
noGasPrice, noGasPrice,
isAssetSendable, isAssetSendable,
isEIP1559Network,
} = this.props; } = this.props;
let gasError; let gasError;
@ -57,7 +59,7 @@ export default class SendContent extends Component {
{this.maybeRenderAddContact()} {this.maybeRenderAddContact()}
<SendAssetRow /> <SendAssetRow />
<SendAmountRow /> <SendAmountRow />
{process.env.SHOW_EIP_1559_UI ? null : <SendGasRow />} {!isEIP1559Network && <SendGasRow />}
{this.props.showHexData && <SendHexDataRow />} {this.props.showHexData && <SendHexDataRow />}
</div> </div>
</PageContainerContent> </PageContainerContent>

@ -5,7 +5,6 @@ import Dialog from '../../../components/ui/dialog';
import SendContent from './send-content.component'; import SendContent from './send-content.component';
import SendAmountRow from './send-amount-row/send-amount-row.container'; import SendAmountRow from './send-amount-row/send-amount-row.container';
import SendGasRow from './send-gas-row/send-gas-row.container';
import SendHexDataRow from './send-hex-data-row/send-hex-data-row.container'; import SendHexDataRow from './send-hex-data-row/send-hex-data-row.container';
import SendAssetRow from './send-asset-row/send-asset-row.container'; import SendAssetRow from './send-asset-row/send-asset-row.container';
@ -15,6 +14,7 @@ describe('SendContent Component', () => {
const defaultProps = { const defaultProps = {
showHexData: true, showHexData: true,
gasIsExcessive: false, gasIsExcessive: false,
isEIP1559Network: true,
}; };
beforeEach(() => { beforeEach(() => {
@ -51,11 +51,8 @@ describe('SendContent Component', () => {
expect( expect(
PageContainerContentChild.childAt(2).is(SendAmountRow), PageContainerContentChild.childAt(2).is(SendAmountRow),
).toStrictEqual(true); ).toStrictEqual(true);
expect(PageContainerContentChild.childAt(3).is(SendGasRow)).toStrictEqual(
true,
);
expect( expect(
PageContainerContentChild.childAt(4).is(SendHexDataRow), PageContainerContentChild.childAt(3).is(SendHexDataRow),
).toStrictEqual(true); ).toStrictEqual(true);
}); });
@ -73,9 +70,6 @@ describe('SendContent Component', () => {
expect( expect(
PageContainerContentChild.childAt(2).is(SendAmountRow), PageContainerContentChild.childAt(2).is(SendAmountRow),
).toStrictEqual(true); ).toStrictEqual(true);
expect(PageContainerContentChild.childAt(3).is(SendGasRow)).toStrictEqual(
true,
);
expect(wrapper.find(SendHexDataRow)).toHaveLength(0); expect(wrapper.find(SendHexDataRow)).toHaveLength(0);
}); });
@ -93,9 +87,6 @@ describe('SendContent Component', () => {
expect( expect(
PageContainerContentChild.childAt(1).is(SendAmountRow), PageContainerContentChild.childAt(1).is(SendAmountRow),
).toStrictEqual(true); ).toStrictEqual(true);
expect(PageContainerContentChild.childAt(2).is(SendGasRow)).toStrictEqual(
true,
);
expect(wrapper.find(Dialog)).toHaveLength(0); expect(wrapper.find(Dialog)).toHaveLength(0);
}); });
@ -113,9 +104,6 @@ describe('SendContent Component', () => {
expect( expect(
PageContainerContentChild.childAt(1).is(SendAmountRow), PageContainerContentChild.childAt(1).is(SendAmountRow),
).toStrictEqual(true); ).toStrictEqual(true);
expect(PageContainerContentChild.childAt(2).is(SendGasRow)).toStrictEqual(
true,
);
expect(wrapper.find(Dialog)).toHaveLength(0); expect(wrapper.find(Dialog)).toHaveLength(0);
}); });
}); });

@ -5,7 +5,7 @@ import {
getIsEthGasPriceFetched, getIsEthGasPriceFetched,
getNoGasPriceFetched, getNoGasPriceFetched,
} from '../../../selectors'; } from '../../../selectors';
import { isEIP1559Network } from '../../../ducks/metamask/metamask';
import { getIsAssetSendable, getSendTo } from '../../../ducks/send'; import { getIsAssetSendable, getSendTo } from '../../../ducks/send';
import * as actions from '../../../store/actions'; import * as actions from '../../../store/actions';
@ -25,6 +25,7 @@ function mapStateToProps(state) {
isEthGasPrice: getIsEthGasPriceFetched(state), isEthGasPrice: getIsEthGasPriceFetched(state),
noGasPrice: getNoGasPriceFetched(state), noGasPrice: getNoGasPriceFetched(state),
to, to,
isEIP1559Network: isEIP1559Network(state),
}; };
} }

@ -11,7 +11,7 @@ export default class SendGasRow extends Component {
gasFeeError: PropTypes.bool, gasFeeError: PropTypes.bool,
gasLoadingError: PropTypes.bool, gasLoadingError: PropTypes.bool,
gasTotal: PropTypes.string, gasTotal: PropTypes.string,
showCustomizeGasModal: PropTypes.func, showLegacyCustomizeGasModal: PropTypes.func,
updateGasPrice: PropTypes.func, updateGasPrice: PropTypes.func,
updateGasLimit: PropTypes.func, updateGasLimit: PropTypes.func,
gasInputMode: PropTypes.oneOf(Object.values(GAS_INPUT_MODES)), gasInputMode: PropTypes.oneOf(Object.values(GAS_INPUT_MODES)),
@ -31,7 +31,7 @@ export default class SendGasRow extends Component {
renderAdvancedOptionsButton() { renderAdvancedOptionsButton() {
const { trackEvent } = this.context; const { trackEvent } = this.context;
const { showCustomizeGasModal } = this.props; const { showLegacyCustomizeGasModal } = this.props;
return ( return (
<div <div
className="advanced-gas-options-btn" className="advanced-gas-options-btn"
@ -40,7 +40,7 @@ export default class SendGasRow extends Component {
category: 'Transactions', category: 'Transactions',
event: 'Clicked "Advanced Options"', event: 'Clicked "Advanced Options"',
}); });
showCustomizeGasModal(); showLegacyCustomizeGasModal();
}} }}
> >
{this.context.t('advancedOptions')} {this.context.t('advancedOptions')}
@ -52,7 +52,6 @@ export default class SendGasRow extends Component {
const { const {
gasLoadingError, gasLoadingError,
gasTotal, gasTotal,
showCustomizeGasModal,
gasPriceButtonGroupProps, gasPriceButtonGroupProps,
gasInputMode, gasInputMode,
resetGasButtons, resetGasButtons,
@ -89,7 +88,6 @@ export default class SendGasRow extends Component {
gasLoadingError={gasLoadingError} gasLoadingError={gasLoadingError}
gasTotal={gasTotal} gasTotal={gasTotal}
onReset={resetGasButtons} onReset={resetGasButtons}
onClick={showCustomizeGasModal}
/> />
); );
const advancedGasInputs = ( const advancedGasInputs = (

@ -10,6 +10,7 @@ import GasFeeDisplay from './gas-fee-display/gas-fee-display.component';
const propsMethodSpies = { const propsMethodSpies = {
showCustomizeGasModal: sinon.spy(), showCustomizeGasModal: sinon.spy(),
showLegacyCustomizeGasModal: sinon.spy(),
resetGasButtons: sinon.spy(), resetGasButtons: sinon.spy(),
}; };
@ -27,6 +28,9 @@ describe('SendGasRow Component', () => {
gasTotal="mockGasTotal" gasTotal="mockGasTotal"
gasInputMode={GAS_INPUT_MODES.CUSTOM} gasInputMode={GAS_INPUT_MODES.CUSTOM}
showCustomizeGasModal={propsMethodSpies.showCustomizeGasModal} showCustomizeGasModal={propsMethodSpies.showCustomizeGasModal}
showLegacyCustomizeGasModal={
propsMethodSpies.showLegacyCustomizeGasModal
}
resetGasButtons={propsMethodSpies.resetGasButtons} resetGasButtons={propsMethodSpies.resetGasButtons}
gasPriceButtonGroupProps={{ gasPriceButtonGroupProps={{
someGasPriceButtonGroupProp: 'foo', someGasPriceButtonGroupProp: 'foo',
@ -104,9 +108,13 @@ describe('SendGasRow Component', () => {
const advancedOptionsButton = rendered.childAt(0); const advancedOptionsButton = rendered.childAt(0);
expect(advancedOptionsButton.text()).toStrictEqual('advancedOptions_t'); expect(advancedOptionsButton.text()).toStrictEqual('advancedOptions_t');
expect(propsMethodSpies.showCustomizeGasModal.callCount).toStrictEqual(0); expect(
propsMethodSpies.showLegacyCustomizeGasModal.callCount,
).toStrictEqual(0);
advancedOptionsButton.props().onClick(); advancedOptionsButton.props().onClick();
expect(propsMethodSpies.showCustomizeGasModal.callCount).toStrictEqual(1); expect(
propsMethodSpies.showLegacyCustomizeGasModal.callCount,
).toStrictEqual(1);
}); });
}); });
}); });

@ -67,8 +67,8 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
return { return {
showCustomizeGasModal: () => showLegacyCustomizeGasModal: () =>
dispatch(showModal({ name: 'CUSTOMIZE_GAS', hideBasic: true })), dispatch(showModal({ name: 'LEGACY_CUSTOMIZE_GAS', hideBasic: true })),
updateGasPrice: (gasPrice) => { updateGasPrice: (gasPrice) => {
dispatch(updateGasPrice(gasPrice)); dispatch(updateGasPrice(gasPrice));
dispatch(setCustomGasPrice(gasPrice)); dispatch(setCustomGasPrice(gasPrice));

@ -60,12 +60,12 @@ describe('send-gas-row container', () => {
mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy); mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy);
}); });
describe('showCustomizeGasModal()', () => { describe('showLegacyCustomizeGasModal()', () => {
it('should dispatch an action', () => { it('should dispatch an action', () => {
mapDispatchToPropsObject.showCustomizeGasModal(); mapDispatchToPropsObject.showLegacyCustomizeGasModal();
expect(dispatchSpy.calledOnce).toStrictEqual(true); expect(dispatchSpy.calledOnce).toStrictEqual(true);
expect(showModal).toHaveBeenCalledWith({ expect(showModal).toHaveBeenCalledWith({
name: 'CUSTOMIZE_GAS', name: 'LEGACY_CUSTOMIZE_GAS',
hideBasic: true, hideBasic: true,
}); });
}); });

Loading…
Cancel
Save