From 9785d8ae1c7787b975684e80f76973605536efc3 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Thu, 25 Jan 2024 17:58:36 +0100 Subject: [PATCH 01/17] v11.10.0 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 092e55e4f89b..f655c96a0e51 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] +## [11.10.0] + ## [11.7.3] ### Fixed - Ensure fiat token balances are displayed on the homescreen [#22295](https://github.com/MetaMask/metamask-extension/pull/22295) @@ -4266,7 +4268,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.7.3...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...HEAD +[11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.7.3...v11.10.0 [11.7.3]: https://github.com/MetaMask/metamask-extension/compare/v11.7.2...v11.7.3 [11.7.2]: https://github.com/MetaMask/metamask-extension/compare/v11.7.1...v11.7.2 [11.7.1]: https://github.com/MetaMask/metamask-extension/compare/v11.7.0...v11.7.1 diff --git a/package.json b/package.json index 6ec20d359401..684e3527a2d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.7.3", + "version": "11.10.0", "private": true, "repository": { "type": "git", From 4c90ff7920e554f726b9975ff0dd3506cc387473 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 7 Feb 2024 13:22:29 +0100 Subject: [PATCH 02/17] Cherry pick hook fix to RC (#22849) ## **Description** Cherry-picks https://github.com/MetaMask/metamask-extension/commit/8ec8643f3f975ddccbe2b623d038d13f8e5bda78 to the RC. This fixes the `getIsLocked` hook, which would previously always return `false`. We were using the result of `appStateController.isUnlocked`, but that's a function rather than a boolean. Co-authored-by: Maarten Zuidhoorn --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 2d030212fc61..952347a7b6df 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -4861,7 +4861,7 @@ export default class MetamaskController extends EventEmitter { origin, ), getIsLocked: () => { - return !this.appStateController.isUnlocked; + return !this.appStateController.isUnlocked(); }, ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) From a1d3446085d94dd51fe179088f4edd8ce2159ee7 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 7 Feb 2024 20:55:14 -0330 Subject: [PATCH 03/17] Cherry-picks 7a3d9e2 (#22676) into Version-v11.10.0 (#22858) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Cherry-picks 7a3d9e2 (Cancel transaction signing from activity list (#22676)) into Version-v11.10.0 ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Co-authored-by: Matthew Walsh --- app/_locales/en/messages.json | 6 + app/scripts/metamask-controller.js | 2 + lavamoat/browserify/beta/policy.json | 47 ++---- lavamoat/browserify/desktop/policy.json | 47 ++---- lavamoat/browserify/flask/policy.json | 47 ++---- lavamoat/browserify/main/policy.json | 47 ++---- lavamoat/browserify/mmi/policy.json | 47 ++---- package.json | 2 +- test/data/mock-pending-transaction-data.json | 2 +- .../app/cancel-button/cancel-button.js | 27 ++-- ...onfirm-page-container-content.component.js | 18 ++- ...m-page-container-content.component.test.js | 14 ++ .../transaction-list-item.component.js | 34 +++- .../transaction-list-item.component.test.js | 116 ++++++++++---- .../transaction-status-label.test.js.snap | 21 +-- .../app/transaction-status-label/index.scss | 1 + .../transaction-status-label.js | 24 ++- .../transaction-status-label.test.js | 22 +-- ui/helpers/constants/error-keys.js | 1 + .../confirm-transaction-base.component.js | 14 +- .../confirm-transaction-base.container.js | 6 + ui/selectors/transactions.js | 13 ++ ui/selectors/transactions.test.js | 47 ++++++ ui/store/actions.test.js | 18 +++ ui/store/actions.ts | 14 ++ yarn.lock | 147 +++++++++++++----- 26 files changed, 481 insertions(+), 303 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 99f28118f8eb..4770ccf2e6fb 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2209,6 +2209,9 @@ "ipfsToggleModalSettings": { "message": "Settings > Security and privacy" }, + "isSigningOrSubmitting": { + "message": "A previous transaction is still being signed or submitted" + }, "jazzAndBlockies": { "message": "Jazzicons and Blockies are two different styles of unique icons that help you identify an account at a glance." }, @@ -4273,6 +4276,9 @@ "signin": { "message": "Sign-In" }, + "signing": { + "message": "Signing" + }, "simulationErrorMessageV2": { "message": "We were not able to estimate gas. There might be an error in the contract and this transaction may fail." }, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 47c298ebb679..6d4d16b841b9 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3024,6 +3024,8 @@ export default class MetamaskController extends EventEmitter { txController.updateTransactionSendFlowHistory.bind(txController), updatePreviousGasParams: txController.updatePreviousGasParams.bind(txController), + abortTransactionSigning: + txController.abortTransactionSigning.bind(txController), // decryptMessageController decryptMessage: this.decryptMessageController.decryptMessage.bind( diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 8ed58efdfc6c..0ffa820ae3ff 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -741,7 +741,7 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1462,6 +1462,12 @@ "immer": true } }, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { + "packages": { + "@metamask/ethjs>number-to-bn": true, + "bn.js": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1478,8 +1484,8 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/message-manager>@metamask/base-controller": true, - "@metamask/message-manager>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, @@ -1488,37 +1494,6 @@ "webpack>events": true } }, - "@metamask/message-manager>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/message-manager>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1830,7 +1805,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -1875,7 +1850,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index e153c85706b9..6237039b011a 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -741,7 +741,7 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1539,6 +1539,12 @@ "immer": true } }, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { + "packages": { + "@metamask/ethjs>number-to-bn": true, + "bn.js": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1555,8 +1561,8 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/message-manager>@metamask/base-controller": true, - "@metamask/message-manager>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, @@ -1565,37 +1571,6 @@ "webpack>events": true } }, - "@metamask/message-manager>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/message-manager>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1971,7 +1946,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -2016,7 +1991,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index d475accd352f..4ef6f7bd2812 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -741,7 +741,7 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1539,6 +1539,12 @@ "immer": true } }, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { + "packages": { + "@metamask/ethjs>number-to-bn": true, + "bn.js": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1555,8 +1561,8 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/message-manager>@metamask/base-controller": true, - "@metamask/message-manager>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, @@ -1565,37 +1571,6 @@ "webpack>events": true } }, - "@metamask/message-manager>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/message-manager>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -2007,7 +1982,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -2052,7 +2027,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 0a169bea7d35..f0c1fccbf7b4 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -741,7 +741,7 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1462,6 +1462,12 @@ "immer": true } }, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { + "packages": { + "@metamask/ethjs>number-to-bn": true, + "bn.js": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1478,8 +1484,8 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/message-manager>@metamask/base-controller": true, - "@metamask/message-manager>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, @@ -1488,37 +1494,6 @@ "webpack>events": true } }, - "@metamask/message-manager>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/message-manager>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1930,7 +1905,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -1975,7 +1950,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index f311b03a3bd9..339a51643b09 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -873,7 +873,7 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1594,6 +1594,12 @@ "immer": true } }, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { + "packages": { + "@metamask/ethjs>number-to-bn": true, + "bn.js": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1610,8 +1616,8 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/message-manager>@metamask/base-controller": true, - "@metamask/message-manager>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, @@ -1620,37 +1626,6 @@ "webpack>events": true } }, - "@metamask/message-manager>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/message-manager>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -2026,7 +2001,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -2071,7 +2046,7 @@ }, "packages": { "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/message-manager>@metamask/controller-utils>ethjs-unit": true, + "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, diff --git a/package.json b/package.json index 5628576505ff..c6f18680c51d 100644 --- a/package.json +++ b/package.json @@ -296,7 +296,7 @@ "@metamask/snaps-rpc-methods": "^5.0.0", "@metamask/snaps-sdk": "^1.4.0", "@metamask/snaps-utils": "^5.2.0", - "@metamask/transaction-controller": "^20.0.0", + "@metamask/transaction-controller": "^21.1.0", "@metamask/user-operation-controller": "^1.0.0", "@metamask/utils": "^8.2.1", "@ngraveio/bc-ur": "^1.1.6", diff --git a/test/data/mock-pending-transaction-data.json b/test/data/mock-pending-transaction-data.json index 36f1d74767fe..12575a92df6c 100644 --- a/test/data/mock-pending-transaction-data.json +++ b/test/data/mock-pending-transaction-data.json @@ -78,7 +78,7 @@ "primaryTransaction": { "id": 6854191329910881, "time": 1631558469046, - "status": "approved", + "status": "submitted", "chainId": "0x5", "loadingDefaults": false, "dappSuggestedGasFees": null, diff --git a/ui/components/app/cancel-button/cancel-button.js b/ui/components/app/cancel-button/cancel-button.js index c751fa668847..37e454db62f2 100644 --- a/ui/components/app/cancel-button/cancel-button.js +++ b/ui/components/app/cancel-button/cancel-button.js @@ -3,6 +3,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import classnames from 'classnames'; +import { TransactionStatus } from '@metamask/transaction-controller'; import Button from '../../ui/button'; import { getMaximumGasTotalInHexWei } from '../../../../shared/modules/gas.utils'; import { getConversionRate } from '../../../ducks/metamask/metamask'; @@ -17,18 +18,20 @@ export default function CancelButton({ detailsModal, }) { const t = useI18nContext(); - + const { status } = transaction; const customCancelGasSettings = useIncrementedGasFees(transaction); - const selectedAccount = useSelector(getSelectedAccount); const conversionRate = useSelector(getConversionRate); - const hasEnoughCancelGas = isBalanceSufficient({ - amount: '0x0', - gasTotal: getMaximumGasTotalInHexWei(customCancelGasSettings), - balance: selectedAccount.balance, - conversionRate, - }); + const isDisabled = + status === TransactionStatus.approved + ? false + : !isBalanceSufficient({ + amount: '0x0', + gasTotal: getMaximumGasTotalInHexWei(customCancelGasSettings), + balance: selectedAccount.balance, + conversionRate, + }); const btn = ( ); - return hasEnoughCancelGas ? ( - btn - ) : ( + return isDisabled ? (
{btn}
+ ) : ( + btn ); } diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index acc4d81fd378..a8b932117e07 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -11,7 +11,10 @@ import { BannerAlert, } from '../../../component-library'; import { PageContainerFooter } from '../../../ui/page-container'; -import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../../helpers/constants/error-keys'; +import { + INSUFFICIENT_FUNDS_ERROR_KEY, + IS_SIGNING_OR_SUBMITTING, +} from '../../../../helpers/constants/error-keys'; import { Severity } from '../../../../helpers/constants/design-system'; import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.'; @@ -185,6 +188,9 @@ export default class ConfirmPageContainerContent extends Component { const showInsuffienctFundsError = (errorKey || errorMessage) && errorKey === INSUFFICIENT_FUNDS_ERROR_KEY; + const showIsSigningOrSubmittingError = + errorKey === IS_SIGNING_OR_SUBMITTING; + return (
)} + {showIsSigningOrSubmittingError && ( + + )} { ); expect(getByRole('button', { name: 'Buy' })).toBeInTheDocument(); }); + + it('should show is signing or submitting error', () => { + const { queryByText } = renderWithProvider( + , + store, + ); + expect( + queryByText('A previous transaction is still being signed or submitted'), + ).toBeInTheDocument(); + }); }); diff --git a/ui/components/app/transaction-list-item/transaction-list-item.component.js b/ui/components/app/transaction-list-item/transaction-list-item.component.js index e48d5d7682c3..76688f59b0cb 100644 --- a/ui/components/app/transaction-list-item/transaction-list-item.component.js +++ b/ui/components/app/transaction-list-item/transaction-list-item.component.js @@ -3,7 +3,7 @@ import React, { useMemo, useState, useCallback, useContext } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useHistory } from 'react-router-dom'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { TransactionStatus } from '@metamask/transaction-controller'; import { useTransactionDisplayData } from '../../../hooks/useTransactionDisplayData'; @@ -64,6 +64,7 @@ import EditGasFeePopover from '../edit-gas-fee-popover'; import EditGasPopover from '../edit-gas-popover'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { ActivityListItem } from '../../multichain'; +import { abortTransactionSigning } from '../../../store/actions'; function TransactionListItemInner({ transactionGroup, @@ -80,6 +81,7 @@ function TransactionListItemInner({ const { supportsEIP1559 } = useGasFeeContext(); const { openModal } = useTransactionModalContext(); const testNetworkBackgroundColor = useSelector(getTestNetworkBackgroundColor); + const dispatch = useDispatch(); const { initialTransaction: { id }, @@ -120,14 +122,24 @@ function TransactionListItemInner({ legacy_event: true, }, }); - if (supportsEIP1559) { + if (status === TransactionStatus.approved) { + dispatch(abortTransactionSigning(id)); + } else if (supportsEIP1559) { setEditGasMode(EditGasModes.cancel); openModal('cancelSpeedUpTransaction'); } else { setShowCancelEditGasPopover(true); } }, - [trackEvent, openModal, setEditGasMode, supportsEIP1559], + [ + trackEvent, + openModal, + setEditGasMode, + supportsEIP1559, + status, + dispatch, + id, + ], ); const shouldShowSpeedUp = useShouldShowSpeedUp( @@ -154,6 +166,8 @@ function TransactionListItemInner({ const isApproval = category === TransactionGroupCategory.approval; const isUnapproved = status === TransactionStatus.unapproved; const isSwap = category === TransactionGroupCategory.swap; + const isSigning = status === TransactionStatus.approved; + const isSubmitting = status === TransactionStatus.signed; ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) const isCustodian = Boolean(transactionGroup.primaryTransaction.custodyId); ///: END:ONLY_INCLUDE_IF @@ -206,12 +220,19 @@ function TransactionListItemInner({ } ///: END:ONLY_INCLUDE_IF - if (!shouldShowSpeedUp || !isPending || isUnapproved) { + if ( + !shouldShowSpeedUp || + !isPending || + isUnapproved || + isSigning || + isSubmitting + ) { return null; } return (
`; -exports[`TransactionStatusLabel Component should render PENDING properly when status is APPROVED 1`] = ` +exports[`TransactionStatusLabel Component should render QUEUED properly 1`] = `
-
- Pending -
+ Queued
`; -exports[`TransactionStatusLabel Component should render QUEUED properly 1`] = ` +exports[`TransactionStatusLabel Component should render SIGNING if status is approved 1`] = `
- Queued + Signing
`; diff --git a/ui/components/app/transaction-status-label/index.scss b/ui/components/app/transaction-status-label/index.scss index 79e14bc20d77..cc0cf5d2c8cd 100644 --- a/ui/components/app/transaction-status-label/index.scss +++ b/ui/components/app/transaction-status-label/index.scss @@ -13,6 +13,7 @@ } &--unapproved, + &--signing, &--pending { color: var(--color-warning-default); } diff --git a/ui/components/app/transaction-status-label/transaction-status-label.js b/ui/components/app/transaction-status-label/transaction-status-label.js index 7c912007152e..bb5824acb05d 100644 --- a/ui/components/app/transaction-status-label/transaction-status-label.js +++ b/ui/components/app/transaction-status-label/transaction-status-label.js @@ -7,6 +7,7 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import { TransactionGroupStatus } from '../../../../shared/constants/transaction'; const QUEUED_PSEUDO_STATUS = 'queued'; +const SIGNING_PSUEDO_STATUS = 'signing'; ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) const CUSTODIAN_PSEUDO_STATUS = 'inCustody'; ///: END:ONLY_INCLUDE_IF @@ -24,7 +25,6 @@ const CUSTODIAN_PSEUDO_STATUS = 'inCustody'; const pendingStatusHash = { [TransactionStatus.submitted]: TransactionGroupStatus.pending, [TransactionStatus.approved]: TransactionGroupStatus.pending, - [TransactionStatus.signed]: TransactionGroupStatus.pending, }; const statusToClassNameHash = { @@ -40,6 +40,20 @@ const statusToClassNameHash = { ///: END:ONLY_INCLUDE_IF }; +function getStatusKey(status, isEarliestNonce) { + if (status === TransactionStatus.approved) { + return SIGNING_PSUEDO_STATUS; + } + + if (pendingStatusHash[status]) { + return isEarliestNonce + ? TransactionGroupStatus.pending + : QUEUED_PSEUDO_STATUS; + } + + return status; +} + export default function TransactionStatusLabel({ status, date, @@ -53,14 +67,8 @@ export default function TransactionStatusLabel({ ///: END:ONLY_INCLUDE_IF }) { const t = useI18nContext(); + const statusKey = getStatusKey(status, isEarliestNonce); let tooltipText = error?.rpc?.message || error?.message; - let statusKey = status; - if (pendingStatusHash[status]) { - statusKey = isEarliestNonce - ? TransactionGroupStatus.pending - : QUEUED_PSEUDO_STATUS; - } - let statusText = statusKey && t(statusKey); ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) diff --git a/ui/components/app/transaction-status-label/transaction-status-label.test.js b/ui/components/app/transaction-status-label/transaction-status-label.test.js index 28f6cd17bdc9..e05dee4808aa 100644 --- a/ui/components/app/transaction-status-label/transaction-status-label.test.js +++ b/ui/components/app/transaction-status-label/transaction-status-label.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { EthAccountType, EthMethod } from '@metamask/keyring-api'; +import { TransactionStatus } from '@metamask/transaction-controller'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import TransactionStatusLabel from '.'; @@ -46,11 +47,11 @@ describe('TransactionStatusLabel Component', () => { expect(container).toMatchSnapshot(); }); - it('should render PENDING properly when status is APPROVED', () => { + it('should render PENDING properly', () => { const props = { - status: 'approved', + date: 'June 1', + status: TransactionStatus.submitted, isEarliestNonce: true, - error: { message: 'test-title' }, }; const { container } = renderWithProvider( @@ -61,11 +62,10 @@ describe('TransactionStatusLabel Component', () => { expect(container).toMatchSnapshot(); }); - it('should render PENDING properly', () => { + it('should render QUEUED properly', () => { const props = { - date: 'June 1', - status: 'submitted', - isEarliestNonce: true, + status: TransactionStatus.submitted, + isEarliestNonce: false, }; const { container } = renderWithProvider( @@ -76,9 +76,9 @@ describe('TransactionStatusLabel Component', () => { expect(container).toMatchSnapshot(); }); - it('should render QUEUED properly', () => { + it('should render UNAPPROVED properly', () => { const props = { - status: 'queued', + status: TransactionStatus.unapproved, }; const { container } = renderWithProvider( @@ -89,9 +89,9 @@ describe('TransactionStatusLabel Component', () => { expect(container).toMatchSnapshot(); }); - it('should render UNAPPROVED properly', () => { + it('should render SIGNING if status is approved', () => { const props = { - status: 'unapproved', + status: TransactionStatus.approved, }; const { container } = renderWithProvider( diff --git a/ui/helpers/constants/error-keys.js b/ui/helpers/constants/error-keys.js index 7d3cb020f724..dfa4cc142806 100644 --- a/ui/helpers/constants/error-keys.js +++ b/ui/helpers/constants/error-keys.js @@ -7,3 +7,4 @@ export const GAS_PRICE_EXCESSIVE_ERROR_KEY = 'gasPriceExcessive'; export const UNSENDABLE_ASSET_ERROR_KEY = 'unsendableAsset'; export const INSUFFICIENT_FUNDS_FOR_GAS_ERROR_KEY = 'insufficientFundsForGas'; export const INVALID_ASSET_TYPE = 'invalidAssetType'; +export const IS_SIGNING_OR_SUBMITTING = 'isSigningOrSubmitting'; 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 27ad6263e486..3a300b37f2e6 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -12,6 +12,7 @@ import { GAS_LIMIT_TOO_LOW_ERROR_KEY, ETH_GAS_PRICE_FETCH_WARNING_KEY, GAS_PRICE_FETCH_FAILURE_ERROR_KEY, + IS_SIGNING_OR_SUBMITTING, } from '../../helpers/constants/error-keys'; import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display'; @@ -153,6 +154,7 @@ export default class ConfirmTransactionBase extends Component { tokenSymbol: PropTypes.string, updateTransaction: PropTypes.func, isUsingPaymaster: PropTypes.bool, + isSigningOrSubmitting: PropTypes.bool, }; state = { @@ -243,6 +245,7 @@ export default class ConfirmTransactionBase extends Component { customGas, noGasPrice, gasFeeIsCustom, + isSigningOrSubmitting, } = this.props; const insufficientBalance = @@ -275,6 +278,13 @@ export default class ConfirmTransactionBase extends Component { }; } + if (isSigningOrSubmitting) { + return { + valid: false, + errorKey: IS_SIGNING_OR_SUBMITTING, + }; + } + return { valid: true, }; @@ -958,6 +968,7 @@ export default class ConfirmTransactionBase extends Component { assetStandard, displayAccountBalanceHeader, title, + isSigningOrSubmitting, ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) isNoteToTraderSupported, ///: END:ONLY_INCLUDE_IF @@ -1051,7 +1062,8 @@ export default class ConfirmTransactionBase extends Component { !valid || submitting || hardwareWalletRequiresConnection || - (gasIsLoading && !gasFeeIsCustom) + (gasIsLoading && !gasFeeIsCustom) || + isSigningOrSubmitting } onEdit={() => this.handleEdit()} onCancelAll={() => this.handleCancelAll()} diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js index a9b4042b7aff..8f2400ffd519 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -50,6 +50,7 @@ import { getUseCurrencyRateCheck, getUnapprovedTransactions, getInternalAccountByAddress, + getApprovedAndSignedTransactions, } from '../../selectors'; import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { @@ -247,6 +248,10 @@ const mapStateToProps = (state, ownProps) => { const isMultiLayerFeeNetwork = getIsMultiLayerFeeNetwork(state); const isUsingPaymaster = getIsUsingPaymaster(state); + const isSigningOrSubmitting = Boolean( + getApprovedAndSignedTransactions(state).length, + ); + return { balance, fromAddress, @@ -299,6 +304,7 @@ const mapStateToProps = (state, ownProps) => { useCurrencyRateCheck: getUseCurrencyRateCheck(state), keyringForAccount: keyring, isUsingPaymaster, + isSigningOrSubmitting, ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) accountType, isNoteToTraderSupported, diff --git a/ui/selectors/transactions.js b/ui/selectors/transactions.js index 13496dd32a79..5c116b2cd866 100644 --- a/ui/selectors/transactions.js +++ b/ui/selectors/transactions.js @@ -56,6 +56,19 @@ export const getUnapprovedTransactions = createDeepEqualSelector( (transactions) => transactions, ); +export const getApprovedAndSignedTransactions = createDeepEqualSelector( + (state) => { + const currentNetworkTransactions = getCurrentNetworkTransactions(state); + + return currentNetworkTransactions.filter((transaction) => + [TransactionStatus.approved, TransactionStatus.signed].includes( + transaction.status, + ), + ); + }, + (transactions) => transactions, +); + export const incomingTxListSelector = createDeepEqualSelector( (state) => { const { incomingTransactionsPreferences } = state.metamask; diff --git a/ui/selectors/transactions.test.js b/ui/selectors/transactions.test.js index 697ef64f841f..16a57a004fe8 100644 --- a/ui/selectors/transactions.test.js +++ b/ui/selectors/transactions.test.js @@ -10,6 +10,7 @@ import { nonceSortedCompletedTransactionsSelector, submittedPendingTransactionsSelector, hasTransactionPendingApprovals, + getApprovedAndSignedTransactions, } from './transactions'; describe('Transaction Selectors', () => { @@ -544,4 +545,50 @@ describe('Transaction Selectors', () => { }, ); }); + + describe('getApprovedAndSignedTransactions', () => { + it('returns transactions with status of approved or signed on current network', () => { + const state = { + metamask: { + providerConfig: { + chainId: CHAIN_IDS.MAINNET, + }, + transactions: [ + { + id: 0, + chainId: CHAIN_IDS.MAINNET, + status: TransactionStatus.approved, + }, + { + id: 1, + chainId: CHAIN_IDS.MAINNET, + status: TransactionStatus.submitted, + }, + { + id: 2, + chainId: CHAIN_IDS.MAINNET, + status: TransactionStatus.unapproved, + }, + { + id: 3, + chainId: CHAIN_IDS.MAINNET, + status: TransactionStatus.signed, + }, + { + id: 4, + chainId: CHAIN_IDS.GOERLI, + status: TransactionStatus.signed, + }, + ], + }, + }; + + const results = getApprovedAndSignedTransactions(state); + + expect(results).toStrictEqual([ + state.metamask.transactions[0], + state.metamask.transactions[3], + ]); + }); + }); }); diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index ec2fefaed364..a2f74da3b759 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -63,6 +63,7 @@ describe('Actions', () => { background.signMessage = sinon.stub(); background.signPersonalMessage = sinon.stub(); background.signTypedMessage = sinon.stub(); + background.abortTransactionSigning = sinon.stub(); }); describe('#tryUnlockMetamask', () => { @@ -2110,6 +2111,23 @@ describe('Actions', () => { }); }); + describe('abortTransactionSigning', () => { + it('submits request to background', async () => { + const transactionIdMock = '123-456'; + const store = mockStore(); + + setBackgroundConnection(background); + + store.dispatch(actions.abortTransactionSigning(transactionIdMock)); + + expect(background.abortTransactionSigning.callCount).toStrictEqual(1); + expect(background.abortTransactionSigning.getCall(0).args).toStrictEqual([ + transactionIdMock, + expect.any(Function), + ]); + }); + }); + describe('Desktop', () => { describe('#setDesktopEnabled', () => { it('calls background setDesktopEnabled method', async () => { diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 6d18be0f5d02..a553a1e8cdf9 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -2117,6 +2117,20 @@ export function clearPendingTokens(): Action { }; } +export function abortTransactionSigning( + transactionId: string, +): ThunkAction, MetaMaskReduxState, any, AnyAction> { + return async (dispatch: MetaMaskReduxDispatch) => { + try { + await submitRequestToBackground('abortTransactionSigning', [ + transactionId, + ]); + } catch (error) { + dispatch(displayWarning(error)); + } + }; +} + export function createCancelTransaction( txId: string, customGasSettings: CustomGasSettings, diff --git a/yarn.lock b/yarn.lock index f0c61e358193..3f825c1cab85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3946,18 +3946,18 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^8.0.1": - version: 8.0.1 - resolution: "@metamask/controller-utils@npm:8.0.1" +"@metamask/controller-utils@npm:^8.0.1, @metamask/controller-utils@npm:^8.0.2": + version: 8.0.2 + resolution: "@metamask/controller-utils@npm:8.0.2" dependencies: "@metamask/eth-query": "npm:^4.0.0" "@metamask/ethjs-unit": "npm:^0.2.1" - "@metamask/utils": "npm:^8.2.0" + "@metamask/utils": "npm:^8.3.0" "@spruceid/siwe-parser": "npm:1.1.3" eth-ens-namehash: "npm:^2.0.8" ethereumjs-util: "npm:^7.0.10" fast-deep-equal: "npm:^3.1.3" - checksum: c3f125d9a33a003e369b0312af4634f6205729ce718046a1f0add9e135a0602b405b948ddbd4caf700ba21c724c8ac9936f3e96630fb9286c9e0a312ef552e62 + checksum: 6a8099b883c51b47494678998fb14291cd0ea9904823b8e3a8cd1621dfc321b59b071e0f264225901177e4826499c32243d5b18388c521bbef351ab87a9d332b languageName: node linkType: hard @@ -4089,14 +4089,14 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-json-rpc-provider@npm:^2.1.0, @metamask/eth-json-rpc-provider@npm:^2.2.0, @metamask/eth-json-rpc-provider@npm:^2.3.1": - version: 2.3.1 - resolution: "@metamask/eth-json-rpc-provider@npm:2.3.1" +"@metamask/eth-json-rpc-provider@npm:^2.1.0, @metamask/eth-json-rpc-provider@npm:^2.2.0, @metamask/eth-json-rpc-provider@npm:^2.3.2": + version: 2.3.2 + resolution: "@metamask/eth-json-rpc-provider@npm:2.3.2" dependencies: - "@metamask/json-rpc-engine": "npm:^7.3.1" + "@metamask/json-rpc-engine": "npm:^7.3.2" "@metamask/safe-event-emitter": "npm:^3.0.0" - "@metamask/utils": "npm:^8.2.0" - checksum: fa0a987eb7e0dcff495489e95c358f6786a4a793a42ac900bb022027d27e6534ded743092e79a2191b9b4d760f418f39f6cfb99a5a5a0085f252016579be6865 + "@metamask/utils": "npm:^8.3.0" + checksum: e6731271aad3b972d85b9230c26d35a9b88722f3bd3024675ad2f568e634e9fdfef4717ef2892f3cc512d381cf17a4e20dbd5eb808ced765082bea3379ad6ddc languageName: node linkType: hard @@ -4148,7 +4148,7 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-sig-util@npm:^7.0.0": +"@metamask/eth-sig-util@npm:^7.0.0, @metamask/eth-sig-util@npm:^7.0.1": version: 7.0.1 resolution: "@metamask/eth-sig-util@npm:7.0.1" dependencies: @@ -4358,6 +4358,26 @@ __metadata: languageName: node linkType: hard +"@metamask/gas-fee-controller@npm:^13.0.0": + version: 13.0.0 + resolution: "@metamask/gas-fee-controller@npm:13.0.0" + dependencies: + "@metamask/base-controller": "npm:^4.1.1" + "@metamask/controller-utils": "npm:^8.0.2" + "@metamask/eth-query": "npm:^4.0.0" + "@metamask/ethjs-unit": "npm:^0.2.1" + "@metamask/network-controller": "npm:^17.2.0" + "@metamask/polling-controller": "npm:^5.0.0" + "@metamask/utils": "npm:^8.3.0" + "@types/uuid": "npm:^8.3.0" + ethereumjs-util: "npm:^7.0.10" + uuid: "npm:^8.3.2" + peerDependencies: + "@metamask/network-controller": ^17.2.0 + checksum: 8edbe4412a1bf80eb3a3c6305c35b45ee38f9262a4dd3b38c30d2e81e0f84d2f8ee261e3548fb25a049f53cf76ccf8238c4aca31ec6cd0c5b46ba9c58a705bc8 + languageName: node + linkType: hard + "@metamask/jazzicon@npm:^2.0.0": version: 2.0.0 resolution: "@metamask/jazzicon@npm:2.0.0" @@ -4368,14 +4388,14 @@ __metadata: languageName: node linkType: hard -"@metamask/json-rpc-engine@npm:^7.1.1, @metamask/json-rpc-engine@npm:^7.2.0, @metamask/json-rpc-engine@npm:^7.3.1": - version: 7.3.1 - resolution: "@metamask/json-rpc-engine@npm:7.3.1" +"@metamask/json-rpc-engine@npm:^7.1.1, @metamask/json-rpc-engine@npm:^7.2.0, @metamask/json-rpc-engine@npm:^7.3.1, @metamask/json-rpc-engine@npm:^7.3.2": + version: 7.3.2 + resolution: "@metamask/json-rpc-engine@npm:7.3.2" dependencies: "@metamask/rpc-errors": "npm:^6.1.0" "@metamask/safe-event-emitter": "npm:^3.0.0" - "@metamask/utils": "npm:^8.2.0" - checksum: 3988ec9229964c8c3c9172ad8ef36bea2f20e63d0dd720431db89a0031b7692c5ebaa2c53afe9896a823b334f4d5eb718e48a5db00477fe8b7643d332ae3010d + "@metamask/utils": "npm:^8.3.0" + checksum: d90e5fdf88461aa90af41ba0304729200afa8226ab8b73db348704a1f545e416c49281a1dfd58591dde769e1ab263080b26d5a0ab1be8362398639dc2d6354de languageName: node linkType: hard @@ -4485,18 +4505,18 @@ __metadata: linkType: hard "@metamask/message-manager@npm:^7.3.0, @metamask/message-manager@npm:^7.3.5": - version: 7.3.5 - resolution: "@metamask/message-manager@npm:7.3.5" + version: 7.3.8 + resolution: "@metamask/message-manager@npm:7.3.8" dependencies: - "@metamask/base-controller": "npm:^3.2.3" - "@metamask/controller-utils": "npm:^5.0.2" - "@metamask/eth-sig-util": "npm:^7.0.0" - "@metamask/utils": "npm:^8.1.0" + "@metamask/base-controller": "npm:^4.1.1" + "@metamask/controller-utils": "npm:^8.0.2" + "@metamask/eth-sig-util": "npm:^7.0.1" + "@metamask/utils": "npm:^8.3.0" "@types/uuid": "npm:^8.3.0" ethereumjs-util: "npm:^7.0.10" jsonschema: "npm:^1.2.4" uuid: "npm:^8.3.2" - checksum: 6ee9214847d24228dcb2efe25ef1f40c82dd021780ff3e4bcc03d3703eb03ffdbc92f4a85e8276a499215dec994a4aa6bc6e0ab8a1cdfffcf36ba54f604dfd2a + checksum: 0aa94422751e405b542af1f2b6a6f89aa61c991a9a9312b2a4d5a2bbb007aae84bda2dae2e084206003bbfe75f06bd170820d88c9a39492a0f8f0e9edcb4afe3 languageName: node linkType: hard @@ -4540,25 +4560,25 @@ __metadata: languageName: node linkType: hard -"@metamask/network-controller@npm:^17.0.0, @metamask/network-controller@npm:^17.1.0": - version: 17.1.0 - resolution: "@metamask/network-controller@npm:17.1.0" +"@metamask/network-controller@npm:^17.0.0, @metamask/network-controller@npm:^17.1.0, @metamask/network-controller@npm:^17.2.0": + version: 17.2.0 + resolution: "@metamask/network-controller@npm:17.2.0" dependencies: - "@metamask/base-controller": "npm:^4.0.1" - "@metamask/controller-utils": "npm:^8.0.1" + "@metamask/base-controller": "npm:^4.1.1" + "@metamask/controller-utils": "npm:^8.0.2" "@metamask/eth-json-rpc-infura": "npm:^9.0.0" "@metamask/eth-json-rpc-middleware": "npm:^12.0.1" - "@metamask/eth-json-rpc-provider": "npm:^2.3.1" + "@metamask/eth-json-rpc-provider": "npm:^2.3.2" "@metamask/eth-query": "npm:^4.0.0" - "@metamask/json-rpc-engine": "npm:^7.3.1" + "@metamask/json-rpc-engine": "npm:^7.3.2" "@metamask/rpc-errors": "npm:^6.1.0" - "@metamask/swappable-obj-proxy": "npm:^2.1.0" - "@metamask/utils": "npm:^8.2.0" + "@metamask/swappable-obj-proxy": "npm:^2.2.0" + "@metamask/utils": "npm:^8.3.0" async-mutex: "npm:^0.2.6" eth-block-tracker: "npm:^8.0.0" immer: "npm:^9.0.6" uuid: "npm:^8.3.2" - checksum: 57408c06a307cfeb604abb4e2e4e04d3985efab92562f3bec618aafcd088aea67a8d9b039834a27fd3d1b72d4a0f0908fee01698f918947c73f052af534bb435 + checksum: 0fa7cf92cdcde5dba68e4d35d0f23c060d43f8da8062922aa2b468a9ab7bbd51a600b93c9f80091bbe0fbc760f263b7d8ddd3e5130662b55fc6d9b4974654285 languageName: node linkType: hard @@ -4680,6 +4700,23 @@ __metadata: languageName: node linkType: hard +"@metamask/polling-controller@npm:^5.0.0": + version: 5.0.0 + resolution: "@metamask/polling-controller@npm:5.0.0" + dependencies: + "@metamask/base-controller": "npm:^4.1.1" + "@metamask/controller-utils": "npm:^8.0.2" + "@metamask/network-controller": "npm:^17.2.0" + "@metamask/utils": "npm:^8.3.0" + "@types/uuid": "npm:^8.3.0" + fast-json-stable-stringify: "npm:^2.1.0" + uuid: "npm:^8.3.2" + peerDependencies: + "@metamask/network-controller": ^17.2.0 + checksum: 78655074916c445594787e8573e10a992933477cf702aa458c28396b49dbcd13a60bfb1fac46f680819139f918eacff1f4c1e6386f5d74ceaa3715f8ee48d79f + languageName: node + linkType: hard + "@metamask/post-message-stream@npm:^7.0.0": version: 7.0.0 resolution: "@metamask/post-message-stream@npm:7.0.0" @@ -5050,10 +5087,10 @@ __metadata: languageName: node linkType: hard -"@metamask/swappable-obj-proxy@npm:^2.1.0": - version: 2.1.0 - resolution: "@metamask/swappable-obj-proxy@npm:2.1.0" - checksum: e6628ffbb9c34c07aee2e7f97f00f06eba2d00fcd3f6cac555256dd1b37a73d81eff53030cd129c9dd6db711c9e10c41e857082816f8a0e3de724448c1f2edaa +"@metamask/swappable-obj-proxy@npm:^2.1.0, @metamask/swappable-obj-proxy@npm:^2.2.0": + version: 2.2.0 + resolution: "@metamask/swappable-obj-proxy@npm:2.2.0" + checksum: bc7a1f496d06327f1db84fe2ed75637b6f2f5db0806d3927f250d5abab9cc70a26ff37283ea7f2db7987e48d2540f6821091d1f3000d6771f29c4d91c402f724 languageName: node linkType: hard @@ -5096,6 +5133,38 @@ __metadata: languageName: node linkType: hard +"@metamask/transaction-controller@npm:^21.1.0": + version: 21.1.0 + resolution: "@metamask/transaction-controller@npm:21.1.0" + dependencies: + "@ethereumjs/common": "npm:^3.2.0" + "@ethereumjs/tx": "npm:^4.2.0" + "@ethersproject/abi": "npm:^5.7.0" + "@metamask/approval-controller": "npm:^5.1.2" + "@metamask/base-controller": "npm:^4.1.1" + "@metamask/controller-utils": "npm:^8.0.2" + "@metamask/eth-query": "npm:^4.0.0" + "@metamask/gas-fee-controller": "npm:^13.0.0" + "@metamask/metamask-eth-abis": "npm:^3.0.0" + "@metamask/network-controller": "npm:^17.2.0" + "@metamask/rpc-errors": "npm:^6.1.0" + "@metamask/utils": "npm:^8.3.0" + async-mutex: "npm:^0.2.6" + eth-method-registry: "npm:^3.0.0" + ethereumjs-util: "npm:^7.0.10" + fast-json-patch: "npm:^3.1.1" + lodash: "npm:^4.17.21" + nonce-tracker: "npm:^3.0.0" + uuid: "npm:^8.3.2" + peerDependencies: + "@metamask/approval-controller": ^5.1.2 + "@metamask/gas-fee-controller": ^13.0.0 + "@metamask/network-controller": ^17.2.0 + babel-runtime: ^6.26.0 + checksum: 5dbe811870fb0775d017470ec4529fbf46969f072527e3ac7ce18370faafffda32056eeec02ff8b56ed35463aec8ceaeb667c64362db90529faf4b8e2c9c2631 + languageName: node + linkType: hard + "@metamask/user-operation-controller@npm:^1.0.0": version: 1.0.0 resolution: "@metamask/user-operation-controller@npm:1.0.0" @@ -24594,7 +24663,7 @@ __metadata: "@metamask/snaps-sdk": "npm:^1.4.0" "@metamask/snaps-utils": "npm:^5.2.0" "@metamask/test-dapp": "npm:^7.3.1" - "@metamask/transaction-controller": "npm:^20.0.0" + "@metamask/transaction-controller": "npm:^21.1.0" "@metamask/user-operation-controller": "npm:^1.0.0" "@metamask/utils": "npm:^8.2.1" "@ngraveio/bc-ur": "npm:^1.1.6" From 95292fa8547bc05b802c1b46db9e2218a5ac3c9a Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 6 Feb 2024 12:56:39 -0330 Subject: [PATCH 04/17] Stop blocking display of transaction approval window on resolution of ppom security alert response (#22778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Solves this problem: For people on slow networks, the amount of time it takes from "Dapp button click" -> "Popup notification window appears" might be a problem. When blockaid is toggled off, and the network is throttled to slow via the chrome dev tools, I see a ~3 second worse case for this time, but when blockaid is toggled on, I see a 12 second (or even a bit longer) worst case scenario for this time. The risk here is that users unexpectedly see a longer delay then usual, and so think they need to click the button again, and then get shown multiple confirmation requests and confirm all of them, leading to fund loss. This can happen on either slow internet connections, or if an infura request is taking longer than usual (which could effect people regardless of internet connection). Yesterday when I first saw this issue, I wasn't slowing down my connection, but it still took ~20 seconds to open. Probably a somewhat rare case (because as I mentioned I didn't notice any problems again until I intentionally throttled the network requests), but even if it only affected 10% of users only once a month, that would be enough to get plenty of "why did metamask just take 20 seconds to open a confirmation window?!?" complaints. Fixes: 1. Go to this page... 2. 3. - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/scripts/lib/ppom/ppom-middleware.ts | 9 +- app/scripts/lib/transaction/util.test.ts | 13 +- app/scripts/lib/transaction/util.ts | 93 +++++-- app/scripts/metamask-controller.js | 2 + .../ppom-blockaid-alert-simple-send.spec.js | 246 ++++++++++++++++++ 5 files changed, 335 insertions(+), 28 deletions(-) create mode 100644 test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index 3653884075e2..d5f3e869c218 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -10,14 +10,7 @@ import { import { CHAIN_IDS } from '../../../../shared/constants/network'; import { SIGNING_METHODS } from '../../../../shared/constants/transaction'; import PreferencesController from '../../controllers/preferences'; - -type SecurityAlertResponse = { - reason: string; - features?: string[]; - result_type: string; - providerRequestsCount?: Record; - securityAlertId?: string; -}; +import { SecurityAlertResponse } from '../transaction/util'; const { sentry } = global as any; diff --git a/app/scripts/lib/transaction/util.test.ts b/app/scripts/lib/transaction/util.test.ts index fbb8cb9b198a..16cfb21a844d 100644 --- a/app/scripts/lib/transaction/util.test.ts +++ b/app/scripts/lib/transaction/util.test.ts @@ -16,6 +16,15 @@ import { addTransaction, } from './util'; +jest.mock('uuid', () => { + const actual = jest.requireActual('uuid'); + + return { + ...actual, + v4: jest.fn(), + }; +}); + const TRANSACTION_PARAMS_MOCK: TransactionParams = { from: '0x1', }; @@ -380,8 +389,8 @@ describe('Transaction Utils', () => { ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { ...TRANSACTION_OPTIONS_MOCK, securityAlertResponse: { - reason: 'testReason', - result_type: 'testResultType', + reason: 'loading', + result_type: 'validation_in_progress', }, }); diff --git a/app/scripts/lib/transaction/util.ts b/app/scripts/lib/transaction/util.ts index 8e4420b1bc50..b5695dc0d296 100644 --- a/app/scripts/lib/transaction/util.ts +++ b/app/scripts/lib/transaction/util.ts @@ -3,6 +3,10 @@ import { TransactionController, TransactionMeta, TransactionParams, + WalletDevice, + TransactionType, + SendFlowHistoryEntry, + Result, } from '@metamask/transaction-controller'; import { AddUserOperationOptions, @@ -12,11 +16,45 @@ import { import { PPOMController } from '@metamask/ppom-validator'; import { captureException } from '@sentry/browser'; import { addHexPrefix } from 'ethereumjs-util'; +import { v4 as uuid } from 'uuid'; import { SUPPORTED_CHAIN_IDS } from '../ppom/ppom-middleware'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../../shared/constants/security-provider'; ///: END:ONLY_INCLUDE_IF +/** + * Type for security alert response from transaction validator. + */ +export type SecurityAlertResponse = { + reason: string; + features?: string[]; + result_type: string; + providerRequestsCount?: Record; + securityAlertId?: string; +}; + export type AddTransactionOptions = NonNullable< - Parameters[1] + Parameters< + ( + txParams: TransactionParams, + options?: { + actionId?: string; + deviceConfirmedOn?: WalletDevice; + method?: string; + origin?: string; + requireApproval?: boolean | undefined; + securityAlertResponse?: SecurityAlertResponse; + sendFlowHistory?: SendFlowHistoryEntry[]; + swaps?: { + hasApproveTx?: boolean; + meta?: Partial; + }; + type?: TransactionType; + }, + ) => Promise + >[1] >; type BaseAddTransactionRequest = { @@ -30,16 +68,6 @@ type BaseAddTransactionRequest = { userOperationController: UserOperationController; }; -/** - * Type for security alert response from transaction validator. - */ -export type SecurityAlertResponse = { - reason: string; - features?: string[]; - result_type: string; - providerRequestsCount?: Record; -}; - type FinalAddTransactionRequest = BaseAddTransactionRequest & { transactionOptions: AddTransactionOptions; }; @@ -83,6 +111,12 @@ export async function addDappTransaction( export async function addTransaction( request: AddTransactionRequest, + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) + updateSecurityAlertResponseByTxId: ( + req: AddTransactionOptions | undefined, + securityAlertResponse: SecurityAlertResponse, + ) => void, + ///: END:ONLY_INCLUDE_IF ): Promise { ///: BEGIN:ONLY_INCLUDE_IF(blockaid) const { @@ -109,13 +143,36 @@ export async function addTransaction( ], }; - const securityAlertResponse = await ppomController.usePPOM( - async (ppom) => { - return ppom.validateJsonRpc(ppomRequest); - }, - ); - - request.transactionOptions.securityAlertResponse = securityAlertResponse; + const securityAlertId = uuid(); + + ppomController.usePPOM(async (ppom) => { + try { + const securityAlertResponse = await ppom.validateJsonRpc(ppomRequest); + updateSecurityAlertResponseByTxId( + request.transactionOptions, + securityAlertResponse, + ); + } catch (e) { + captureException(e); + console.error('Error validating JSON RPC using PPOM: ', e); + const securityAlertResponse = { + result_type: BlockaidResultType.Failed, + reason: BlockaidReason.failed, + description: + 'Validating the confirmation failed by throwing error.', + }; + updateSecurityAlertResponseByTxId( + request.transactionOptions, + securityAlertResponse, + ); + } + }); + + request.transactionOptions.securityAlertResponse = { + reason: BlockaidResultType.Loading, + result_type: BlockaidReason.inProgress, + securityAlertId, + }; } catch (e) { captureException(e); } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6d4d16b841b9..ce5ed0961540 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2995,6 +2995,7 @@ export default class MetamaskController extends EventEmitter { transactionOptions, waitForSubmit: false, }), + this.updateSecurityAlertResponseByTxId.bind(this), ), addTransactionAndWaitForPublish: ( transactionParams, @@ -3006,6 +3007,7 @@ export default class MetamaskController extends EventEmitter { transactionOptions, waitForSubmit: true, }), + this.updateSecurityAlertResponseByTxId.bind(this), ), createTransactionEventFragment: createTransactionEventFragmentWithTxId.bind( diff --git a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js new file mode 100644 index 000000000000..161e15e88aa6 --- /dev/null +++ b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js @@ -0,0 +1,246 @@ +const { strict: assert } = require('assert'); +const FixtureBuilder = require('../fixture-builder'); +const { mockServerJsonRpc } = require('../mock-server-json-rpc'); + +const { + defaultGanacheOptions, + withFixtures, + sendScreenToConfirmScreen, + unlockWallet, +} = require('../helpers'); + +const bannerAlertSelector = '[data-testid="security-provider-banner-alert"]'; +const mockMaliciousAddress = '0x5fbdb2315678afecb367f032d93f642f64180aa3'; +const mockBenignAddress = '0x50587E46C5B96a3F6f9792922EC647F13E6EFAE4'; + +const expectedMaliciousTitle = 'This is a deceptive request'; +const expectedMaliciousDescription = + 'If you approve this request, a third party known for scams will take all your assets.'; + +async function mockInfura(mockServer) { + await mockServerJsonRpc(mockServer, [ + ['eth_blockNumber'], + ['eth_call'], + ['eth_estimateGas'], + ['eth_feeHistory'], + ['eth_gasPrice'], + ['eth_getBalance'], + ['eth_getBlockByNumber'], + ['eth_getCode'], + ['eth_getTransactionCount'], + ]); +} + +async function mockInfuraWithBenignResponses(mockServer) { + await mockInfura(mockServer); + + await mockServer + .forPost() + .withJsonBodyIncluding({ + method: 'debug_traceCall', + }) + .thenCallback(async (req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: (await req.body.getJson()).id, + result: { + type: 'CALL', + from: '0x0000000000000000000000000000000000000000', + to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567', + value: '0xde0b6b3a7640000', + gas: '0x16c696eb7', + gasUsed: '0x0', + input: '0x', + output: '0x', + }, + }, + }; + }); +} + +async function mockInfuraWithMaliciousResponses(mockServer) { + await mockInfura(mockServer); + + await mockServer + .forPost() + .withJsonBodyIncluding({ + method: 'debug_traceCall', + params: [{ accessList: [], data: '0x00000000' }], + }) + .thenCallback(async (req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: (await req.body.getJson()).id, + result: { + calls: [ + { + error: 'execution reverted', + from: '0x0000000000000000000000000000000000000000', + gas: '0x1d55c2cb', + gasUsed: '0x39c', + input: '0x00000000', + to: mockMaliciousAddress, + type: 'DELEGATECALL', + value: '0x0', + }, + ], + error: 'execution reverted', + from: '0x0000000000000000000000000000000000000000', + gas: '0x1dcd6500', + gasUsed: '0x721e', + input: '0x00000000', + to: mockMaliciousAddress, + type: 'CALL', + value: '0x0', + }, + }, + }; + }); +} + +async function mockInfuraWithFailedResponses(mockServer) { + await mockInfura(mockServer); + + await mockServer + .forPost() + .withJsonBodyIncluding({ + method: 'debug_traceCall', + params: [{ accessList: [], data: '0x00000000' }], + }) + .thenCallback(() => { + return { + statusCode: 500, + }; + }); +} + +/** + * Tests various Blockaid PPOM security alerts. Some other tests live in separate files due to + * the need for more sophisticated JSON-RPC mock requests. Some example PPOM Blockaid + * requests and responses are provided here: + * + * @see {@link https://wobbly-nutmeg-8a5.notion.site/MM-E2E-Testing-1e51b617f79240a49cd3271565c6e12d} + */ +describe('Simple Send Security Alert - Blockaid @no-mmi', function () { + if (process.env.MULTICHAIN) { + return; + } + it('should not show security alerts for benign requests', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withPreferencesController({ + securityAlertsEnabled: true, + }) + .build(), + defaultGanacheOptions, + testSpecificMock: mockInfuraWithBenignResponses, + title: this.test.fullTitle(), + }, + + async ({ driver }) => { + // await driver.delay(10000) + await unlockWallet(driver); + + await sendScreenToConfirmScreen(driver, mockBenignAddress, '1'); + // await driver.delay(100000) + const isPresent = await driver.isElementPresent(bannerAlertSelector); + assert.equal(isPresent, false, `Banner alert unexpectedly found.`); + }, + ); + }); + + /** + * Disclaimer: This test does not test all reason types. e.g. 'blur_farming', + * 'malicious_domain'. Some other tests are found in other files: + * e.g. test/e2e/flask/ppom-blockaid-alert-.spec.js + */ + it('should show security alerts for malicious requests', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withPreferencesController({ + securityAlertsEnabled: true, + }) + .build(), + defaultGanacheOptions, + testSpecificMock: mockInfuraWithMaliciousResponses, + title: this.test.fullTitle(), + }, + + async ({ driver }) => { + await unlockWallet(driver); + + await sendScreenToConfirmScreen( + driver, + '0x985c30949c92df7a0bd42e0f3e3d539ece98db24', + '1', + ); + + // Find element by title + const bannerAlertFoundByTitle = await driver.findElement({ + css: bannerAlertSelector, + text: expectedMaliciousTitle, + }); + const bannerAlertText = await bannerAlertFoundByTitle.getText(); + + assert( + bannerAlertFoundByTitle, + `Banner alert not found. Expected Title: ${expectedMaliciousTitle}`, + ); + assert( + bannerAlertText.includes(expectedMaliciousDescription), + `Unexpected banner alert description. Expected: ${expectedMaliciousDescription}`, + ); + }, + ); + }); + + it('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withPreferencesController({ + securityAlertsEnabled: true, + }) + .build(), + defaultGanacheOptions, + testSpecificMock: mockInfuraWithFailedResponses, + title: this.test.fullTitle(), + }, + + async ({ driver }) => { + // await driver.delay(10000) + await unlockWallet(driver); + + await sendScreenToConfirmScreen( + driver, + '0x985c30949c92df7a0bd42e0f3e3d539ece98db24', + '1', + ); + // await driver.delay(100000) + const expectedTitle = 'Request may not be safe'; + + const bannerAlert = await driver.findElement({ + css: bannerAlertSelector, + text: expectedTitle, + }); + + assert( + bannerAlert, + `Banner alert not found. Expected Title: ${expectedTitle}`, + ); + }, + ); + }); +}); From 6d17bb313cdc6674aebb1dc3044da6aaae5930a0 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 9 Feb 2024 02:47:56 -0330 Subject: [PATCH 05/17] Stop doing ppom validation on metamask swaps (#22847) --- app/scripts/lib/transaction/util.test.ts | 44 ++++++++++++++++++++++++ app/scripts/lib/transaction/util.ts | 17 ++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/transaction/util.test.ts b/app/scripts/lib/transaction/util.test.ts index 16cfb21a844d..7d27624e8cde 100644 --- a/app/scripts/lib/transaction/util.test.ts +++ b/app/scripts/lib/transaction/util.test.ts @@ -425,6 +425,50 @@ describe('Transaction Utils', () => { expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); }); + + it('does not validate if blockaid is enabled and chain id is supported, but transaction type is swap', async () => { + const swapRequest = { ...request }; + swapRequest.transactionOptions.type = TransactionType.swap; + await addTransaction({ + ...swapRequest, + securityAlertsEnabled: true, + chainId: '0x1', + }); + + expect( + request.transactionController.addTransaction, + ).toHaveBeenCalledTimes(1); + expect( + request.transactionController.addTransaction, + ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { + ...TRANSACTION_OPTIONS_MOCK, + type: TransactionType.swap, + }); + + expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + }); + + it('does not validate if blockaid is enabled and chain id is supported, but transaction type is swapApproval', async () => { + const swapRequest = { ...request }; + swapRequest.transactionOptions.type = TransactionType.swapApproval; + await addTransaction({ + ...swapRequest, + securityAlertsEnabled: true, + chainId: '0x1', + }); + + expect( + request.transactionController.addTransaction, + ).toHaveBeenCalledTimes(1); + expect( + request.transactionController.addTransaction, + ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { + ...TRANSACTION_OPTIONS_MOCK, + type: TransactionType.swapApproval, + }); + + expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + }); }); describe('when blockaid is disabled', () => { diff --git a/app/scripts/lib/transaction/util.ts b/app/scripts/lib/transaction/util.ts index b5695dc0d296..4aab8e8fa0f1 100644 --- a/app/scripts/lib/transaction/util.ts +++ b/app/scripts/lib/transaction/util.ts @@ -109,6 +109,13 @@ export async function addDappTransaction( return (await waitForHash()) as string; } +///: BEGIN:ONLY_INCLUDE_IF(blockaid) +const PPOM_EXCLUDED_TRANSACTION_TYPES = [ + TransactionType.swap, + TransactionType.swapApproval, +]; +///: END:ONLY_INCLUDE_IF + export async function addTransaction( request: AddTransactionRequest, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) @@ -127,7 +134,15 @@ export async function addTransaction( chainId, } = request; - if (securityAlertsEnabled && SUPPORTED_CHAIN_IDS.includes(chainId)) { + const typeIsExcludedFromPPOM = + transactionOptions.type && + PPOM_EXCLUDED_TRANSACTION_TYPES.includes(transactionOptions.type); + + if ( + securityAlertsEnabled && + SUPPORTED_CHAIN_IDS.includes(chainId) && + !typeIsExcludedFromPPOM + ) { try { const ppomRequest = { method: 'eth_sendTransaction', From 9bbe682ee28237368f5d1d3816711138c53406ed Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Thu, 15 Feb 2024 01:18:42 +0100 Subject: [PATCH 06/17] fix: Remove unnecessary resolution for socks (#22960) Remove unnecessary resolution for the `socks` package. This removes the risk of the resolution causing problems in future updates, reducing maintenance burdens for the team. --- package.json | 3 +-- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 798832c254b5..41ca4661ef21 100644 --- a/package.json +++ b/package.json @@ -219,8 +219,7 @@ "nonce-tracker@npm:^3.0.0": "patch:nonce-tracker@npm%3A3.0.0#~/.yarn/patches/nonce-tracker-npm-3.0.0-c5e9a93f9d.patch", "@trezor/connect-web": "9.0.11", "lavamoat-core@npm:^15.1.1": "patch:lavamoat-core@npm%3A15.1.1#~/.yarn/patches/lavamoat-core-npm-15.1.1-51fbe39988.patch", - "tar-stream@npm:^3.1.6": "patch:tar-stream@npm%3A3.1.6#~/.yarn/patches/tar-stream-npm-3.1.6-ce3ac17e49.patch", - "socks": "^2.7.3" + "tar-stream@npm:^3.1.6": "patch:tar-stream@npm%3A3.1.6#~/.yarn/patches/tar-stream-npm-3.1.6-ce3ac17e49.patch" }, "dependencies": { "@babel/runtime": "^7.23.2", diff --git a/yarn.lock b/yarn.lock index b08f6ae5b9a8..8398b061ea3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31584,7 +31584,7 @@ __metadata: languageName: node linkType: hard -"socks@npm:^2.7.3": +"socks@npm:^2.6.1, socks@npm:^2.6.2, socks@npm:^2.7.1": version: 2.8.0 resolution: "socks@npm:2.8.0" dependencies: From 11945f75569a1b70e64976daaf91dcf72fc88ae9 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 29 Jan 2024 22:10:07 +0800 Subject: [PATCH 07/17] fix: Create patch for custody keyring type in accounts controller (#22692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR creates a patch to check for all types of custodian keyrings that start with the prefix `Custody` - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- ...nts-controller-npm-10.0.0-247993ca9a.patch | 88 +++++++++++++++++++ package.json | 2 +- yarn.lock | 25 +++++- 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 .yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch diff --git a/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch b/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch new file mode 100644 index 000000000000..4d04b1c74db2 --- /dev/null +++ b/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch @@ -0,0 +1,88 @@ +diff --git a/dist/utils.js b/dist/utils.js +index 810f229841ffff83f7a28191bc558862b1809e01..aa2ea845d4cccfac8e28f575d7972bd2dba8decf 100644 +--- a/dist/utils.js ++++ b/dist/utils.js +@@ -11,35 +11,40 @@ const uuid_1 = require("uuid"); + * @returns The name of the keyring type. + */ + function keyringTypeToName(keyringType) { +- switch (keyringType) { +- case keyring_controller_1.KeyringTypes.simple: { +- return 'Account'; +- } +- case keyring_controller_1.KeyringTypes.hd: { +- return 'Account'; +- } +- case keyring_controller_1.KeyringTypes.trezor: { +- return 'Trezor'; +- } +- case keyring_controller_1.KeyringTypes.ledger: { +- return 'Ledger'; +- } +- case keyring_controller_1.KeyringTypes.lattice: { +- return 'Lattice'; +- } +- case keyring_controller_1.KeyringTypes.qr: { +- return 'QR'; +- } +- case keyring_controller_1.KeyringTypes.snap: { +- return 'Snap Account'; +- } +- case keyring_controller_1.KeyringTypes.custody: { +- return 'Custody'; +- } +- default: { +- throw new Error(`Unknown keyring ${keyringType}`); +- } ++ // Custody Keyrings follow this pattern ++ if (/^Custody.*/.test(keyringType)) { ++ return "Custody"; ++ } ++ ++ switch (keyringType) { ++ case keyring_controller_1.KeyringTypes.simple: { ++ return "Account"; + } ++ case keyring_controller_1.KeyringTypes.hd: { ++ return "Account"; ++ } ++ case keyring_controller_1.KeyringTypes.trezor: { ++ return "Trezor"; ++ } ++ case keyring_controller_1.KeyringTypes.ledger: { ++ return "Ledger"; ++ } ++ case keyring_controller_1.KeyringTypes.lattice: { ++ return "Lattice"; ++ } ++ case keyring_controller_1.KeyringTypes.qr: { ++ return "QR"; ++ } ++ case keyring_controller_1.KeyringTypes.snap: { ++ return "Snap Account"; ++ } ++ case keyring_controller_1.KeyringTypes.custody: { ++ return "Custody"; ++ } ++ default: { ++ throw new Error(`Unknown keyring ${keyringType}`); ++ } ++ } + } + exports.keyringTypeToName = keyringTypeToName; + /** +@@ -48,10 +53,10 @@ exports.keyringTypeToName = keyringTypeToName; + * @returns The generated UUID. + */ + function getUUIDFromAddressOfNormalAccount(address) { +- const v4options = { +- random: (0, ethereumjs_util_1.sha256FromString)(address).slice(0, 16), +- }; +- return (0, uuid_1.v4)(v4options); ++ const v4options = { ++ random: (0, ethereumjs_util_1.sha256FromString)(address).slice(0, 16), ++ }; ++ return (0, uuid_1.v4)(v4options); + } + exports.getUUIDFromAddressOfNormalAccount = getUUIDFromAddressOfNormalAccount; + //# sourceMappingURL=utils.js.map diff --git a/package.json b/package.json index 41ca4661ef21..07a4faee64a7 100644 --- a/package.json +++ b/package.json @@ -245,7 +245,7 @@ "@metamask-institutional/rpc-allowlist": "^1.0.0", "@metamask-institutional/sdk": "^0.1.23", "@metamask-institutional/transaction-update": "^0.1.32", - "@metamask/accounts-controller": "^10.0.0", + "@metamask/accounts-controller": "patch:@metamask/accounts-controller@npm%3A10.0.0#~/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch", "@metamask/address-book-controller": "^3.0.0", "@metamask/announcement-controller": "^5.0.1", "@metamask/approval-controller": "^5.1.1", diff --git a/yarn.lock b/yarn.lock index 8398b061ea3a..965a00393045 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3766,7 +3766,7 @@ __metadata: languageName: node linkType: hard -"@metamask/accounts-controller@npm:^10.0.0": +"@metamask/accounts-controller@npm:10.0.0": version: 10.0.0 resolution: "@metamask/accounts-controller@npm:10.0.0" dependencies: @@ -3787,6 +3787,27 @@ __metadata: languageName: node linkType: hard +"@metamask/accounts-controller@patch:@metamask/accounts-controller@npm%3A10.0.0#~/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch": + version: 10.0.0 + resolution: "@metamask/accounts-controller@patch:@metamask/accounts-controller@npm%3A10.0.0#~/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch::version=10.0.0&hash=0a18f3" + dependencies: + "@metamask/base-controller": "npm:^4.1.1" + "@metamask/eth-snap-keyring": "npm:^2.1.1" + "@metamask/keyring-api": "npm:^3.0.0" + "@metamask/snaps-sdk": "npm:^1.3.2" + "@metamask/snaps-utils": "npm:^5.1.2" + "@metamask/utils": "npm:^8.3.0" + deepmerge: "npm:^4.2.2" + ethereumjs-util: "npm:^7.0.10" + immer: "npm:^9.0.6" + uuid: "npm:^8.3.2" + peerDependencies: + "@metamask/keyring-controller": ^12.2.0 + "@metamask/snaps-controllers": ^4.0.0 + checksum: 809c1a3bfe0982b6113c7c76c43576fc9a454c66ec5403b839e10468ec753d742027cb7674045c9005de32ca7822dcd2bc0a19f68be37e1184486652c7befba3 + languageName: node + linkType: hard + "@metamask/address-book-controller@npm:^3.0.0": version: 3.0.0 resolution: "@metamask/address-book-controller@npm:3.0.0" @@ -24664,7 +24685,7 @@ __metadata: "@metamask-institutional/rpc-allowlist": "npm:^1.0.0" "@metamask-institutional/sdk": "npm:^0.1.23" "@metamask-institutional/transaction-update": "npm:^0.1.32" - "@metamask/accounts-controller": "npm:^10.0.0" + "@metamask/accounts-controller": "patch:@metamask/accounts-controller@npm%3A10.0.0#~/.yarn/patches/@metamask-accounts-controller-npm-10.0.0-247993ca9a.patch" "@metamask/address-book-controller": "npm:^3.0.0" "@metamask/announcement-controller": "npm:^5.0.1" "@metamask/approval-controller": "npm:^5.1.1" From 4b24c1c5ef68482c89e6e8e6efe8d270f6eed155 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 16 Feb 2024 11:52:01 -0330 Subject: [PATCH 08/17] Cherry-pick 67eb0bca9e (#22997) to v11.10.0 (#23002) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Cherry pick of #22997 to v11.10.0. That PR's description is below Update the hardfork in the transaction common used to estimate L1 optimism fees to London, fixing display of Layer 1 optimsim fees The bug was that Layer 1 fees were not being displayed on the confirmation screen for transactions on Optimism. This was because `estimatedL1Fees` was null, because `fetchEstimatedL1Fee` was failing, because `TransactionFactory.fromTxData(txParams, { common })` in `buildUnserializedTransaction` was throwing an error, because `txParams` has a `type` === `2`, but EIP-1559 transactions are not supported on the spurious dragon hardfork, which is what was being used in the `common` configuration of that `TransactionFactory.fromTxData` call. This became a problem after https://github.com/MetaMask/core/pull/3817/files. That PR correctly fixed a bug which could result in the transaction type being removed from the `txMeta.txParams` when `addTransaction` in the tx controller was called. With that bug fix, there was now a `type` present on the `txParams` that got passed to the aforementioned `TransactionFactory.fromTxData` call. Prior to that bug fix, there was no `type` on `txParams` at that point, the ethereumjs-tx TransactionFactory was treating these transactions as legacy transactions, and so was constructing a type 0 transaction, and the fact that the hardfork was spurious dragon was not a problem This PR fixes the problem by updating the hardfork param used in the `common` configuration of that `TransactionFactory.fromTxData` call. This should not have a functional effect, as this will cause no change in data and value of the tx passed to the smart contract to generate an fee estimate, except that this may result in more accurate L1 fee estimates (that is not certain though). Fixes: #22945 1. Create a transaction on OP Mainnet 2. Click "Fee details" on the confirmation screen 3. The layer 1 fee details should be visible ![Screenshot from 2024-02-16 09-27-25](https://github.com/MetaMask/metamask-extension/assets/7499938/6c759096-f393-4101-b9af-a3542e313571) - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. ## **Description** ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- ui/helpers/utils/optimism/buildUnserializedTransaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/helpers/utils/optimism/buildUnserializedTransaction.js b/ui/helpers/utils/optimism/buildUnserializedTransaction.js index 15f08b021cb9..39d7a2c6f592 100644 --- a/ui/helpers/utils/optimism/buildUnserializedTransaction.js +++ b/ui/helpers/utils/optimism/buildUnserializedTransaction.js @@ -22,7 +22,7 @@ function buildTransactionCommon(txMeta) { // Optimism only supports type-0 transactions; it does not support any of // the newer EIPs since EIP-155. Source: // - defaultHardfork: Hardfork.SpuriousDragon, + defaultHardfork: Hardfork.London, }); } From 0c433f6acdd84fb41c87ae77466abe6f90852988 Mon Sep 17 00:00:00 2001 From: Marina Boboc <120041701+benjisclowder@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:45:16 +0200 Subject: [PATCH 09/17] V11.10.0 changelog (#22827) Adding 11.10.0 changelog --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f43aa221a83a..18db909ce3ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [11.10.0] +### Added +- Added preset network image avatars in the 'Select a network' pop-up ([#22643](https://github.com/MetaMask/metamask-extension/pull/22643)) +- Expanded Blockaid banner support to include send requests from wallets ([#22321](https://github.com/MetaMask/metamask-extension/pull/22321)) +- Expanded Blockaid banner support to include BNB chain, Polygon, Arbitrum, Optimism, Avalanche, and Linea networks ([#22633](https://github.com/MetaMask/metamask-extension/pull/22633)) +- Added support for imToken Wallet using EIP-4527 ([#21804](https://github.com/MetaMask/metamask-extension/pull/21804)) +- [FLASK] Introduced user operation support, enhancing transaction handling and alert display for user operations ([#22469](https://github.com/MetaMask/metamask-extension/pull/22469)) +- [FLASK] Added support for the Lattice hardware wallet in MV3 ([#22528](https://github.com/MetaMask/metamask-extension/pull/22528)) +- [FLASK] Added a 'You're sending to a contract' warning to the new send page ([#22551](https://github.com/MetaMask/metamask-extension/pull/22551)) + +### Changed +- Improved error messaging for Ledger connection issues ([#21038](https://github.com/MetaMask/metamask-extension/pull/21038)) +- Updated 'What's New' and 'Settings' to communicate the extension's additional network coverage ([#22618](https://github.com/MetaMask/metamask-extension/pull/22618)) +- Enhanced Token List layout for clearer token name and value display ([#22601](https://github.com/MetaMask/metamask-extension/pull/22601)) +- Updated the date for the upcoming user survey displayed on the home screen ([#22581](https://github.com/MetaMask/metamask-extension/pull/22581)) +- Improved QR code density for compatibility with the ZERO hardware wallet ([#22135](https://github.com/MetaMask/metamask-extension/pull/22135)) +- Updated snaps packages to the latest versions ([#22595](https://github.com/MetaMask/metamask-extension/pull/22595)) +- Updated the Gas API URL to ensure accurate gas fee calculations for Send and Swap transactions ([#22544](https://github.com/MetaMask/metamask-extension/pull/22544)) + +### Fixed +- Fixed an issue where clicking on the redirection link did not close the notification window ([#22583](https://github.com/MetaMask/metamask-extension/pull/22583)) +- Improved Blockaid 'What's New' image display for users in OS dark mode ([#22649](https://github.com/MetaMask/metamask-extension/pull/22649)) +- Added Blockaid dark mode support in the 'What's New' feature and introduced a new theme management utility ([#22613](https://github.com/MetaMask/metamask-extension/pull/22613)) +- Ensured all security alert banners correctly trigger events ([#22553](https://github.com/MetaMask/metamask-extension/pull/22553)) +- Updated 'What's New' Blockaid image to have a transparent background ([#22539](https://github.com/MetaMask/metamask-extension/pull/22539)) +- Fixed unresponsiveness on the phishing warning page ([#22645](https://github.com/MetaMask/metamask-extension/pull/22645)) +- Improved Trezor integration by updating to the correct version of the SDK ([#22591](https://github.com/MetaMask/metamask-extension/pull/22591)) +- Improved account list links to display the correct explorer domain based on the selected network ([#22483](https://github.com/MetaMask/metamask-extension/pull/22483)) +- Improved the reliability of snap installations by resolving an underlying technical issue ([#22602](https://github.com/MetaMask/metamask-extension/pull/22602)) + ## [11.9.5] ### Fixed - Fixed sometimes failing confirmation screen security validation checks ([$22978](https://github.com/MetaMask/metamask-extension/pull/22978)) @@ -4361,10 +4390,7 @@ Update styles and spacing on the critical error page ([#20350](https://github.c - Added the ability to restore accounts from seed words. [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...HEAD -[11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.7.3...v11.10.0 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.9.0...HEAD -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...HEAD -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...HEAD +[11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 [11.9.5]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...v11.9.5 [11.9.4]: https://github.com/MetaMask/metamask-extension/compare/v11.9.3...v11.9.4 [11.9.3]: https://github.com/MetaMask/metamask-extension/compare/v11.9.2...v11.9.3 From c2d8a9b5fb19b7a7771eee1947ef0a3e9b723c75 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:46:32 +0100 Subject: [PATCH 10/17] Cherry pick 2 metric PRs for Blockaid (#23022) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Cherry picks: - [[Bug|Feat] blockaid external link clicked metric update (](https://github.com/MetaMask/metamask-extension/pull/23022/commits/2f5e64c9e9443988dca7a6beea94f1605f44ef9a)https://github.com/MetaMask/metamask-extension/pull/22631[)](https://github.com/MetaMask/metamask-extension/pull/23022/commits/2f5e64c9e9443988dca7a6beea94f1605f44ef9a) [2f5e64c](https://github.com/MetaMask/metamask-extension/pull/23022/commits/2f5e64c9e9443988dca7a6beea94f1605f44ef9a) - [fix: for realease blocker bugs (](https://github.com/MetaMask/metamask-extension/pull/23022/commits/9c391caf5b82dc7af3e6fb2459b408f2e90c8ac4)https://github.com/MetaMask/metamask-extension/pull/22874[)](https://github.com/MetaMask/metamask-extension/pull/23022/commits/9c391caf5b82dc7af3e6fb2459b408f2e90c8ac4) ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Signed-off-by: Akintayo A. Olusegun Co-authored-by: Ariella Vu <20778143+digiwand@users.noreply.github.com> Co-authored-by: Olusegun Akintayo Co-authored-by: Jyoti Puri --- app/scripts/controllers/app-state.js | 6 + .../lib/createRPCMethodTrackingMiddleware.js | 38 +++- .../createRPCMethodTrackingMiddleware.test.js | 21 +++ app/scripts/lib/ppom/ppom-middleware.ts | 43 +++-- app/scripts/lib/transaction/metrics.test.ts | 2 - app/scripts/lib/transaction/metrics.ts | 52 ++---- app/scripts/lib/transaction/util.ts | 48 ++--- app/scripts/metamask-controller.js | 3 + shared/constants/metametrics.ts | 7 + .../tests/metrics/signature-approved.spec.js | 7 +- .../blockaid-banner-alert.js | 14 ++ .../blockaid-banner-alert.test.js | 94 ++++++++-- .../signature-request-original.component.js | 24 +-- .../signature-request-siwe.js | 55 +----- .../signature-request/signature-request.js | 27 +-- .../terms-of-use-popup.test.js | 7 +- .../transaction-alerts/transaction-alerts.js | 37 +--- ui/helpers/utils/metric.test.js | 77 -------- ui/helpers/utils/metrics.js | 78 +++++---- ui/helpers/utils/metrics.test.js | 164 ++++++++++++++++++ ui/hooks/useTransactionEventFragment.js | 10 +- .../confirm-approve-content.component.js | 24 +-- ui/pages/token-allowance/token-allowance.js | 27 +-- 23 files changed, 470 insertions(+), 395 deletions(-) delete mode 100644 ui/helpers/utils/metric.test.js create mode 100644 ui/helpers/utils/metrics.test.js diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 8f4f8a834d86..345960ea812c 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -444,6 +444,12 @@ export default class AppStateController extends EventEmitter { } ///: END:ONLY_INCLUDE_IF + getSignatureSecurityAlertResponse(securityAlertId) { + return this.store.getState().signatureSecurityAlertResponses[ + securityAlertId + ]; + } + addSignatureSecurityAlertResponse(securityAlertResponse) { const currentState = this.store.getState(); const { signatureSecurityAlertResponses } = currentState; diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.js index e851ad9b9807..d16bb9f74b4f 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.js @@ -10,13 +10,15 @@ import { } from '../../../shared/constants/metametrics'; import { SECOND } from '../../../shared/constants/time'; -///: BEGIN:ONLY_INCLUDE_IF(blockaid) import { - BlockaidReason, BlockaidResultType, + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) + BlockaidReason, + ///: END:ONLY_INCLUDE_IF } from '../../../shared/constants/security-provider'; -///: END:ONLY_INCLUDE_IF +import { SIGNING_METHODS } from '../../../shared/constants/transaction'; +import { getBlockaidMetricsProps } from '../../../ui/helpers/utils/metrics'; import { getSnapAndHardwareInfoForMetrics } from './snap-keyring/metrics'; /** @@ -121,6 +123,7 @@ const rateLimitTimeouts = {}; * @param {Function} opts.getAccountType * @param {Function} opts.getDeviceModel * @param {RestrictedControllerMessenger} opts.snapAndHardwareMessenger + * @param {AppStateController} opts.appStateController * @returns {Function} */ export default function createRPCMethodTrackingMiddleware({ @@ -131,6 +134,7 @@ export default function createRPCMethodTrackingMiddleware({ getAccountType, getDeviceModel, snapAndHardwareMessenger, + appStateController, }) { return async function rpcMethodTrackingMiddleware( /** @type {any} */ req, @@ -310,13 +314,39 @@ export default function createRPCMethodTrackingMiddleware({ event = eventType.APPROVED; } + let blockaidMetricProps = {}; + + if (!isDisabledRPCMethod) { + if (SIGNING_METHODS.includes(method)) { + const securityAlertResponse = + appStateController.getSignatureSecurityAlertResponse( + req.securityAlertResponse?.securityAlertId, + ); + + blockaidMetricProps = getBlockaidMetricsProps({ + securityAlertResponse, + }); + } + } + + const properties = { + ...eventProperties, + ...blockaidMetricProps, + // if security_alert_response from blockaidMetricProps is Benign, force set security_alert_reason to empty string + security_alert_reason: + blockaidMetricProps.security_alert_response === + BlockaidResultType.Benign + ? '' + : blockaidMetricProps.security_alert_reason, + }; + trackEvent({ event, category: MetaMetricsEventCategory.InpageProvider, referrer: { url: origin, }, - properties: eventProperties, + properties, }); return callback(); diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js index 65820078539d..2f3f563b3594 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js @@ -24,11 +24,30 @@ const securityProviderRequest = () => { }; }; +const appStateController = { + store: { + getState: () => ({ + signatureSecurityAlertResponses: { + 1: { + result_type: BlockaidResultType.Malicious, + reason: BlockaidReason.maliciousDomain, + }, + }, + }), + }, + getSignatureSecurityAlertResponse: (id) => { + return appStateController.store.getState().signatureSecurityAlertResponses[ + id + ]; + }, +}; + const handler = createRPCMethodTrackingMiddleware({ trackEvent, getMetricsState, rateLimitSeconds: 1, securityProviderRequest, + appStateController, }); function getNext(timeout = 500) { @@ -122,6 +141,7 @@ describe('createRPCMethodTrackingMiddleware', () => { securityAlertResponse: { result_type: BlockaidResultType.Malicious, reason: BlockaidReason.maliciousDomain, + securityAlertId: 1, }, }; @@ -154,6 +174,7 @@ describe('createRPCMethodTrackingMiddleware', () => { eth_call: 5, eth_getCode: 3, }, + securityAlertId: 1, }, }; diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index d5f3e869c218..31afeae8b92a 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -69,26 +69,35 @@ export function createPPOMMiddleware( // eslint-disable-next-line require-atomic-updates const securityAlertId = uuid(); - ppomController.usePPOM(async (ppom: PPOM) => { - try { - const securityAlertResponse = await ppom.validateJsonRpc(req); - securityAlertResponse.securityAlertId = securityAlertId; - updateSecurityAlertResponseByTxId(req, securityAlertResponse); - } catch (error: any) { - sentry?.captureException(error); - console.error('Error validating JSON RPC using PPOM: ', error); - const securityAlertResponse = { - result_type: BlockaidResultType.Failed, - reason: BlockaidReason.failed, - description: - 'Validating the confirmation failed by throwing error.', - }; - updateSecurityAlertResponseByTxId(req, securityAlertResponse); - } - }); + ppomController + .usePPOM(async (ppom: PPOM) => { + try { + const securityAlertResponse = await ppom.validateJsonRpc(req); + return securityAlertResponse; + } catch (error: any) { + sentry?.captureException(error); + console.error('Error validating JSON RPC using PPOM: ', error); + const securityAlertResponse = { + result_type: BlockaidResultType.Failed, + reason: BlockaidReason.failed, + description: + 'Validating the confirmation failed by throwing error.', + }; + + return securityAlertResponse; + } + }) + .then((securityAlertResponse) => { + updateSecurityAlertResponseByTxId(req, { + ...securityAlertResponse, + securityAlertId, + }); + }); if (SIGNING_METHODS.includes(req.method)) { req.securityAlertResponse = { + reason: BlockaidResultType.Loading, + result_type: BlockaidReason.inProgress, securityAlertId, }; appStateController.addSignatureSecurityAlertResponse({ diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index 55a3794c7734..6a0f4cc9bcf2 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -135,8 +135,6 @@ describe('Transaction metrics', () => { gas_edit_type: 'none', network: mockNetworkId, referrer: ORIGIN_METAMASK, - security_alert_reason: BlockaidReason.notApplicable, - security_alert_response: BlockaidReason.notApplicable, source: MetaMetricsTransactionEventSource.User, status: 'unapproved', token_standard: TokenStandard.none, diff --git a/app/scripts/lib/transaction/metrics.ts b/app/scripts/lib/transaction/metrics.ts index 1d76e70c46e0..a9c601ef4566 100644 --- a/app/scripts/lib/transaction/metrics.ts +++ b/app/scripts/lib/transaction/metrics.ts @@ -25,6 +25,7 @@ import { MetaMetricsEventCategory, MetaMetricsEventFragment, MetaMetricsEventName, + MetaMetricsEventUiCustomization, MetaMetricsPageObject, MetaMetricsReferrerObject, } from '../../../../shared/constants/metametrics'; @@ -35,11 +36,7 @@ import { TRANSACTION_ENVELOPE_TYPE_NAMES, } from '../../../../shared/lib/transactions-controller-utils'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) -import { - BlockaidReason, - BlockaidResultType, -} from '../../../../shared/constants/security-provider'; -import { getBlockaidMetricsParams } from '../../../../ui/helpers/utils/metrics'; +import { getBlockaidMetricsProps } from '../../../../ui/helpers/utils/metrics'; ///: END:ONLY_INCLUDE_IF import { getSnapAndHardwareInfoForMetrics, @@ -763,9 +760,6 @@ async function buildEventFragmentProperties({ finalApprovalAmount, contractMethodName, securityProviderResponse, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - securityAlertResponse, - ///: END:ONLY_INCLUDE_IF simulationFails, } = transactionMeta; const query = new EthQuery(transactionMetricsRequest.provider); @@ -928,37 +922,30 @@ async function buildEventFragmentProperties({ } } - let uiCustomizations; - let additionalBlockaidParams; + const uiCustomizations = []; + /** securityProviderResponse is used by the OpenSea <> Blockaid provider */ // eslint-disable-next-line no-lonely-if if (securityProviderResponse?.flagAsDangerous === 1) { - uiCustomizations = ['flagged_as_malicious']; + uiCustomizations.push(MetaMetricsEventUiCustomization.FlaggedAsMalicious); } else if (securityProviderResponse?.flagAsDangerous === 2) { - uiCustomizations = ['flagged_as_safety_unknown']; - } else { - uiCustomizations = null; + uiCustomizations.push( + MetaMetricsEventUiCustomization.FlaggedAsSafetyUnknown, + ); } ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - if (securityAlertResponse?.result_type === BlockaidResultType.Failed) { - uiCustomizations = ['security_alert_failed']; - } else { - additionalBlockaidParams = getBlockaidMetricsParams( - securityAlertResponse as any, - ); - uiCustomizations = additionalBlockaidParams?.ui_customizations ?? null; - } + const blockaidProperties: any = getBlockaidMetricsProps(transactionMeta); + if (blockaidProperties?.ui_customizations?.length > 0) { + uiCustomizations.push(...blockaidProperties.ui_customizations); + } ///: END:ONLY_INCLUDE_IF if (simulationFails) { - if (uiCustomizations === null) { - uiCustomizations = ['gas_estimation_failed']; - } else { - uiCustomizations.push('gas_estimation_failed'); - } + uiCustomizations.push(MetaMetricsEventUiCustomization.GasEstimationFailed); } + /** The transaction status property is not considered sensitive and is now included in the non-anonymous event */ let properties = { chain_id: chainId, @@ -969,6 +956,7 @@ async function buildEventFragmentProperties({ eip_1559_version: eip1559Version, gas_edit_type: 'none', gas_edit_attempted: 'none', + gas_estimation_failed: Boolean(simulationFails), account_type: await transactionMetricsRequest.getAccountType( transactionMetricsRequest.getSelectedAddress(), ), @@ -979,15 +967,11 @@ async function buildEventFragmentProperties({ token_standard: tokenStandard, transaction_type: transactionType, transaction_speed_up: type === TransactionType.retry, - ...additionalBlockaidParams, - ui_customizations: uiCustomizations?.length > 0 ? uiCustomizations : null, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - security_alert_response: - securityAlertResponse?.result_type ?? BlockaidResultType.NotApplicable, - security_alert_reason: - securityAlertResponse?.reason ?? BlockaidReason.notApplicable, + ...blockaidProperties, ///: END:ONLY_INCLUDE_IF - gas_estimation_failed: Boolean(simulationFails), + // ui_customizations must come after ...blockaidProperties + ui_customizations: uiCustomizations.length > 0 ? uiCustomizations : null, } as Record; const snapAndHardwareInfo = await getSnapAndHardwareInfoForMetrics( diff --git a/app/scripts/lib/transaction/util.ts b/app/scripts/lib/transaction/util.ts index 4aab8e8fa0f1..cb621794a08f 100644 --- a/app/scripts/lib/transaction/util.ts +++ b/app/scripts/lib/transaction/util.ts @@ -160,28 +160,32 @@ export async function addTransaction( const securityAlertId = uuid(); - ppomController.usePPOM(async (ppom) => { - try { - const securityAlertResponse = await ppom.validateJsonRpc(ppomRequest); - updateSecurityAlertResponseByTxId( - request.transactionOptions, - securityAlertResponse, - ); - } catch (e) { - captureException(e); - console.error('Error validating JSON RPC using PPOM: ', e); - const securityAlertResponse = { - result_type: BlockaidResultType.Failed, - reason: BlockaidReason.failed, - description: - 'Validating the confirmation failed by throwing error.', - }; - updateSecurityAlertResponseByTxId( - request.transactionOptions, - securityAlertResponse, - ); - } - }); + ppomController + .usePPOM(async (ppom) => { + try { + const securityAlertResponse = await ppom.validateJsonRpc( + ppomRequest, + ); + return securityAlertResponse; + } catch (e) { + captureException(e); + console.error('Error validating JSON RPC using PPOM: ', e); + const securityAlertResponse = { + securityAlertId, + result_type: BlockaidResultType.Failed, + reason: BlockaidReason.failed, + description: + 'Validating the confirmation failed by throwing error.', + }; + return securityAlertResponse; + } + }) + .then((securityAlertResponse) => { + updateSecurityAlertResponseByTxId(request.transactionOptions, { + ...securityAlertResponse, + securityAlertId, + }); + }); request.transactionOptions.securityAlertResponse = { reason: BlockaidResultType.Loading, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ce5ed0961540..64989ab83d6c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -4717,6 +4717,9 @@ export default class MetamaskController extends EventEmitter { 'AccountsController:getSelectedAccount', ], }), + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) + appStateController: this.appStateController, + ///: END:ONLY_INCLUDE_IF }), ); diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 9820fa70c36c..fa3c9c2f7ad1 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -492,6 +492,11 @@ export const REJECT_NOTIFICATION_CLOSE = 'Cancel Via Notification Close'; export const REJECT_NOTIFICATION_CLOSE_SIG = 'Cancel Sig Request Via Notification Close'; +/** + * The name of the event. Event definitions with corresponding properties can be found in the following document: + * + * @see {@link https://www.notion.so/f2997ab32326441793ff790ba5c60a6a?v=267d984721cd4a26be610b5caa3e25b7&pvs=4} + */ export enum MetaMetricsEventName { AccountAdded = 'Account Added', AccountAddSelected = 'Account Add Selected', @@ -754,7 +759,9 @@ export enum MetaMetricsEventLocation { export enum MetaMetricsEventUiCustomization { FlaggedAsMalicious = 'flagged_as_malicious', FlaggedAsSafetyUnknown = 'flagged_as_safety_unknown', + FlaggedAsWarning = 'flagged_as_warning', GasEstimationFailed = 'gas_estimation_failed', + SecurityAlertFailed = 'security_alert_failed', Siwe = 'sign_in_with_ethereum', } diff --git a/test/e2e/tests/metrics/signature-approved.spec.js b/test/e2e/tests/metrics/signature-approved.spec.js index bde3c6519d7f..274f1d2ba117 100644 --- a/test/e2e/tests/metrics/signature-approved.spec.js +++ b/test/e2e/tests/metrics/signature-approved.spec.js @@ -73,6 +73,7 @@ describe('Signature Approved Event @no-mmi', function () { await validateContractDetails(driver); await clickSignOnSignatureConfirmation(driver); const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].properties, { account_type: 'MetaMask', signature_type: 'eth_signTypedData_v4', @@ -83,6 +84,7 @@ describe('Signature Approved Event @no-mmi', function () { security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', }); + assert.deepStrictEqual(events[1].properties, { account_type: 'MetaMask', signature_type: 'eth_signTypedData_v4', @@ -90,7 +92,6 @@ describe('Signature Approved Event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'background', - security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', }); }, @@ -138,7 +139,6 @@ describe('Signature Approved Event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'background', - security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', }); }, @@ -185,7 +185,6 @@ describe('Signature Approved Event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'background', - security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', }); }, @@ -232,7 +231,6 @@ describe('Signature Approved Event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'background', - security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', }); }, @@ -288,7 +286,6 @@ describe('Signature Approved Event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'background', - security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', }); }, diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js index f736d52b510b..9c83a0457250 100644 --- a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js @@ -9,6 +9,7 @@ import { Severity, } from '../../../../helpers/constants/design-system'; import { I18nContext } from '../../../../contexts/i18n'; +import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment'; import { BlockaidReason, BlockaidResultType, @@ -57,6 +58,7 @@ function BlockaidBannerAlert({ txData, ...props }) { txData; const t = useContext(I18nContext); + const { updateTransactionEventFragment } = useTransactionEventFragment(); if ( !securityAlertResponse || @@ -121,6 +123,17 @@ function BlockaidBannerAlert({ txData, ...props }) { const reportUrl = getReportUrl(encodedData); + const onClickSupportLink = () => { + updateTransactionEventFragment( + { + properties: { + external_link_clicked: 'security_alert_support_link', + }, + }, + txData.id, + ); + }; + return ( ); diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js index 93b46dc35c16..6b64bdca2572 100644 --- a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js @@ -1,7 +1,9 @@ import React from 'react'; import * as Sentry from '@sentry/browser'; -import { renderWithLocalization } from '../../../../../test/lib/render-helpers'; +import { fireEvent, screen } from '@testing-library/react'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import { Severity } from '../../../../helpers/constants/design-system'; +import configureStore from '../../../../store/store'; import { BlockaidReason, BlockaidResultType, @@ -13,6 +15,18 @@ jest.mock('zlib', () => ({ gzipSync: (val) => val, })); +const mockUpdateTransactionEventFragment = jest.fn(); + +jest.mock('../../../../hooks/useTransactionEventFragment', () => { + return { + useTransactionEventFragment: () => { + return { + updateTransactionEventFragment: mockUpdateTransactionEventFragment, + }; + }, + }; +}); + const mockSecurityAlertResponse = { result_type: BlockaidResultType.Warning, reason: BlockaidReason.setApprovalForAll, @@ -26,19 +40,20 @@ const mockSecurityAlertResponse = { describe('Blockaid Banner Alert', () => { it('should not render when securityAlertResponse is not present', () => { - const { container } = renderWithLocalization( + const { container } = renderWithProvider( , + configureStore(), ); expect(container.querySelector('.mm-banner-alert')).toBeNull(); }); it(`should not render when securityAlertResponse.result_type is '${BlockaidResultType.Benign}'`, () => { - const { container } = renderWithLocalization( + const { container } = renderWithProvider( { }, }} />, + configureStore(), ); expect(container.querySelector('.mm-banner-alert')).toBeNull(); }); it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Failed}`, () => { - const { container } = renderWithLocalization( + const { container } = renderWithProvider( { }, }} />, + configureStore(), ); const warningBannerAlert = container.querySelector( '.mm-banner-alert--severity-warning', @@ -72,12 +89,13 @@ describe('Blockaid Banner Alert', () => { }); it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Warning}`, () => { - const { container } = renderWithLocalization( + const { container } = renderWithProvider( , + configureStore(), ); const warningBannerAlert = container.querySelector( '.mm-banner-alert--severity-warning', @@ -88,7 +106,7 @@ describe('Blockaid Banner Alert', () => { }); it(`should render '${Severity.Danger}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Malicious}`, () => { - const { container } = renderWithLocalization( + const { container } = renderWithProvider( { }, }} />, + configureStore(), ); const dangerBannerAlert = container.querySelector( '.mm-banner-alert--severity-danger', @@ -107,19 +126,20 @@ describe('Blockaid Banner Alert', () => { }); it('should render title, "This is a deceptive request"', () => { - const { getByText } = renderWithLocalization( + const { getByText } = renderWithProvider( , + configureStore(), ); expect(getByText('This is a deceptive request')).toBeInTheDocument(); }); it(`should render title, "This is a suspicious request", when the reason is "${BlockaidReason.failed}"`, () => { - const { getByText } = renderWithLocalization( + const { getByText } = renderWithProvider( { }, }} />, + configureStore(), ); expect(getByText('Request may not be safe')).toBeInTheDocument(); }); it(`should render title, "This is a suspicious request", when the reason is "${BlockaidReason.rawSignatureFarming}"`, () => { - const { getByText } = renderWithLocalization( + const { getByText } = renderWithProvider( { }, }} />, + configureStore(), ); expect(getByText('This is a suspicious request')).toBeInTheDocument(); @@ -154,7 +176,7 @@ describe('Blockaid Banner Alert', () => { 'Operator is untrusted according to previous activity', ]; - const { container, getByText } = renderWithLocalization( + const { container, getByText } = renderWithProvider( { }, }} />, + configureStore(), ); expect(container).toMatchSnapshot(); @@ -173,13 +196,14 @@ describe('Blockaid Banner Alert', () => { }); it('should render details section even when features is not provided', () => { - const { container } = renderWithLocalization( + const { container } = renderWithProvider( , + configureStore(), ); expect(container).toMatchSnapshot(); @@ -187,13 +211,14 @@ describe('Blockaid Banner Alert', () => { }); it('should render link to report url', () => { - const { container, getByText, getByRole } = renderWithLocalization( + const { container, getByText, getByRole } = renderWithProvider( , + configureStore(), ); expect(container).toMatchSnapshot(); @@ -204,13 +229,14 @@ describe('Blockaid Banner Alert', () => { }); it('should pass required data in Report an issue URL', () => { - const { getByRole } = renderWithLocalization( + const { getByRole } = renderWithProvider( , + configureStore(), ); const elm = getByRole('link', { name: 'Report an issue' }); @@ -249,7 +275,7 @@ describe('Blockaid Banner Alert', () => { 'If you approve this request, a third party known for scams will take all your assets.', }).forEach(([reason, expectedDescription]) => { it(`should render for '${reason}' correctly`, () => { - const { getByText } = renderWithLocalization( + const { getByText } = renderWithProvider( { }, }} />, + configureStore(), ); expect(getByText(expectedDescription)).toBeInTheDocument(); @@ -269,7 +296,7 @@ describe('Blockaid Banner Alert', () => { it('renders the "other" description translation and logs a Sentry exception', () => { const stubOtherDescription = 'If you approve this request, you might lose your assets.'; - const { getByText } = renderWithLocalization( + const { getByText } = renderWithProvider( { }, }} />, + configureStore(), ); expect(getByText(stubOtherDescription)).toBeInTheDocument(); expect(Sentry.captureException).toHaveBeenCalledTimes(1); }); }); + + describe('when clicking "See details" > "Report an issue"', () => { + it('calls updateTransactionEventFragment to add "external_link_clicked" prop to metric', () => { + const stubScrollIntoView = jest.fn(); + const originalScrollIntoView = + window.HTMLElement.prototype.scrollIntoView; + window.HTMLElement.prototype.scrollIntoView = stubScrollIntoView; + + renderWithProvider( + , + configureStore(), + ); + + fireEvent.click(screen.queryByText('See details')); + fireEvent.click(screen.queryByText('Report an issue')); + + expect(mockUpdateTransactionEventFragment).toHaveBeenCalledTimes(1); + expect(mockUpdateTransactionEventFragment).toHaveBeenCalledWith( + { + properties: { + external_link_clicked: 'security_alert_support_link', + }, + }, + '1', + ); + window.HTMLElement.prototype.scrollIntoView = originalScrollIntoView; + }); + }); }); diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js index 8a03537c7ba3..6c95907dad53 100644 --- a/ui/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/components/app/signature-request-original/signature-request-original.component.js @@ -45,10 +45,6 @@ import { } from '../../component-library'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) -import { - MetaMetricsEventCategory, - MetaMetricsEventName, -} from '../../../../shared/constants/metametrics'; import BlockaidBannerAlert from '../security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; ///: END:ONLY_INCLUDE_IF @@ -152,20 +148,6 @@ export default class SignatureRequestOriginal extends Component { rows = [{ name: this.context.t('message'), value: data }]; } - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const onClickSupportLink = () => { - this.context.trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.ExternalLinkClicked, - properties: { - action: 'Sign Request', - origin: txData?.origin, - external_link_clicked: 'security_alert_support_link', - }, - }); - }; - ///: END:ONLY_INCLUDE_IF - const targetSubjectMetadata = txData.msgParams.origin ? subjectMetadata?.[txData.msgParams.origin] : null; @@ -174,11 +156,7 @@ export default class SignatureRequestOriginal extends Component {
{ ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - + ///: END:ONLY_INCLUDE_IF } {isSuspiciousResponse(txData?.securityProviderResponse) && ( diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe.js b/ui/components/app/signature-request-siwe/signature-request-siwe.js index 9d97dcf2df51..cca280868ad3 100644 --- a/ui/components/app/signature-request-siwe/signature-request-siwe.js +++ b/ui/components/app/signature-request-siwe/signature-request-siwe.js @@ -1,11 +1,4 @@ -import React, { - useCallback, - useContext, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - useEffect, - ///: END:ONLY_INCLUDE_IF - useState, -} from 'react'; +import React, { useCallback, useContext, useState } from 'react'; import PropTypes from 'prop-types'; import { useSelector, useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; @@ -47,12 +40,6 @@ import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-pa import { getMostRecentOverviewPage } from '../../../ducks/history/history'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import BlockaidBannerAlert from '../security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -import { getBlockaidMetricsParams } from '../../../helpers/utils/metrics'; -import { MetaMetricsContext } from '../../../contexts/metametrics'; -import { - MetaMetricsEventCategory, - MetaMetricsEventName, -} from '../../../../shared/constants/metametrics'; ///: END:ONLY_INCLUDE_IF import LedgerInstructionField from '../ledger-instruction-field'; @@ -70,40 +57,6 @@ export default function SignatureRequestSIWE({ txData }) { const messagesList = useSelector(unconfirmedMessagesHashSelector); const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const trackEvent = useContext(MetaMetricsContext); - - useEffect(() => { - if (txData.securityAlertResponse) { - const blockaidMetricsParams = getBlockaidMetricsParams( - txData.securityAlertResponse, - ); - - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.SignatureRequested, - properties: { - action: 'Sign Request', - ...blockaidMetricsParams, - }, - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const onClickSupportLink = useCallback(() => { - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.ExternalLinkClicked, - properties: { - action: 'Sign Request SIWE', - origin: txData?.origin, - external_link_clicked: 'security_alert_support_link', - }, - }); - }, [trackEvent, txData?.origin]); - ///: END:ONLY_INCLUDE_IF - const { msgParams: { from, @@ -180,11 +133,7 @@ export default function SignatureRequestSIWE({ txData }) { { ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - + ///: END:ONLY_INCLUDE_IF } {showSecurityProviderBanner && ( diff --git a/ui/components/app/signature-request/signature-request.js b/ui/components/app/signature-request/signature-request.js index 5a666166058a..874f89485f2b 100644 --- a/ui/components/app/signature-request/signature-request.js +++ b/ui/components/app/signature-request/signature-request.js @@ -1,11 +1,4 @@ -import React, { - useContext, - useState, - useEffect, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - useCallback, - ///: END:ONLY_INCLUDE_IF -} from 'react'; +import React, { useContext, useState, useEffect } from 'react'; import { useDispatch, useSelector, @@ -56,7 +49,7 @@ import ContractDetailsModal from '../modals/contract-details-modal'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { MetaMetricsEventCategory, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi,blockaid) + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) MetaMetricsEventName, ///: END:ONLY_INCLUDE_IF } from '../../../../shared/constants/metametrics'; @@ -162,21 +155,6 @@ const SignatureRequest = ({ txData }) => { return { sanitizedMessage, domain, primaryType }; }); - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const onClickSupportLink = useCallback(() => { - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.ExternalLinkClicked, - properties: { - action: 'Sign Request', - type, - version, - external_link_clicked: 'security_alert_support_link', - }, - }); - }, [trackEvent, type, version]); - ///: END:ONLY_INCLUDE_IF - const onSign = async () => { ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) if (accountType === 'custody') { @@ -272,7 +250,6 @@ const SignatureRequest = ({ txData }) => { marginLeft={4} marginRight={4} marginBottom={4} - onClickSupportLink={onClickSupportLink} /> ///: END:ONLY_INCLUDE_IF } diff --git a/ui/components/app/terms-of-use-popup/terms-of-use-popup.test.js b/ui/components/app/terms-of-use-popup/terms-of-use-popup.test.js index 02125e981ccd..5373308337d1 100644 --- a/ui/components/app/terms-of-use-popup/terms-of-use-popup.test.js +++ b/ui/components/app/terms-of-use-popup/terms-of-use-popup.test.js @@ -34,15 +34,20 @@ describe('TermsOfUsePopup', () => { }); it('scrolls down when handleScrollDownClick is called', () => { - render(); const mockScrollIntoView = jest.fn(); + const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; window.HTMLElement.prototype.scrollIntoView = mockScrollIntoView; + + render(); const button = document.querySelector( "[data-testid='popover-scroll-button']", ); + fireEvent.click(button); expect(mockScrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth', }); + + window.HTMLElement.prototype.scrollIntoView = originalScrollIntoView; }); }); diff --git a/ui/components/app/transaction-alerts/transaction-alerts.js b/ui/components/app/transaction-alerts/transaction-alerts.js index a38d068ca2c8..92e8792ea147 100644 --- a/ui/components/app/transaction-alerts/transaction-alerts.js +++ b/ui/components/app/transaction-alerts/transaction-alerts.js @@ -1,9 +1,4 @@ -import React, { - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - useCallback, - useContext, - ///: END:ONLY_INCLUDE_IF -} from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { TransactionType } from '@metamask/transaction-controller'; @@ -15,9 +10,6 @@ import { BannerAlert, ButtonLink, Text } from '../../component-library'; import SimulationErrorMessage from '../../ui/simulation-error-message'; import { SEVERITIES } from '../../../helpers/constants/design-system'; import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; -///: BEGIN:ONLY_INCLUDE_IF(blockaid) -import { MetaMetricsContext } from '../../../contexts/metametrics'; -///: END:ONLY_INCLUDE_IF import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) @@ -27,12 +19,6 @@ import SecurityProviderBannerMessage from '../security-provider-banner-message/s import { getNativeCurrency } from '../../../ducks/metamask/metamask'; import { parseStandardTokenTransactionData } from '../../../../shared/modules/transaction.utils'; import { getTokenValueParam } from '../../../../shared/lib/metamask-controller-utils'; -///: BEGIN:ONLY_INCLUDE_IF(blockaid) -import { - MetaMetricsEventCategory, - MetaMetricsEventName, -} from '../../../../shared/constants/metametrics'; -///: END:ONLY_INCLUDE_IF const TransactionAlerts = ({ userAcknowledgedGasMissing, @@ -69,30 +55,11 @@ const TransactionAlerts = ({ hasProperTxType && (currentTokenAmount === '0x0' || currentTokenAmount === '0'); - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const trackEvent = useContext(MetaMetricsContext); - - const onClickSupportLink = useCallback(() => { - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.ExternalLinkClicked, - properties: { - action: 'Confirm Screen', - origin: txData?.origin, - external_link_clicked: 'security_alert_support_link', - }, - }); - }, [trackEvent, txData?.origin]); - ///: END:ONLY_INCLUDE_IF - return (
{ ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - + ///: END:ONLY_INCLUDE_IF } {isSuspiciousResponse(txData?.securityProviderResponse) && ( diff --git a/ui/helpers/utils/metric.test.js b/ui/helpers/utils/metric.test.js deleted file mode 100644 index 5dbfb8ced832..000000000000 --- a/ui/helpers/utils/metric.test.js +++ /dev/null @@ -1,77 +0,0 @@ -import { - BlockaidReason, - BlockaidResultType, -} from '../../../shared/constants/security-provider'; -import { getBlockaidMetricsParams, getMethodName } from './metrics'; - -describe('getMethodName', () => { - it('should get correct method names', () => { - expect(getMethodName(undefined)).toStrictEqual(''); - expect(getMethodName({})).toStrictEqual(''); - expect(getMethodName('confirm')).toStrictEqual('confirm'); - expect(getMethodName('balanceOf')).toStrictEqual('balance Of'); - expect(getMethodName('ethToTokenSwapInput')).toStrictEqual( - 'eth To Token Swap Input', - ); - }); -}); - -describe('getBlockaidMetricsParams', () => { - it('should return empty object when securityAlertResponse is not defined', () => { - const result = getBlockaidMetricsParams(undefined); - expect(result).toStrictEqual({}); - }); - - it('should return additionalParams object when securityAlertResponse defined', () => { - const securityAlertResponse = { - result_type: BlockaidResultType.Malicious, - reason: BlockaidReason.notApplicable, - providerRequestsCount: { - eth_call: 5, - eth_getCode: 3, - }, - features: [], - }; - - const result = getBlockaidMetricsParams(securityAlertResponse); - expect(result).toStrictEqual({ - ui_customizations: ['flagged_as_malicious'], - security_alert_response: BlockaidResultType.Malicious, - security_alert_reason: BlockaidReason.notApplicable, - ppom_eth_call_count: 5, - ppom_eth_getCode_count: 3, - }); - }); - - it('should not return eth call counts if providerRequestsCount is empty', () => { - const securityAlertResponse = { - result_type: BlockaidResultType.Malicious, - reason: BlockaidReason.notApplicable, - features: [], - providerRequestsCount: {}, - }; - - const result = getBlockaidMetricsParams(securityAlertResponse); - expect(result).toStrictEqual({ - ui_customizations: ['flagged_as_malicious'], - security_alert_response: BlockaidResultType.Malicious, - security_alert_reason: BlockaidReason.notApplicable, - }); - }); - - it('should not return eth call counts if providerRequestsCount is undefined', () => { - const securityAlertResponse = { - result_type: BlockaidResultType.Malicious, - reason: BlockaidReason.notApplicable, - features: [], - providerRequestsCount: undefined, - }; - - const result = getBlockaidMetricsParams(securityAlertResponse); - expect(result).toStrictEqual({ - ui_customizations: ['flagged_as_malicious'], - security_alert_response: BlockaidResultType.Malicious, - security_alert_reason: BlockaidReason.notApplicable, - }); - }); -}); diff --git a/ui/helpers/utils/metrics.js b/ui/helpers/utils/metrics.js index 4c8b2a2ae871..8902f1bed336 100644 --- a/ui/helpers/utils/metrics.js +++ b/ui/helpers/utils/metrics.js @@ -3,6 +3,7 @@ import { BlockaidReason, BlockaidResultType, } from '../../../shared/constants/security-provider'; +import { MetaMetricsEventUiCustomization } from '../../../shared/constants/metametrics'; ///: END:ONLY_INCLUDE_IF export function getMethodName(camelCase) { @@ -25,42 +26,61 @@ export function formatAccountType(accountType) { } ///: BEGIN:ONLY_INCLUDE_IF(blockaid) -export const getBlockaidMetricsParams = (securityAlertResponse = null) => { - const additionalParams = {}; +/** + * Returns the ui_customization string value based on the result type + * + * @param {BlockaidResultType} resultType + * @returns {MetaMetricsEventUiCustomization} + */ +const getBlockaidMetricUiCustomization = (resultType) => { + let uiCustomization; - if (securityAlertResponse) { - const { - result_type: resultType, - reason, - providerRequestsCount, - } = securityAlertResponse; + if (resultType === BlockaidResultType.Failed) { + uiCustomization = [MetaMetricsEventUiCustomization.SecurityAlertFailed]; + } else if (resultType === BlockaidResultType.Malicious) { + uiCustomization = [MetaMetricsEventUiCustomization.FlaggedAsMalicious]; + } else if (resultType === BlockaidResultType.Warning) { + uiCustomization = [MetaMetricsEventUiCustomization.FlaggedAsWarning]; + } + + return uiCustomization; +}; - if (resultType === BlockaidResultType.Malicious) { - additionalParams.ui_customizations = ['flagged_as_malicious']; - } +/** + * @param {import('@metamask/transaction-controller').TransactionMeta} transactionMeta + * @returns {object} + */ +export const getBlockaidMetricsProps = ({ securityAlertResponse }) => { + if (!securityAlertResponse) { + return {}; + } - if (resultType === BlockaidResultType.Failed) { - additionalParams.ui_customizations = ['security_alert_failed']; - } + const params = {}; + const { + providerRequestsCount, + reason, + result_type: resultType, + } = securityAlertResponse; - if (resultType !== BlockaidResultType.Benign) { - additionalParams.security_alert_reason = BlockaidReason.notApplicable; + const uiCustomization = getBlockaidMetricUiCustomization(resultType); + if (uiCustomization) { + params.ui_customizations = uiCustomization; + } - if (reason) { - additionalParams.security_alert_response = resultType; - additionalParams.security_alert_reason = reason; - } - } + if (resultType !== BlockaidResultType.Benign) { + params.security_alert_reason = reason ?? BlockaidReason.notApplicable; + } + params.security_alert_response = + resultType ?? BlockaidResultType.NotApplicable; - // add counts of each RPC call - if (providerRequestsCount) { - Object.keys(providerRequestsCount).forEach((key) => { - const metricKey = `ppom_${key}_count`; - additionalParams[metricKey] = providerRequestsCount[key]; - }); - } + // add counts of each RPC call + if (providerRequestsCount) { + Object.keys(providerRequestsCount).forEach((key) => { + const metricKey = `ppom_${key}_count`; + params[metricKey] = providerRequestsCount[key]; + }); } - return additionalParams; + return params; }; ///: END:ONLY_INCLUDE_IF diff --git a/ui/helpers/utils/metrics.test.js b/ui/helpers/utils/metrics.test.js new file mode 100644 index 000000000000..b75f5b7b2693 --- /dev/null +++ b/ui/helpers/utils/metrics.test.js @@ -0,0 +1,164 @@ +import { + BlockaidReason, + BlockaidResultType, +} from '../../../shared/constants/security-provider'; +import { getBlockaidMetricsProps, getMethodName } from './metrics'; + +describe('getMethodName', () => { + it('gets correct method names', () => { + expect(getMethodName(undefined)).toStrictEqual(''); + expect(getMethodName({})).toStrictEqual(''); + expect(getMethodName('confirm')).toStrictEqual('confirm'); + expect(getMethodName('balanceOf')).toStrictEqual('balance Of'); + expect(getMethodName('ethToTokenSwapInput')).toStrictEqual( + 'eth To Token Swap Input', + ); + }); +}); + +const securityAlertResponse = { + result_type: BlockaidResultType.Malicious, + reason: BlockaidReason.setApprovalForAll, + features: [], +}; + +describe('getBlockaidMetricsProps', () => { + it('returns an empty object when securityAlertResponse is not defined', () => { + const result = getBlockaidMetricsProps({}); + expect(result).toStrictEqual({}); + }); + + it('returns metric props when securityAlertResponse defined', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse, + }); + expect(result).toStrictEqual({ + security_alert_reason: BlockaidReason.setApprovalForAll, + security_alert_response: BlockaidResultType.Malicious, + ui_customizations: ['flagged_as_malicious'], + }); + }); + + it('includes not applicable reason or result type when they are not provided', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + reason: null, + result_type: null, + }, + }); + + expect(result.security_alert_reason).toBe(BlockaidReason.notApplicable); + expect(result.security_alert_response).toBe( + BlockaidResultType.NotApplicable, + ); + }); + + it('includes "security_alert_failed" ui_customization when type is failed', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + result_type: BlockaidResultType.Failed, + }, + }); + + expect(result).toStrictEqual({ + security_alert_reason: BlockaidReason.setApprovalForAll, + security_alert_response: BlockaidResultType.Failed, + ui_customizations: ['security_alert_failed'], + }); + }); + + it('includes "flagged_as_malicious" ui_customization when type is malicious', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + result_type: BlockaidResultType.Malicious, + }, + }); + + expect(result).toStrictEqual({ + security_alert_reason: BlockaidReason.setApprovalForAll, + security_alert_response: BlockaidResultType.Malicious, + ui_customizations: ['flagged_as_malicious'], + }); + }); + + it('includes "flagged_as_warning" ui_customization when type is a warning', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + result_type: BlockaidResultType.Malicious, + }, + }); + + expect(result).toStrictEqual({ + security_alert_reason: BlockaidReason.setApprovalForAll, + security_alert_response: BlockaidResultType.Malicious, + ui_customizations: ['flagged_as_malicious'], + }); + }); + + it('excludes reason when type is benign', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + result_type: BlockaidResultType.Benign, + }, + }); + + expect(result).toStrictEqual({ + security_alert_response: BlockaidResultType.Benign, + }); + }); + + it('includes eth call counts when providerRequestsCount is provided', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + providerRequestsCount: { + eth_call: 5, + eth_getCode: 3, + }, + }, + }); + + expect(result).toStrictEqual({ + ppom_eth_call_count: 5, + ppom_eth_getCode_count: 3, + ui_customizations: ['flagged_as_malicious'], + security_alert_response: BlockaidResultType.Malicious, + security_alert_reason: BlockaidReason.setApprovalForAll, + }); + }); + + it('excludes eth call counts if providerRequestsCount is empty', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + providerRequestsCount: {}, + }, + }); + + expect(result).toStrictEqual({ + ui_customizations: ['flagged_as_malicious'], + security_alert_response: BlockaidResultType.Malicious, + security_alert_reason: BlockaidReason.setApprovalForAll, + }); + }); + + it('excludes eth call counts if providerRequestsCount is undefined', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + providerRequestsCount: undefined, + }, + }); + + expect(result).toStrictEqual({ + ui_customizations: ['flagged_as_malicious'], + security_alert_response: BlockaidResultType.Malicious, + security_alert_reason: BlockaidReason.setApprovalForAll, + }); + }); +}); diff --git a/ui/hooks/useTransactionEventFragment.js b/ui/hooks/useTransactionEventFragment.js index f304e5ebdeec..ea3a70cf5750 100644 --- a/ui/hooks/useTransactionEventFragment.js +++ b/ui/hooks/useTransactionEventFragment.js @@ -18,14 +18,16 @@ export const useTransactionEventFragment = () => { ); const updateTransactionEventFragment = useCallback( - async (params) => { - if (!transaction || !transaction.id) { + async (params, _transactionId) => { + const transactionId = _transactionId || transaction?.id; + + if (!transactionId) { return; } if (!fragment) { - await createTransactionEventFragment(transaction.id); + await createTransactionEventFragment(transactionId); } - updateEventFragment(`transaction-added-${transaction.id}`, params); + updateEventFragment(`transaction-added-${transactionId}`, params); }, [fragment, transaction], ); 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 8db0c3665862..0e0e37cb8898 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 @@ -21,10 +21,6 @@ import { ConfirmPageContainerWarning } from '../../../components/app/confirm-pag import LedgerInstructionField from '../../../components/app/ledger-instruction-field'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import BlockaidBannerAlert from '../../../components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -import { - MetaMetricsEventCategory, - MetaMetricsEventName, -} from '../../../../shared/constants/metametrics'; ///: END:ONLY_INCLUDE_IF import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils'; @@ -545,20 +541,6 @@ export default class ConfirmApproveContent extends Component { } = this.props; const { showFullTxDetails, setShowContractDetails } = this.state; - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const onClickSupportLink = () => { - this.context.trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.ExternalLinkClicked, - properties: { - action: 'Confirm Approve', - origin: txData?.origin, - external_link_clicked: 'security_alert_support_link', - }, - }); - }; - ///: END:ONLY_INCLUDE_IF - return (
{ ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - + ///: END:ONLY_INCLUDE_IF } {isSuspiciousResponse(txData?.securityProviderResponse) && ( diff --git a/ui/pages/token-allowance/token-allowance.js b/ui/pages/token-allowance/token-allowance.js index 4c4fc9f4c97d..2a0224186ce6 100644 --- a/ui/pages/token-allowance/token-allowance.js +++ b/ui/pages/token-allowance/token-allowance.js @@ -64,11 +64,6 @@ import { isSuspiciousResponse } from '../../../shared/modules/security-provider. ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import BlockaidBannerAlert from '../../components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -import { MetaMetricsContext } from '../../contexts/metametrics'; -import { - MetaMetricsEventCategory, - MetaMetricsEventName, -} from '../../../shared/constants/metametrics'; ///: END:ONLY_INCLUDE_IF import { ConfirmPageContainerNavigation } from '../../components/app/confirm-page-container'; @@ -213,22 +208,6 @@ export default function TokenAllowance({ const networkName = NETWORK_TO_NAME_MAP[fullTxData.chainId] || networkIdentifier; - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const trackEvent = useContext(MetaMetricsContext); - - const onClickSupportLink = useCallback(() => { - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: MetaMetricsEventName.ExternalLinkClicked, - properties: { - action: 'Confirm Screen', - origin: txData?.origin, - external_link_clicked: 'security_alert_support_link', - }, - }); - }, [trackEvent, txData?.origin]); - ///: END:ONLY_INCLUDE_IF - const customNonceMerge = (transactionData) => customNonceValue ? { @@ -400,11 +379,7 @@ export default function TokenAllowance({ /> { ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - + ///: END:ONLY_INCLUDE_IF } {isSuspiciousResponse(txData?.securityProviderResponse) && ( From dcaec4d09fb2797b312cb579155c788c4f7f8921 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 16 Feb 2024 19:06:30 -0330 Subject: [PATCH 11/17] Cherry-pick 167036f (#22856) into v11.10.0 (#23023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: fix selectedAddress and nftController instantiation (#22856) Noticed that when you freshly import the extension, usse testDapp to deploy and mint an NFT, then manually import the NFT. you will be able to see the NFT. Then when you switch to another account and go back to the account that has the NFT; 1- you wont be able to see the NFTs you imported earlier 2- When you try to import them again you will get an error (fired from core when trying to verify ownership) Noticed that this was due to core having the wrong userAddress to check ownership for, and then in metamask.js, the selectedAddress retrieved does not match the user's selected Address This behavior is also reported to be on v11.10.0, on this issue: https://github.com/MetaMask/metamask-extension/issues/22796 Fixes: https://github.com/MetaMask/metamask-extension/issues/22796 Fixes: https://github.com/MetaMask/metamask-extension/issues/22798 1. Remove and reimport the extension 2. Use testDapp to deploy and mint the NFT 3. Add the NFT manually by clicking "import NFT" 4. You should be able to see your newly import NFT 5. Create new account 6. Go back to the account that has the NFT 7. You should be able to see the NFT you imported https://github.com/MetaMask/metamask-extension/assets/10994169/a74cbf0b-014b-4e39-82ac-e8452941fc6e https://github.com/MetaMask/metamask-extension/assets/10994169/987dbb27-b938-4bce-9b43-4269d714ee33 - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- ## **Description** ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Co-authored-by: sahar-fehri Co-authored-by: Monte Lai --- app/scripts/metamask-controller.js | 11 +++- test/e2e/tests/nft/import-nft.spec.js | 92 +++++++++++++++++++++++++++ ui/ducks/metamask/metamask.js | 9 ++- ui/store/actions.test.js | 7 ++ ui/store/actions.ts | 1 + 5 files changed, 114 insertions(+), 6 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 64989ab83d6c..dea79e72e80f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2827,10 +2827,10 @@ export default class MetamaskController extends EventEmitter { ), // PreferencesController setSelectedAddress: (address) => { - this.preferencesController.setSelectedAddress(address); const account = this.accountsController.getAccountByAddress(address); if (account) { this.accountsController.setSelectedAccount(account.id); + this.preferencesController.setSelectedAddress(address); } else { throw new Error(`No account found for address: ${address}`); } @@ -2875,8 +2875,13 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IF // AccountsController - setSelectedInternalAccount: - accountsController.setSelectedAccount.bind(accountsController), + setSelectedInternalAccount: (id) => { + const account = this.accountsController.getAccount(id); + if (account) { + this.preferencesController.setSelectedAddress(account.address); + this.accountsController.setSelectedAccount(id); + } + }, setAccountName: accountsController.setAccountName.bind(accountsController), diff --git a/test/e2e/tests/nft/import-nft.spec.js b/test/e2e/tests/nft/import-nft.spec.js index bf6f3114e62f..445d135d9f2a 100644 --- a/test/e2e/tests/nft/import-nft.spec.js +++ b/test/e2e/tests/nft/import-nft.spec.js @@ -3,6 +3,8 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + findAnotherAccountFromAccountList, + waitForAccountRendered, } = require('../../helpers'); const { SMART_CONTRACTS } = require('../../seeder/smart-contracts'); const FixtureBuilder = require('../../fixture-builder'); @@ -57,6 +59,96 @@ describe('Import NFT', function () { ); }); + it('should continue to display an imported NFT after importing, adding a new account, and switching back', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions: defaultGanacheOptions, + smartContract, + title: this.test.fullTitle(), + }, + async ({ driver, _, contractRegistry }) => { + const contractAddress = + contractRegistry.getContractAddress(smartContract); + await unlockWallet(driver); + + // After login, go to NFTs tab, open the import NFT form + await driver.clickElement('[data-testid="home__nfts-tab"]'); + await driver.clickElement({ text: 'Import NFT', tag: 'button' }); + + // Enter a valid NFT that belongs to user and check success message appears + await driver.fill('#address', contractAddress); + await driver.fill('#token-id', '1'); + await driver.clickElement( + '[data-testid="import-nfts-modal-import-button"]', + ); + + const newNftNotification = await driver.findElement({ + text: 'NFT was successfully added!', + tag: 'h6', + }); + assert.equal(await newNftNotification.isDisplayed(), true); + + // Check the imported NFT and its image are displayed in the NFT tab + const importedNft = await driver.waitForSelector({ + css: 'h5', + text: 'TestDappNFTs', + }); + const importedNftImage = await driver.findElement( + '.nft-item__container', + ); + assert.equal(await importedNft.isDisplayed(), true); + assert.equal(await importedNftImage.isDisplayed(), true); + + await driver.clickElement({ text: 'Tokens', tag: 'button' }); + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + await driver.clickElement({ text: 'Add a new account', tag: 'button' }); + + // set account name + await driver.fill('[placeholder="Account 2"]', '2nd account'); + await driver.delay(400); + await driver.clickElement({ text: 'Create', tag: 'button' }); + + await driver.isElementPresent({ + tag: 'span', + text: '2nd account', + }); + + const accountOneSelector = await findAnotherAccountFromAccountList( + driver, + 1, + 'Account 1', + ); + await waitForAccountRendered(driver); + await driver.clickElement(accountOneSelector); + + await driver.clickElement({ text: 'NFTs', tag: 'button' }); + const nftIsStillDisplayed = await driver.isElementPresentAndVisible({ + css: 'h5', + text: 'TestDappNFTs', + }); + const nftImageIsStillDisplayed = + await driver.isElementPresentAndVisible('.nft-item__container'); + assert.equal( + nftIsStillDisplayed, + true, + 'Nft is no longer displayed after adding an account and switching back to account 1', + ); + assert.equal( + nftImageIsStillDisplayed, + true, + 'Nft image is no longer displayed after adding an account and switching back to account 1', + ); + }, + ); + }); + it('should not be able to import an NFT that does not belong to user', async function () { await withFixtures( { diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 885fe50b7eb8..a198c5ff06bc 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -14,6 +14,7 @@ import { checkNetworkAndAccountSupports1559, getAddressBook, getSelectedNetworkClientId, + getSelectedInternalAccount, } from '../../selectors'; import * as actionConstants from '../../store/actionConstants'; import { updateTransactionGasFees } from '../../store/actions'; @@ -271,8 +272,10 @@ export function getNftsDropdownState(state) { export const getNfts = (state) => { const { - metamask: { allNfts, selectedAddress }, + metamask: { allNfts }, } = state; + const { address: selectedAddress } = getSelectedInternalAccount(state); + const { chainId } = getProviderConfig(state); return allNfts?.[selectedAddress]?.[chainId] ?? []; @@ -280,10 +283,10 @@ export const getNfts = (state) => { export const getNftContracts = (state) => { const { - metamask: { allNftContracts, selectedAddress }, + metamask: { allNftContracts }, } = state; + const { address: selectedAddress } = getSelectedInternalAccount(state); const { chainId } = getProviderConfig(state); - return allNftContracts?.[selectedAddress]?.[chainId] ?? []; }; diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index a2f74da3b759..61f7da4aa835 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -889,15 +889,20 @@ describe('Actions', () => { const setSelectedInternalAccountSpy = sinon .stub() .callsFake((_, cb) => cb()); + const setSelectedAddressSpy = sinon.stub().callsFake((_, cb) => cb()); background.getApi.returns({ setSelectedInternalAccount: setSelectedInternalAccountSpy, + setSelectedAddress: setSelectedAddressSpy, }); setBackgroundConnection(background.getApi()); await store.dispatch(actions.setSelectedAccount('0x123')); expect(setSelectedInternalAccountSpy.callCount).toStrictEqual(1); + expect(setSelectedInternalAccountSpy.calledWith('mock-id')).toBe(true); + expect(setSelectedAddressSpy.callCount).toStrictEqual(1); + expect(setSelectedAddressSpy.calledWith('0x123')).toBe(true); }); it('displays warning if setSelectedAccount throws', async () => { @@ -936,9 +941,11 @@ describe('Actions', () => { const setSelectedInternalAccountSpy = sinon .stub() .callsFake((_, cb) => cb(new Error('error'))); + const setSelectedAddressSpy = sinon.stub().callsFake((_, cb) => cb()); background.getApi.returns({ setSelectedInternalAccount: setSelectedInternalAccountSpy, + setSelectedAddress: setSelectedAddressSpy, }); setBackgroundConnection(background.getApi()); diff --git a/ui/store/actions.ts b/ui/store/actions.ts index a553a1e8cdf9..70e79d8e2315 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -1757,6 +1757,7 @@ export function setSelectedAccount( !currentTabIsConnectedToNextAddress; try { + await _setSelectedAddress(address); await _setSelectedInternalAccount(internalAccount.id); await forceUpdateMetamaskState(dispatch); } catch (error) { From 54b3eec81f331ad4d635424ab30fa483a60cc325 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Tue, 20 Feb 2024 15:18:37 +0100 Subject: [PATCH 12/17] resolve merge conflit --- app/scripts/lib/ppom/ppom-middleware.ts | 4 - lavamoat/browserify/beta/policy.json | 75 ---- lavamoat/browserify/desktop/policy.json | 75 ---- lavamoat/browserify/flask/policy.json | 75 ---- lavamoat/browserify/main/policy.json | 75 ---- lavamoat/browserify/mmi/policy.json | 75 ---- package.json | 3 - test/e2e/tests/nft/import-nft.spec.js | 8 - .../ppom-blockaid-alert-simple-send.spec.js | 6 - .../signature-request-siwe.js | 250 ----------- .../signature-request/signature-request.js | 393 ------------------ .../token-list-item/token-list-item.js | 8 - ...onfirm-page-container-content.component.js | 10 - .../blockaid-banner-alert.js | 30 -- .../blockaid-banner-alert.test.js | 10 - .../transaction-alerts/transaction-alerts.js | 17 - .../confirm-approve-content.component.js | 4 - .../confirm-transaction-base.component.js | 8 - .../confirm-transaction-base.container.js | 8 - .../token-allowance/token-allowance.js | 4 - yarn.lock | 21 - 21 files changed, 1159 deletions(-) delete mode 100644 ui/components/app/signature-request-siwe/signature-request-siwe.js delete mode 100644 ui/components/app/signature-request/signature-request.js diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index 5cb14504566b..4f742e4af078 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -9,11 +9,7 @@ import { } from '../../../../shared/constants/security-provider'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import { SIGNING_METHODS } from '../../../../shared/constants/transaction'; -<<<<<<< HEAD -import PreferencesController from '../../controllers/preferences'; -======= import { PreferencesController } from '../../controllers/preferences'; ->>>>>>> origin/develop import { SecurityAlertResponse } from '../transaction/util'; const { sentry } = global as any; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index f4ebd3e1ae55..c156a7b706b2 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -738,10 +738,6 @@ "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1491,23 +1487,6 @@ "uuid": true } }, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, -======= ->>>>>>> origin/develop "@metamask/logo": { "globals": { "addEventListener": true, @@ -1828,34 +1807,6 @@ "webpack>events": true } }, -<<<<<<< HEAD - "@metamask/signature-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/signature-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, -======= ->>>>>>> origin/develop "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -1894,10 +1845,6 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -3500,28 +3447,6 @@ "@metamask/ppom-validator>elliptic": true } }, -<<<<<<< HEAD - "globalthis>define-properties": { - "packages": { - "globalthis>define-properties>define-data-property": true, - "globalthis>define-properties>has-property-descriptors": true, - "globalthis>define-properties>object-keys": true - } - }, - "globalthis>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "globalthis>define-properties>has-property-descriptors": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true - } - }, -======= ->>>>>>> origin/develop "gulp>vinyl-fs>object.assign": { "packages": { "@lavamoat/lavapack>json-stable-stringify>object-keys": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 7bdd400db1a7..0388d2497a8c 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -738,10 +738,6 @@ "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1568,23 +1564,6 @@ "uuid": true } }, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, -======= ->>>>>>> origin/develop "@metamask/logo": { "globals": { "addEventListener": true, @@ -1969,34 +1948,6 @@ "webpack>events": true } }, -<<<<<<< HEAD - "@metamask/signature-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/signature-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, -======= ->>>>>>> origin/develop "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -2035,10 +1986,6 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -3757,28 +3704,6 @@ "@metamask/ppom-validator>elliptic": true } }, -<<<<<<< HEAD - "globalthis>define-properties": { - "packages": { - "globalthis>define-properties>define-data-property": true, - "globalthis>define-properties>has-property-descriptors": true, - "globalthis>define-properties>object-keys": true - } - }, - "globalthis>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "globalthis>define-properties>has-property-descriptors": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true - } - }, -======= ->>>>>>> origin/develop "gulp>vinyl-fs>object.assign": { "packages": { "@lavamoat/lavapack>json-stable-stringify>object-keys": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 5ae06626f7d1..88c78d04b032 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -738,10 +738,6 @@ "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1568,23 +1564,6 @@ "uuid": true } }, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, -======= ->>>>>>> origin/develop "@metamask/logo": { "globals": { "addEventListener": true, @@ -2005,34 +1984,6 @@ "webpack>events": true } }, -<<<<<<< HEAD - "@metamask/signature-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/signature-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, -======= ->>>>>>> origin/develop "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -2071,10 +2022,6 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -3793,28 +3740,6 @@ "@metamask/ppom-validator>elliptic": true } }, -<<<<<<< HEAD - "globalthis>define-properties": { - "packages": { - "globalthis>define-properties>define-data-property": true, - "globalthis>define-properties>has-property-descriptors": true, - "globalthis>define-properties>object-keys": true - } - }, - "globalthis>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "globalthis>define-properties>has-property-descriptors": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true - } - }, -======= ->>>>>>> origin/develop "gulp>vinyl-fs>object.assign": { "packages": { "@lavamoat/lavapack>json-stable-stringify>object-keys": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 5721a7174bd1..a84465a1832d 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -738,10 +738,6 @@ "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1491,23 +1487,6 @@ "uuid": true } }, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, -======= ->>>>>>> origin/develop "@metamask/logo": { "globals": { "addEventListener": true, @@ -1928,34 +1907,6 @@ "webpack>events": true } }, -<<<<<<< HEAD - "@metamask/signature-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/signature-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, -======= ->>>>>>> origin/develop "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -1994,10 +1945,6 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -3716,28 +3663,6 @@ "@metamask/ppom-validator>elliptic": true } }, -<<<<<<< HEAD - "globalthis>define-properties": { - "packages": { - "globalthis>define-properties>define-data-property": true, - "globalthis>define-properties>has-property-descriptors": true, - "globalthis>define-properties>object-keys": true - } - }, - "globalthis>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "globalthis>define-properties>has-property-descriptors": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true - } - }, -======= ->>>>>>> origin/develop "gulp>vinyl-fs>object.assign": { "packages": { "@lavamoat/lavapack>json-stable-stringify>object-keys": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 62780d695cb3..c2f3259316ee 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -870,10 +870,6 @@ "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1623,23 +1619,6 @@ "uuid": true } }, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>number-to-bn": true, - "bn.js": true - } - }, -======= ->>>>>>> origin/develop "@metamask/logo": { "globals": { "addEventListener": true, @@ -2024,34 +2003,6 @@ "webpack>events": true } }, -<<<<<<< HEAD - "@metamask/signature-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/signature-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, -======= ->>>>>>> origin/develop "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -2090,10 +2041,6 @@ "packages": { "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, -<<<<<<< HEAD - "@metamask/logging-controller>@metamask/controller-utils>ethjs-unit": true, -======= ->>>>>>> origin/develop "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, @@ -3812,28 +3759,6 @@ "@metamask/ppom-validator>elliptic": true } }, -<<<<<<< HEAD - "globalthis>define-properties": { - "packages": { - "globalthis>define-properties>define-data-property": true, - "globalthis>define-properties>has-property-descriptors": true, - "globalthis>define-properties>object-keys": true - } - }, - "globalthis>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "globalthis>define-properties>has-property-descriptors": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true - } - }, -======= ->>>>>>> origin/develop "gulp>vinyl-fs>object.assign": { "packages": { "@lavamoat/lavapack>json-stable-stringify>object-keys": true, diff --git a/package.json b/package.json index 0b8b2a32d82d..4f238f88a560 100644 --- a/package.json +++ b/package.json @@ -398,10 +398,7 @@ "@babel/preset-typescript": "^7.23.2", "@babel/register": "^7.22.15", "@lavamoat/allow-scripts": "^3.0.1", -<<<<<<< HEAD -======= "@lavamoat/lavadome-core": "0.0.10", ->>>>>>> origin/develop "@lavamoat/lavapack": "^6.1.0", "@metamask/auto-changelog": "^2.1.0", "@metamask/build-utils": "^1.0.0", diff --git a/test/e2e/tests/nft/import-nft.spec.js b/test/e2e/tests/nft/import-nft.spec.js index 3dcad74c95b1..be3254cfea52 100644 --- a/test/e2e/tests/nft/import-nft.spec.js +++ b/test/e2e/tests/nft/import-nft.spec.js @@ -103,10 +103,6 @@ describe('Import NFT', function () { assert.equal(await importedNft.isDisplayed(), true); assert.equal(await importedNftImage.isDisplayed(), true); -<<<<<<< HEAD - await driver.clickElement({ text: 'Tokens', tag: 'button' }); -======= ->>>>>>> origin/develop await driver.clickElement('[data-testid="account-menu-icon"]'); await driver.clickElement( '[data-testid="multichain-account-menu-popover-action-button"]', @@ -131,10 +127,6 @@ describe('Import NFT', function () { await waitForAccountRendered(driver); await driver.clickElement(accountOneSelector); -<<<<<<< HEAD - await driver.clickElement({ text: 'NFTs', tag: 'button' }); -======= ->>>>>>> origin/develop const nftIsStillDisplayed = await driver.isElementPresentAndVisible({ css: 'h5', text: 'TestDappNFTs', diff --git a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js index ceaa20dbdc6d..bf99c19c12c8 100644 --- a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js @@ -126,12 +126,6 @@ async function mockInfuraWithFailedResponses(mockServer) { * @see {@link https://wobbly-nutmeg-8a5.notion.site/MM-E2E-Testing-1e51b617f79240a49cd3271565c6e12d} */ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { -<<<<<<< HEAD - if (process.env.MULTICHAIN) { - return; - } -======= ->>>>>>> origin/develop it('should not show security alerts for benign requests', async function () { await withFixtures( { diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe.js b/ui/components/app/signature-request-siwe/signature-request-siwe.js deleted file mode 100644 index cca280868ad3..000000000000 --- a/ui/components/app/signature-request-siwe/signature-request-siwe.js +++ /dev/null @@ -1,250 +0,0 @@ -import React, { useCallback, useContext, useState } from 'react'; -import PropTypes from 'prop-types'; -import { useSelector, useDispatch } from 'react-redux'; -import { useHistory } from 'react-router-dom'; -import log from 'loglevel'; -import { isValidSIWEOrigin } from '@metamask/controller-utils'; -import { ethErrors, serializeError } from 'eth-rpc-errors'; -import { BannerAlert, Text } from '../../component-library'; -import Popover from '../../ui/popover'; -import Checkbox from '../../ui/check-box'; -import Button from '../../ui/button'; -import { I18nContext } from '../../../contexts/i18n'; -import { PageContainerFooter } from '../../ui/page-container'; -import { isAddressLedger } from '../../../ducks/metamask/metamask'; -import { - accountsWithSendEtherInfoSelector, - getSubjectMetadata, - getTotalUnapprovedMessagesCount, - unconfirmedMessagesHashSelector, -} from '../../../selectors'; -import { getAccountByAddress, valuesFor } from '../../../helpers/utils/util'; -import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils'; -import { formatMessageParams } from '../../../../shared/modules/siwe'; -import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'; - -import { - SEVERITIES, - TextVariant, -} from '../../../helpers/constants/design-system'; -import { - resolvePendingApproval, - rejectPendingApproval, - rejectAllMessages, - completedTx, - showModal, -} from '../../../store/actions'; - -import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message'; -import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation'; -import { getMostRecentOverviewPage } from '../../../ducks/history/history'; -///: BEGIN:ONLY_INCLUDE_IF(blockaid) -import BlockaidBannerAlert from '../security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -///: END:ONLY_INCLUDE_IF -import LedgerInstructionField from '../ledger-instruction-field'; - -import SignatureRequestHeader from '../signature-request-header'; -import Header from './signature-request-siwe-header'; -import Message from './signature-request-siwe-message'; - -export default function SignatureRequestSIWE({ txData }) { - const dispatch = useDispatch(); - const history = useHistory(); - const t = useContext(I18nContext); - const allAccounts = useSelector(accountsWithSendEtherInfoSelector); - const subjectMetadata = useSelector(getSubjectMetadata); - const messagesCount = useSelector(getTotalUnapprovedMessagesCount); - const messagesList = useSelector(unconfirmedMessagesHashSelector); - const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); - - const { - msgParams: { - from, - origin, - siwe: { parsedMessage }, - }, - id, - } = txData; - - const isLedgerWallet = useSelector((state) => isAddressLedger(state, from)); - - const fromAccount = getAccountByAddress(allAccounts, from); - const targetSubjectMetadata = subjectMetadata[origin]; - - const isMatchingAddress = - from.toLowerCase() === parsedMessage.address.toLowerCase(); - - const isSIWEDomainValid = isValidSIWEOrigin(txData.msgParams); - - const [isShowingDomainWarning, setIsShowingDomainWarning] = useState(false); - const [hasAgreedToDomainWarning, setHasAgreedToDomainWarning] = - useState(false); - - const showSecurityProviderBanner = isSuspiciousResponse( - txData?.securityProviderResponse, - ); - - const onSign = useCallback(async () => { - try { - await dispatch(resolvePendingApproval(id, null)); - dispatch(completedTx(id)); - } catch (e) { - log.error(e); - } - }, [id, dispatch]); - - const onCancel = useCallback(async () => { - try { - await dispatch( - rejectPendingApproval( - id, - serializeError(ethErrors.provider.userRejectedRequest()), - ), - ); - } catch (e) { - log.error(e); - } - }, [dispatch, id]); - - const handleCancelAll = () => { - const unapprovedTxCount = messagesCount; - - dispatch( - showModal({ - name: 'REJECT_TRANSACTIONS', - unapprovedTxCount, - onSubmit: async () => { - await dispatch(rejectAllMessages(valuesFor(messagesList))); - dispatch(clearConfirmTransaction()); - history.push(mostRecentOverviewPage); - }, - }), - ); - }; - - const rejectNText = t('rejectRequestsN', [messagesCount]); - - return ( -
-
- -
- - - { - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - - ///: END:ONLY_INCLUDE_IF - } - {showSecurityProviderBanner && ( - - )} - -
- - {!isMatchingAddress && ( - - {t('SIWEAddressInvalid', [ - parsedMessage.address, - fromAccount.address, - ])} - - )} - {isLedgerWallet && ( -
- -
- )} - {!isSIWEDomainValid && ( - - - {t('SIWEDomainInvalidTitle')} - {' '} - {t('SIWEDomainInvalidText')} - - )} - setIsShowingDomainWarning(true) - } - cancelText={t('cancel')} - submitText={t('signin')} - submitButtonType={isSIWEDomainValid ? 'primary' : 'danger-primary'} - /> - {messagesCount > 1 ? ( - - ) : null} - {isShowingDomainWarning && ( - setIsShowingDomainWarning(false)} - title={t('SIWEWarningTitle')} - subtitle={t('SIWEWarningSubtitle')} - className="signature-request-siwe__warning-popover" - footerClassName="signature-request-siwe__warning-popover__footer" - footer={ - setIsShowingDomainWarning(false)} - cancelText={t('cancel')} - cancelButtonType="default" - onSubmit={onSign} - submitText={t('confirm')} - submitButtonType="danger-primary" - disabled={!hasAgreedToDomainWarning} - /> - } - > -
- setHasAgreedToDomainWarning((checked) => !checked)} - /> - -
-
- )} -
- ); -} - -SignatureRequestSIWE.propTypes = { - /** - * The display content of transaction data - */ - txData: PropTypes.object.isRequired, -}; diff --git a/ui/components/app/signature-request/signature-request.js b/ui/components/app/signature-request/signature-request.js deleted file mode 100644 index 874f89485f2b..000000000000 --- a/ui/components/app/signature-request/signature-request.js +++ /dev/null @@ -1,393 +0,0 @@ -import React, { useContext, useState, useEffect } from 'react'; -import { - useDispatch, - useSelector, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - shallowEqual, - ///: END:ONLY_INCLUDE_IF -} from 'react-redux'; -import PropTypes from 'prop-types'; -import { memoize } from 'lodash'; -import { ethErrors, serializeError } from 'eth-rpc-errors'; -///: BEGIN:ONLY_INCLUDE_IF(build-mmi) -import { showCustodianDeepLink } from '@metamask-institutional/extension'; -///: END:ONLY_INCLUDE_IF -import { - resolvePendingApproval, - completedTx, - rejectPendingApproval, -} from '../../../store/actions'; -import { - doesAddressRequireLedgerHidConnection, - getSubjectMetadata, - getTotalUnapprovedMessagesCount, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - accountsWithSendEtherInfoSelector, - getSelectedAccount, - getAccountType, - ///: END:ONLY_INCLUDE_IF -} from '../../../selectors'; -import { - getProviderConfig, - isAddressLedger, -} from '../../../ducks/metamask/metamask'; -import { - sanitizeMessage, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - getAccountByAddress, - shortenAddress, - ///: END:ONLY_INCLUDE_IF -} from '../../../helpers/utils/util'; -import { useI18nContext } from '../../../hooks/useI18nContext'; -import { useRejectTransactionModal } from '../../../hooks/useRejectTransactionModal'; - -import { ConfirmPageContainerNavigation } from '../confirm-page-container'; -import SignatureRequestHeader from '../signature-request-header/signature-request-header'; -import SecurityProviderBannerMessage from '../security-provider-banner-message'; -import LedgerInstructionField from '../ledger-instruction-field'; -import ContractDetailsModal from '../modals/contract-details-modal'; -import { MetaMetricsContext } from '../../../contexts/metametrics'; -import { - MetaMetricsEventCategory, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - MetaMetricsEventName, - ///: END:ONLY_INCLUDE_IF -} from '../../../../shared/constants/metametrics'; -import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider'; - -import { - TextAlign, - TextColor, - TextVariant, - Size, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - IconColor, - BackgroundColor, - Display, - BlockSize, - ///: END:ONLY_INCLUDE_IF -} from '../../../helpers/constants/design-system'; -import { - ButtonVariant, - Button, - ButtonLink, - TagUrl, - Text, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - Icon, - IconName, - Box, - ///: END:ONLY_INCLUDE_IF -} from '../../component-library'; - -///: BEGIN:ONLY_INCLUDE_IF(build-mmi) -// eslint-disable-next-line import/order -import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'; -import { getEnvironmentType } from '../../../../app/scripts/lib/util'; -import { mmiActionsFactory } from '../../../store/institutional/institution-background'; -import { showCustodyConfirmLink } from '../../../store/institutional/institution-actions'; -import { useMMICustodySignMessage } from '../../../hooks/useMMICustodySignMessage'; -///: END:ONLY_INCLUDE_IF -///: BEGIN:ONLY_INCLUDE_IF(blockaid) -import BlockaidBannerAlert from '../security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -///: END:ONLY_INCLUDE_IF - -import Message from './signature-request-message'; -import Footer from './signature-request-footer'; - -const SignatureRequest = ({ txData }) => { - const trackEvent = useContext(MetaMetricsContext); - const dispatch = useDispatch(); - const t = useI18nContext(); - - const [hasScrolledMessage, setHasScrolledMessage] = useState(false); - const [showContractDetails, setShowContractDetails] = useState(false); - const [messageRootRef, setMessageRootRef] = useState(null); - const [messageIsScrollable, setMessageIsScrollable] = useState(false); - - const { - id, - type, - msgParams: { from, data, origin, version }, - } = txData; - - // not forwarded to component - const hardwareWalletRequiresConnection = useSelector((state) => - doesAddressRequireLedgerHidConnection(state, from), - ); - const { chainId, rpcPrefs } = useSelector(getProviderConfig); - const unapprovedMessagesCount = useSelector(getTotalUnapprovedMessagesCount); - const subjectMetadata = useSelector(getSubjectMetadata); - const isLedgerWallet = useSelector((state) => isAddressLedger(state, from)); - const { handleCancelAll } = useRejectTransactionModal(); - - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - // Used to show a warning if the signing account is not the selected account - // Largely relevant for contract wallet custodians - const selectedAccount = useSelector(getSelectedAccount); - const mmiActions = mmiActionsFactory(); - const accountType = useSelector(getAccountType); - const isNotification = getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION; - const allAccounts = useSelector( - accountsWithSendEtherInfoSelector, - shallowEqual, - ); - const { address } = getAccountByAddress(allAccounts, from) || {}; - const { custodySignFn } = useMMICustodySignMessage(); - ///: END:ONLY_INCLUDE_IF - - useEffect(() => { - setMessageIsScrollable( - messageRootRef?.scrollHeight > messageRootRef?.clientHeight, - ); - }, [messageRootRef]); - - const targetSubjectMetadata = subjectMetadata?.[origin] || null; - - const parseMessage = memoize((dataToParse) => { - const { - message, - domain = {}, - primaryType, - types, - } = JSON.parse(dataToParse); - const sanitizedMessage = sanitizeMessage(message, primaryType, types); - return { sanitizedMessage, domain, primaryType }; - }); - - const onSign = async () => { - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - if (accountType === 'custody') { - await custodySignFn(txData); - } - ///: END:ONLY_INCLUDE_IF - - await dispatch(resolvePendingApproval(id)); - completedTx(id); - - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: 'Confirm', - properties: { - action: 'Sign Request', - legacy_event: true, - type, - version, - }, - }); - }; - - const onCancel = async () => { - await dispatch( - rejectPendingApproval( - id, - serializeError(ethErrors.provider.userRejectedRequest()), - ), - ); - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: 'Cancel', - properties: { - action: 'Sign Request', - legacy_event: true, - type, - version, - }, - }); - }; - - const { - sanitizedMessage, - domain: { verifyingContract }, - primaryType, - } = parseMessage(data); - - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - useEffect(() => { - if (txData.custodyId) { - showCustodianDeepLink({ - dispatch, - mmiActions, - txId: undefined, - custodyId: txData.custodyId, - fromAddress: address, - isSignature: true, - closeNotification: isNotification, - onDeepLinkFetched: () => undefined, - onDeepLinkShown: () => { - trackEvent({ - category: MetaMetricsEventCategory.MMI, - event: MetaMetricsEventName.SignatureDeeplinkDisplayed, - }); - }, - showCustodyConfirmLink, - }); - } - }, [ - dispatch, - mmiActions, - txData.custodyId, - address, - isNotification, - trackEvent, - ]); - ///: END:ONLY_INCLUDE_IF - - return ( -
- -
- -
-
- { - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - - ///: END:ONLY_INCLUDE_IF - } - {(txData?.securityProviderResponse?.flagAsDangerous !== undefined && - txData?.securityProviderResponse?.flagAsDangerous !== - SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS) || - (txData?.securityProviderResponse && - Object.keys(txData.securityProviderResponse).length === 0) ? ( - - ) : null} - { - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - selectedAccount.address === address ? null : ( - - - - {t('mismatchAccount', [ - shortenAddress(selectedAccount.address), - shortenAddress(address), - ])} - - - ) - ///: END:ONLY_INCLUDE_IF - } -
- -
- - {t('sigRequest')} - - - {t('signatureRequestGuidance')} - - {verifyingContract ? ( -
- -
- ) : null} -
- {isLedgerWallet ? ( -
- -
- ) : null} - setHasScrolledMessage(true)} - setMessageRootRef={setMessageRootRef} - messageRootRef={messageRootRef} - messageIsScrollable={messageIsScrollable} - primaryType={primaryType} - /> -
- {showContractDetails && ( - setShowContractDetails(false)} - isContractRequestingSignature - /> - )} - {unapprovedMessagesCount > 1 ? ( - - {t('rejectRequestsN', [unapprovedMessagesCount])} - - ) : null} -
- ); -}; - -SignatureRequest.propTypes = { - txData: PropTypes.object, -}; - -export default SignatureRequest; diff --git a/ui/components/multichain/token-list-item/token-list-item.js b/ui/components/multichain/token-list-item/token-list-item.js index d68090ec759b..d5066208bf13 100644 --- a/ui/components/multichain/token-list-item/token-list-item.js +++ b/ui/components/multichain/token-list-item/token-list-item.js @@ -221,9 +221,6 @@ export const TokenListItem = ({ variant={TextVariant.bodyMd} ellipsis > -<<<<<<< HEAD - {tokenTitle} -======= {isStakeable ? ( <> {tokenSymbol} {stakeableTitle} @@ -231,7 +228,6 @@ export const TokenListItem = ({ ) : ( tokenSymbol )} ->>>>>>> origin/develop ) : ( @@ -241,9 +237,6 @@ export const TokenListItem = ({ variant={TextVariant.bodyMd} ellipsis > -<<<<<<< HEAD - {tokenTitle} -======= {isStakeable ? ( {tokenSymbol} {stakeableTitle} @@ -251,7 +244,6 @@ export const TokenListItem = ({ ) : ( tokenSymbol )} ->>>>>>> origin/develop )} diff --git a/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index bfa3c211b274..cebfa3460ad0 100644 --- a/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/pages/confirmations/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -9,15 +9,6 @@ import { BUTTON_VARIANT, ///: END:ONLY_INCLUDE_IF BannerAlert, -<<<<<<< HEAD:ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js -} from '../../../component-library'; -import { PageContainerFooter } from '../../../ui/page-container'; -import { - INSUFFICIENT_FUNDS_ERROR_KEY, - IS_SIGNING_OR_SUBMITTING, -} from '../../../../helpers/constants/error-keys'; -import { Severity } from '../../../../helpers/constants/design-system'; -======= } from '../../../../../components/component-library'; import { PageContainerFooter } from '../../../../../components/ui/page-container'; import { @@ -25,7 +16,6 @@ import { IS_SIGNING_OR_SUBMITTING, } from '../../../../../helpers/constants/error-keys'; import { Severity } from '../../../../../helpers/constants/design-system'; ->>>>>>> origin/develop:ui/pages/confirmations/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.'; diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js index 9b6ba5f4fc15..6920cdacd142 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js @@ -7,14 +7,8 @@ import { NETWORK_TO_NAME_MAP } from '../../../../../../shared/constants/network' import { OverflowWrap, Severity, -<<<<<<< HEAD:ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js -} from '../../../../helpers/constants/design-system'; -import { I18nContext } from '../../../../contexts/i18n'; -import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment'; -======= } from '../../../../../helpers/constants/design-system'; import { I18nContext } from '../../../../../contexts/i18n'; ->>>>>>> origin/develop:ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js import { BlockaidReason, BlockaidResultType, @@ -143,26 +137,6 @@ function BlockaidBannerAlert({ txData, ...props }) { ); }; -<<<<<<< HEAD:ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js - const jsonData = JSON.stringify(reportData); - - const encodedData = zlib?.gzipSync?.(jsonData) ?? jsonData; - - const reportUrl = getReportUrl(encodedData); - - const onClickSupportLink = () => { - updateTransactionEventFragment( - { - properties: { - external_link_clicked: 'security_alert_support_link', - }, - }, - txData.id, - ); - }; - -======= ->>>>>>> origin/develop:ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js return ( >>>>>> origin/develop:ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js onClickSupportLink={onClickSupportLink} {...props} /> diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js index a892e156d500..b34d9d9b0e0a 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js @@ -1,17 +1,11 @@ import React from 'react'; import * as Sentry from '@sentry/browser'; import { fireEvent, screen } from '@testing-library/react'; -<<<<<<< HEAD:ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js -import { renderWithProvider } from '../../../../../test/lib/render-helpers'; -import { Severity } from '../../../../helpers/constants/design-system'; -import configureStore from '../../../../store/store'; -======= import { renderWithProvider } from '../../../../../../test/lib/render-helpers'; import { Severity } from '../../../../../helpers/constants/design-system'; import configureStore from '../../../../../store/store'; ->>>>>>> origin/develop:ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js import { BlockaidReason, BlockaidResultType, @@ -25,11 +19,7 @@ jest.mock('zlib', () => ({ const mockUpdateTransactionEventFragment = jest.fn(); -<<<<<<< HEAD:ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js -jest.mock('../../../../hooks/useTransactionEventFragment', () => { -======= jest.mock('../../../hooks/useTransactionEventFragment', () => { ->>>>>>> origin/develop:ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js return { useTransactionEventFragment: () => { return { diff --git a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js index 3bd47229b294..ece1f397831f 100644 --- a/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js +++ b/ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js @@ -2,16 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { TransactionType } from '@metamask/transaction-controller'; -<<<<<<< HEAD:ui/components/app/transaction-alerts/transaction-alerts.js -import { PriorityLevels } from '../../../../shared/constants/gas'; -import { submittedPendingTransactionsSelector } from '../../../selectors'; -import { useGasFeeContext } from '../../../contexts/gasFee'; -import { useI18nContext } from '../../../hooks/useI18nContext'; -import { BannerAlert, ButtonLink, Text } from '../../component-library'; -import SimulationErrorMessage from '../../ui/simulation-error-message'; -import { SEVERITIES } from '../../../helpers/constants/design-system'; -import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; -======= import { PriorityLevels } from '../../../../../shared/constants/gas'; import { submittedPendingTransactionsSelector } from '../../../../selectors'; import { useGasFeeContext } from '../../../../contexts/gasFee'; @@ -24,22 +14,15 @@ import { import SimulationErrorMessage from '../simulation-error-message'; import { SEVERITIES } from '../../../../helpers/constants/design-system'; import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url'; ->>>>>>> origin/develop:ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js import { isSuspiciousResponse } from '../../../../../shared/modules/security-provider.utils'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import BlockaidBannerAlert from '../security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; ///: END:ONLY_INCLUDE_IF import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message'; -<<<<<<< HEAD:ui/components/app/transaction-alerts/transaction-alerts.js -import { getNativeCurrency } from '../../../ducks/metamask/metamask'; -import { parseStandardTokenTransactionData } from '../../../../shared/modules/transaction.utils'; -import { getTokenValueParam } from '../../../../shared/lib/metamask-controller-utils'; -======= import { getNativeCurrency } from '../../../../ducks/metamask/metamask'; import { parseStandardTokenTransactionData } from '../../../../../shared/modules/transaction.utils'; import { getTokenValueParam } from '../../../../../shared/lib/metamask-controller-utils'; ->>>>>>> origin/develop:ui/pages/confirmations/components/transaction-alerts/transaction-alerts.js const TransactionAlerts = ({ userAcknowledgedGasMissing, diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index 22f2d854077e..3ec563ab4f44 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -20,11 +20,7 @@ import { import { ConfirmPageContainerWarning } from '../../components/confirm-page-container/confirm-page-container-content'; import LedgerInstructionField from '../../components/ledger-instruction-field'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) -<<<<<<< HEAD:ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js -import BlockaidBannerAlert from '../../../components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -======= import BlockaidBannerAlert from '../../components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; ->>>>>>> origin/develop:ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js ///: END:ONLY_INCLUDE_IF import { isSuspiciousResponse } from '../../../../../shared/modules/security-provider.utils'; diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js index c072ad70d400..e0d5bd682217 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js @@ -13,13 +13,8 @@ import { ETH_GAS_PRICE_FETCH_WARNING_KEY, GAS_PRICE_FETCH_FAILURE_ERROR_KEY, IS_SIGNING_OR_SUBMITTING, -<<<<<<< HEAD:ui/pages/confirm-transaction-base/confirm-transaction-base.component.js -} from '../../helpers/constants/error-keys'; -import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display'; -======= } from '../../../helpers/constants/error-keys'; import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display'; ->>>>>>> origin/develop:ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import TextField from '../../../components/ui/text-field'; @@ -160,11 +155,8 @@ export default class ConfirmTransactionBase extends Component { updateTransaction: PropTypes.func, isUsingPaymaster: PropTypes.bool, isSigningOrSubmitting: PropTypes.bool, -<<<<<<< HEAD:ui/pages/confirm-transaction-base/confirm-transaction-base.component.js -======= useMaxValue: PropTypes.bool, maxValue: PropTypes.string, ->>>>>>> origin/develop:ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js }; state = { diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js index b8573997ed9d..39ce79d51420 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js @@ -51,13 +51,8 @@ import { getUnapprovedTransactions, getInternalAccountByAddress, getApprovedAndSignedTransactions, -<<<<<<< HEAD:ui/pages/confirm-transaction-base/confirm-transaction-base.container.js -} from '../../selectors'; -import { getMostRecentOverviewPage } from '../../ducks/history/history'; -======= } from '../../../selectors'; import { getMostRecentOverviewPage } from '../../../ducks/history/history'; ->>>>>>> origin/develop:ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js import { isAddressLedger, updateGasFees, @@ -319,11 +314,8 @@ const mapStateToProps = (state, ownProps) => { keyringForAccount: keyring, isUsingPaymaster, isSigningOrSubmitting, -<<<<<<< HEAD:ui/pages/confirm-transaction-base/confirm-transaction-base.container.js -======= useMaxValue, maxValue, ->>>>>>> origin/develop:ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) accountType, isNoteToTraderSupported, diff --git a/ui/pages/confirmations/token-allowance/token-allowance.js b/ui/pages/confirmations/token-allowance/token-allowance.js index a1143fcb352d..a7c6b4b368b6 100644 --- a/ui/pages/confirmations/token-allowance/token-allowance.js +++ b/ui/pages/confirmations/token-allowance/token-allowance.js @@ -63,11 +63,7 @@ import { import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) -<<<<<<< HEAD:ui/pages/token-allowance/token-allowance.js -import BlockaidBannerAlert from '../../components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; -======= import BlockaidBannerAlert from '../components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert'; ->>>>>>> origin/develop:ui/pages/confirmations/token-allowance/token-allowance.js ///: END:ONLY_INCLUDE_IF import { ConfirmPageContainerNavigation } from '../components/confirm-page-container'; diff --git a/yarn.lock b/yarn.lock index 08834b3a5f8e..61cae79f646e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1640,11 +1640,7 @@ __metadata: languageName: node linkType: hard -<<<<<<< HEAD -"@babel/traverse@npm:7.23.9, @babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.12.5, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.7.2": -======= "@babel/traverse@npm:7.23.9, @babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.12.5, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.23.2": ->>>>>>> origin/develop version: 7.23.9 resolution: "@babel/traverse@npm:7.23.9" dependencies: @@ -3407,8 +3403,6 @@ __metadata: languageName: node linkType: hard -<<<<<<< HEAD -======= "@lavamoat/lavadome-core@npm:0.0.10": version: 0.0.10 resolution: "@lavamoat/lavadome-core@npm:0.0.10" @@ -3438,7 +3432,6 @@ __metadata: languageName: node linkType: hard ->>>>>>> origin/develop "@lavamoat/lavapack@npm:^6.1.0": version: 6.1.0 resolution: "@lavamoat/lavapack@npm:6.1.0" @@ -3453,8 +3446,6 @@ __metadata: through2: "npm:4.0.2" umd: "npm:3.0.3" checksum: faf4425e740c5abb9a441b6e872921943d48129f8f2120ce26672119824cea5dfcbcb7ae7113ece639a34c924794e3f6088564281672421bf31b40c25cfc93dc -<<<<<<< HEAD -======= languageName: node linkType: hard @@ -3462,7 +3453,6 @@ __metadata: version: 2.0.0 resolution: "@lavamoat/preinstall-always-fail@npm:2.0.0" checksum: a69c712e9a01029cacc8f77f7b9a944a285d9532583c09fc6050baef098d962d7dea18f17f446ca1f0ec3cd1eea07bfaedd583a704e016889cae1eba7f3552fd ->>>>>>> origin/develop languageName: node linkType: hard @@ -4538,11 +4528,7 @@ __metadata: languageName: node linkType: hard -<<<<<<< HEAD -"@metamask/message-manager@npm:^7.3.0, @metamask/message-manager@npm:^7.3.5": -======= "@metamask/message-manager@npm:^7.3.0, @metamask/message-manager@npm:^7.3.8": ->>>>>>> origin/develop version: 7.3.8 resolution: "@metamask/message-manager@npm:7.3.8" dependencies: @@ -24353,11 +24339,8 @@ __metadata: "@keystonehq/bc-ur-registry-eth": "npm:^0.19.1" "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" "@lavamoat/allow-scripts": "npm:^3.0.1" -<<<<<<< HEAD -======= "@lavamoat/lavadome-core": "npm:0.0.10" "@lavamoat/lavadome-react": "npm:0.0.11" ->>>>>>> origin/develop "@lavamoat/lavapack": "npm:^6.1.0" "@lavamoat/snow": "npm:^2.0.1" "@material-ui/core": "npm:^4.11.0" @@ -32723,11 +32706,7 @@ __metadata: languageName: node linkType: hard -<<<<<<< HEAD -"through2@npm:^2.0.0, through2@npm:^2.0.1, through2@npm:^2.0.3, through2@npm:^2.0.5, through2@npm:~2.0.0, through2@npm:~2.0.3": -======= "through2@npm:^2.0.0, through2@npm:^2.0.1, through2@npm:^2.0.3, through2@npm:~2.0.0, through2@npm:~2.0.3": ->>>>>>> origin/develop version: 2.0.5 resolution: "through2@npm:2.0.5" dependencies: From e4a0f401703940b4f0d271f4a82c3a2006b487ac Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Tue, 20 Feb 2024 15:28:48 +0100 Subject: [PATCH 13/17] resolve merge conflit --- lavamoat/browserify/beta/policy.json | 6 ---- lavamoat/browserify/desktop/policy.json | 6 ---- lavamoat/browserify/flask/policy.json | 6 ---- lavamoat/browserify/main/policy.json | 6 ---- lavamoat/browserify/mmi/policy.json | 6 ---- lavamoat/build-system/policy.json | 33 -------------------- yarn.lock | 41 ++++++++++--------------- 7 files changed, 16 insertions(+), 88 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index c156a7b706b2..36c8cc479675 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -4163,17 +4163,11 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-define-property": true, "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>call-bind>es-define-property": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, "string.prototype.matchall>call-bind>set-function-length": { "packages": { "string.prototype.matchall>call-bind>es-errors": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 0388d2497a8c..d792a0114e82 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -4529,17 +4529,11 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-define-property": true, "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>call-bind>es-define-property": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, "string.prototype.matchall>call-bind>set-function-length": { "packages": { "string.prototype.matchall>call-bind>es-errors": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 88c78d04b032..9250120ac60f 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -4565,17 +4565,11 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-define-property": true, "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>call-bind>es-define-property": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, "string.prototype.matchall>call-bind>set-function-length": { "packages": { "string.prototype.matchall>call-bind>es-errors": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index a84465a1832d..6987a8dea4ff 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -4488,17 +4488,11 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-define-property": true, "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>call-bind>es-define-property": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, "string.prototype.matchall>call-bind>set-function-length": { "packages": { "string.prototype.matchall>call-bind>es-errors": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index c2f3259316ee..f8dce4372499 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -4560,17 +4560,11 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-define-property": true, "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>call-bind>es-define-property": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, "string.prototype.matchall>call-bind>set-function-length": { "packages": { "string.prototype.matchall>call-bind>es-errors": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 0087d1f7f9c0..959d228d357f 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -3406,33 +3406,6 @@ "setTimeout": true } }, -<<<<<<< HEAD - "globalthis": { - "packages": { - "globalthis>define-properties": true - } - }, - "globalthis>define-properties": { - "packages": { - "globalthis>define-properties>define-data-property": true, - "globalthis>define-properties>has-property-descriptors": true, - "globalthis>define-properties>object-keys": true - } - }, - "globalthis>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "globalthis>define-properties>has-property-descriptors": { - "packages": { - "string.prototype.matchall>call-bind>es-define-property": true - } - }, -======= ->>>>>>> origin/develop "globby": { "builtin": { "fs.Stats": true, @@ -7541,17 +7514,11 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-define-property": true, "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>call-bind>es-define-property": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, "string.prototype.matchall>call-bind>set-function-length": { "packages": { "string.prototype.matchall>call-bind>es-errors": true, diff --git a/yarn.lock b/yarn.lock index 61cae79f646e..cb6d990fbe01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12756,15 +12756,14 @@ __metadata: linkType: hard "call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.5": - version: 1.0.7 - resolution: "call-bind@npm:1.0.7" + version: 1.0.6 + resolution: "call-bind@npm:1.0.6" dependencies: - es-define-property: "npm:^1.0.0" es-errors: "npm:^1.3.0" function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.1" - checksum: cd6fe658e007af80985da5185bff7b55e12ef4c2b6f41829a26ed1eef254b1f1c12e3dfd5b2b068c6ba8b86aba62390842d81752e67dcbaec4f6f76e7113b6b7 + get-intrinsic: "npm:^1.2.3" + set-function-length: "npm:^1.2.0" + checksum: d99d92dc414d13a03b8b6f2307fc2f0d16a135b523a14d804a2ba7aaa8aae8223cb40d058703c1e66eed11acaff2dc1bcd6358395fa0eb151d84a42c21dedb19 languageName: node linkType: hard @@ -14692,13 +14691,14 @@ __metadata: linkType: hard "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.2": - version: 1.1.4 - resolution: "define-data-property@npm:1.1.4" + version: 1.1.2 + resolution: "define-data-property@npm:1.1.2" dependencies: - es-define-property: "npm:^1.0.0" es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.2" gopd: "npm:^1.0.1" - checksum: abdcb2505d80a53524ba871273e5da75e77e52af9e15b3aa65d8aad82b8a3a424dad7aee2cc0b71470ac7acf501e08defac362e8b6a73cdb4309f028061df4ae + has-property-descriptors: "npm:^1.0.1" + checksum: 19336750149644b2eb53d281ba685c3561abf98d2b0d2a173ee065bb388b977350df2a08c2597b3401bf0e89f313fc69d7582f0373931cc74df0777fb5202cd0 languageName: node linkType: hard @@ -15963,15 +15963,6 @@ __metadata: languageName: node linkType: hard -"es-define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "es-define-property@npm:1.0.0" - dependencies: - get-intrinsic: "npm:^1.2.4" - checksum: f66ece0a887b6dca71848fa71f70461357c0e4e7249696f81bad0a1f347eed7b31262af4a29f5d726dc026426f085483b6b90301855e647aa8e21936f07293c6 - languageName: node - linkType: hard - "es-errors@npm:^1.3.0": version: 1.3.0 resolution: "es-errors@npm:1.3.0" @@ -18696,7 +18687,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -19633,11 +19624,11 @@ __metadata: linkType: hard "has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.1": - version: 1.0.2 - resolution: "has-property-descriptors@npm:1.0.2" + version: 1.0.1 + resolution: "has-property-descriptors@npm:1.0.1" dependencies: - es-define-property: "npm:^1.0.0" - checksum: 2d8c9ab8cebb572e3362f7d06139a4592105983d4317e68f7adba320fe6ddfc8874581e0971e899e633fd5f72e262830edce36d5a0bc863dad17ad20572484b2 + get-intrinsic: "npm:^1.2.2" + checksum: 21a47bb080a24e79594aef1ce71e1a18a1c5ab4120308e218088f67ebb7f6f408847541e2d96e5bd00e90eef5c5a49e4ebbdc8fc2d5b365a2c379aef071642f0 languageName: node linkType: hard @@ -30893,7 +30884,7 @@ __metadata: languageName: node linkType: hard -"set-function-length@npm:^1.2.1": +"set-function-length@npm:^1.2.0": version: 1.2.1 resolution: "set-function-length@npm:1.2.1" dependencies: From 2ed467e6674a222694cc5919501c27bed68dad02 Mon Sep 17 00:00:00 2001 From: Olusegun Akintayo Date: Wed, 21 Feb 2024 05:48:57 +0100 Subject: [PATCH 14/17] fix: Capture more details of ppom errors (#22728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We're seeing ppom throwing errors on Flask, but we don't have further details on what the error is. We should capture more details about the error. This solution leverages both Sentry or Mixpanel. we are passing the error as the value for `security_alert_reason` property at the same time sending the error to sentry. ## **Related issues** Fixes: [#1535](https://github.com/MetaMask/MetaMask-planning/issues/1535) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/_locales/de/messages.json | 2 +- app/_locales/el/messages.json | 2 +- app/_locales/en/messages.json | 2 +- app/_locales/es/messages.json | 2 +- app/_locales/fr/messages.json | 2 +- app/_locales/hi/messages.json | 2 +- app/_locales/id/messages.json | 2 +- app/_locales/ja/messages.json | 2 +- app/_locales/ko/messages.json | 2 +- app/_locales/pt/messages.json | 2 +- app/_locales/ru/messages.json | 2 +- app/_locales/tl/messages.json | 2 +- app/_locales/tr/messages.json | 2 +- app/_locales/vi/messages.json | 2 +- app/_locales/zh_CN/messages.json | 2 +- .../lib/createRPCMethodTrackingMiddleware.js | 9 ++++++++ app/scripts/lib/ppom/ppom-middleware.test.ts | 12 +++++++--- app/scripts/lib/ppom/ppom-middleware.ts | 16 +++++++------ app/scripts/lib/transaction/util.ts | 13 ++++++----- shared/constants/metametrics.ts | 2 +- shared/constants/security-provider.ts | 3 +-- test/e2e/helpers.js | 18 +++++++++++++++ .../ppom-blockaid-alert-simple-send.spec.js | 4 ++-- ui/helpers/utils/metrics.js | 12 +++++++--- ui/helpers/utils/metrics.test.js | 23 +++++++++++++++---- .../blockaid-banner-alert.test.js.snap | 2 +- .../blockaid-banner-alert.js | 6 ++--- .../blockaid-banner-alert.test.js | 14 +++++------ 28 files changed, 110 insertions(+), 54 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 7b6977e25821..257611b700c5 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Wenn Sie diese Anfrage genehmigen, kann jemand Ihre bei Blur aufgelisteten Assets stehlen." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Aufgrund eines Fehlers wurde diese Anfrage vom Sicherheitsanbieter nicht überprüft. Gehen Sie mit Bedacht vor." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 00bff68f0a7d..aa32480036bd 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Εάν εγκρίνετε αυτό το αίτημα, κάποιος μπορεί να κλέψει τα περιουσιακά σας στοιχεία που είναι καταχωρημένα στο Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Λόγω κάποιου σφάλματος, αυτό το αίτημα δεν επαληθεύτηκε από τον πάροχο ασφαλείας. Προχωρήστε με προσοχή." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index b6df11414bc6..9591a91da069 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -601,7 +601,7 @@ "blockaidDescriptionBlurFarming": { "message": "If you approve this request, someone can steal your assets listed on Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Because of an error, this request was not verified by the security provider. Proceed with caution." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index f7b538aca64a..b53d55eff620 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Si aprueba esta solicitud, alguien puede robar sus activos enlistados en Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Debido a un error, el proveedor de seguridad no verificó esta solicitud. Proceda con precaución." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index c1105e208141..d477599060dd 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Si vous approuvez cette demande, quelqu’un pourrait s'emparer de vos actifs répertoriés sur Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "À la suite d’une erreur, cette demande n’a pas été vérifiée par le fournisseur de services de sécurité. Veuillez agir avec prudence." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 85d174911664..50027209b4f5 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "यदि आप इस रिक्वेस्ट को स्वीकार करते हैं, तो कोई Blur पर लिस्टेड आपके सारे एसेट चुरा सकता है।" }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "कोई समस्या होने के कारण, इस रिक्वेस्ट को सिक्यूरिटी प्रोवाइडर द्वारा वेरीफ़ाई नहीं किया गया। सावधानी से आगे बढ़ें।" }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 60a00061ec26..fdbd48de0e55 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Jika Anda menyetujui permintaan ini, seseorang dapat mencuri aset Anda yang terdaftar di Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Karena terjadi kesalahan, permintaan ini tidak diverifikasi oleh penyedia keamanan. Lanjutkan dengan hati-hati." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index ca9452e7092a..076254176f8b 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "このリクエストを承認すると、Blurに登録されている資産を誰かに盗まれる可能性があります。" }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "エラーが発生したため、このリクエストはセキュリティプロバイダーにより確認されませんでした。慎重に進めてください。" }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 03b0bf2861fc..668779dfc90d 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "이 요청을 승인하면, Blur에 있는 자산을 타인이 갈취할 수 있습니다." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "오류로 인해 보안업체에서 이 요청을 확인하지 못했습니다. 주의하여 진행하세요." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 67d40144bf57..eac5878b5df5 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Se você aprovar essa solicitação, alguém poderá roubar seus ativos listados na Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Em razão de um erro, essa solicitação não foi confirmada pelo provedor de segurança. Prossiga com cautela." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 993611e4dc9d..857be230dc68 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Если вы одобрите этот запрос, кто-то может украсть ваши активы, указанные в Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Из-за ошибки этот запрос не был подтвержден поставщиком услуг безопасности. Действуйте осторожно." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 701370abde42..1127db132f1c 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Kung aaprubahan mo ang kahilingang ito, posibleng nakawin ng ibang tao ang mga asset mo na nakalista sa Blur." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Dahil sa error, hindi na-verify ang kahilingang ito ng tagapagbigay ng seguridad. Magpatuloy nang may pag-iingat." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 8f549b74f9a6..429d838df65d 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Bu talebi onaylarsanız birisi Blur üzerinde yer alan varlıklarınızı çalabilir." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Bu talep bir hatadan dolayı güvenlik sağlayıcısı tarafından doğrulanmadı. Dikkatli bir şekilde ilerleyin." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 1c0386cbb69c..e0705352ea6b 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "Nếu bạn chấp thuận yêu cầu này, người khác có thể đánh cắp tài sản được niêm yết trên Blur của bạn." }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "Do có lỗi, yêu cầu này đã không được nhà cung cấp dịch vụ bảo mật xác minh. Hãy thực hiện cẩn thận." }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 99e51271cfe0..7b336018586b 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -556,7 +556,7 @@ "blockaidDescriptionBlurFarming": { "message": "如果您批准此请求,则有人可以窃取您列于Blur上的资产。" }, - "blockaidDescriptionFailed": { + "blockaidDescriptionErrored": { "message": "由于出现错误,安全提供程序无法验证此请求。请谨慎操作。" }, "blockaidDescriptionMaliciousDomain": { diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.js index d16bb9f74b4f..02bbb7c55df8 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.js @@ -216,6 +216,15 @@ export default function createRPCMethodTrackingMiddleware({ BlockaidResultType.NotApplicable; eventProperties.security_alert_reason = req.securityAlertResponse?.reason ?? BlockaidReason.notApplicable; + + if ( + req.securityAlertResponse?.result_type === + BlockaidResultType.Errored && + req.securityAlertResponse?.description + ) { + eventProperties.security_alert_description = + req.securityAlertResponse.description; + } ///: END:ONLY_INCLUDE_IF const snapAndHardwareInfo = await getSnapAndHardwareInfoForMetrics( diff --git a/app/scripts/lib/ppom/ppom-middleware.test.ts b/app/scripts/lib/ppom/ppom-middleware.test.ts index 281506421605..ff21e4502806 100644 --- a/app/scripts/lib/ppom/ppom-middleware.test.ts +++ b/app/scripts/lib/ppom/ppom-middleware.test.ts @@ -35,10 +35,16 @@ const createMiddleWare = ( const networkController = { state: { providerConfig: { chainId: chainId || CHAIN_IDS.MAINNET } }, }; + const appStateController = { + addSignatureSecurityAlertResponse: () => undefined, + }; + return createPPOMMiddleware( ppomController as any, preferenceController as any, networkController as any, + appStateController as any, + () => undefined, ); }; @@ -87,7 +93,7 @@ describe('PPOMMiddleware', () => { expect(req.securityAlertResponse).toBeUndefined(); }); - it('should set Failed type in response if usePPOM throw error', async () => { + it('should set error type in response if usePPOM throw error', async () => { const usePPOM = async () => { throw new Error('some error'); }; @@ -98,10 +104,10 @@ describe('PPOMMiddleware', () => { }; await middlewareFunction(req, undefined, () => undefined); expect((req.securityAlertResponse as any)?.result_type).toBe( - BlockaidResultType.Failed, + BlockaidResultType.Errored, ); expect((req.securityAlertResponse as any)?.reason).toBe( - BlockaidReason.failed, + BlockaidReason.errored, ); }); diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index 4f742e4af078..87c25d6f1fae 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -73,15 +73,16 @@ export function createPPOMMiddleware( .usePPOM(async (ppom: PPOM) => { try { const securityAlertResponse = await ppom.validateJsonRpc(req); + securityAlertResponse.securityAlertId = securityAlertId; return securityAlertResponse; } catch (error: any) { sentry?.captureException(error); + const errorObject = error as unknown as Error; console.error('Error validating JSON RPC using PPOM: ', error); const securityAlertResponse = { - result_type: BlockaidResultType.Failed, - reason: BlockaidReason.failed, - description: - 'Validating the confirmation failed by throwing error.', + result_type: BlockaidResultType.Errored, + reason: BlockaidReason.errored, + description: `${errorObject.name}: ${errorObject.message}`, }; return securityAlertResponse; @@ -114,12 +115,13 @@ export function createPPOMMiddleware( } } } catch (error: any) { + const errorObject = error as unknown as Error; sentry?.captureException(error); console.error('Error validating JSON RPC using PPOM: ', error); req.securityAlertResponse = { - result_type: BlockaidResultType.Failed, - reason: BlockaidReason.failed, - description: 'Validating the confirmation failed by throwing error.', + result_type: BlockaidResultType.Errored, + reason: BlockaidReason.errored, + description: `${errorObject.name}: ${errorObject.message}`, }; } finally { next(); diff --git a/app/scripts/lib/transaction/util.ts b/app/scripts/lib/transaction/util.ts index cb621794a08f..5c0516eb7c2e 100644 --- a/app/scripts/lib/transaction/util.ts +++ b/app/scripts/lib/transaction/util.ts @@ -119,7 +119,7 @@ const PPOM_EXCLUDED_TRANSACTION_TYPES = [ export async function addTransaction( request: AddTransactionRequest, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - updateSecurityAlertResponseByTxId: ( + updateSecurityAlertResponseByTxId?: ( req: AddTransactionOptions | undefined, securityAlertResponse: SecurityAlertResponse, ) => void, @@ -169,19 +169,19 @@ export async function addTransaction( return securityAlertResponse; } catch (e) { captureException(e); + const errorObject = e as unknown as Error; console.error('Error validating JSON RPC using PPOM: ', e); const securityAlertResponse = { securityAlertId, - result_type: BlockaidResultType.Failed, - reason: BlockaidReason.failed, - description: - 'Validating the confirmation failed by throwing error.', + result_type: BlockaidResultType.Errored, + reason: BlockaidReason.errored, + description: `${errorObject.name}: ${errorObject.message}`, }; return securityAlertResponse; } }) .then((securityAlertResponse) => { - updateSecurityAlertResponseByTxId(request.transactionOptions, { + updateSecurityAlertResponseByTxId?.(request.transactionOptions, { ...securityAlertResponse, securityAlertId, }); @@ -193,6 +193,7 @@ export async function addTransaction( securityAlertId, }; } catch (e) { + console.error('Error validating JSON RPC using PPOM: ', e); captureException(e); } } diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 563665135b41..397fa0472039 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -773,7 +773,7 @@ export enum MetaMetricsEventUiCustomization { FlaggedAsSafetyUnknown = 'flagged_as_safety_unknown', FlaggedAsWarning = 'flagged_as_warning', GasEstimationFailed = 'gas_estimation_failed', - SecurityAlertFailed = 'security_alert_failed', + SecurityAlertError = 'security_alert_error', Siwe = 'sign_in_with_ethereum', } diff --git a/shared/constants/security-provider.ts b/shared/constants/security-provider.ts index e18888d25178..537d0bd41e5c 100644 --- a/shared/constants/security-provider.ts +++ b/shared/constants/security-provider.ts @@ -47,7 +47,7 @@ export enum BlockaidReason { other = 'other', // MetaMask defined reasons - failed = 'Failed', + errored = 'Error', notApplicable = 'NotApplicable', inProgress = 'validation_in_progress', } @@ -59,7 +59,6 @@ export enum BlockaidResultType { Errored = 'Error', // MetaMask defined result types - Failed = 'Failed', NotApplicable = 'NotApplicable', Loading = 'loading', } diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index e986c302df1d..210790844a50 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -719,6 +719,24 @@ const sendScreenToConfirmScreen = async ( await driver.fill('[data-testid="ens-input"]', recipientAddress); await driver.fill('.unit-input__input', quantity); if (process.env.MULTICHAIN) { + // check if element exists and click it + await driver + .findElement({ + text: 'I understand', + tag: 'button', + }) + .then( + (_found) => { + driver.clickElement({ + text: 'I understand', + tag: 'button', + }); + }, + (error) => { + console.error('Element not found.', error); + }, + ); + await driver.clickElement({ text: 'Continue', tag: 'button', diff --git a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js index bf99c19c12c8..cb4dce5ba29c 100644 --- a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js @@ -222,8 +222,8 @@ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { await sendScreenToConfirmScreen( driver, - '0x985c30949c92df7a0bd42e0f3e3d539ece98db24', - '1', + '0xB8c77482e45F1F44dE1745F52C74426C631bDD52', + '1.1', ); // await driver.delay(100000) const expectedTitle = 'Request may not be safe'; diff --git a/ui/helpers/utils/metrics.js b/ui/helpers/utils/metrics.js index 8902f1bed336..ad50da93ff5a 100644 --- a/ui/helpers/utils/metrics.js +++ b/ui/helpers/utils/metrics.js @@ -35,12 +35,12 @@ export function formatAccountType(accountType) { const getBlockaidMetricUiCustomization = (resultType) => { let uiCustomization; - if (resultType === BlockaidResultType.Failed) { - uiCustomization = [MetaMetricsEventUiCustomization.SecurityAlertFailed]; - } else if (resultType === BlockaidResultType.Malicious) { + if (resultType === BlockaidResultType.Malicious) { uiCustomization = [MetaMetricsEventUiCustomization.FlaggedAsMalicious]; } else if (resultType === BlockaidResultType.Warning) { uiCustomization = [MetaMetricsEventUiCustomization.FlaggedAsWarning]; + } else if (resultType === BlockaidResultType.Errored) { + uiCustomization = [MetaMetricsEventUiCustomization.SecurityAlertError]; } return uiCustomization; @@ -60,6 +60,7 @@ export const getBlockaidMetricsProps = ({ securityAlertResponse }) => { providerRequestsCount, reason, result_type: resultType, + description, } = securityAlertResponse; const uiCustomization = getBlockaidMetricUiCustomization(resultType); @@ -70,6 +71,11 @@ export const getBlockaidMetricsProps = ({ securityAlertResponse }) => { if (resultType !== BlockaidResultType.Benign) { params.security_alert_reason = reason ?? BlockaidReason.notApplicable; } + + if (resultType === BlockaidResultType.Errored && description) { + params.security_alert_description = description; + } + params.security_alert_response = resultType ?? BlockaidResultType.NotApplicable; diff --git a/ui/helpers/utils/metrics.test.js b/ui/helpers/utils/metrics.test.js index b75f5b7b2693..d1a2f1a5d72e 100644 --- a/ui/helpers/utils/metrics.test.js +++ b/ui/helpers/utils/metrics.test.js @@ -54,18 +54,18 @@ describe('getBlockaidMetricsProps', () => { ); }); - it('includes "security_alert_failed" ui_customization when type is failed', () => { + it('includes "security_alert_error" ui_customization when type is error', () => { const result = getBlockaidMetricsProps({ securityAlertResponse: { ...securityAlertResponse, - result_type: BlockaidResultType.Failed, + result_type: BlockaidResultType.Errored, }, }); expect(result).toStrictEqual({ security_alert_reason: BlockaidReason.setApprovalForAll, - security_alert_response: BlockaidResultType.Failed, - ui_customizations: ['security_alert_failed'], + security_alert_response: BlockaidResultType.Errored, + ui_customizations: ['security_alert_error'], }); }); @@ -132,6 +132,21 @@ describe('getBlockaidMetricsProps', () => { }); }); + it('includes "security_alert_error" ui_customization when type is an error', () => { + const result = getBlockaidMetricsProps({ + securityAlertResponse: { + ...securityAlertResponse, + result_type: BlockaidResultType.Errored, + reason: 'error: error message', + }, + }); + expect(result).toStrictEqual({ + ui_customizations: ['security_alert_error'], + security_alert_response: BlockaidResultType.Errored, + security_alert_reason: 'error: error message', + }); + }); + it('excludes eth call counts if providerRequestsCount is empty', () => { const result = getBlockaidMetricsProps({ securityAlertResponse: { diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap index 1979110264ea..04b2a4843aab 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap @@ -93,7 +93,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo
`; -exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResponse.result_type is 'Failed 1`] = ` +exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResponse.result_type is 'Error 1`] = `
) : null; - const isFailedResultType = resultType === BlockaidResultType.Failed; + const isFailedResultType = resultType === BlockaidResultType.Errored; const severity = resultType === BlockaidResultType.Malicious diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js index b34d9d9b0e0a..4abd67e10685 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js @@ -70,13 +70,13 @@ describe('Blockaid Banner Alert', () => { expect(container.querySelector('.mm-banner-alert')).toBeNull(); }); - it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Failed}`, () => { + it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Errored}`, () => { const { container } = renderWithProvider( , @@ -140,13 +140,13 @@ describe('Blockaid Banner Alert', () => { expect(getByText('This is a deceptive request')).toBeInTheDocument(); }); - it(`should render title, "This is a suspicious request", when the reason is "${BlockaidReason.failed}"`, () => { + it(`should render title, "This is a suspicious request", when the reason is "${BlockaidReason.errored}"`, () => { const { getByText } = renderWithProvider( , @@ -248,14 +248,14 @@ describe('Blockaid Banner Alert', () => { }); describe('when constructing the Blockaid Report URL', () => { - describe(`when result_type='${BlockaidResultType.Failed}'`, () => { + describe(`when result_type='${BlockaidResultType.Errored}'`, () => { it('should pass the classification as "error" and the resultType as "Error"', () => { const { getByRole } = renderWithProvider( , @@ -276,7 +276,7 @@ describe('Blockaid Banner Alert', () => { 'If you approve this request, a third party known for scams might take all your assets.', [BlockaidReason.blurFarming]: 'If you approve this request, someone can steal your assets listed on Blur.', - [BlockaidReason.failed]: + [BlockaidReason.errored]: 'Because of an error, this request was not verified by the security provider. Proceed with caution.', [BlockaidReason.maliciousDomain]: "You're interacting with a malicious domain. If you approve this request, you might lose your assets.", From be604fced1ff3c39fcc578a366ec08b2d6bd8c85 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Wed, 21 Feb 2024 08:52:47 +0100 Subject: [PATCH 15/17] test: add scenario sign typed v3 with hardware wallet (#23063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** In this PR we add the scenario for the flow: sign typed v3 with hardware wallet. Note: sign typed data v3 only work with QR-based wallets, not with Trezor nor Ledger. This task belongs to the effort of documenting manual QA flows[ in this Epic](https://github.com/MetaMask/metamask-extension/issues/21962). ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/22028 ## **Manual testing steps** Check steps are coherent with the flow in the video (at the end of the video the signature is closed due to a current identified [issue](https://github.com/MetaMask/metamask-extension/issues/23074)) Note: You can see the table rendered [here](https://github.com/MetaMask/metamask-extension/blob/1c387482f46acd9c1fd16b26f44acea9817152d6/test/scenarios/13.%20sign/sign%20typed%20data%20v3%20with%20hardware%20wallet.csv) for an easier review ## **Screenshots/Recordings** https://github.com/MetaMask/metamask-extension/assets/54408225/322eda2a-5e5d-411b-bd17-29dd46cb137b ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- ...ign typed data v3 with hardware wallet.csv | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/scenarios/13. sign/sign typed data v3 with hardware wallet.csv diff --git a/test/scenarios/13. sign/sign typed data v3 with hardware wallet.csv b/test/scenarios/13. sign/sign typed data v3 with hardware wallet.csv new file mode 100644 index 000000000000..cebeaffd5c02 --- /dev/null +++ b/test/scenarios/13. sign/sign typed data v3 with hardware wallet.csv @@ -0,0 +1,25 @@ +Steps,Test Steps,Preconditions,Test Data,Expected Result,Notes +1,Open the extension.,,,The Welcome Back screen is shown., +2,Proceed to Unlock the wallet.,,password (8 characters min).,"The Ether balance is shown on the overview. +The wallet address is shown on the overview.", +3,"Click on account menu icon. Click ""Add account or hardware wallet"".",,,"The ""Add account"" modal is shown.", +4,"On ""Add account"" modal, click ""Add hardware wallet"" button.",,,"""Connect a hardware wallet"" screen is shown. User can choose between different options to connect a hardware: Ledger, Trezor, Lattice, or QR-based. ""Continue"" button is disabled.", +5,Choose an option to connect hardware wallet.,We need to have a QR-based hardware wallet set up to test this functionality.,"e.g. choose ""QR-based""","""Continue"" button is enabled.", +6,"Unlock the QR-based wallet and sync it with MetaMask.",,Password for hardware wallet,"Hardware wallet is detected by MetaMask. ""Select an account"" screen is shown on MetaMask, accounts on hardware wallet are shown on this screen.","Note: using Ledger or Trezor won't work for this flow, since they don't support Sign Typed Data V3." +7,"Choose one or multiples accounts that user wants to connect. Then click ""Unlock"".",,,, +8,Click account menu icon to open accounts list.,,,"In accounts list, all selected hardware wallet accounts are shown, and they are all flagged with harware wallet name to be distinguished from other accounts.", +9,Select one hardware wallet account.,,,"The Ether balance for the selected hardware wallet account is shown on the overview. +The selected account address is shown on the overview.", +10,Open the test dapp in another tab.,,https://metamask.github.io/test-dapp/,, +11,Click Connect.,,,"The MetaMask popup is opened with the Connect with MetaMask screen displayed. +Your imported hardware wallet account is selected.", +12,Click Next and Connect with the hardware wallet account.,,,"The MetaMask popup is closed. +You are connected to the test dapp.", +13,"Click ""Sign Typed Data V3"".",,,"The MetaMask popup is open. +The signature message is displayed in JSON formatting.", +14,"Click ""Sign"".",,,The QR code modal with the signature request is displayed., +15,"Scan the QR code with the QR-based wallet.",,,The signature QR code is displayed in the QR-based wallet., +15,"Click ""Get Signature"".",,,The computer camera is opened., +16,Scan the Signature from the QR-based wallet.,,,"The signature hash is displayed in the test-dapp result. +The MetaMask popup is closed.", +17,Verify signed hash.,,,The signed address is correctly verified.,The address shown in the test dapp is the same as the hardware wallet account. From cb14ec537747fe75c975259aea73a8c45eea90ed Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Wed, 21 Feb 2024 15:52:04 +0530 Subject: [PATCH 16/17] UX: Show same balance on eth overview and account list item (#23059) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is to ensure total balance shows up for both eth overview and account list item ## **Related issues** Fixes: #23058 ## **Manual testing steps** 1. Go to Eth Overview section, on a non test network. Look at the eth overview balance 2. Account list item should show same balance as eth overview 3. Total balance logic works only for NON-TEST Networks ## **Screenshots/Recordings** ### **Before** https://github.com/MetaMask/metamask-extension/assets/39872794/aaab32c5-cbb8-43e2-b78d-6d3ee71535ee ### **After** https://github.com/MetaMask/metamask-extension/assets/39872794/54d61617-33e1-4b99-a699-cfd372d21b72 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: David Walsh --- test/e2e/tests/account-token-list.spec.js | 35 ++++++++----------- .../app/wallet-overview/eth-overview.js | 17 ++++++--- .../account-list-item.test.js.snap | 4 +-- .../account-list-item/account-list-item.js | 16 ++++++--- .../__snapshots__/your-accounts.test.tsx.snap | 4 +-- ui/selectors/selectors.js | 5 +++ 6 files changed, 47 insertions(+), 34 deletions(-) diff --git a/test/e2e/tests/account-token-list.spec.js b/test/e2e/tests/account-token-list.spec.js index 582a5cd59e90..1285027ed3e3 100644 --- a/test/e2e/tests/account-token-list.spec.js +++ b/test/e2e/tests/account-token-list.spec.js @@ -2,27 +2,24 @@ const { strict: assert } = require('assert'); const { withFixtures, defaultGanacheOptions, - unlockWallet, + logInWithBalanceValidation, } = require('../helpers'); + const FixtureBuilder = require('../fixture-builder'); -const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); describe('Settings', function () { - const smartContract = SMART_CONTRACTS.ERC1155; it('Should match the value of token list item and account list item for eth conversion', async function () { await withFixtures( { - dapp: true, fixtures: new FixtureBuilder().build(), - defaultGanacheOptions, - smartContract, + ganacheOptions: defaultGanacheOptions, title: this.test.fullTitle(), }, - async ({ driver }) => { - await unlockWallet(driver); + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); await driver.clickElement('[data-testid="home__asset-tab"]'); - const tokenValue = '0 ETH'; + const tokenValue = '25 ETH'; const tokenListAmount = await driver.findElement( '[data-testid="multichain-token-list-item-value"]', ); @@ -33,7 +30,7 @@ describe('Settings', function () { '.multichain-account-list-item .multichain-account-list-item__avatar-currency .currency-display-component__text', ); - assert.equal(await accountTokenValue.getText(), '0', 'ETH'); + assert.equal(await accountTokenValue.getText(), '25', 'ETH'); }, ); }); @@ -41,14 +38,12 @@ describe('Settings', function () { it('Should match the value of token list item and account list item for fiat conversion', async function () { await withFixtures( { - dapp: true, fixtures: new FixtureBuilder().build(), - defaultGanacheOptions, - smartContract, + ganacheOptions: defaultGanacheOptions, title: this.test.fullTitle(), }, - async ({ driver }) => { - await unlockWallet(driver); + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); await driver.clickElement( '[data-testid="account-options-menu-button"]', @@ -65,18 +60,16 @@ describe('Settings', function () { ); await driver.clickElement('[data-testid="home__asset-tab"]'); - const tokenValue = '0 ETH'; const tokenListAmount = await driver.findElement( - '[data-testid="multichain-token-list-item-value"]', + '.eth-overview__primary-container', ); - assert.equal(await tokenListAmount.getText(), tokenValue); - + assert.equal(await tokenListAmount.getText(), '$42,500.00\nUSD'); await driver.clickElement('[data-testid="account-menu-icon"]'); const accountTokenValue = await driver.waitForSelector( - '.multichain-account-list-item .multichain-account-list-item__avatar-currency .currency-display-component__text', + '.multichain-account-list-item .multichain-account-list-item__asset', ); - assert.equal(await accountTokenValue.getText(), '0', 'ETH'); + assert.equal(await accountTokenValue.getText(), '$42,500.00USD'); }, ); }); diff --git a/ui/components/app/wallet-overview/eth-overview.js b/ui/components/app/wallet-overview/eth-overview.js index 585386ece792..dece08d61f14 100644 --- a/ui/components/app/wallet-overview/eth-overview.js +++ b/ui/components/app/wallet-overview/eth-overview.js @@ -34,6 +34,7 @@ import { getShouldHideZeroBalanceTokens, getCurrentNetwork, getSelectedAccountCachedBalance, + getShowFiatInTestnets, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) getSwapsDefaultToken, getCurrentKeyring, @@ -106,10 +107,15 @@ const EthOverview = ({ className, showAddress }) => { selectedAddress, shouldHideZeroBalanceTokens, ); + const showFiatInTestnets = useSelector(getShowFiatInTestnets); + const showFiat = + TEST_NETWORKS.includes(currentNetwork?.nickname) && !showFiatInTestnets; - const balanceToUse = TEST_NETWORKS.includes(currentNetwork?.nickname) - ? balance - : totalWeiBalance; + let balanceToUse = totalWeiBalance; + + if (showFiat) { + balanceToUse = balance; + } const isSwapsChain = useSelector(getIsSwapsChain); @@ -196,7 +202,10 @@ const EthOverview = ({ className, showAddress }) => { ? PRIMARY : SECONDARY } - showFiat={!TEST_NETWORKS.includes(currentNetwork?.nickname)} + showFiat={ + !showFiat || + !TEST_NETWORKS.includes(currentNetwork?.nickname) + } ethNumberOfDecimals={4} hideTitle /> diff --git a/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap b/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap index cc754b6c907f..0acee96e7f7d 100644 --- a/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap +++ b/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap @@ -71,12 +71,12 @@ exports[`AccountListItem renders AccountListItem component and shows account nam >
- $3.31 + $880.18 { setAccountListItemMenuElement(ref); }; - + const showFiatInTestnets = useSelector(getShowFiatInTestnets); + const showFiat = + TEST_NETWORKS.includes(currentNetwork?.nickname) && !showFiatInTestnets; const { totalWeiBalance, orderedTokenList } = useAccountTotalFiatBalance( identity.address, ); - const balanceToTranslate = TEST_NETWORKS.includes(currentNetwork?.nickname) - ? totalWeiBalance - : identity.balance; + let balanceToTranslate = totalWeiBalance; + if (showFiat) { + balanceToTranslate = identity.balance; + } // If this is the selected item in the Account menu, // scroll the item into view @@ -209,7 +213,9 @@ export const AccountListItem = ({ ethNumberOfDecimals={MAXIMUM_CURRENCY_DECIMALS} value={balanceToTranslate} type={PRIMARY} - showFiat={!TEST_NETWORKS.includes(currentNetwork?.nickname)} + showFiat={ + !showFiat || !TEST_NETWORKS.includes(currentNetwork?.nickname) + } /> diff --git a/ui/components/multichain/pages/send/components/__snapshots__/your-accounts.test.tsx.snap b/ui/components/multichain/pages/send/components/__snapshots__/your-accounts.test.tsx.snap index 04ea196e505b..d213c98faec4 100644 --- a/ui/components/multichain/pages/send/components/__snapshots__/your-accounts.test.tsx.snap +++ b/ui/components/multichain/pages/send/components/__snapshots__/your-accounts.test.tsx.snap @@ -74,12 +74,12 @@ exports[`SendPageYourAccounts render renders correctly 1`] = ` >
- $537,761.36 + $880.18 { return state.metamask.useSafeChainsListValidation; }; +export function getShowFiatInTestnets(state) { + const { showFiatInTestnets } = getPreferences(state); + return showFiatInTestnets; +} + /** * To get the useCurrencyRateCheck flag which to check if the user prefers currency conversion * From a13de550347f0202a10903dd09efde820da0a0ad Mon Sep 17 00:00:00 2001 From: Harika Jetpoluru <153644847+hjetpoluru@users.noreply.github.com> Date: Wed, 21 Feb 2024 08:05:22 -0500 Subject: [PATCH 17/17] Fix test failure caused by previous revert - 22946 (#23076) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** PR #22762, an e2e test for the update network, was functioning correctly but started failing after being merged into the develop branch due to changes introduced in PR #22832. This PR addresses and fixes the test failure caused by the previous revert in PR #22946. Note:- The changes from the develop branch had to be reverted due to time constraints. ## **Related issues** #22949 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- test/e2e/tests/network/update-network.spec.ts | 113 ++++++++++++++++++ .../add-network-modal.test.js.snap | 4 + .../networks-form/networks-form.js | 4 + 3 files changed, 121 insertions(+) create mode 100644 test/e2e/tests/network/update-network.spec.ts diff --git a/test/e2e/tests/network/update-network.spec.ts b/test/e2e/tests/network/update-network.spec.ts new file mode 100644 index 000000000000..db5d2a43402b --- /dev/null +++ b/test/e2e/tests/network/update-network.spec.ts @@ -0,0 +1,113 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import FixtureBuilder from '../../fixture-builder'; +import { + defaultGanacheOptions, + unlockWallet, + withFixtures, +} from '../../helpers'; +import { Driver } from '../../webdriver/driver'; + +const selectors = { + accountOptionsMenuButton: '[data-testid="account-options-menu-button"]', + informationSymbol: '[data-testid="info-tooltip"]', + settingsOption: { text: 'Settings', tag: 'div' }, + networkOption: { text: 'Networks', tag: 'div' }, + generalOption: { text: 'General', tag: 'div' }, + ethereumNetwork: { text: 'Ethereum Mainnet', tag: 'div' }, + deleteButton: { text: 'Delete', tag: 'button' }, + cancelButton: { text: 'Cancel', tag: 'button' }, + saveButton: { text: 'Save', tag: 'button' }, + updatedNetworkDropDown: { tag: 'span', text: 'Update Network' }, + errorMessageInvalidUrl: { + tag: 'h6', + text: 'URLs require the appropriate HTTP/HTTPS prefix.', + }, + networkNameInputField: '[data-testid="network-form-network-name"]', + rpcUrlInputField: '[data-testid="network-form-rpc-url"]', + chainIdInputField: '[data-testid="network-form-chain-id"]', + errorContainer: '.settings-tab__error', +}; + +const inputData = { + networkName: 'Update Network', + rpcUrl: 'test', + chainId: '0x539', +}; + +async function navigateToEditNetwork(driver: Driver) { + await driver.clickElement(selectors.accountOptionsMenuButton); + await driver.clickElement(selectors.settingsOption); + await driver.clickElement(selectors.networkOption); +} +describe('Update Network:', function (this: Suite) { + it('update network details and validate the ui elements', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + await navigateToEditNetwork(driver); + await driver.fill( + selectors.networkNameInputField, + inputData.networkName, + ); + await driver.fill(selectors.chainIdInputField, inputData.chainId); + await driver.clickElement(selectors.saveButton); + + // Validate the network name is updated + const updatedNetworkNamePresent = await driver.isElementPresent( + selectors.updatedNetworkDropDown, + ); + assert.equal( + updatedNetworkNamePresent, + true, + 'Network name is not updated', + ); + + await navigateToEditNetwork(driver); + await driver.fill(selectors.rpcUrlInputField, inputData.rpcUrl); + + // Validate the error message that appears for the invalid url format + const errorMessage = await driver.isElementPresent( + selectors.errorMessageInvalidUrl, + ); + assert.equal( + errorMessage, + true, + 'Error message for the invalid url did not appear', + ); + + // Validate the Save button is disabled for the invalid url format + const saveButton = await driver.findElement(selectors.saveButton); + const saveButtonEnabled = await saveButton.isEnabled(); + assert.equal(saveButtonEnabled, false, 'Save button is enabled'); + + // Validate the information symbol appears for chain id + const informationSymbolAppears = await driver.isElementPresent( + selectors.informationSymbol, + ); + assert.equal( + informationSymbolAppears, + true, + 'Information symbol did not appear for chain id', + ); + + await driver.clickElement(selectors.ethereumNetwork); + + // Validate the Save,Cancel Delete button is not present for the default network + await driver.assertElementNotPresent(selectors.deleteButton); + await driver.assertElementNotPresent(selectors.cancelButton); + await driver.assertElementNotPresent(selectors.saveButton); + + // Validate the error does not appear for updating the network name and chain id + await driver.clickElement(selectors.generalOption); + await driver.assertElementNotPresent(selectors.errorContainer); + }, + ); + }); +}); \ No newline at end of file diff --git a/ui/pages/onboarding-flow/add-network-modal/__snapshots__/add-network-modal.test.js.snap b/ui/pages/onboarding-flow/add-network-modal/__snapshots__/add-network-modal.test.js.snap index cf1180fdc481..9b0bd89d8cfb 100644 --- a/ui/pages/onboarding-flow/add-network-modal/__snapshots__/add-network-modal.test.js.snap +++ b/ui/pages/onboarding-flow/add-network-modal/__snapshots__/add-network-modal.test.js.snap @@ -60,6 +60,7 @@ exports[`Add Network Modal should render 1`] = `
@@ -90,6 +91,7 @@ exports[`Add Network Modal should render 1`] = `
@@ -144,6 +146,7 @@ exports[`Add Network Modal should render 1`] = `
@@ -201,6 +204,7 @@ exports[`Add Network Modal should render 1`] = `
diff --git a/ui/pages/settings/networks-tab/networks-form/networks-form.js b/ui/pages/settings/networks-tab/networks-form/networks-form.js index f7b892b894a0..e71f6bf3a0a7 100644 --- a/ui/pages/settings/networks-tab/networks-form/networks-form.js +++ b/ui/pages/settings/networks-tab/networks-form/networks-form.js @@ -709,6 +709,7 @@ const NetworksForm = ({ titleText={t('networkName')} value={networkName} disabled={viewOnly} + dataTestId="network-form-network-name" />