From e577a1b66e256bfe200b2125c90adbdc41245aa8 Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Fri, 22 Jul 2022 20:44:27 +0000 Subject: [PATCH 01/22] Version v10.18.1 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06e058fbf..3ad68ccff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.18.1] + ## [10.18.0] ### Added - Add setApprovalForAll confirmation view so granted permissions are displayed in a digested manner, instead of a simple contract interaction([#15010](https://github.com/MetaMask/metamask-extension/pull/15010)) @@ -3084,7 +3086,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...HEAD +[10.18.1]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...v10.18.1 [10.18.0]: https://github.com/MetaMask/metamask-extension/compare/v10.17.0...v10.18.0 [10.17.0]: https://github.com/MetaMask/metamask-extension/compare/v10.16.2...v10.17.0 [10.16.2]: https://github.com/MetaMask/metamask-extension/compare/v10.16.1...v10.16.2 diff --git a/package.json b/package.json index 828853ae2..8acdb39d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.18.0", + "version": "10.18.1", "private": true, "repository": { "type": "git", From d35d3ca7452663f9dd20c69fce971579a8f3fc0d Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Fri, 22 Jul 2022 18:18:52 -0230 Subject: [PATCH 02/22] Update changelog for v10.18.1 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ad68ccff..c961f703f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [10.18.1] +### Changed +- Move the metrics opt-in screen to the second screen of the onboarding flow ([#15313](https://github.com/MetaMask/metamask-extension/pull/15313)) ## [10.18.0] ### Added From 99f753d73f5ce67374bcaf7b2ed1afdbece72739 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 22 Jul 2022 18:09:48 -0230 Subject: [PATCH 03/22] Metrics adjustments (#15313) * Don't send errors to sentry if users have not opted-in to participate in metametrics * Don't capture opt-out metrics * Move the metrics-opt in screen to immediately after the welcome screen * Ensure that global.getSentryState is set in the background * Fix e2e tests after rearranging onboardin flow * Fix unit tests * More e2e test fixes * Remove unnecessary wrappers around capture exception --- app/scripts/background.js | 17 +++++++++++ app/scripts/lib/setupSentry.js | 12 +++++++- shared/modules/object.utils.js | 22 ++++++++++++++ test/e2e/helpers.js | 12 ++++---- test/e2e/metamask-ui.spec.js | 8 ++--- test/e2e/tests/incremental-security.spec.js | 6 ++-- test/e2e/tests/metamask-responsive-ui.spec.js | 6 ++-- ui/index.js | 24 +-------------- .../metametrics-opt-in.component.js | 29 ++----------------- .../metametrics-opt-in.container.js | 2 -- .../select-action/select-action.component.js | 9 ++++-- .../welcome/welcome.component.js | 21 +++++++++++--- .../welcome/welcome.container.js | 7 ++++- .../first-time-flow/welcome/welcome.test.js | 8 ++--- 14 files changed, 103 insertions(+), 80 deletions(-) create mode 100644 shared/modules/object.utils.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 311cd2781..0246c5d73 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -24,11 +24,14 @@ import { REJECT_NOTFICIATION_CLOSE_SIG, } from '../../shared/constants/metametrics'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; +import { maskObject } from '../../shared/modules/object.utils'; import migrations from './migrations'; import Migrator from './lib/migrator'; import ExtensionPlatform from './platforms/extension'; import LocalStore from './lib/local-store'; import ReadOnlyNetworkStore from './lib/network-store'; +import { SENTRY_STATE } from './lib/setupSentry'; + import createStreamSink from './lib/createStreamSink'; import NotificationManager, { NOTIFICATION_MANAGER_EVENTS, @@ -353,6 +356,8 @@ function setupController(initState, initLangCode, remoteSourcePort) { }, ); + setupSentryGetStateGlobal(controller.store); + /** * Assigns the given state to the versioned object (with metadata), and returns that. * @@ -755,3 +760,15 @@ browser.runtime.onInstalled.addListener(({ reason }) => { platform.openExtensionInBrowser(); } }); + +function setupSentryGetStateGlobal(store) { + global.getSentryState = function () { + const fullState = store.getState(); + const debugState = maskObject(fullState, SENTRY_STATE); + return { + browser: window.navigator.userAgent, + store: debugState, + version: global.platform.getVersion(), + }; + }; +} diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 7332041bb..196389439 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -103,7 +103,17 @@ export default function setupSentry({ release, getState }) { environment, integrations: [new Dedupe(), new ExtraErrorData()], release, - beforeSend: (report) => rewriteReport(report), + beforeSend: (report) => { + if (getState) { + const appState = getState(); + if (!appState?.store?.metamask?.participateInMetaMetrics) { + return null; + } + } else { + return null; + } + return rewriteReport(report); + }, }); function rewriteReport(report) { diff --git a/shared/modules/object.utils.js b/shared/modules/object.utils.js new file mode 100644 index 000000000..ea2af06c4 --- /dev/null +++ b/shared/modules/object.utils.js @@ -0,0 +1,22 @@ +/** + * Return a "masked" copy of the given object. + * + * The returned object includes only the properties present in the mask. The + * mask is an object that mirrors the structure of the given object, except + * the only values are `true` or a sub-mask. `true` implies the property + * should be included, and a sub-mask implies the property should be further + * masked according to that sub-mask. + * + * @param {Object} object - The object to mask + * @param {Object} mask - The mask to apply to the object + */ +export function maskObject(object, mask) { + return Object.keys(object).reduce((state, key) => { + if (mask[key] === true) { + state[key] = object[key]; + } else if (mask[key]) { + state[key] = maskObject(object[key], mask[key]); + } + return state; + }, {}); +} diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index cd05e38e0..827d9752b 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -237,12 +237,12 @@ const completeImportSRPOnboardingFlow = async ( tag: 'button', }); - // clicks the "Import Wallet" option - await driver.clickElement({ text: 'Import wallet', tag: 'button' }); - // clicks the "No thanks" option on the metametrics opt-in screen await driver.clickElement('.btn-secondary'); + // clicks the "Import Wallet" option + await driver.clickElement({ text: 'Import wallet', tag: 'button' }); + // Import Secret Recovery Phrase await driver.pasteIntoField( '[data-testid="import-srp__srp-word-0"]', @@ -279,12 +279,12 @@ const completeImportSRPOnboardingFlowWordByWord = async ( tag: 'button', }); - // clicks the "Import Wallet" option - await driver.clickElement({ text: 'Import wallet', tag: 'button' }); - // clicks the "No thanks" option on the metametrics opt-in screen await driver.clickElement('.btn-secondary'); + // clicks the "Import Wallet" option + await driver.clickElement({ text: 'Import wallet', tag: 'button' }); + const words = seedPhrase.split(' '); for (const word of words) { await driver.pasteIntoField( diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index 854b597a0..9e85bff84 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -99,13 +99,13 @@ describe('MetaMask', function () { await driver.delay(largeDelayMs); }); - it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); + it('clicks the "No thanks" option on the metametrics opt-in screen', async function () { + await driver.clickElement('.btn-secondary'); await driver.delay(largeDelayMs); }); - it('clicks the "No thanks" option on the metametrics opt-in screen', async function () { - await driver.clickElement('.btn-secondary'); + it('clicks the "Create New Wallet" option', async function () { + await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); await driver.delay(largeDelayMs); }); diff --git a/test/e2e/tests/incremental-security.spec.js b/test/e2e/tests/incremental-security.spec.js index a94f0f3e2..a12f49831 100644 --- a/test/e2e/tests/incremental-security.spec.js +++ b/test/e2e/tests/incremental-security.spec.js @@ -38,12 +38,12 @@ describe('Incremental Security', function () { tag: 'button', }); - // clicks the "Create New Wallet" option - await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); - // clicks the "No thanks" option on the metametrics opt-in screen await driver.clickElement('.btn-secondary'); + // clicks the "Create New Wallet" option + await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); + // accepts a secure password await driver.fill( '.first-time-flow__form #create-password', diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/metamask-responsive-ui.spec.js index e51c449de..3b796834e 100644 --- a/test/e2e/tests/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/metamask-responsive-ui.spec.js @@ -87,12 +87,12 @@ describe('MetaMask Responsive UI', function () { }); await driver.delay(tinyDelayMs); - // clicks the "Create New Wallet" option - await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); - // clicks the "I Agree" option on the metametrics opt-in screen await driver.clickElement('.btn-primary'); + // clicks the "Create New Wallet" option + await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); + // accepts a secure password await driver.fill( '.first-time-flow__form #create-password', diff --git a/ui/index.js b/ui/index.js index be61e7c9c..842d0f2a9 100644 --- a/ui/index.js +++ b/ui/index.js @@ -7,6 +7,7 @@ import browser from 'webextension-polyfill'; import { getEnvironmentType } from '../app/scripts/lib/util'; import { ALERT_TYPES } from '../shared/constants/alerts'; +import { maskObject } from '../shared/modules/object.utils'; import { SENTRY_STATE } from '../app/scripts/lib/setupSentry'; import { ENVIRONMENT_TYPE_POPUP } from '../shared/constants/app'; import * as actions from './store/actions'; @@ -171,29 +172,6 @@ async function startApp(metamaskState, backgroundConnection, opts) { return store; } -/** - * Return a "masked" copy of the given object. - * - * The returned object includes only the properties present in the mask. The - * mask is an object that mirrors the structure of the given object, except - * the only values are `true` or a sub-mask. `true` implies the property - * should be included, and a sub-mask implies the property should be further - * masked according to that sub-mask. - * - * @param {Object} object - The object to mask - * @param {Object} mask - The mask to apply to the object - */ -function maskObject(object, mask) { - return Object.keys(object).reduce((state, key) => { - if (mask[key] === true) { - state[key] = object[key]; - } else if (mask[key]) { - state[key] = maskObject(object[key], mask[key]); - } - return state; - }, {}); -} - function setupDebuggingHelpers(store) { window.getCleanAppState = async function () { const state = clone(store.getState()); diff --git a/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js b/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js index 673d1c7f3..7fc24e657 100644 --- a/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js +++ b/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js @@ -3,12 +3,12 @@ import PropTypes from 'prop-types'; import MetaFoxLogo from '../../../components/ui/metafox-logo'; import PageContainerFooter from '../../../components/ui/page-container/page-container-footer'; import { EVENT } from '../../../../shared/constants/metametrics'; +import { INITIALIZE_SELECT_ACTION_ROUTE } from '../../../helpers/constants/routes'; export default class MetaMetricsOptIn extends Component { static propTypes = { history: PropTypes.object, setParticipateInMetaMetrics: PropTypes.func, - nextRoute: PropTypes.string, firstTimeSelectionMetaMetricsName: PropTypes.string, participateInMetaMetrics: PropTypes.bool, }; @@ -21,7 +21,6 @@ export default class MetaMetricsOptIn extends Component { render() { const { trackEvent, t } = this.context; const { - nextRoute, history, setParticipateInMetaMetrics, firstTimeSelectionMetaMetricsName, @@ -105,29 +104,7 @@ export default class MetaMetricsOptIn extends Component { onCancel={async () => { await setParticipateInMetaMetrics(false); - try { - if ( - participateInMetaMetrics === null || - participateInMetaMetrics === true - ) { - await trackEvent( - { - category: EVENT.CATEGORIES.ONBOARDING, - event: 'Metrics Opt Out', - properties: { - action: 'Metrics Option', - legacy_event: true, - }, - }, - { - isOptIn: true, - flushImmediately: true, - }, - ); - } - } finally { - history.push(nextRoute); - } + history.push(INITIALIZE_SELECT_ACTION_ROUTE); }} cancelText={t('noThanks')} hideCancel={false} @@ -177,7 +154,7 @@ export default class MetaMetricsOptIn extends Component { ); await Promise.all(metrics); } finally { - history.push(nextRoute); + history.push(INITIALIZE_SELECT_ACTION_ROUTE); } }} submitText={t('affirmAgree')} diff --git a/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js b/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js index e336a9dd2..9e607ccf7 100644 --- a/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js +++ b/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; import { setParticipateInMetaMetrics } from '../../../store/actions'; -import { getFirstTimeFlowTypeRoute } from '../../../selectors'; import MetaMetricsOptIn from './metametrics-opt-in.component'; const firstTimeFlowTypeNameMap = { @@ -12,7 +11,6 @@ const mapStateToProps = (state) => { const { firstTimeFlowType, participateInMetaMetrics } = state.metamask; return { - nextRoute: getFirstTimeFlowTypeRoute(state), firstTimeSelectionMetaMetricsName: firstTimeFlowTypeNameMap[firstTimeFlowType], participateInMetaMetrics, diff --git a/ui/pages/first-time-flow/select-action/select-action.component.js b/ui/pages/first-time-flow/select-action/select-action.component.js index 7feadb9a3..51d2876d7 100644 --- a/ui/pages/first-time-flow/select-action/select-action.component.js +++ b/ui/pages/first-time-flow/select-action/select-action.component.js @@ -2,7 +2,10 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import Button from '../../../components/ui/button'; import MetaFoxLogo from '../../../components/ui/metafox-logo'; -import { INITIALIZE_METAMETRICS_OPT_IN_ROUTE } from '../../../helpers/constants/routes'; +import { + INITIALIZE_CREATE_PASSWORD_ROUTE, + INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, +} from '../../../helpers/constants/routes'; export default class SelectAction extends PureComponent { static propTypes = { @@ -26,12 +29,12 @@ export default class SelectAction extends PureComponent { handleCreate = () => { this.props.setFirstTimeFlowType('create'); - this.props.history.push(INITIALIZE_METAMETRICS_OPT_IN_ROUTE); + this.props.history.push(INITIALIZE_CREATE_PASSWORD_ROUTE); }; handleImport = () => { this.props.setFirstTimeFlowType('import'); - this.props.history.push(INITIALIZE_METAMETRICS_OPT_IN_ROUTE); + this.props.history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE); }; render() { diff --git a/ui/pages/first-time-flow/welcome/welcome.component.js b/ui/pages/first-time-flow/welcome/welcome.component.js index 20a929372..46bf36d22 100644 --- a/ui/pages/first-time-flow/welcome/welcome.component.js +++ b/ui/pages/first-time-flow/welcome/welcome.component.js @@ -6,6 +6,7 @@ import Button from '../../../components/ui/button'; import { INITIALIZE_CREATE_PASSWORD_ROUTE, INITIALIZE_SELECT_ACTION_ROUTE, + INITIALIZE_METAMETRICS_OPT_IN_ROUTE, } from '../../../helpers/constants/routes'; import { isBeta } from '../../../helpers/utils/build-types'; import WelcomeFooter from './welcome-footer.component'; @@ -16,6 +17,7 @@ export default class Welcome extends PureComponent { history: PropTypes.object, participateInMetaMetrics: PropTypes.bool, welcomeScreenSeen: PropTypes.bool, + isInitialized: PropTypes.bool, }; static contextTypes = { @@ -29,17 +31,28 @@ export default class Welcome extends PureComponent { } componentDidMount() { - const { history, participateInMetaMetrics, welcomeScreenSeen } = this.props; + const { + history, + participateInMetaMetrics, + welcomeScreenSeen, + isInitialized, + } = this.props; - if (welcomeScreenSeen && participateInMetaMetrics !== null) { + if ( + welcomeScreenSeen && + isInitialized && + participateInMetaMetrics !== null + ) { history.push(INITIALIZE_CREATE_PASSWORD_ROUTE); - } else if (welcomeScreenSeen) { + } else if (welcomeScreenSeen && participateInMetaMetrics !== null) { history.push(INITIALIZE_SELECT_ACTION_ROUTE); + } else if (welcomeScreenSeen) { + history.push(INITIALIZE_METAMETRICS_OPT_IN_ROUTE); } } handleContinue = () => { - this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE); + this.props.history.push(INITIALIZE_METAMETRICS_OPT_IN_ROUTE); }; render() { diff --git a/ui/pages/first-time-flow/welcome/welcome.container.js b/ui/pages/first-time-flow/welcome/welcome.container.js index 77909d25b..27bd2e198 100644 --- a/ui/pages/first-time-flow/welcome/welcome.container.js +++ b/ui/pages/first-time-flow/welcome/welcome.container.js @@ -5,11 +5,16 @@ import { closeWelcomeScreen } from '../../../store/actions'; import Welcome from './welcome.component'; const mapStateToProps = ({ metamask }) => { - const { welcomeScreenSeen, participateInMetaMetrics } = metamask; + const { + welcomeScreenSeen, + participateInMetaMetrics, + isInitialized, + } = metamask; return { welcomeScreenSeen, participateInMetaMetrics, + isInitialized, }; }; diff --git a/ui/pages/first-time-flow/welcome/welcome.test.js b/ui/pages/first-time-flow/welcome/welcome.test.js index 14d1a22cc..2c0f79106 100644 --- a/ui/pages/first-time-flow/welcome/welcome.test.js +++ b/ui/pages/first-time-flow/welcome/welcome.test.js @@ -15,7 +15,7 @@ describe('Welcome', () => { sinon.restore(); }); - it('routes to select action when participateInMetaMetrics is not initialized', () => { + it('routes to the metametrics screen when participateInMetaMetrics is not initialized', () => { const props = { history: { push: sinon.spy(), @@ -32,11 +32,11 @@ describe('Welcome', () => { ); getStartedButton.simulate('click'); expect(props.history.push.getCall(0).args[0]).toStrictEqual( - '/initialize/select-action', + '/initialize/metametrics-opt-in', ); }); - it('routes to correct password when participateInMetaMetrics is initialized', () => { + it('routes to select action when participateInMetaMetrics is initialized', () => { const props = { welcomeScreenSeen: true, participateInMetaMetrics: false, @@ -55,7 +55,7 @@ describe('Welcome', () => { ); getStartedButton.simulate('click'); expect(props.history.push.getCall(0).args[0]).toStrictEqual( - '/initialize/create-password', + '/initialize/select-action', ); }); }); From f503a634f0a500edc325637b8559004dd809f1fd Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Wed, 3 Aug 2022 20:57:32 +0000 Subject: [PATCH 04/22] Version v10.18.2 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c961f703f..1b59428c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.18.2] + ## [10.18.1] ### Changed - Move the metrics opt-in screen to the second screen of the onboarding flow ([#15313](https://github.com/MetaMask/metamask-extension/pull/15313)) @@ -3088,7 +3090,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.2...HEAD +[10.18.2]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...v10.18.2 [10.18.1]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...v10.18.1 [10.18.0]: https://github.com/MetaMask/metamask-extension/compare/v10.17.0...v10.18.0 [10.17.0]: https://github.com/MetaMask/metamask-extension/compare/v10.16.2...v10.17.0 diff --git a/package.json b/package.json index 8acdb39d8..e085b11d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.18.1", + "version": "10.18.2", "private": true, "repository": { "type": "git", From d363bdbb21c620989ff23a8c8263f4e161a86c50 Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Mon, 1 Aug 2022 11:42:58 -0500 Subject: [PATCH 05/22] Fix error that occurs when attempting to display transaction value for an approval transaction with no value argument in the transaction data (#15398) --- ui/hooks/useTokenDisplayValue.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/hooks/useTokenDisplayValue.js b/ui/hooks/useTokenDisplayValue.js index 442dc98e0..dd58c9193 100644 --- a/ui/hooks/useTokenDisplayValue.js +++ b/ui/hooks/useTokenDisplayValue.js @@ -35,6 +35,8 @@ export function useTokenDisplayValue( isTokenTransaction = true, ) { const tokenData = useTokenData(transactionData, isTokenTransaction); + const tokenValue = getTokenValueParam(tokenData); + const shouldCalculateTokenValue = Boolean( // If we are currently processing a token transaction isTokenTransaction && @@ -42,15 +44,17 @@ export function useTokenDisplayValue( transactionData && // and a token object has been provided token && - // and we are able to parse the token details from the raw data - tokenData?.args?.length, + // and the provided token object contains a defined decimal value we need to calculate amount + token.decimals && + // and we are able to parse the token detail we to calculate amount from the raw data + tokenValue, ); const displayValue = useMemo(() => { if (!shouldCalculateTokenValue) { return null; } - const tokenValue = getTokenValueParam(tokenData); + return calcTokenAmount(tokenValue, token.decimals).toString(10); }, [shouldCalculateTokenValue, tokenData, token]); From 8b4e046ac37864a9f4c4a7b7605b4119a21985da Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 2 Aug 2022 15:54:24 -0230 Subject: [PATCH 06/22] Fix optimism send flow (#15419) --- ui/ducks/send/send.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 4ca6b6ca4..1fd410f18 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -513,7 +513,7 @@ export const computeEstimatedGasLimit = createAsyncThunk( value: send.amountMode === AMOUNT_MODES.MAX ? send.selectedAccount.balance - : send.amount.value, + : draftTransaction.amount.value, from: send.selectedAccount.address, data: draftTransaction.userInputHexData, type: '0x0', From 29c7f2227ac0671da71cf302dfc0482c48952a23 Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Tue, 2 Aug 2022 13:38:15 -0500 Subject: [PATCH 07/22] Enhance approval screen title logic (#15406) --- .../confirm-approve-content.component.js | 73 ++++++++++--------- .../confirm-approve-content.component.test.js | 13 +++- .../confirm-approve-content/index.scss | 6 +- 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index b87c405b9..6e7f9e31e 100644 --- a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -29,6 +29,10 @@ import { ConfirmPageContainerWarning } from '../../../components/app/confirm-pag import GasDetailsItem from '../../../components/app/gas-details-item'; import LedgerInstructionField from '../../../components/app/ledger-instruction-field'; import { ERC1155, ERC20, ERC721 } from '../../../helpers/constants/common'; +import { + MAINNET_CHAIN_ID, + TEST_CHAINS, +} from '../../../../shared/constants/network'; export default class ConfirmApproveContent extends Component { static contextTypes = { @@ -458,31 +462,12 @@ export default class ConfirmApproveContent extends Component { userAddress, } = this.props; const { t } = this.context; + const useBlockExplorer = + rpcPrefs?.blockExplorerUrl || + [...TEST_CHAINS, MAINNET_CHAIN_ID].includes(chainId); + let titleTokenDescription = t('token'); - if (rpcPrefs?.blockExplorerUrl || chainId) { - const unknownTokenBlockExplorerLink = getTokenTrackerLink( - tokenAddress, - chainId, - null, - userAddress, - { - blockExplorerUrl: rpcPrefs?.blockExplorerUrl ?? null, - }, - ); - - const unknownTokenLink = ( - - {t('token')} - - ); - titleTokenDescription = unknownTokenLink; - } - + const tokenIdWrapped = tokenId ? ` (#${tokenId})` : ''; if ( assetStandard === ERC20 || (tokenSymbol && !tokenId && !isSetApproveForAll) @@ -495,11 +480,14 @@ export default class ConfirmApproveContent extends Component { (assetName && tokenId) || (tokenSymbol && tokenId) ) { - const tokenIdWrapped = tokenId ? ` (#${tokenId})` : ''; if (assetName || tokenSymbol) { - titleTokenDescription = `${assetName ?? tokenSymbol}${tokenIdWrapped}`; + titleTokenDescription = `${assetName ?? tokenSymbol}`; } else { - const unknownNFTBlockExplorerLink = getTokenTrackerLink( + titleTokenDescription = t('nft'); + } + + if (useBlockExplorer) { + const blockExplorerLink = getTokenTrackerLink( tokenAddress, chainId, null, @@ -508,24 +496,38 @@ export default class ConfirmApproveContent extends Component { blockExplorerUrl: rpcPrefs?.blockExplorerUrl ?? null, }, ); - const unknownNFTLink = ( + const blockExplorerElement = ( <> - {t('nft')} + {titleTokenDescription} {tokenIdWrapped && {tokenIdWrapped}} ); - titleTokenDescription = unknownNFTLink; + return blockExplorerElement; } } - return titleTokenDescription; + return ( + <> + { + copyToClipboard(tokenAddress); + }} + title={tokenAddress} + > + {titleTokenDescription} + + {tokenIdWrapped && {tokenIdWrapped}} + + ); } renderTitle() { @@ -627,7 +629,10 @@ export default class ConfirmApproveContent extends Component { -
+
{this.renderTitle()}
diff --git a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js index dd9cd8dd4..ede4347ec 100644 --- a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js +++ b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js @@ -40,11 +40,16 @@ const props = { describe('ConfirmApproveContent Component', () => { it('should render Confirm approve page correctly', () => { - const { queryByText, getByText, getAllByText } = renderComponent(props); + const { + queryByText, + getByText, + getAllByText, + getByTestId, + } = renderComponent(props); expect(queryByText('metamask.github.io')).toBeInTheDocument(); - expect( - queryByText('Give permission to access your TST?'), - ).toBeInTheDocument(); + expect(getByTestId('confirm-approve-title').textContent).toBe( + ' Give permission to access your TST? ', + ); expect( queryByText( 'By granting permission, you are allowing the following contract to access your funds', diff --git a/ui/pages/confirm-approve/confirm-approve-content/index.scss b/ui/pages/confirm-approve/confirm-approve-content/index.scss index 473be2f7b..8f49b58fc 100644 --- a/ui/pages/confirm-approve/confirm-approve-content/index.scss +++ b/ui/pages/confirm-approve/confirm-approve-content/index.scss @@ -9,10 +9,14 @@ padding: 0 24px 16px 24px; } - &__unknown-asset { + &__approval-asset-link { color: var(--color-primary-default); } + &__approval-asset-title { + cursor: pointer; + } + &__icon-display-content { display: flex; height: 51px; From 4c4ce83b0bc630f1942cb942c4eceb1421a2de34 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Tue, 2 Aug 2022 13:52:09 -0500 Subject: [PATCH 08/22] fix issues relating to race conditions where draftTx does not exist (#15420) * fix issues relating to race conditions where draftTx does not exist * add another fail safe for inflight initializations --- ui/ducks/send/send.js | 96 ++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 1fd410f18..a7bcde735 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -598,7 +598,7 @@ export const initializeSendState = createAsyncThunk( // For instance, in the actions.js file we dispatch this action anytime the // chain changes. if (!draftTransaction) { - thunkApi.rejectWithValue( + return thunkApi.rejectWithValue( 'draftTransaction not found, possibly not on send flow', ); } @@ -673,6 +673,20 @@ export const initializeSendState = createAsyncThunk( // We have to keep the gas slice in sync with the send slice state // so that it'll be initialized correctly if the gas modal is opened. await thunkApi.dispatch(setCustomGasLimit(gasLimit)); + + // There may be a case where the send has been canceled by the user while + // the gas estimate is being computed. So we check again to make sure that + // a currentTransactionUUID exists and matches the previous tx. + const newState = thunkApi.getState(); + if ( + newState.send.currentTransactionUUID !== sendState.currentTransactionUUID + ) { + return thunkApi.rejectWithValue( + `draftTransaction changed during initialization. + A new initializeSendState action must be dispatched.`, + ); + } + return { account, chainId: getCurrentChainId(state), @@ -1398,28 +1412,30 @@ const slice = createSlice({ validateSendState: (state) => { const draftTransaction = state.draftTransactions[state.currentTransactionUUID]; - switch (true) { - case Boolean(draftTransaction.amount.error): - case Boolean(draftTransaction.gas.error): - case Boolean(draftTransaction.asset.error): - case draftTransaction.asset.type === ASSET_TYPES.TOKEN && - draftTransaction.asset.details === null: - case state.stage === SEND_STAGES.ADD_RECIPIENT: - case state.stage === SEND_STAGES.INACTIVE: - case state.gasEstimateIsLoading: - case new BigNumber(draftTransaction.gas.gasLimit, 16).lessThan( - new BigNumber(state.gasLimitMinimum), - ): - draftTransaction.status = SEND_STATUSES.INVALID; - break; - case draftTransaction.recipient.warning === 'loading': - case draftTransaction.recipient.warning === - KNOWN_RECIPIENT_ADDRESS_WARNING && - draftTransaction.recipient.recipientWarningAcknowledged === false: - draftTransaction.status = SEND_STATUSES.INVALID; - break; - default: - draftTransaction.status = SEND_STATUSES.VALID; + if (draftTransaction) { + switch (true) { + case Boolean(draftTransaction.amount.error): + case Boolean(draftTransaction.gas.error): + case Boolean(draftTransaction.asset.error): + case draftTransaction.asset.type === ASSET_TYPES.TOKEN && + draftTransaction.asset.details === null: + case state.stage === SEND_STAGES.ADD_RECIPIENT: + case state.stage === SEND_STAGES.INACTIVE: + case state.gasEstimateIsLoading: + case new BigNumber(draftTransaction.gas.gasLimit, 16).lessThan( + new BigNumber(state.gasLimitMinimum), + ): + draftTransaction.status = SEND_STATUSES.INVALID; + break; + case draftTransaction.recipient.warning === 'loading': + case draftTransaction.recipient.warning === + KNOWN_RECIPIENT_ADDRESS_WARNING && + draftTransaction.recipient.recipientWarningAcknowledged === false: + draftTransaction.status = SEND_STATUSES.INVALID; + break; + default: + draftTransaction.status = SEND_STATUSES.VALID; + } } }, }, @@ -1514,26 +1530,28 @@ const slice = createSlice({ state.selectedAccount.balance = action.payload.account.balance; const draftTransaction = state.draftTransactions[state.currentTransactionUUID]; - draftTransaction.gas.gasLimit = action.payload.gasLimit; + if (draftTransaction) { + draftTransaction.gas.gasLimit = action.payload.gasLimit; + draftTransaction.gas.gasTotal = action.payload.gasTotal; + if (action.payload.chainHasChanged) { + // If the state was reinitialized as a result of the user changing + // the network from the network dropdown, then the selected asset is + // no longer valid and should be set to the native asset for the + // network. + draftTransaction.asset.type = ASSET_TYPES.NATIVE; + draftTransaction.asset.balance = + draftTransaction.fromAccount?.balance ?? + state.selectedAccount.balance; + draftTransaction.asset.details = null; + } + } slice.caseReducers.updateGasFeeEstimates(state, { payload: { gasFeeEstimates: action.payload.gasFeeEstimates, gasEstimateType: action.payload.gasEstimateType, }, }); - draftTransaction.gas.gasTotal = action.payload.gasTotal; state.gasEstimatePollToken = action.payload.gasEstimatePollToken; - if (action.payload.chainHasChanged) { - // If the state was reinitialized as a result of the user changing - // the network from the network dropdown, then the selected asset is - // no longer valid and should be set to the native asset for the - // network. - draftTransaction.asset.type = ASSET_TYPES.NATIVE; - draftTransaction.asset.balance = - draftTransaction.fromAccount?.balance ?? - state.selectedAccount.balance; - draftTransaction.asset.details = null; - } if (action.payload.gasEstimatePollToken) { state.gasEstimateIsLoading = false; } @@ -2630,7 +2648,11 @@ export function isSendStateInitialized(state) { * @type {Selector} */ export function isSendFormInvalid(state) { - return getCurrentDraftTransaction(state).status === SEND_STATUSES.INVALID; + const draftTransaction = getCurrentDraftTransaction(state); + if (!draftTransaction) { + return true; + } + return draftTransaction.status === SEND_STATUSES.INVALID; } /** From 109e46c95f9bb8f34f2e372064f32f6f0490ee35 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Tue, 2 Aug 2022 16:56:35 -0500 Subject: [PATCH 09/22] remove unnecessary usage of renderableGasButton logic (#15422) --- .../send/send-footer/send-footer.component.js | 11 +---------- .../send/send-footer/send-footer.container.js | 18 ------------------ 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/ui/pages/send/send-footer/send-footer.component.js b/ui/pages/send/send-footer/send-footer.component.js index 0e0c03ae4..87dd68295 100644 --- a/ui/pages/send/send-footer/send-footer.component.js +++ b/ui/pages/send/send-footer/send-footer.component.js @@ -20,7 +20,6 @@ export default class SendFooter extends Component { toAccounts: PropTypes.array, sendStage: PropTypes.string, sendErrors: PropTypes.object, - gasEstimateType: PropTypes.string, mostRecentOverviewPage: PropTypes.string.isRequired, cancelTx: PropTypes.func, draftTransactionID: PropTypes.string, @@ -53,14 +52,7 @@ export default class SendFooter extends Component { async onSubmit(event) { event.preventDefault(); - const { - addToAddressBookIfNew, - sign, - to, - toAccounts, - history, - gasEstimateType, - } = this.props; + const { addToAddressBookIfNew, sign, to, toAccounts, history } = this.props; const { trackEvent } = this.context; // TODO: add nickname functionality @@ -74,7 +66,6 @@ export default class SendFooter extends Component { properties: { action: 'Edit Screen', legacy_event: true, - gasChanged: gasEstimateType, }, }); history.push(CONFIRM_TRANSACTION_ROUTE); diff --git a/ui/pages/send/send-footer/send-footer.container.js b/ui/pages/send/send-footer/send-footer.container.js index 3ec6ddbc1..7c36ab9f3 100644 --- a/ui/pages/send/send-footer/send-footer.container.js +++ b/ui/pages/send/send-footer/send-footer.container.js @@ -1,12 +1,7 @@ import { connect } from 'react-redux'; import { addToAddressBook, cancelTx } from '../../../store/actions'; -import { - getRenderableEstimateDataForSmallButtonsFromGWEI, - getDefaultActiveButtonIndex, -} from '../../../selectors'; import { resetSendState, - getGasPrice, getSendStage, getSendTo, getSendErrors, @@ -17,7 +12,6 @@ import { import { getMostRecentOverviewPage } from '../../../ducks/history/history'; import { addHexPrefix } from '../../../../app/scripts/lib/util'; import { getSendToAccounts } from '../../../ducks/metamask/metamask'; -import { CUSTOM_GAS_ESTIMATE } from '../../../../shared/constants/gas'; import SendFooter from './send-footer.component'; export default connect(mapStateToProps, mapDispatchToProps)(SendFooter); @@ -31,17 +25,6 @@ function addressIsNew(toAccounts, newAddress) { } function mapStateToProps(state) { - const gasButtonInfo = getRenderableEstimateDataForSmallButtonsFromGWEI(state); - const gasPrice = getGasPrice(state); - const activeButtonIndex = getDefaultActiveButtonIndex( - gasButtonInfo, - gasPrice, - ); - const gasEstimateType = - activeButtonIndex >= 0 - ? gasButtonInfo[activeButtonIndex].gasEstimateType - : CUSTOM_GAS_ESTIMATE; - return { disabled: isSendFormInvalid(state), to: getSendTo(state), @@ -49,7 +32,6 @@ function mapStateToProps(state) { sendStage: getSendStage(state), sendErrors: getSendErrors(state), draftTransactionID: getDraftTransactionID(state), - gasEstimateType, mostRecentOverviewPage: getMostRecentOverviewPage(state), }; } From 50f8be16738c4a6d852c62f481df8c43ec11741b Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 2 Aug 2022 22:14:21 -0230 Subject: [PATCH 10/22] Stop throwing an error when adding gas defaults for a simple send, that has data, to an address without a response code (#15424) * Stop throwing an error when adding gas defaults for a simple send, that has data, to an address without a response code * Lint fix * fixup lint Co-authored-by: brad-decker --- app/scripts/controllers/transactions/index.js | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 87d56c714..e0023b22c 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -17,7 +17,6 @@ import { addHexPrefix, getChainType, } from '../../lib/util'; -import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/helpers/constants/error-keys'; import { calcGasTotal } from '../../../../ui/pages/send/send.utils'; import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/pages/swaps/swaps.util'; import { @@ -1006,10 +1005,9 @@ export default class TransactionController extends EventEmitter { * Gets default gas limit, or debug information about why gas estimate failed. * * @param {Object} txMeta - The txMeta object - * @param {string} getCodeResponse - The transaction category code response, used for debugging purposes * @returns {Promise} Object containing the default gas limit, or the simulation failure object */ - async _getDefaultGasLimit(txMeta, getCodeResponse) { + async _getDefaultGasLimit(txMeta) { const chainId = this._getCurrentChainId(); const customNetworkGasBuffer = CHAIN_ID_TO_GAS_LIMIT_BUFFER_MAP[chainId]; const chainType = getChainType(chainId); @@ -1019,21 +1017,9 @@ export default class TransactionController extends EventEmitter { } else if ( txMeta.txParams.to && txMeta.type === TRANSACTION_TYPES.SIMPLE_SEND && - chainType !== 'custom' + chainType !== 'custom' && + !txMeta.txParams.data ) { - // if there's data in the params, but there's no contract code, it's not a valid transaction - if (txMeta.txParams.data) { - const err = new Error( - 'TxGasUtil - Trying to call a function on a non-contract address', - ); - // set error key so ui can display localized error message - err.errorKey = TRANSACTION_NO_CONTRACT_ERROR_KEY; - - // set the response on the error so that we can see in logs what the actual response was - err.getCodeResponse = getCodeResponse; - throw err; - } - // This is a standard ether simple send, gas requirement is exactly 21k return { gasLimit: GAS_LIMITS.SIMPLE }; } From 47ae0def787339c5dabce73a7b130c49d96d51ed Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Tue, 2 Aug 2022 20:06:11 -0500 Subject: [PATCH 11/22] add access protection to the getNativeCurrencyImage selector in case it is the source of a mysterious bug on firefox (#15425) --- ui/selectors/selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 5256c3756..4a7bb6a17 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -725,7 +725,7 @@ export function getIsBuyableCoinbasePayChain(state) { } export function getNativeCurrencyImage(state) { - const nativeCurrency = getNativeCurrency(state).toUpperCase(); + const nativeCurrency = getNativeCurrency(state)?.toUpperCase(); return NATIVE_CURRENCY_TOKEN_IMAGE_MAP[nativeCurrency]; } From b6d587223b48ccc6e65daa8db81c0c775e5176ec Mon Sep 17 00:00:00 2001 From: ryanml Date: Wed, 3 Aug 2022 08:37:16 -0700 Subject: [PATCH 12/22] Opening Network Forms in full screen from the popup view (#15442) --- .../networks-tab/networks-list-item/networks-list-item.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js b/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js index b6b13089c..c3c5798fc 100644 --- a/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js +++ b/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js @@ -2,7 +2,6 @@ import React, { useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; -import { useHistory } from 'react-router-dom'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { NETWORK_TYPE_RPC, @@ -10,7 +9,7 @@ import { } from '../../../../../shared/constants/network'; import LockIcon from '../../../../components/ui/lock-icon'; import IconCheck from '../../../../components/ui/icon/icon-check'; -import { NETWORKS_FORM_ROUTE } from '../../../../helpers/constants/routes'; +import { NETWORKS_ROUTE } from '../../../../helpers/constants/routes'; import { setSelectedSettingsRpcUrl } from '../../../../store/actions'; import { getEnvironmentType } from '../../../../../app/scripts/lib/util'; import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../shared/constants/app'; @@ -28,7 +27,6 @@ const NetworksListItem = ({ setSearchedNetworks, }) => { const t = useI18nContext(); - const history = useHistory(); const dispatch = useDispatch(); const environmentType = getEnvironmentType(); const isFullScreen = environmentType === ENVIRONMENT_TYPE_FULLSCREEN; @@ -68,7 +66,7 @@ const NetworksListItem = ({ setSearchedNetworks([]); dispatch(setSelectedSettingsRpcUrl(rpcUrl)); if (!isFullScreen) { - history.push(NETWORKS_FORM_ROUTE); + global.platform.openExtensionInBrowser(NETWORKS_ROUTE); } }} > From d5b95d6e440195af500be850a3a5e06ff88c3cc3 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 3 Aug 2022 14:24:35 -0230 Subject: [PATCH 13/22] Ensure that if max is selected in send flow, the correct value is set after network switch (#15444) --- ui/ducks/send/send.js | 3 +++ ui/store/actions.js | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index a7bcde735..ab8f57240 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -1565,6 +1565,9 @@ const slice = createSlice({ }, }); } + if (state.amountMode === AMOUNT_MODES.MAX) { + slice.caseReducers.updateAmountToMax(state); + } slice.caseReducers.validateAmountField(state); slice.caseReducers.validateGasField(state); slice.caseReducers.validateSendState(state); diff --git a/ui/store/actions.js b/ui/store/actions.js index c177c1e0c..012b04536 100644 --- a/ui/store/actions.js +++ b/ui/store/actions.js @@ -1442,6 +1442,10 @@ export function updateMetamaskState(newState) { }, }); } + dispatch({ + type: actionConstants.UPDATE_METAMASK_STATE, + value: newState, + }); if (provider.chainId !== newProvider.chainId) { dispatch({ type: actionConstants.CHAIN_CHANGED, @@ -1453,10 +1457,6 @@ export function updateMetamaskState(newState) { // progress. dispatch(initializeSendState({ chainHasChanged: true })); } - dispatch({ - type: actionConstants.UPDATE_METAMASK_STATE, - value: newState, - }); }; } From 1073b4adfb340211cabd189a5c05fadc73716eeb Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Wed, 3 Aug 2022 13:14:23 -0500 Subject: [PATCH 14/22] add safegaurd for missing account in action (#15450) * add safegaurd for missing account in action * add test to cover case --- ui/ducks/send/send.js | 10 +++++----- ui/ducks/send/send.test.js | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index ab8f57240..fad268b5f 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -1573,11 +1573,11 @@ const slice = createSlice({ slice.caseReducers.validateSendState(state); }) .addCase(SELECTED_ACCOUNT_CHANGED, (state, action) => { - // If we are on the edit flow the account we are keyed into will be the - // original 'from' account, which may differ from the selected account - if (state.stage !== SEND_STAGES.EDIT) { - // This event occurs when the user selects a new account from the - // account menu, or the currently active account's balance updates. + // This event occurs when the user selects a new account from the + // account menu, or the currently active account's balance updates. + // We only care about new transactions, not edits, here, because we use + // the fromAccount and ACCOUNT_CHANGED action for that. + if (state.stage !== SEND_STAGES.EDIT && action.payload.account) { state.selectedAccount.balance = action.payload.account.balance; state.selectedAccount.address = action.payload.account.address; const draftTransaction = diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 339770198..2789b529f 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -1129,6 +1129,28 @@ describe('Send Slice', () => { action.payload.account.address, ); }); + + it('should gracefully handle missing account in payload', () => { + const olderState = { + ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, + selectedAccount: { + balance: '0x0', + address: '0xAddress', + }, + }; + + const action = { + type: 'SELECTED_ACCOUNT_CHANGED', + payload: { + account: undefined, + }, + }; + + const result = sendReducer(olderState, action); + + expect(result.selectedAccount.balance).toStrictEqual('0x0'); + expect(result.selectedAccount.address).toStrictEqual('0xAddress'); + }); }); describe('Account Changed', () => { From a4f0944517645d2e52eecbe527c5d4b521d4bfc0 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 3 Aug 2022 17:05:34 -0230 Subject: [PATCH 15/22] Ensure smart contract interactions are properly represented on the confirm screen (#15446) * Ensure smart contract interactions are properly represented on the confirm screen * Fix unit tests * Code cleanup * Cleanup * Code cleanup * Fix test --- app/scripts/controllers/transactions/index.js | 1 + ...-preferenced-currency-display.component.js | 3 ++ ui/ducks/send/send.js | 46 +++++++++++++------ ui/ducks/send/send.test.js | 3 ++ ui/helpers/utils/transactions.util.js | 7 ++- .../confirm-transaction-base.component.js | 8 +++- ui/pages/send/send.constants.js | 6 +++ 7 files changed, 57 insertions(+), 17 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index e0023b22c..854088f67 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -74,6 +74,7 @@ const VALID_UNAPPROVED_TRANSACTION_TYPES = [ TRANSACTION_TYPES.SIMPLE_SEND, TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER, TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM, + TRANSACTION_TYPES.CONTRACT_INTERACTION, ]; /** diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js index 6dc94607f..3fc952324 100644 --- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js +++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js @@ -13,6 +13,7 @@ export default function UserPreferencedCurrencyDisplay({ showEthLogo, type, showFiat, + showCurrencySuffix, ...restProps }) { const { currency, numberOfDecimals } = useUserPreferencedCurrency(type, { @@ -43,6 +44,7 @@ export default function UserPreferencedCurrencyDisplay({ data-testid={dataTestId} numberOfDecimals={numberOfDecimals} prefixComponent={prefixComponent} + suffix={showCurrencySuffix && !showEthLogo && currency} /> ); } @@ -68,4 +70,5 @@ UserPreferencedCurrencyDisplay.propTypes = { PropTypes.number, ]), showFiat: PropTypes.bool, + showCurrencySuffix: PropTypes.bool, }; diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index fad268b5f..a892efae5 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -18,6 +18,7 @@ import { INVALID_RECIPIENT_ADDRESS_NOT_ETH_NETWORK_ERROR, KNOWN_RECIPIENT_ADDRESS_WARNING, NEGATIVE_ETH_ERROR, + RECIPIENT_TYPES, } from '../../pages/send/send.constants'; import { @@ -82,6 +83,10 @@ import { getTokens, getUnapprovedTxs, } from '../metamask/metamask'; +import { + isSmartContractAddress, + sumHexes, +} from '../../helpers/utils/transactions.util'; import { resetEnsResolution } from '../ens'; import { @@ -89,7 +94,7 @@ import { isValidHexAddress, toChecksumHexAddress, } from '../../../shared/modules/hexstring-utils'; -import { sumHexes } from '../../helpers/utils/transactions.util'; + import fetchEstimatedL1Fee from '../../helpers/utils/optimism/fetchEstimatedL1Fee'; import { TOKEN_STANDARDS, ETH } from '../../helpers/constants/common'; @@ -383,6 +388,7 @@ export const draftTransactionInitialState = { error: null, nickname: '', warning: null, + type: '', recipientWarningAcknowledged: false, }, status: SEND_STATUSES.VALID, @@ -1172,6 +1178,12 @@ const slice = createSlice({ draftTransaction.recipient.warning = action.payload; }, + updateRecipientType: (state, action) => { + const draftTransaction = + state.draftTransactions[state.currentTransactionUUID]; + draftTransaction.recipient.type = action.payload; + }, + updateDraftTransactionStatus: (state, action) => { const draftTransaction = state.draftTransactions[state.currentTransactionUUID]; @@ -1876,19 +1888,24 @@ export function updateRecipientUserInput(userInput) { const inputIsValidHexAddress = isValidHexAddress(userInput); let isProbablyAnAssetContract = false; if (inputIsValidHexAddress) { - const { symbol, decimals } = getTokenMetadata(userInput, tokenMap) || {}; + const smartContractAddress = await isSmartContractAddress(userInput); + if (smartContractAddress) { + dispatch(actions.updateRecipientType(RECIPIENT_TYPES.SMART_CONTRACT)); + const { symbol, decimals } = + getTokenMetadata(userInput, tokenMap) || {}; - isProbablyAnAssetContract = symbol && decimals !== undefined; + isProbablyAnAssetContract = symbol && decimals !== undefined; - if (!isProbablyAnAssetContract) { - try { - const { standard } = await getTokenStandardAndDetails( - userInput, - sendingAddress, - ); - isProbablyAnAssetContract = Boolean(standard); - } catch (e) { - console.log(e); + if (!isProbablyAnAssetContract) { + try { + const { standard } = await getTokenStandardAndDetails( + userInput, + sendingAddress, + ); + isProbablyAnAssetContract = Boolean(standard); + } catch (e) { + console.log(e); + } } } } @@ -2259,7 +2276,10 @@ export function signTransaction() { updateTransactionGasFees(draftTransaction.id, editingTx.txParams), ); } else { - let transactionType = TRANSACTION_TYPES.SIMPLE_SEND; + let transactionType = + draftTransaction.recipient.type === RECIPIENT_TYPES.SMART_CONTRACT + ? TRANSACTION_TYPES.CONTRACT_INTERACTION + : TRANSACTION_TYPES.SIMPLE_SEND; if (draftTransaction.asset.type !== ASSET_TYPES.NATIVE) { transactionType = diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 2789b529f..d3ed19462 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -2412,6 +2412,7 @@ describe('Send Slice', () => { nickname: '', warning: null, recipientWarningAcknowledged: false, + type: '', }, status: SEND_STATUSES.VALID, transactionType: '0x0', @@ -2554,6 +2555,7 @@ describe('Send Slice', () => { error: null, nickname: '', warning: null, + type: '', recipientWarningAcknowledged: false, }, status: SEND_STATUSES.VALID, @@ -2740,6 +2742,7 @@ describe('Send Slice', () => { error: null, warning: null, nickname: '', + type: '', recipientWarningAcknowledged: false, }, status: SEND_STATUSES.VALID, diff --git a/ui/helpers/utils/transactions.util.js b/ui/helpers/utils/transactions.util.js index 07d37341d..c902bd517 100644 --- a/ui/helpers/utils/transactions.util.js +++ b/ui/helpers/utils/transactions.util.js @@ -144,8 +144,11 @@ export function getLatestSubmittedTxWithNonce( } export async function isSmartContractAddress(address) { - const { isContractCode } = await readAddressAsContract(global.eth, address); - return isContractCode; + const { isContractAddress } = await readAddressAsContract( + global.eth, + address, + ); + return isContractAddress; } export function sumHexes(...args) { diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js index a5435e42b..5e2d9861a 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -864,20 +864,24 @@ export default class ConfirmTransactionBase extends Component { } renderTitleComponent() { - const { title, hexTransactionAmount } = this.props; + const { title, hexTransactionAmount, txData } = this.props; // Title string passed in by props takes priority if (title) { return null; } + const isContractInteraction = + txData.type === TRANSACTION_TYPES.CONTRACT_INTERACTION; + return ( ); } diff --git a/ui/pages/send/send.constants.js b/ui/pages/send/send.constants.js index 9f48bea0a..84bb403b8 100644 --- a/ui/pages/send/send.constants.js +++ b/ui/pages/send/send.constants.js @@ -47,6 +47,11 @@ const ENS_ILLEGAL_CHARACTER = 'ensIllegalCharacter'; const ENS_UNKNOWN_ERROR = 'ensUnknownError'; const ENS_REGISTRATION_ERROR = 'ensRegistrationError'; +const RECIPIENT_TYPES = { + SMART_CONTRACT: 'SMART_CONTRACT', + NON_CONTRACT: 'NON_CONTRACT', +}; + export { MAX_GAS_LIMIT_DEC, HIGH_FEE_WARNING_MULTIPLIER, @@ -73,4 +78,5 @@ export { CONFUSING_ENS_ERROR, TOKEN_TRANSFER_FUNCTION_SIGNATURE, COLLECTIBLE_TRANSFER_FROM_FUNCTION_SIGNATURE, + RECIPIENT_TYPES, }; From 71dd39724bce1b32231d3e759c0dba6c49fa0a61 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Wed, 3 Aug 2022 14:59:02 -0500 Subject: [PATCH 16/22] Use fromAccount instead of selectedAcccount for account updates on edit (#15449) --- ui/ducks/send/send.js | 40 +++++++++++++++++++----------------- ui/ducks/send/send.test.js | 42 +++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index a892efae5..92a7aa2bf 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -1454,28 +1454,30 @@ const slice = createSlice({ extraReducers: (builder) => { builder .addCase(ACCOUNT_CHANGED, (state, action) => { - // If we are on the edit flow then we need to watch for changes to the - // current account.address in state and keep balance updated - // appropriately - if ( - state.stage === SEND_STAGES.EDIT && - action.payload.account.address === state.selectedAccount.address - ) { - // This event occurs when the user's account details update due to - // background state changes. If the account that is being updated is - // the current from account on the edit flow we need to update - // the balance for the account and revalidate the send state. - state.selectedAccount.balance = action.payload.account.balance; - // We need to update the asset balance if the asset is the native - // network asset. Once we update the balance we recompute error state. + // This event occurs when the user's account details update due to + // background state changes. If the account that is being updated is + // the current from account on the edit flow we need to update + // the balance for the account and revalidate the send state. + if (state.stage === SEND_STAGES.EDIT && action.payload.account) { const draftTransaction = state.draftTransactions[state.currentTransactionUUID]; - if (draftTransaction?.asset.type === ASSET_TYPES.NATIVE) { - draftTransaction.asset.balance = action.payload.account.balance; + if ( + draftTransaction && + draftTransaction.fromAccount && + draftTransaction.fromAccount.address === + action.payload.account.address + ) { + draftTransaction.fromAccount.balance = + action.payload.account.balance; + // We need to update the asset balance if the asset is the native + // network asset. Once we update the balance we recompute error state. + if (draftTransaction.asset.type === ASSET_TYPES.NATIVE) { + draftTransaction.asset.balance = action.payload.account.balance; + } + slice.caseReducers.validateAmountField(state); + slice.caseReducers.validateGasField(state); + slice.caseReducers.validateSendState(state); } - slice.caseReducers.validateAmountField(state); - slice.caseReducers.validateGasField(state); - slice.caseReducers.validateSendState(state); } }) .addCase(ADDRESS_BOOK_UPDATED, (state, action) => { diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index d3ed19462..1cdf925f6 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -1154,9 +1154,14 @@ describe('Send Slice', () => { }); describe('Account Changed', () => { - it('should', () => { + it('should correctly update the fromAccount in an edit', () => { const accountsChangedState = { - ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, + ...getInitialSendStateWithExistingTxState({ + fromAccount: { + address: '0xAddress', + balance: '0x0', + }, + }), stage: SEND_STAGES.EDIT, selectedAccount: { address: '0xAddress', @@ -1176,11 +1181,42 @@ describe('Send Slice', () => { const result = sendReducer(accountsChangedState, action); - expect(result.selectedAccount.balance).toStrictEqual( + const draft = getTestUUIDTx(result); + + expect(draft.fromAccount.balance).toStrictEqual( action.payload.account.balance, ); }); + it('should gracefully handle missing account param in payload', () => { + const accountsChangedState = { + ...getInitialSendStateWithExistingTxState({ + fromAccount: { + address: '0xAddress', + balance: '0x0', + }, + }), + stage: SEND_STAGES.EDIT, + selectedAccount: { + address: '0xAddress', + balance: '0x0', + }, + }; + + const action = { + type: 'ACCOUNT_CHANGED', + payload: { + account: undefined, + }, + }; + + const result = sendReducer(accountsChangedState, action); + + const draft = getTestUUIDTx(result); + + expect(draft.fromAccount.balance).toStrictEqual('0x0'); + }); + it(`should not edit account balance if action payload address is not the same as state's address`, () => { const accountsChangedState = { ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, From 298c2d8ee9bc96bb569f74104c6fdfa7e9189934 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 4 Aug 2022 12:08:52 -0230 Subject: [PATCH 17/22] Update changelog v10.18.2 (#15455) * Update changelog v10.18.2 * Update CHANGELOG.md --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b59428c8..1f8384e14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [10.18.2] +### Changed +- Enhance approval screen title logic ([#15406](https://github.com/MetaMask/metamask-extension/pull/15406)) + +### Fixed +- Ensure smart contract interactions are properly represented on the confirm screen ([#15446](https://github.com/MetaMask/metamask-extension/pull/15446)) +- Fix update of max amount in send flow after network switch([#15444](https://github.com/MetaMask/metamask-extension/pull/15444)) +- Fix to ensure user can access full screen editing of network forms from the popup ([#15442](https://github.com/MetaMask/metamask-extension/pull/15442)) +- Possibly fix bug which crashes firefox on startup after upgrade to v10.18.1 ([#15425](https://github.com/MetaMask/metamask-extension/pull/15425)) +- Fix blocking of editing transactions that had a contract address recipient but no tx data ([#15424](https://github.com/MetaMask/metamask-extension/pull/15424)) +- Fix error that could leave the app in a stuck state when quickly moving between the send screen and other screens ([#15420](https://github.com/MetaMask/metamask-extension/pull/15420)) +- Fix send screen for Optimism network ([#15419](https://github.com/MetaMask/metamask-extension/pull/15419)) +- Fix to ensure the correct balance is used when validating send amounts ([#15449](https://github.com/MetaMask/metamask-extension/pull/15449)) +- Fix error that makes app unusable after clicking activity list items for token approval transactions ([#15398](https://github.com/MetaMask/metamask-extension/pull/15398)) ## [10.18.1] ### Changed From 60ba129eb2402db19edbf652039c997aa4cc1dbe Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Thu, 4 Aug 2022 19:56:00 +0000 Subject: [PATCH 18/22] Version v10.18.3 --- CHANGELOG.md | 11 ++++++++++- package.json | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f8384e14..126bdff98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.18.3] +### Uncategorized +- Version v10.18.2 RC ([#15454](https://github.com/MetaMask/metamask-extension/pull/15454)) +- Update changelog v10.18.2 ([#15455](https://github.com/MetaMask/metamask-extension/pull/15455)) +- add safegaurd for missing account in action ([#15450](https://github.com/MetaMask/metamask-extension/pull/15450)) +- remove unnecessary usage of renderableGasButton logic ([#15422](https://github.com/MetaMask/metamask-extension/pull/15422)) +- Version v10.18.2 + ## [10.18.2] ### Changed - Enhance approval screen title logic ([#15406](https://github.com/MetaMask/metamask-extension/pull/15406)) @@ -3103,7 +3111,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.2...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.3...HEAD +[10.18.3]: https://github.com/MetaMask/metamask-extension/compare/v10.18.2...v10.18.3 [10.18.2]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...v10.18.2 [10.18.1]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...v10.18.1 [10.18.0]: https://github.com/MetaMask/metamask-extension/compare/v10.17.0...v10.18.0 diff --git a/package.json b/package.json index e085b11d1..a749aee57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.18.2", + "version": "10.18.3", "private": true, "repository": { "type": "git", From 2955b97f975741f620d515778bec97d5981c6ba0 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 4 Aug 2022 17:20:32 -0230 Subject: [PATCH 19/22] Prevent confirm screen from showing method name from contract registry for txes created within MetaMask (#15472) * Prevent confirm screen from showing method name from contract registry for txes created within MetaMask * Ensure method name does not get sent in state when sending to a contract, with tx data, from metamask send screen --- .../confirm-transaction-base.component.js | 5 ++++- .../confirm-transaction.component.js | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js index 5e2d9861a..21c78f0ae 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -1048,7 +1048,10 @@ export default class ConfirmTransactionBase extends Component { } = this.getNavigateTxData(); let functionType; - if (txData.type === TRANSACTION_TYPES.CONTRACT_INTERACTION) { + if ( + txData.type === TRANSACTION_TYPES.CONTRACT_INTERACTION && + txData.origin !== 'metamask' + ) { functionType = getMethodName(name); } diff --git a/ui/pages/confirm-transaction/confirm-transaction.component.js b/ui/pages/confirm-transaction/confirm-transaction.component.js index 01e876fdb..fb853741f 100644 --- a/ui/pages/confirm-transaction/confirm-transaction.component.js +++ b/ui/pages/confirm-transaction/confirm-transaction.component.js @@ -68,7 +68,7 @@ export default class ConfirmTransaction extends Component { sendTo, history, mostRecentOverviewPage, - transaction: { txParams: { data } = {} } = {}, + transaction: { txParams: { data } = {}, origin } = {}, getContractMethodData, transactionId, paramsTransactionId, @@ -91,7 +91,9 @@ export default class ConfirmTransaction extends Component { return; } - getContractMethodData(data); + if (origin !== 'metamask') { + getContractMethodData(data); + } const txId = transactionId || paramsTransactionId; if (txId) { @@ -107,7 +109,7 @@ export default class ConfirmTransaction extends Component { componentDidUpdate(prevProps) { const { setTransactionToConfirm, - transaction: { txData: { txParams: { data } = {} } = {} }, + transaction: { txData: { txParams: { data } = {}, origin } = {} }, clearConfirmTransaction, getContractMethodData, paramsTransactionId, @@ -124,8 +126,10 @@ export default class ConfirmTransaction extends Component { prevProps.paramsTransactionId !== paramsTransactionId ) { clearConfirmTransaction(); - getContractMethodData(data); setTransactionToConfirm(paramsTransactionId); + if (origin !== 'metamask') { + getContractMethodData(data); + } } else if ( prevProps.transactionId && !transactionId && From ceb068449fe691462a352c8297b43043fddc0be7 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Thu, 4 Aug 2022 17:46:26 -0230 Subject: [PATCH 20/22] Update changelog --- CHANGELOG.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 126bdff98..aef71c924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [10.18.3] -### Uncategorized -- Version v10.18.2 RC ([#15454](https://github.com/MetaMask/metamask-extension/pull/15454)) -- Update changelog v10.18.2 ([#15455](https://github.com/MetaMask/metamask-extension/pull/15455)) -- add safegaurd for missing account in action ([#15450](https://github.com/MetaMask/metamask-extension/pull/15450)) -- remove unnecessary usage of renderableGasButton logic ([#15422](https://github.com/MetaMask/metamask-extension/pull/15422)) -- Version v10.18.2 +### Fixed +- Prevent confirm screen from showing method name from contract registry for transactions created within MetaMask ([#15472](https://github.com/MetaMask/metamask-extension/pull/15472)) ## [10.18.2] ### Changed From 538f6a5b1586ffa529d7ca84a03618229b784295 Mon Sep 17 00:00:00 2001 From: ryanml Date: Thu, 4 Aug 2022 21:42:53 -0700 Subject: [PATCH 21/22] Fix --- ui/ducks/send/send.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 5465772a1..dc64a83b7 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -84,10 +84,6 @@ import { getTokens, getUnapprovedTxs, } from '../metamask/metamask'; -import { - isSmartContractAddress, - sumHexes, -} from '../../helpers/utils/transactions.util'; import { resetEnsResolution } from '../ens'; import { From b013c7712722b8009d7acbd3ebfd0cf30856a204 Mon Sep 17 00:00:00 2001 From: ryanml Date: Thu, 4 Aug 2022 21:57:07 -0700 Subject: [PATCH 22/22] Fixing changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2d684b22..aef71c924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3110,7 +3110,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.3...HEAD [10.18.3]: https://github.com/MetaMask/metamask-extension/compare/v10.18.2...v10.18.3 [10.18.2]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...v10.18.2 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...HEAD [10.18.1]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...v10.18.1 [10.18.0]: https://github.com/MetaMask/metamask-extension/compare/v10.17.0...v10.18.0 [10.17.0]: https://github.com/MetaMask/metamask-extension/compare/v10.16.2...v10.17.0