From 0a790f54a0531fc36c38dbd75607b00b395b9f52 Mon Sep 17 00:00:00 2001 From: hunty Date: Wed, 11 Dec 2024 20:58:08 -0600 Subject: [PATCH 01/17] fix: (MMS-1789) bridge api called when external services disabled (#29077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Bridge API gets called even when all privacy toggles are disabled: https://bridge.api.cx.metamask.io/getAllFeatureFlags [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29077?quickstart=1) ## **Related issues** Fixes: checks if external services are enabled (Basic Functionality toggle) before calling this API in the useBridging hook. ## **Manual testing steps** 1. Start onboarding through the MetaMask wallet. 2. During onboarding, toggle the security feature 'Basic Functionality' OFF. 3. Observe network calls to ensure this endpoint is not hit. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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/hooks/bridge/useBridging.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/hooks/bridge/useBridging.ts b/ui/hooks/bridge/useBridging.ts index a8307658e285..2b7ffb0083c9 100644 --- a/ui/hooks/bridge/useBridging.ts +++ b/ui/hooks/bridge/useBridging.ts @@ -10,6 +10,7 @@ import { getIsBridgeEnabled, getMetaMetricsId, getParticipateInMetaMetrics, + getUseExternalServices, SwapsEthToken, ///: END:ONLY_INCLUDE_IF } from '../../selectors'; @@ -45,6 +46,7 @@ const useBridging = () => { const isMarketingEnabled = useSelector(getDataCollectionForMarketing); const providerConfig = useSelector(getProviderConfig); const keyring = useSelector(getCurrentKeyring); + const isExternalServicesEnabled = useSelector(getUseExternalServices); // @ts-expect-error keyring type is wrong maybe? const usingHardwareWallet = isHardwareKeyring(keyring.type); @@ -52,7 +54,9 @@ const useBridging = () => { const isBridgeChain = useSelector(getIsBridgeChain); useEffect(() => { - dispatch(setBridgeFeatureFlags()); + if (isExternalServicesEnabled) { + dispatch(setBridgeFeatureFlags()); + } }, [dispatch, setBridgeFeatureFlags]); const openBridgeExperience = useCallback( From 1e3af312f6e7866468acd02208569a5e323bbe5a Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 12 Dec 2024 06:55:04 -0330 Subject: [PATCH 02/17] chore: Revert "feat: add websocket support for c2 detection (#28782)" (#29122) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e0f6575a6dc80913532f33202b1d3e91b31137b4, which is causing failing e2e tests on main ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29122?quickstart=1) ## **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 Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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/manifest/v2/_base.json | 2 - app/manifest/v3/_base.json | 4 +- app/scripts/background.js | 2 +- privacy-snapshot.json | 3 +- test/e2e/helpers.js | 44 ----------- test/e2e/tests/phishing-controller/mocks.js | 19 ++--- .../phishing-detection.spec.js | 76 +------------------ 7 files changed, 14 insertions(+), 136 deletions(-) diff --git a/app/manifest/v2/_base.json b/app/manifest/v2/_base.json index 2f41a7e987fa..f29b7458a9e5 100644 --- a/app/manifest/v2/_base.json +++ b/app/manifest/v2/_base.json @@ -66,8 +66,6 @@ "clipboardWrite", "http://*/*", "https://*/*", - "ws://*/*", - "wss://*/*", "activeTab", "webRequest", "webRequestBlocking", diff --git a/app/manifest/v3/_base.json b/app/manifest/v3/_base.json index 89758033f33a..4d6ee38437d3 100644 --- a/app/manifest/v3/_base.json +++ b/app/manifest/v3/_base.json @@ -50,9 +50,7 @@ "http://localhost:8545/", "file://*/*", "http://*/*", - "https://*/*", - "ws://*/*", - "wss://*/*" + "https://*/*" ], "icons": { "16": "images/icon-16.png", diff --git a/app/scripts/background.js b/app/scripts/background.js index 3571be9022fa..e9aaf2cab20b 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -323,7 +323,7 @@ function maybeDetectPhishing(theController) { return {}; }, { - urls: ['http://*/*', 'https://*/*', 'ws://*/*', 'wss://*/*'], + urls: ['http://*/*', 'https://*/*'], }, isManifestV2 ? ['blocking'] : [], ); diff --git a/privacy-snapshot.json b/privacy-snapshot.json index 230634421d52..49eedf275364 100644 --- a/privacy-snapshot.json +++ b/privacy-snapshot.json @@ -72,6 +72,5 @@ "unresponsive-rpc.test", "unresponsive-rpc.url", "user-storage.api.cx.metamask.io", - "www.4byte.directory", - "verify.walletconnect.com" + "www.4byte.directory" ] diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 4ade3f2e48ba..b06c29b17acf 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -4,7 +4,6 @@ const BigNumber = require('bignumber.js'); const mockttp = require('mockttp'); const detectPort = require('detect-port'); const { difference } = require('lodash'); -const WebSocket = require('ws'); const createStaticServer = require('../../development/create-static-server'); const { setupMocking } = require('./mock-e2e'); const { Ganache } = require('./seeder/ganache'); @@ -641,48 +640,6 @@ async function unlockWallet( } } -/** - * Simulates a WebSocket connection by executing a script in the browser context. - * - * @param {WebDriver} driver - The WebDriver instance. - * @param {string} hostname - The hostname to connect to. - */ -async function createWebSocketConnection(driver, hostname) { - try { - await driver.executeScript(async (wsHostname) => { - const url = `ws://${wsHostname}:8000`; - - const socket = new WebSocket(url); - - socket.onopen = () => { - console.log('WebSocket connection opened'); - socket.send('Hello, server!'); - }; - - socket.onerror = (error) => { - console.error( - 'WebSocket error:', - error.message || 'Connection blocked', - ); - }; - - socket.onmessage = (event) => { - console.log('Message received from server:', event.data); - }; - - socket.onclose = () => { - console.log('WebSocket connection closed'); - }; - }, hostname); - } catch (error) { - console.error( - `Failed to execute WebSocket connection script for ws://${hostname}:8081`, - error, - ); - throw error; - } -} - const logInWithBalanceValidation = async (driver, ganacheServer) => { await unlockWallet(driver); // Wait for balance to load @@ -1018,5 +975,4 @@ module.exports = { tempToggleSettingRedesignedTransactionConfirmations, openMenuSafe, sentryRegEx, - createWebSocketConnection, }; diff --git a/test/e2e/tests/phishing-controller/mocks.js b/test/e2e/tests/phishing-controller/mocks.js index 3165847740bf..fe11118c6fd2 100644 --- a/test/e2e/tests/phishing-controller/mocks.js +++ b/test/e2e/tests/phishing-controller/mocks.js @@ -10,9 +10,7 @@ const { const lastUpdated = 1; const defaultHotlist = { data: [] }; const defaultC2DomainBlocklist = { - recentlyAdded: [ - '33c8e026e76cea2df82322428554c932961cd80080fa379454350d7f13371f36', // hash for malicious.localhost - ], + recentlyAdded: [], recentlyRemoved: [], lastFetchedAt: '2024-08-27T15:30:45Z', }; @@ -97,12 +95,15 @@ async function setupPhishingDetectionMocks( }; }); - await mockServer.forGet(C2_DOMAIN_BLOCKLIST_URL).thenCallback(() => { - return { - statusCode: 200, - json: defaultC2DomainBlocklist, - }; - }); + await mockServer + .forGet(C2_DOMAIN_BLOCKLIST_URL) + .withQuery({ timestamp: '2024-08-27T15:30:45Z' }) + .thenCallback(() => { + return { + statusCode: 200, + json: defaultC2DomainBlocklist, + }; + }); await mockServer .forGet('https://github.com/MetaMask/eth-phishing-detect/issues/new') diff --git a/test/e2e/tests/phishing-controller/phishing-detection.spec.js b/test/e2e/tests/phishing-controller/phishing-detection.spec.js index 98184b85224e..ad199cea1e70 100644 --- a/test/e2e/tests/phishing-controller/phishing-detection.spec.js +++ b/test/e2e/tests/phishing-controller/phishing-detection.spec.js @@ -2,13 +2,13 @@ const { strict: assert } = require('assert'); const { createServer } = require('node:http'); const { createDeferredPromise } = require('@metamask/utils'); const { until } = require('selenium-webdriver'); + const { defaultGanacheOptions, withFixtures, openDapp, unlockWallet, WINDOW_TITLES, - createWebSocketConnection, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); const { @@ -315,80 +315,6 @@ describe('Phishing Detection', function () { ); }); - it('should block a website that makes a websocket connection to a malicious command and control server', async function () { - const testPageURL = 'http://localhost:8080'; - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - testSpecificMock: async (mockServer) => { - await mockServer.forAnyWebSocket().thenEcho(); - await setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - }); - }, - dapp: true, - }, - async ({ driver }) => { - await unlockWallet(driver); - - await driver.openNewPage(testPageURL); - - await createWebSocketConnection(driver, 'malicious.localhost'); - - await driver.switchToWindowWithTitle( - 'MetaMask Phishing Detection', - 10000, - ); - - await driver.waitForSelector({ - testId: 'unsafe-continue-loaded', - }); - - await driver.clickElement({ - text: 'Back to safety', - }); - - const currentUrl = await driver.getCurrentUrl(); - const expectedPortfolioUrl = `https://portfolio.metamask.io/?metamaskEntry=phishing_page_portfolio_button`; - - assert.equal(currentUrl, expectedPortfolioUrl); - }, - ); - }); - - it('should not block a website that makes a safe WebSocket connection', async function () { - const testPageURL = 'http://localhost:8080/'; - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - testSpecificMock: async (mockServer) => { - await mockServer.forAnyWebSocket().thenEcho(); - await setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - }); - }, - dapp: true, - }, - async ({ driver }) => { - await unlockWallet(driver); - - await driver.openNewPage(testPageURL); - - await createWebSocketConnection(driver, 'safe.localhost'); - - await driver.wait(until.titleIs(WINDOW_TITLES.TestDApp), 10000); - - const currentUrl = await driver.getCurrentUrl(); - - assert.equal(currentUrl, testPageURL); - }, - ); - }); - describe('Phishing redirect protections', function () { /** * Status codes 305 (via Location header) and 306 (Set-Proxy) header do not From b8f6ba7395c95a9333ab93025d07951c637ecaf3 Mon Sep 17 00:00:00 2001 From: infiniteflower <139582705+infiniteflower@users.noreply.github.com> Date: Thu, 12 Dec 2024 04:52:26 -0500 Subject: [PATCH 03/17] fix: send up requestId for squid (#29042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29042?quickstart=1) This PR fixes issues with calling the Bridge API for `getTxStatus` for bridges that expect a `requestId`. ## **Related issues** Fixes: ## **Manual testing steps** 1. Get a bridge quote 2. Select Axelar/Squid 3. Execute the bridge 4. See your status update correctly ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../controllers/bridge-status/utils.ts | 25 +++++++++++++++---- shared/types/bridge-status.ts | 10 ++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/scripts/controllers/bridge-status/utils.ts b/app/scripts/controllers/bridge-status/utils.ts index 33af3c09cb03..d8dbac9e1590 100644 --- a/app/scripts/controllers/bridge-status/utils.ts +++ b/app/scripts/controllers/bridge-status/utils.ts @@ -6,6 +6,7 @@ import fetchWithCache from '../../../../shared/lib/fetch-with-cache'; import { StatusResponse, StatusRequestWithSrcTxHash, + StatusRequestDto, } from '../../../../shared/types/bridge-status'; // TODO fix this // eslint-disable-next-line import/no-restricted-paths @@ -16,18 +17,32 @@ const CLIENT_ID_HEADER = { 'X-Client-Id': BRIDGE_CLIENT_ID }; export const BRIDGE_STATUS_BASE_URL = `${BRIDGE_API_BASE_URL}/getTxStatus`; -export const fetchBridgeTxStatus = async ( +export const getStatusRequestDto = ( statusRequest: StatusRequestWithSrcTxHash, -) => { - // Assemble params +): StatusRequestDto => { const { quote, ...statusRequestNoQuote } = statusRequest; + const statusRequestNoQuoteFormatted = Object.fromEntries( Object.entries(statusRequestNoQuote).map(([key, value]) => [ key, value.toString(), ]), - ); - const params = new URLSearchParams(statusRequestNoQuoteFormatted); + ) as unknown as Omit; + + const requestId: { requestId: string } | Record = + quote?.requestId ? { requestId: quote.requestId } : {}; + + return { + ...statusRequestNoQuoteFormatted, + ...requestId, + }; +}; + +export const fetchBridgeTxStatus = async ( + statusRequest: StatusRequestWithSrcTxHash, +) => { + const statusRequestDto = getStatusRequestDto(statusRequest); + const params = new URLSearchParams(statusRequestDto); // Fetch const url = `${BRIDGE_STATUS_BASE_URL}?${params.toString()}`; diff --git a/shared/types/bridge-status.ts b/shared/types/bridge-status.ts index 4c3f79bcd672..fc9357ef968a 100644 --- a/shared/types/bridge-status.ts +++ b/shared/types/bridge-status.ts @@ -28,6 +28,16 @@ export type StatusRequest = { refuel?: boolean; // lifi }; +export type StatusRequestDto = Omit< + StatusRequest, + 'quote' | 'srcChainId' | 'destChainId' | 'refuel' +> & { + srcChainId: string; // lifi, socket, squid + destChainId: string; // lifi, socket, squid + requestId?: string; + refuel?: string; // lifi +}; + export type StatusRequestWithSrcTxHash = StatusRequest & { srcTxHash: string; }; From 09b4c80d46cf040ef77dc01c7d279f9bd7db7d30 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Thu, 12 Dec 2024 10:06:40 +0000 Subject: [PATCH 04/17] feat: Add link to pending transaction alert (#28721) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR substitutes a purely text based alert for pending transactions with one that includes a hyperlink to the docs. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/28721?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/28308 ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ![Screenshot 2024-12-02 at 11 13 58](https://github.com/user-attachments/assets/146b353d-a515-40db-95cd-5e091700cf18) ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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. ## **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 | 3 - app/_locales/el/messages.json | 3 - app/_locales/en/messages.json | 14 +++-- app/_locales/en_GB/messages.json | 3 - app/_locales/es/messages.json | 3 - app/_locales/fr/messages.json | 3 - app/_locales/hi/messages.json | 3 - app/_locales/id/messages.json | 3 - app/_locales/ja/messages.json | 3 - app/_locales/ko/messages.json | 3 - app/_locales/pt/messages.json | 3 - app/_locales/ru/messages.json | 3 - app/_locales/tl/messages.json | 3 - app/_locales/tr/messages.json | 3 - app/_locales/vi/messages.json | 3 - app/_locales/zh_CN/messages.json | 3 - jest.integration.config.js | 3 +- .../transactions/alerts.test.tsx | 2 +- .../alert-system/alert-modal/alert-modal.tsx | 15 +++-- .../general-alert/general-alert.tsx | 4 +- ui/ducks/confirm-alerts/confirm-alerts.ts | 32 ++++++++-- .../components/confirm/title/title.tsx | 1 + .../PendingTransactionAlertMessage.tsx | 32 ++++++++++ .../usePendingTransactionAlerts.test.ts | 58 +++++++++++++++++-- .../usePendingTransactionAlerts.ts | 12 ++-- 25 files changed, 141 insertions(+), 77 deletions(-) create mode 100644 ui/pages/confirmations/hooks/alerts/transactions/PendingTransactionAlertMessage.tsx diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 6d0878b57d5c..06d2f690716d 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Wir können mit dieser Transaktion nicht fortfahren, bis Sie die Gebühr manuell aktualisieren." }, - "alertMessagePendingTransactions": { - "message": "Diese Transaktion wird erst dann durchgeführt, wenn eine vorherige Transaktion abgeschlossen ist. Erfahren Sie, wie Sie eine Transaktion abbrechen oder beschleunigen können." - }, "alertMessageSignInDomainMismatch": { "message": "Die Website, die die Anfrage stellt, ist nicht die Website, bei der Sie sich anmelden. Dies könnte ein Versuch sein, Ihre Anmeldedaten zu stehlen." }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 58045c5b0578..8d09e2c6658f 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Δεν μπορούμε να συνεχίσουμε με αυτή τη συναλλαγή μέχρι να ενημερώσετε τα τέλη μη αυτόματα." }, - "alertMessagePendingTransactions": { - "message": "Αυτή η συναλλαγή δεν θα πραγματοποιηθεί μέχρι να ολοκληρωθεί μια προηγούμενη συναλλαγή. Μάθετε πώς να ακυρώσετε ή να επισπεύσετε μια συναλλαγή." - }, "alertMessageSignInDomainMismatch": { "message": "Ο ιστότοπος που υποβάλλει το αίτημα δεν είναι ο ιστότοπος στον οποίο έχετε συνδεθεί. Αυτό θα μπορούσε να είναι μια απόπειρα κλοπής των στοιχείων σύνδεσής σας." }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f42a539277d1..9d63e212d88c 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -440,9 +440,6 @@ "alertMessageNoGasPrice": { "message": "We can’t move forward with this transaction until you manually update the fee." }, - "alertMessagePendingTransactions": { - "message": "This transaction won’t go through until a previous transaction is complete. Learn how to cancel or speed up a transaction." - }, "alertMessageSignInDomainMismatch": { "message": "The site making the request is not the site you’re signing into. This could be an attempt to steal your login credentials." }, @@ -750,8 +747,7 @@ "message": "Beta" }, "betaHeaderText": { - "message": "This is a beta version. Please report bugs $1", - "description": "$1 represents the word 'here' in a hyperlink" + "message": "This is a beta version. Please report bugs $1" }, "betaMetamaskInstitutionalVersion": { "message": "MetaMask Institutional Beta Version" @@ -3994,6 +3990,14 @@ "pending": { "message": "Pending" }, + "pendingTransactionAlertMessage": { + "message": "This transaction won't go through until a previous transaction is complete. $1", + "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" + }, + "pendingTransactionAlertMessageHyperlink": { + "message": "Learn how to cancel or speed up a transaction.", + "description": "The text for the hyperlink in the pending transaction alert message" + }, "pendingTransactionInfo": { "message": "This transaction will not process until that one is complete." }, diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json index 2addf34f3c26..c72cccd973d9 100644 --- a/app/_locales/en_GB/messages.json +++ b/app/_locales/en_GB/messages.json @@ -421,9 +421,6 @@ "alertMessageNoGasPrice": { "message": "We can’t move forward with this transaction until you manually update the fee." }, - "alertMessagePendingTransactions": { - "message": "This transaction won’t go through until a previous transaction is complete. Learn how to cancel or speed up a transaction." - }, "alertMessageSignInDomainMismatch": { "message": "The site making the request is not the site you’re signing into. This could be an attempt to steal your login credentials." }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index f5bec514637e..2861d508743d 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "No podemos seguir adelante con esta transacción hasta que actualice manualmente la tarifa." }, - "alertMessagePendingTransactions": { - "message": "Esta transacción no se realizará hasta que se complete una transacción anterior. Aprenda cómo cancelar o acelerar una transacción." - }, "alertMessageSignInDomainMismatch": { "message": "El sitio que realiza la solicitud no es el sitio en el que está iniciando sesión. Esto podría ser un intento de robar sus credenciales de inicio de sesión." }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 4d5e59b25c52..5ae9377d8a69 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Nous ne pouvons pas valider cette transaction tant que vous n’avez pas mis à jour manuellement les frais." }, - "alertMessagePendingTransactions": { - "message": "La transaction précédente doit être finalisée avant que celle-ci ne soit traitée. Découvrez comment vous pouvez annuler ou accélérer une transaction." - }, "alertMessageSignInDomainMismatch": { "message": "Le site auquel vous êtes en train de vous connecter n’est pas le site à l’origine de la demande. Il pourrait s’agir d’une tentative de vol de vos identifiants de connexion." }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 2d4bcc52b891..a036aef959ce 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "जब तक आप शुल्क को मैन्युअल रूप से अपडेट नहीं करते, हम इस ट्रांसेक्शन को आगे नहीं बढ़ा सकते।" }, - "alertMessagePendingTransactions": { - "message": "यह ट्रांसेक्शन तब तक नहीं होगा जब तक पिछला ट्रांसेक्शन पूरा न हो जाए। किसी ट्रांसेक्शन को रद्द करने या तेज़ करने का तरीका जानें।" - }, "alertMessageSignInDomainMismatch": { "message": "अनुरोध करने वाली साइट वह साइट नहीं है जिस पर आप साइन इन कर रहे हैं। यह आपके लॉगिन क्रेडेंशियल चुराने का प्रयास हो सकता है।" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 9135a2e56bcf..5777f05c2322 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Kami tidak dapat melanjutkan transaksi ini hingga Anda memperbarui biayanya secara manual." }, - "alertMessagePendingTransactions": { - "message": "Transaksi ini tidak akan dilanjutkan hingga transaksi sebelumnya selesai. Pelajari cara membatalkan atau mempercepat transaksi." - }, "alertMessageSignInDomainMismatch": { "message": "Situs yang membuat permintaan bukanlah situs yang Anda masuki. Ini dapat merupakan upaya untuk mencuri kredensial login Anda." }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 8404c4eb3af4..561411606feb 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "手数料を手動で更新するまでこのトランザクションを進めることができません。" }, - "alertMessagePendingTransactions": { - "message": "前のトランザクションが完了するまでこのトランザクションを実行できません。トランザクションをキャンセルするか加速させる方法をご覧ください。" - }, "alertMessageSignInDomainMismatch": { "message": "要求元のサイトはサインインしようとしているサイトではありません。ログイン情報を盗もうとしている可能性があります。" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index cbd48592c7d0..941010db2abe 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "수수료를 직접 업데이트할 때까지는 이 트랜잭션을 진행할 수 없습니다." }, - "alertMessagePendingTransactions": { - "message": "이 트랜잭션은 이전 트랜잭션이 완료될 때까지 진행되지 않습니다. 트랜잭션을 취소하거나 속도를 올리는 법을 알아보세요." - }, "alertMessageSignInDomainMismatch": { "message": "요청을 보낸 사이트에 로그인되어 있지 않습니다. 이는 로그인 정보를 도용하려는 시도일 수 있습니다." }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 3a01b378c686..553b0ad31508 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Não podemos prosseguir com essa transação até você atualizar manualmente a taxa." }, - "alertMessagePendingTransactions": { - "message": "Essa transação não será processada até que a transação anterior seja concluída. Saiba como cancelar ou acelerar uma transação." - }, "alertMessageSignInDomainMismatch": { "message": "O site solicitante não é o mesmo em que você está entrando. Isso pode se tratar de uma tentativa de roubar suas credenciais de login." }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 385670721c1f..1403b6084d27 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Мы не сможем продолжить эту транзакцию, пока вы не обновите комиссию вручную." }, - "alertMessagePendingTransactions": { - "message": "Эта транзакция не будет выполнена, пока не завершится предыдущая транзакция. Узнайте, как отменить или ускорить транзакцию." - }, "alertMessageSignInDomainMismatch": { "message": "Сайт, отправляющий запрос, не является сайтом, на который вы входите. Это может быть попыткой украсть ваши учетные данные." }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index a13c9c6d3006..60855b61765d 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Hindi tayo makakapagpatuloy sa transaksyong ito hanggang sa manwal mong i-update ang bayad." }, - "alertMessagePendingTransactions": { - "message": "Hindi magpapatuloy ang transaksyong ito hanggang makumpleto ang naunang transaksyon. Alamin kung paano kanselahin o pabilisin ang transaksyon." - }, "alertMessageSignInDomainMismatch": { "message": "Ang site na humihiling ay hindi ang site kung saan ka nagsa-signin. Ito ay maaring isang pagtatangka para nakawin ang iyong mga kredensiyal sa pag-login." }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 8f761e554caa..6bcd1b8a61fc 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Siz ücreti manuel olarak güncelleyene dek bu işleme devam edemiyoruz." }, - "alertMessagePendingTransactions": { - "message": "Önceki bir işlem tamamlanana dek bu işlem gerçekleşmeyecektir. Bir işlemi nasıl iptal edeceğinizi veya hızlandıracağınızı öğrenin." - }, "alertMessageSignInDomainMismatch": { "message": "Talepte bulunan site giriş yaptığınız site değil. Bu durum oturum açma bilgilerinizi çalma teşebbüsü olabilir." }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 883f08f49a7e..3901eed1fc07 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "Chúng tôi không thể tiếp tục giao dịch này cho đến khi bạn cập nhật phí thủ công." }, - "alertMessagePendingTransactions": { - "message": "Giao dịch này sẽ không được thực hiện cho đến khi giao dịch trước đó hoàn tất. Tìm hiểu cách hủy hoặc đẩy nhanh giao dịch." - }, "alertMessageSignInDomainMismatch": { "message": "Trang web đưa ra yêu cầu không phải là trang web bạn đang đăng nhập. Đây có thể là một nỗ lực đánh cắp thông tin đăng nhập của bạn." }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index fb7ed008d6f6..4d548221769f 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -437,9 +437,6 @@ "alertMessageNoGasPrice": { "message": "您手动更新费用后,我们才能继续进行此交易。" }, - "alertMessagePendingTransactions": { - "message": "上一笔交易完成后,此交易才能继续进行。了解如何取消或加快交易。" - }, "alertMessageSignInDomainMismatch": { "message": "提出请求的网站不是您正在登录的网站。这可能试图窃取您的登录凭据。" }, diff --git a/jest.integration.config.js b/jest.integration.config.js index 685080330fb3..5a110d7a5632 100644 --- a/jest.integration.config.js +++ b/jest.integration.config.js @@ -25,8 +25,7 @@ module.exports = { setupFilesAfterEnv: ['/test/integration/config/setupAfter.js'], testMatch: ['/test/integration/**/*.test.(js|ts|tsx)'], testPathIgnorePatterns: ['/test/integration/config/*'], - // This was increased from 5500 to 10000 to when lazy loading was introduced - testTimeout: 10000, + testTimeout: 15000, // We have to specify the environment we are running in, which is jsdom. The // default is 'node'. This can be modified *per file* using a comment at the // head of the file. So it may be worthwhile to switch to 'node' in any diff --git a/test/integration/confirmations/transactions/alerts.test.tsx b/test/integration/confirmations/transactions/alerts.test.tsx index ffbad48b352b..72acf02efc60 100644 --- a/test/integration/confirmations/transactions/alerts.test.tsx +++ b/test/integration/confirmations/transactions/alerts.test.tsx @@ -362,7 +362,7 @@ describe('Contract Interaction Confirmation Alerts', () => { expect( await screen.findByTestId('alert-modal__selected-alert'), ).toHaveTextContent( - 'This transaction won’t go through until a previous transaction is complete. Learn how to cancel or speed up a transaction.', + "This transaction won't go through until a previous transaction is complete. Learn how to cancel or speed up a transaction.", ); }); diff --git a/ui/components/app/alert-system/alert-modal/alert-modal.tsx b/ui/components/app/alert-system/alert-modal/alert-modal.tsx index 10f5d90c3e77..2eb78fba44c1 100644 --- a/ui/components/app/alert-system/alert-modal/alert-modal.tsx +++ b/ui/components/app/alert-system/alert-modal/alert-modal.tsx @@ -164,12 +164,15 @@ function AlertDetails({ > {customDetails ?? ( - - {selectedAlert.message} - + {Boolean(selectedAlert.content) && selectedAlert.content} + {Boolean(selectedAlert.message) && ( + + {selectedAlert.message} + + )} {selectedAlert.alertDetails?.length ? ( {t('alertModalDetails')} diff --git a/ui/components/app/alert-system/general-alert/general-alert.tsx b/ui/components/app/alert-system/general-alert/general-alert.tsx index 5ac2b2a335fb..5c222902b3ab 100644 --- a/ui/components/app/alert-system/general-alert/general-alert.tsx +++ b/ui/components/app/alert-system/general-alert/general-alert.tsx @@ -21,13 +21,14 @@ import { AlertProvider } from '../alert-provider'; import { AlertSeverity } from '../../../../ducks/confirm-alerts/confirm-alerts'; export type GeneralAlertProps = { - description: string; + description?: string; details?: React.ReactNode | string[]; onClickSupportLink?: () => void; provider?: SecurityProvider; reportUrl?: string; severity: AlertSeverity; title?: string; + children?: React.ReactNode; }; function ReportLink({ @@ -119,6 +120,7 @@ function GeneralAlert({ description={description} {...props} > + {props.children} ))} diff --git a/ui/pages/confirmations/hooks/alerts/transactions/PendingTransactionAlertMessage.tsx b/ui/pages/confirmations/hooks/alerts/transactions/PendingTransactionAlertMessage.tsx new file mode 100644 index 000000000000..472567ddb093 --- /dev/null +++ b/ui/pages/confirmations/hooks/alerts/transactions/PendingTransactionAlertMessage.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { ButtonLink, Text } from '../../../../../components/component-library'; +import { + TextColor, + TextVariant, +} from '../../../../../helpers/constants/design-system'; +import ZENDESK_URLS from '../../../../../helpers/constants/zendesk-url'; +import { useI18nContext } from '../../../../../hooks/useI18nContext'; + +export const PendingTransactionAlertMessage = () => { + const t = useI18nContext(); + + return ( + + {t('pendingTransactionAlertMessage', [ + + {t('pendingTransactionAlertMessageHyperlink')} + , + ])} + + ); +}; diff --git a/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.test.ts b/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.test.ts index b9b3d12dc7d0..f7be0f93e2c1 100644 --- a/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.test.ts +++ b/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.test.ts @@ -4,14 +4,34 @@ import { TransactionStatus, TransactionType, } from '@metamask/transaction-controller'; - -import { getMockConfirmState } from '../../../../../../test/data/confirmations/helper'; +import { useSelector } from 'react-redux'; +import { useParams } from 'react-router-dom'; import { genUnapprovedContractInteractionConfirmation } from '../../../../../../test/data/confirmations/contract-interaction'; +import { getMockConfirmState } from '../../../../../../test/data/confirmations/helper'; import { renderHookWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers'; -import { Severity } from '../../../../../helpers/constants/design-system'; import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants'; +import { Severity } from '../../../../../helpers/constants/design-system'; +import { + getRedesignedTransactionsEnabled, + submittedPendingTransactionsSelector, +} from '../../../../../selectors'; +import { PendingTransactionAlertMessage } from './PendingTransactionAlertMessage'; import { usePendingTransactionAlerts } from './usePendingTransactionAlerts'; +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +jest.mock('./PendingTransactionAlertMessage', () => ({ + PendingTransactionAlertMessage: () => 'PendingTransactionAlertMessage', +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: jest.fn().mockReturnValue({ id: 'mock-transaction-id' }), +})); + const ACCOUNT_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; const TRANSACTION_ID_MOCK = '123-456'; @@ -63,8 +83,19 @@ function runHook({ } describe('usePendingTransactionAlerts', () => { + const useSelectorMock = useSelector as jest.Mock; + beforeEach(() => { jest.resetAllMocks(); + + (useParams as jest.Mock).mockReturnValue({ id: 'mock-transaction-id' }); + + useSelectorMock.mockImplementation((selector) => { + if (selector.toString().includes('pendingApprovalsSortedSelector')) { + return []; + } + return undefined; + }); }); it('returns no alerts if no confirmation', () => { @@ -121,6 +152,24 @@ describe('usePendingTransactionAlerts', () => { }); it('returns alert if submitted transaction', () => { + useSelectorMock.mockImplementation((selector) => { + if (selector === submittedPendingTransactionsSelector) { + return [ + { name: 'first transaction', id: '1' }, + { name: 'second transaction', id: '2' }, + ]; + } else if (selector === getRedesignedTransactionsEnabled) { + return true; + } else if (selector.toString().includes('getUnapprovedTransaction')) { + return { type: TransactionType.contractInteraction }; + } else if ( + selector.toString().includes('pendingApprovalsSortedSelector') + ) { + return []; + } + return undefined; + }); + const alerts = runHook({ currentConfirmation: CONFIRMATION_MOCK, transactions: [TRANSACTION_META_MOCK], @@ -130,8 +179,7 @@ describe('usePendingTransactionAlerts', () => { { field: RowAlertKey.Speed, key: 'pendingTransactions', - message: - 'This transaction won’t go through until a previous transaction is complete. Learn how to cancel or speed up a transaction.', + content: PendingTransactionAlertMessage(), reason: 'Pending transaction', severity: Severity.Warning, }, diff --git a/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.ts b/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.ts index 5753b5329ea8..6ef15b5ff41f 100644 --- a/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.ts +++ b/ui/pages/confirmations/hooks/alerts/transactions/usePendingTransactionAlerts.ts @@ -1,14 +1,14 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; - -import { submittedPendingTransactionsSelector } from '../../../../../selectors'; -import { useI18nContext } from '../../../../../hooks/useI18nContext'; +import { isCorrectDeveloperTransactionType } from '../../../../../../shared/lib/confirmation.utils'; +import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants'; import { Alert } from '../../../../../ducks/confirm-alerts/confirm-alerts'; import { Severity } from '../../../../../helpers/constants/design-system'; -import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants'; +import { useI18nContext } from '../../../../../hooks/useI18nContext'; +import { submittedPendingTransactionsSelector } from '../../../../../selectors'; import { useConfirmContext } from '../../../context/confirm'; -import { isCorrectDeveloperTransactionType } from '../../../../../../shared/lib/confirmation.utils'; +import { PendingTransactionAlertMessage } from './PendingTransactionAlertMessage'; export function usePendingTransactionAlerts(): Alert[] { const t = useI18nContext(); @@ -30,7 +30,7 @@ export function usePendingTransactionAlerts(): Alert[] { { field: RowAlertKey.Speed, key: 'pendingTransactions', - message: t('alertMessagePendingTransactions'), + content: PendingTransactionAlertMessage(), reason: t('alertReasonPendingTransactions'), severity: Severity.Warning, }, From 714fa10bd5f1a78e20d46965802eae087ad6fa33 Mon Sep 17 00:00:00 2001 From: Alejandro Garcia Anglada Date: Thu, 12 Dec 2024 11:51:28 +0100 Subject: [PATCH 05/17] fix: solana balance on accounts selector (#29054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2024-12-10 at 15 45 14 ## **Description** Solana native balance weren't showing before [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29054?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** As of right now, manually testing is a bit complex, it needs to run the snap manually and the extension, since we 1st need to publish a new release to npm with more up to date work. The snap version we have in npm is outdated and won't support this flow. That said, if you want to go ahead and run locally the steps are the following: 1. Clone the [ Solana Snap monorepo](https://github.com/MetaMask/snap-solana-wallet) and run it locally with `yarn` and then `yarn start` 2. In the extension, at this branch, apply the following changes and run the extension as flask: ``` At builds.yml add the solana feature to the flask build: features: - build-flask - keyring-snaps + - solana At shared/lib/accounts/solana-wallet-snap.ts point the snap ID to the snap localhost: -export const SOLANA_WALLET_SNAP_ID: SnapId = SolanaWalletSnap.snapId as SnapId; +//export const SOLANA_WALLET_SNAP_ID: SnapId = SolanaWalletSnap.snapId as SnapId; +export const SOLANA_WALLET_SNAP_ID: SnapId = "local:http://localhost:8080/"; ``` 3. Manually install the snap via the snap dapp at http://localhost:3000 4. Enable the Solana account via Settings > Experimental > Enable Solana account 5. Create a Solana account from the account-list menu and see the account balance on it ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. --- package.json | 2 +- .../account-list-item.test.js.snap | 37 ++++++++++++------- .../account-list-item/account-list-item.js | 5 +-- .../account-list-item.test.js | 6 +-- yarn.lock | 31 +++------------- 5 files changed, 35 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index 223372f5dcc5..601400f80f7a 100644 --- a/package.json +++ b/package.json @@ -347,7 +347,7 @@ "@metamask/snaps-rpc-methods": "^11.7.0", "@metamask/snaps-sdk": "^6.13.0", "@metamask/snaps-utils": "^8.6.1", - "@metamask/solana-wallet-snap": "^0.1.9", + "@metamask/solana-wallet-snap": "^1.0.3", "@metamask/transaction-controller": "^42.0.0", "@metamask/user-operation-controller": "^19.0.0", "@metamask/utils": "^10.0.1", 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 ab9bc540fe7a..fb3bed6fd34b 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 @@ -269,25 +269,36 @@ exports[`AccountListItem renders AccountListItem component and shows account nam

+ BTC logo +
+
-
- undefined logo -
+ 1 + + + BTC +
diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index 365d09de8ecf..3ab048597f40 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -367,8 +367,7 @@ const AccountListItem = ({ {shortenAddress(normalizeSafeAddress(account.address))} - {/* For non-EVM networks we always want to show tokens */} - {mappedOrderedTokenList.length > 1 || !isEvmNetwork ? ( + {mappedOrderedTokenList.length > 1 ? ( ) : ( { expect(avatarGroup).not.toBeInTheDocument(); }); - it('renders fiat for non-EVM account', () => { + it('renders fiat and native balance for non-EVM account', () => { const { container } = render( { account: mockNonEvmAccount, @@ -308,8 +308,8 @@ describe('AccountListItem', () => { expectedBalance, ); expect(firstCurrencyDisplay.lastChild.textContent).toContain('USD'); - expect(secondCurrencyDisplay).not.toBeInTheDocument(); - expect(avatarGroup).toBeInTheDocument(); + expect(secondCurrencyDisplay.textContent).toContain('1BTC'); + expect(avatarGroup).not.toBeInTheDocument(); }); }); }); diff --git a/yarn.lock b/yarn.lock index f925a60fee76..e61b6efeef05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5605,23 +5605,6 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^9.0.0": - version: 9.0.0 - resolution: "@metamask/keyring-api@npm:9.0.0" - dependencies: - "@metamask/snaps-sdk": "npm:^6.7.0" - "@metamask/superstruct": "npm:^3.1.0" - "@metamask/utils": "npm:^9.2.1" - "@types/uuid": "npm:^9.0.8" - bech32: "npm:^2.0.0" - uuid: "npm:^9.0.1" - webextension-polyfill: "npm:^0.12.0" - peerDependencies: - "@metamask/providers": ^17.2.0 - checksum: 10/ff552c04a4d06c7b1a43d52809a9c141d38772586388f0ab96123bce445f148aa7f7e8165d03fa92ac391351de252c4b299fc2c16e690193f669b5329941fe75 - languageName: node - linkType: hard - "@metamask/keyring-controller@npm:^19.0.0, @metamask/keyring-controller@npm:^19.0.1": version: 19.0.1 resolution: "@metamask/keyring-controller@npm:19.0.1" @@ -6296,14 +6279,10 @@ __metadata: languageName: node linkType: hard -"@metamask/solana-wallet-snap@npm:^0.1.9": - version: 0.1.9 - resolution: "@metamask/solana-wallet-snap@npm:0.1.9" - dependencies: - "@metamask/keyring-api": "npm:^9.0.0" - "@metamask/snaps-sdk": "npm:^6.9.0" - buffer: "npm:^6.0.3" - checksum: 10/ec540948e1b5c693b0a31a32521d84c5d3796a5d62d1dfa0986cae47483040a0381c30419af4a86b2402efa5e95283b45a5d17bb705c11a181d0c6fa70b5be60 +"@metamask/solana-wallet-snap@npm:^1.0.3": + version: 1.0.3 + resolution: "@metamask/solana-wallet-snap@npm:1.0.3" + checksum: 10/4c7c0f05676e7bb84140226c1a3bd716493a6f3582142de83575df682e8351c7583fc5db6209fbde1b43f376fd4eda4d2063f0e651d8209e92001514fc8caf81 languageName: node linkType: hard @@ -26485,7 +26464,7 @@ __metadata: "@metamask/snaps-rpc-methods": "npm:^11.7.0" "@metamask/snaps-sdk": "npm:^6.13.0" "@metamask/snaps-utils": "npm:^8.6.1" - "@metamask/solana-wallet-snap": "npm:^0.1.9" + "@metamask/solana-wallet-snap": "npm:^1.0.3" "@metamask/test-bundler": "npm:^1.0.0" "@metamask/test-dapp": "npm:8.13.0" "@metamask/transaction-controller": "npm:^42.0.0" From 2e8ef02370f72febe0fa40370db62b7d61b641f0 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 12 Dec 2024 07:46:55 -0330 Subject: [PATCH 06/17] fix: Revert gridplus sdk version bumps (#29125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR reverts #27973 and #28008, and then forces an secp256k1 resolution to deal with a yarn audit failure. This is necessary to fix typed message signing with the lattice gridplus hardware wallet. All of this had been done on release branches and master in the past, when it should have been done directly on develop. We do want to restore the #27973 and #28008 changes soon, but that requires getting to root of why those changes result in typed message signing failure with lattice griduplus [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29125?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** Test "Sign Typed Message" v4 in the test dapp with a gridplus hardware wallet. It should succeed without error ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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: Charly Chevalier Co-authored-by: MetaMask Bot --- lavamoat/browserify/beta/policy.json | 238 +++++++++------- lavamoat/browserify/flask/policy.json | 238 +++++++++------- lavamoat/browserify/main/policy.json | 238 +++++++++------- lavamoat/browserify/mmi/policy.json | 238 +++++++++------- package.json | 24 +- yarn.lock | 380 ++++++++++++++++---------- 6 files changed, 820 insertions(+), 536 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 79058c8c6954..4212ef454eea 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,11 +158,6 @@ "webpack>events": true } }, - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -188,8 +183,8 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/curves": { @@ -197,32 +192,14 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, - "@metamask/utils>@scure/base": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@metamask/utils>@scure/base": true, + "@noble/hashes": true } }, "@ethersproject/abi": { @@ -389,9 +366,9 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, + "@keystonehq/metamask-airgapped-keyring>rlp": true, "@metamask/obs-store": true, "browserify>buffer": true, - "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -401,15 +378,16 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, + "eth-lattice-keyring>rlp": true, "uuid": true } }, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { - "globals": { - "TextEncoder": true + "@keystonehq/metamask-airgapped-keyring>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@lavamoat/lavadome-react": { @@ -1608,12 +1586,18 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>rlp": true + "ethereumjs-util>create-hash": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@metamask/logging-controller": { @@ -2364,9 +2348,20 @@ "@metamask/smart-transactions-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { "@metamask/smart-transactions-controller>@ethereumjs/util": true, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": true + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true } }, "@metamask/smart-transactions-controller>@ethereumjs/util": { @@ -2376,7 +2371,7 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "webpack>events": true } }, @@ -2615,6 +2610,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, "@ethersproject/contracts": true, @@ -2627,7 +2623,6 @@ "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, "@metamask/rpc-errors": true, - "@metamask/transaction-controller>@ethereumjs/common": true, "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, @@ -2639,14 +2634,6 @@ "webpack>events": true } }, - "@metamask/transaction-controller>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, @@ -3101,23 +3088,6 @@ "define": true } }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": { - "packages": { - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": true, - "webpack>events": true - } - }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": { - "globals": { - "console.warn": true, - "fetch": true - }, - "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true - } - }, "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { "packages": { "@swc/helpers>tslib": true, @@ -3749,16 +3719,59 @@ "setInterval": true }, "packages": { - "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, + "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, + "eth-lattice-keyring>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { + "packages": { + "browserify": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { + "globals": { + "WeakRef": true + }, + "packages": { + "browserify": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3776,54 +3789,67 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, - "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, + "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>bs58check": true, - "eth-lattice-keyring>gridplus-sdk>secp256k1": true, + "eth-lattice-keyring>gridplus-sdk>elliptic": true, + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, + "eth-lattice-keyring>rlp": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, + "ganache>secp256k1": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { "globals": { - "console.warn": true, - "fetch": true + "TextDecoder": true, + "crypto": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -3837,6 +3863,11 @@ "define": true } }, + "eth-lattice-keyring>gridplus-sdk>bitwise": { + "packages": { + "browserify>buffer": true + } + }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -3858,24 +3889,28 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true, - "navigator": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bs58check": { - "packages": { - "@noble/hashes": true, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true + "location": true } }, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { + "eth-lattice-keyring>gridplus-sdk>elliptic": { "packages": { - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { + "globals": { + "intToBuffer": true + }, "packages": { - "@metamask/ppom-validator>elliptic": true + "@metamask/ethjs>js-sha3": true, + "bn.js": true, + "buffer": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4199,9 +4234,20 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, - "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true + "ethers>@ethersproject/properties": true, + "ethers>@ethersproject/signing-key>elliptic": true + } + }, + "ethers>@ethersproject/signing-key>elliptic": { + "packages": { + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, "ethers>@ethersproject/solidity": { diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 79058c8c6954..4212ef454eea 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,11 +158,6 @@ "webpack>events": true } }, - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -188,8 +183,8 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/curves": { @@ -197,32 +192,14 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, - "@metamask/utils>@scure/base": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@metamask/utils>@scure/base": true, + "@noble/hashes": true } }, "@ethersproject/abi": { @@ -389,9 +366,9 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, + "@keystonehq/metamask-airgapped-keyring>rlp": true, "@metamask/obs-store": true, "browserify>buffer": true, - "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -401,15 +378,16 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, + "eth-lattice-keyring>rlp": true, "uuid": true } }, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { - "globals": { - "TextEncoder": true + "@keystonehq/metamask-airgapped-keyring>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@lavamoat/lavadome-react": { @@ -1608,12 +1586,18 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>rlp": true + "ethereumjs-util>create-hash": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@metamask/logging-controller": { @@ -2364,9 +2348,20 @@ "@metamask/smart-transactions-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { "@metamask/smart-transactions-controller>@ethereumjs/util": true, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": true + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true } }, "@metamask/smart-transactions-controller>@ethereumjs/util": { @@ -2376,7 +2371,7 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "webpack>events": true } }, @@ -2615,6 +2610,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, "@ethersproject/contracts": true, @@ -2627,7 +2623,6 @@ "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, "@metamask/rpc-errors": true, - "@metamask/transaction-controller>@ethereumjs/common": true, "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, @@ -2639,14 +2634,6 @@ "webpack>events": true } }, - "@metamask/transaction-controller>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, @@ -3101,23 +3088,6 @@ "define": true } }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": { - "packages": { - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": true, - "webpack>events": true - } - }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": { - "globals": { - "console.warn": true, - "fetch": true - }, - "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true - } - }, "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { "packages": { "@swc/helpers>tslib": true, @@ -3749,16 +3719,59 @@ "setInterval": true }, "packages": { - "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, + "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, + "eth-lattice-keyring>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { + "packages": { + "browserify": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { + "globals": { + "WeakRef": true + }, + "packages": { + "browserify": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3776,54 +3789,67 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, - "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, + "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>bs58check": true, - "eth-lattice-keyring>gridplus-sdk>secp256k1": true, + "eth-lattice-keyring>gridplus-sdk>elliptic": true, + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, + "eth-lattice-keyring>rlp": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, + "ganache>secp256k1": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { "globals": { - "console.warn": true, - "fetch": true + "TextDecoder": true, + "crypto": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -3837,6 +3863,11 @@ "define": true } }, + "eth-lattice-keyring>gridplus-sdk>bitwise": { + "packages": { + "browserify>buffer": true + } + }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -3858,24 +3889,28 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true, - "navigator": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bs58check": { - "packages": { - "@noble/hashes": true, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true + "location": true } }, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { + "eth-lattice-keyring>gridplus-sdk>elliptic": { "packages": { - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { + "globals": { + "intToBuffer": true + }, "packages": { - "@metamask/ppom-validator>elliptic": true + "@metamask/ethjs>js-sha3": true, + "bn.js": true, + "buffer": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4199,9 +4234,20 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, - "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true + "ethers>@ethersproject/properties": true, + "ethers>@ethersproject/signing-key>elliptic": true + } + }, + "ethers>@ethersproject/signing-key>elliptic": { + "packages": { + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, "ethers>@ethersproject/solidity": { diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 79058c8c6954..4212ef454eea 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,11 +158,6 @@ "webpack>events": true } }, - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -188,8 +183,8 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/curves": { @@ -197,32 +192,14 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, - "@metamask/utils>@scure/base": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@metamask/utils>@scure/base": true, + "@noble/hashes": true } }, "@ethersproject/abi": { @@ -389,9 +366,9 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, + "@keystonehq/metamask-airgapped-keyring>rlp": true, "@metamask/obs-store": true, "browserify>buffer": true, - "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -401,15 +378,16 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, + "eth-lattice-keyring>rlp": true, "uuid": true } }, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { - "globals": { - "TextEncoder": true + "@keystonehq/metamask-airgapped-keyring>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@lavamoat/lavadome-react": { @@ -1608,12 +1586,18 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>rlp": true + "ethereumjs-util>create-hash": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@metamask/logging-controller": { @@ -2364,9 +2348,20 @@ "@metamask/smart-transactions-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { "@metamask/smart-transactions-controller>@ethereumjs/util": true, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": true + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true } }, "@metamask/smart-transactions-controller>@ethereumjs/util": { @@ -2376,7 +2371,7 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "webpack>events": true } }, @@ -2615,6 +2610,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, "@ethersproject/contracts": true, @@ -2627,7 +2623,6 @@ "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, "@metamask/rpc-errors": true, - "@metamask/transaction-controller>@ethereumjs/common": true, "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, @@ -2639,14 +2634,6 @@ "webpack>events": true } }, - "@metamask/transaction-controller>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, @@ -3101,23 +3088,6 @@ "define": true } }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": { - "packages": { - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": true, - "webpack>events": true - } - }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": { - "globals": { - "console.warn": true, - "fetch": true - }, - "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true - } - }, "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { "packages": { "@swc/helpers>tslib": true, @@ -3749,16 +3719,59 @@ "setInterval": true }, "packages": { - "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, + "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, + "eth-lattice-keyring>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { + "packages": { + "browserify": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { + "globals": { + "WeakRef": true + }, + "packages": { + "browserify": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3776,54 +3789,67 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, - "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, + "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>bs58check": true, - "eth-lattice-keyring>gridplus-sdk>secp256k1": true, + "eth-lattice-keyring>gridplus-sdk>elliptic": true, + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, + "eth-lattice-keyring>rlp": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, + "ganache>secp256k1": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { "globals": { - "console.warn": true, - "fetch": true + "TextDecoder": true, + "crypto": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -3837,6 +3863,11 @@ "define": true } }, + "eth-lattice-keyring>gridplus-sdk>bitwise": { + "packages": { + "browserify>buffer": true + } + }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -3858,24 +3889,28 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true, - "navigator": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bs58check": { - "packages": { - "@noble/hashes": true, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true + "location": true } }, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { + "eth-lattice-keyring>gridplus-sdk>elliptic": { "packages": { - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { + "globals": { + "intToBuffer": true + }, "packages": { - "@metamask/ppom-validator>elliptic": true + "@metamask/ethjs>js-sha3": true, + "bn.js": true, + "buffer": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4199,9 +4234,20 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, - "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true + "ethers>@ethersproject/properties": true, + "ethers>@ethersproject/signing-key>elliptic": true + } + }, + "ethers>@ethersproject/signing-key>elliptic": { + "packages": { + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, "ethers>@ethersproject/solidity": { diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 08a75ac8612b..5234fe8d6fbb 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,11 +158,6 @@ "webpack>events": true } }, - "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -188,8 +183,8 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/curves": { @@ -197,32 +192,14 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, - "@metamask/utils>@scure/base": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@metamask/utils>@scure/base": true, + "@noble/hashes": true } }, "@ethersproject/abi": { @@ -389,9 +366,9 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, + "@keystonehq/metamask-airgapped-keyring>rlp": true, "@metamask/obs-store": true, "browserify>buffer": true, - "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -401,15 +378,16 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, + "eth-lattice-keyring>rlp": true, "uuid": true } }, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { - "globals": { - "TextEncoder": true + "@keystonehq/metamask-airgapped-keyring>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@lavamoat/lavadome-react": { @@ -1700,12 +1678,18 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>rlp": true + "ethereumjs-util>create-hash": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { + "packages": { + "bn.js": true, + "browserify>buffer": true } }, "@metamask/logging-controller": { @@ -2456,9 +2440,20 @@ "@metamask/smart-transactions-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { "@metamask/smart-transactions-controller>@ethereumjs/util": true, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": true + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true } }, "@metamask/smart-transactions-controller>@ethereumjs/util": { @@ -2468,7 +2463,7 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "webpack>events": true } }, @@ -2707,6 +2702,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, "@ethersproject/contracts": true, @@ -2719,7 +2715,6 @@ "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, "@metamask/rpc-errors": true, - "@metamask/transaction-controller>@ethereumjs/common": true, "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, @@ -2731,14 +2726,6 @@ "webpack>events": true } }, - "@metamask/transaction-controller>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, @@ -3193,23 +3180,6 @@ "define": true } }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common": { - "packages": { - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": true, - "webpack>events": true - } - }, - "@trezor/connect-web>@trezor/connect>@ethereumjs/common>@ethereumjs/util": { - "globals": { - "console.warn": true, - "fetch": true - }, - "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true - } - }, "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { "packages": { "@swc/helpers>tslib": true, @@ -3841,16 +3811,59 @@ "setInterval": true }, "packages": { - "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, + "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, + "eth-lattice-keyring>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { + "packages": { + "browserify": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { + "globals": { + "WeakRef": true + }, + "packages": { + "browserify": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3868,54 +3881,67 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, - "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, + "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>bs58check": true, - "eth-lattice-keyring>gridplus-sdk>secp256k1": true, + "eth-lattice-keyring>gridplus-sdk>elliptic": true, + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, + "eth-lattice-keyring>rlp": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, + "ganache>secp256k1": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethersproject/providers": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "browserify>buffer": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { "globals": { - "console.warn": true, - "fetch": true + "TextDecoder": true, + "crypto": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, - "webpack>events": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true + } + }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -3929,6 +3955,11 @@ "define": true } }, + "eth-lattice-keyring>gridplus-sdk>bitwise": { + "packages": { + "browserify>buffer": true + } + }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -3950,24 +3981,28 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true, - "navigator": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bs58check": { - "packages": { - "@noble/hashes": true, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true + "location": true } }, - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { + "eth-lattice-keyring>gridplus-sdk>elliptic": { "packages": { - "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { + "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { + "globals": { + "intToBuffer": true + }, "packages": { - "@metamask/ppom-validator>elliptic": true + "@metamask/ethjs>js-sha3": true, + "bn.js": true, + "buffer": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4291,9 +4326,20 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, - "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true + "ethers>@ethersproject/properties": true, + "ethers>@ethersproject/signing-key>elliptic": true + } + }, + "ethers>@ethersproject/signing-key>elliptic": { + "packages": { + "@metamask/ppom-validator>elliptic>brorand": true, + "@metamask/ppom-validator>elliptic>hmac-drbg": true, + "@metamask/ppom-validator>elliptic>minimalistic-assert": true, + "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, + "bn.js": true, + "ethers>@ethersproject/sha2>hash.js": true, + "pumpify>inherits": true } }, "ethers>@ethersproject/solidity": { diff --git a/package.json b/package.json index 601400f80f7a..8533cd4b4e16 100644 --- a/package.json +++ b/package.json @@ -134,11 +134,6 @@ }, "resolutions": { "chokidar": "^3.6.0", - "gridplus-sdk/elliptic": "^6.5.7", - "gridplus-sdk/secp256k1": "^5.0.1", - "eth-lattice-keyring/@ethereumjs/tx": "^4.2.0", - "@ethersproject/signing-key/elliptic": "^6.5.7", - "ganache/secp256k1": "^4.0.4", "simple-update-notifier@^1.0.0": "^2.0.0", "@types/react": "^16.9.53", "analytics-node/axios": "^0.21.2", @@ -251,7 +246,11 @@ "@ledgerhq/hw-app-eth@npm:^6.39.0": "patch:@ledgerhq/hw-app-eth@npm%3A6.39.0#~/.yarn/patches/@ledgerhq-hw-app-eth-npm-6.39.0-866309bbbe.patch", "@ledgerhq/evm-tools@npm:^1.2.3": "patch:@ledgerhq/evm-tools@npm%3A1.2.3#~/.yarn/patches/@ledgerhq-evm-tools-npm-1.2.3-414f44baa9.patch", "cross-spawn@npm:^5.0.1": "^7.0.6", - "@solana/web3.js@npm:^1.95.0": "^1.95.8" + "@solana/web3.js@npm:^1.95.0": "^1.95.8", + "secp256k1@npm:^4.0.0": "4.0.4", + "secp256k1@npm:^4.0.1": "4.0.4", + "secp256k1@npm:4.0.2": "4.0.4", + "secp256k1@npm:4.0.3": "4.0.4" }, "dependencies": { "@babel/runtime": "patch:@babel/runtime@npm%3A7.25.9#~/.yarn/patches/@babel-runtime-npm-7.25.9-fe8c62510a.patch", @@ -692,10 +691,17 @@ "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>@ledgerhq/hw-transport-node-hid-noevents>node-hid": false, "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>node-hid": false, "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>usb": false, + "@metamask/controllers>web3-provider-engine>ethereumjs-util>keccak": false, + "@metamask/controllers>web3-provider-engine>ethereumjs-util>secp256k1": false, + "@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>keccak": false, + "@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>secp256k1": false, + "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": false, "@storybook/api>core-js": false, "@storybook/core>@storybook/core-client>@storybook/ui>core-js-pure": false, "@storybook/test-runner>@storybook/core-common>esbuild": false, - "eth-lattice-keyring>gridplus-sdk": true, + "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>keccak": false, + "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false, + "eth-lattice-keyring>gridplus-sdk": false, "ethereumjs-util>ethereum-cryptography>keccak": false, "ganache>@trufflesuite/bigint-buffer": false, "ganache>@trufflesuite/uws-js-unofficial>bufferutil": false, @@ -705,10 +711,13 @@ "ganache>leveldown": false, "ganache>secp256k1": false, "ganache>utf-8-validate": false, + "ethereumjs-util>ethereum-cryptography>secp256k1": false, "gulp-watch>chokidar>fsevents": false, "gulp>glob-watcher>chokidar>fsevents": false, "webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, + "@keystonehq/bc-ur-registry-eth>hdkey>secp256k1": false, "eth-lattice-keyring>gridplus-sdk>secp256k1": false, + "eth-lattice-keyring>secp256k1": false, "@storybook/react>@pmmmwh/react-refresh-webpack-plugin>core-js-pure": false, "@testing-library/jest-dom>aria-query>@babel/runtime-corejs3>core-js-pure": false, "web3": false, @@ -717,6 +726,7 @@ "web3>web3-core>web3-core-requestmanager>web3-providers-ws>websocket>es5-ext": false, "web3>web3-core>web3-core-requestmanager>web3-providers-ws>websocket>utf-8-validate": false, "web3>web3-shh": false, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>hdkey>secp256k1": false, "@metamask/base-controller>simple-git-hooks": false, "@storybook/core>@storybook/core-server>webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, "resolve-url-loader>es6-iterator>es5-ext": false, diff --git a/yarn.lock b/yarn.lock index e61b6efeef05..a4163ea118e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1684,6 +1684,33 @@ __metadata: languageName: node linkType: hard +"@chainsafe/as-sha256@npm:^0.3.1": + version: 0.3.1 + resolution: "@chainsafe/as-sha256@npm:0.3.1" + checksum: 10/3bae7b4bc6e307baa3cf1f9d2c75827874cd0fb458bc592656d741d374b48e71c042fe21616a506cb821487a5abfc6b92181e4b7fbf49b7370cee4df0b67d95a + languageName: node + linkType: hard + +"@chainsafe/persistent-merkle-tree@npm:^0.4.2": + version: 0.4.2 + resolution: "@chainsafe/persistent-merkle-tree@npm:0.4.2" + dependencies: + "@chainsafe/as-sha256": "npm:^0.3.1" + checksum: 10/a7e59f80be3ce0a86fe452a3c003bd159a1719ed22cae22e9841668f0eda8c35412fa16b3b150d96f583a24f430a5cc2a1bfcabafc1b9cf6e1fdb227e98c4dc7 + languageName: node + linkType: hard + +"@chainsafe/ssz@npm:0.9.4": + version: 0.9.4 + resolution: "@chainsafe/ssz@npm:0.9.4" + dependencies: + "@chainsafe/as-sha256": "npm:^0.3.1" + "@chainsafe/persistent-merkle-tree": "npm:^0.4.2" + case: "npm:^1.6.3" + checksum: 10/2fe83d0b3ef131e14b51b88bb3343b14e7a02185fa9fd3da84b4726dbd857daaa4f7f6f4840fe3772fc1380352b1675a13b5f6153c4211c0f00ffa542b62bf2f + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -2295,16 +2322,17 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/common@npm:4.3.0": - version: 4.3.0 - resolution: "@ethereumjs/common@npm:4.3.0" +"@ethereumjs/common@npm:3.1.1": + version: 3.1.1 + resolution: "@ethereumjs/common@npm:3.1.1" dependencies: - "@ethereumjs/util": "npm:^9.0.3" - checksum: 10/90f7fe1ba6827b65cd25e9bb4adf07a117ea554a950bb364d5fd9873cb770d383addb0ad34839a91fbec22ebc25516c6fb7e70ae0198c78f933920bf39797a94 + "@ethereumjs/util": "npm:^8.0.5" + crc-32: "npm:^1.2.0" + checksum: 10/dcc3dd9ec23e8817ec0bf5bb2217619a8db08ea937603258831a906702e79c6f6e93b47d6edde551c7f46ce4a0268febacc23cefcb4ca2865be3b5c0bf5ec670 languageName: node linkType: hard -"@ethereumjs/common@npm:^3.2.0": +"@ethereumjs/common@npm:^3.1.1, @ethereumjs/common@npm:^3.2.0": version: 3.2.0 resolution: "@ethereumjs/common@npm:3.2.0" dependencies: @@ -2341,15 +2369,22 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/tx@npm:5.3.0": - version: 5.3.0 - resolution: "@ethereumjs/tx@npm:5.3.0" +"@ethereumjs/tx@npm:4.1.1": + version: 4.1.1 + resolution: "@ethereumjs/tx@npm:4.1.1" dependencies: - "@ethereumjs/common": "npm:^4.3.0" - "@ethereumjs/rlp": "npm:^5.0.2" - "@ethereumjs/util": "npm:^9.0.3" - ethereum-cryptography: "npm:^2.1.3" - checksum: 10/4eb48e763d81ea0978648367d61c568c8d10f769c1ea7d32307ebe02299d4fa9fe5d7bf794ec1ee22e92edef6bfe1f459d5816e1c62d3f93602d931807ca488b + "@chainsafe/ssz": "npm:0.9.4" + "@ethereumjs/common": "npm:^3.1.1" + "@ethereumjs/rlp": "npm:^4.0.1" + "@ethereumjs/util": "npm:^8.0.5" + "@ethersproject/providers": "npm:^5.7.2" + ethereum-cryptography: "npm:^1.1.2" + peerDependencies: + c-kzg: ^1.0.8 + peerDependenciesMeta: + c-kzg: + optional: true + checksum: 10/3074e198e0a550dd47dc359d16aa3bb9336fc52b14681fb0b1bcc8d4bdac62cc384962a13347819488da18bedf9578d4d5f2491e3609cb7fa7b2f6cafeb18b23 languageName: node linkType: hard @@ -2388,7 +2423,7 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/util@npm:^9.0.2, @ethereumjs/util@npm:^9.0.3, @ethereumjs/util@npm:^9.1.0": +"@ethereumjs/util@npm:^9.0.2, @ethereumjs/util@npm:^9.1.0": version: 9.1.0 resolution: "@ethereumjs/util@npm:9.1.0" dependencies: @@ -6514,6 +6549,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.1.2": + version: 1.1.2 + resolution: "@noble/hashes@npm:1.1.2" + checksum: 10/2826c94ea30b8d2447fda549f4ffa97a637a480eeef5c96702a2f932c305038465f7436caf5b2bad41eb43c08c270b921e101488b18165feebe3854091b56d91 + languageName: node + linkType: hard + "@noble/hashes@npm:1.3.2": version: 1.3.2 resolution: "@noble/hashes@npm:1.3.2" @@ -6521,17 +6563,17 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.4.0, @noble/hashes@npm:~1.4.0": +"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:~1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" checksum: 10/e156e65794c473794c52fa9d06baf1eb20903d0d96719530f523cc4450f6c721a957c544796e6efd0197b2296e7cd70efeb312f861465e17940a3e3c7e0febc6 languageName: node linkType: hard -"@noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0": - version: 1.5.0 - resolution: "@noble/hashes@npm:1.5.0" - checksum: 10/da7fc7af52af7afcf59810a7eea6155075464ff462ffda2572dc6d57d53e2669b1ea2ec774e814f6273f1697e567f28d36823776c9bf7068cba2a2855140f26e +"@noble/hashes@npm:~1.1.1": + version: 1.1.3 + resolution: "@noble/hashes@npm:1.1.3" + checksum: 10/42e9883649abd85e6a65cfa528e72b2a81ebb601b44db1d71b6ba927cede0627d7d8c649df159a7f84a949dfe17fe268d4b664c5a36c7e0b2a3d4198bc19f5e4 languageName: node linkType: hard @@ -6542,6 +6584,13 @@ __metadata: languageName: node linkType: hard +"@noble/secp256k1@npm:1.6.3, @noble/secp256k1@npm:~1.6.0": + version: 1.6.3 + resolution: "@noble/secp256k1@npm:1.6.3" + checksum: 10/e4f4b0cfa1c5d23fb1b9938fa3cce1a1160a76a89eb91f6dde98075bbdf328709d51771c85b6b4b118f8ce5a6c6554da6c9af7de7716aba56cef30f61a715bd7 + languageName: node + linkType: hard + "@noble/secp256k1@npm:^1.7.0": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" @@ -7666,10 +7715,21 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": - version: 1.1.9 - resolution: "@scure/base@npm:1.1.9" - checksum: 10/f0ab7f687bbcdee2a01377fe3cd808bf63977999672751295b6a92625d5322f4754a96d40f6bd579bc367aad48ecf8a4e6d0390e70296e6ded1076f52adb16bb +"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.1.0, @scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": + version: 1.1.7 + resolution: "@scure/base@npm:1.1.7" + checksum: 10/fc50ffaab36cb46ff9fa4dc5052a06089ab6a6707f63d596bb34aaaec76173c9a564ac312a0b981b5e7a5349d60097b8878673c75d6cbfc4da7012b63a82099b + languageName: node + linkType: hard + +"@scure/bip32@npm:1.1.0": + version: 1.1.0 + resolution: "@scure/bip32@npm:1.1.0" + dependencies: + "@noble/hashes": "npm:~1.1.1" + "@noble/secp256k1": "npm:~1.6.0" + "@scure/base": "npm:~1.1.0" + checksum: 10/e58660fc96dc5c87d0047bf41150fa3b424617e6289ba522cc81bdeecaf1a26e34f01dcd9d76f3e5c2c570ced608a527733cc375abfce4dc9b8e2365719ea5d3 languageName: node linkType: hard @@ -7684,6 +7744,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.1.0": + version: 1.1.0 + resolution: "@scure/bip39@npm:1.1.0" + dependencies: + "@noble/hashes": "npm:~1.1.1" + "@scure/base": "npm:~1.1.0" + checksum: 10/d843be225dda4b6b2c0f90e52e00eef708df3cecbc944902298d487c669a6d219bd41877b20adaf72ba84aec2f0cb1e4567dafc6ce7295d9f132bdb0dcb375b3 + languageName: node + linkType: hard + "@scure/bip39@npm:1.3.0": version: 1.3.0 resolution: "@scure/bip39@npm:1.3.0" @@ -8037,13 +8107,6 @@ __metadata: languageName: node linkType: hard -"@sovpro/delimited-stream@npm:^1.1.0": - version: 1.1.0 - resolution: "@sovpro/delimited-stream@npm:1.1.0" - checksum: 10/e78fc97a8509c07b55483df2253137de07b10f14db15d230526a6dd95c86e99d8f54c7af8697806bd16522eec2c50e44e5b4e0294bed80da833a2185f17f3ab6 - languageName: node - linkType: hard - "@spruceid/siwe-parser@npm:2.1.0": version: 2.1.0 resolution: "@spruceid/siwe-parser@npm:2.1.0" @@ -11118,13 +11181,6 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:^10.0.0": - version: 10.0.0 - resolution: "@types/uuid@npm:10.0.0" - checksum: 10/e3958f8b0fe551c86c14431f5940c3470127293280830684154b91dc7eb3514aeb79fe3216968833cf79d4d1c67f580f054b5be2cd562bebf4f728913e73e944 - languageName: node - linkType: hard - "@types/uuid@npm:^8.3.0": version: 8.3.0 resolution: "@types/uuid@npm:8.3.0" @@ -11132,7 +11188,7 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:^9.0.1, @types/uuid@npm:^9.0.8": +"@types/uuid@npm:^9.0.0, @types/uuid@npm:^9.0.1, @types/uuid@npm:^9.0.8": version: 9.0.8 resolution: "@types/uuid@npm:9.0.8" checksum: 10/b8c60b7ba8250356b5088302583d1704a4e1a13558d143c549c408bf8920535602ffc12394ede77f8a8083511b023704bc66d1345792714002bfa261b17c5275 @@ -12175,7 +12231,7 @@ __metadata: languageName: node linkType: hard -"aes-js@npm:^3.1.2": +"aes-js@npm:^3.1.1, aes-js@npm:^3.1.2": version: 3.1.2 resolution: "aes-js@npm:3.1.2" checksum: 10/b65916767034a51375a3ac5aad62af452d89a386c1ae7b607bb9145d0bb8b8823bf2f3eba85bdfa52d61c65d5aed90ba90f677b8c826bfa1a8b7ae2fa3b54d91 @@ -13370,13 +13426,6 @@ __metadata: languageName: node linkType: hard -"base-x@npm:^5.0.0": - version: 5.0.0 - resolution: "base-x@npm:5.0.0" - checksum: 10/fa82bc9a963f7a765a3287ba632661669fe553d06ee0d4d4e282640335bff30ec685e3c3b1714e265f697b234facd02a310f1e2465db88f4f1a448e6267fbc65 - languageName: node - linkType: hard - "base32-encode@npm:^1.2.0": version: 1.2.0 resolution: "base32-encode@npm:1.2.0" @@ -13595,10 +13644,10 @@ __metadata: languageName: node linkType: hard -"bitwise@npm:^2.2.1": - version: 2.2.1 - resolution: "bitwise@npm:2.2.1" - checksum: 10/517aea40f326847935a8ae4367d6beca596982ad55db1d0288a4055c9eba78c6b3ccd10d9ad423df356d946d9a898b36c0d5c06673fba4fb98fb1b58df74788e +"bitwise@npm:^2.0.4": + version: 2.1.0 + resolution: "bitwise@npm:2.1.0" + checksum: 10/d075220e8b8d1e41d0e60c7081811eef108024a094c4e7f5c2ad67235f3bcac9f6ffd218884900591d602fbd61aff9a6c1d650cd5a0e0e34f12e11623aab5da1 languageName: node linkType: hard @@ -13726,23 +13775,33 @@ __metadata: languageName: node linkType: hard -"borc@npm:^3.0.0": - version: 3.0.0 - resolution: "borc@npm:3.0.0" +"borc@npm:2.1.2": + version: 2.1.2 + resolution: "borc@npm:2.1.2" dependencies: bignumber.js: "npm:^9.0.0" - buffer: "npm:^6.0.3" + buffer: "npm:^5.5.0" commander: "npm:^2.15.0" ieee754: "npm:^1.1.13" - iso-url: "npm:^1.1.5" - json-text-sequence: "npm:~0.3.0" + iso-url: "npm:~0.4.7" + json-text-sequence: "npm:~0.1.0" readable-stream: "npm:^3.6.0" - bin: - cbor2comment: bin/cbor2comment.js - cbor2diag: bin/cbor2diag.js - cbor2json: bin/cbor2json.js - json2cbor: bin/json2cbor.js - checksum: 10/fc9eaae0a544a300d0eaa4173d523649c9b85ed13f46156d802b5514c75aa4ec80c7ff183afd2bb4067a3166a7561f1a362edeb1673a7760d401b801b688477e + checksum: 10/a506aec97c3de0a015bf43729a82fe7e7c1ca1f3af72151dacda5d901a673719bfa6e4241d9e09d4b0abdfaf090f5f0645c3397d28e4d4d637f6e3e36e1ed268 + languageName: node + linkType: hard + +"borc@patch:borc@npm%3A2.1.2#./.yarn/patches/borc-npm-2.1.2-8ffcc2dd81.patch::locator=metamask-crx%40workspace%3A.": + version: 2.1.2 + resolution: "borc@patch:borc@npm%3A2.1.2#./.yarn/patches/borc-npm-2.1.2-8ffcc2dd81.patch::version=2.1.2&hash=3e0a96&locator=metamask-crx%40workspace%3A." + dependencies: + bignumber.js: "npm:^9.0.0" + buffer: "npm:^5.5.0" + commander: "npm:^2.15.0" + ieee754: "npm:^1.1.13" + iso-url: "npm:~0.4.7" + json-text-sequence: "npm:~0.1.0" + readable-stream: "npm:^3.6.0" + checksum: 10/f72b4bb1cef3422a817acbf45201904b36fc00d03613506a3b36d63e6b14713b35970cf1bb8f25721c38d8ac12bbf9ca6098430a1c6b39666d60722641ea8bd3 languageName: node linkType: hard @@ -14102,15 +14161,6 @@ __metadata: languageName: node linkType: hard -"bs58@npm:^6.0.0": - version: 6.0.0 - resolution: "bs58@npm:6.0.0" - dependencies: - base-x: "npm:^5.0.0" - checksum: 10/7c9bb2b2d93d997a8c652de3510d89772007ac64ee913dc4e16ba7ff47624caad3128dcc7f360763eb6308760c300b3e9fd91b8bcbd489acd1a13278e7949c4e - languageName: node - linkType: hard - "bs58check@npm:2.1.2, bs58check@npm:^2.1.2": version: 2.1.2 resolution: "bs58check@npm:2.1.2" @@ -14132,16 +14182,6 @@ __metadata: languageName: node linkType: hard -"bs58check@npm:^4.0.0": - version: 4.0.0 - resolution: "bs58check@npm:4.0.0" - dependencies: - "@noble/hashes": "npm:^1.2.0" - bs58: "npm:^6.0.0" - checksum: 10/cf5691bdfdf317574f722582360a834f01a36e8f6c850bd5791f04e040b334a0800b7c322ad24c77979c3ed6ef6cf31a6373366b4018223e3005278d491d8799 - languageName: node - linkType: hard - "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -14541,6 +14581,13 @@ __metadata: languageName: node linkType: hard +"case@npm:^1.6.3": + version: 1.6.3 + resolution: "case@npm:1.6.3" + checksum: 10/2fc1df75bbb4118339e06141b9a54aba95cc62460ac92730290144fbec6b6a04f5bf7abf6a6486a1338f5821bd184402f216cec8cea0472451759c27e20fc332 + languageName: node + linkType: hard + "cashaddrjs@npm:0.4.4": version: 0.4.4 resolution: "cashaddrjs@npm:0.4.4" @@ -15718,12 +15765,15 @@ __metadata: languageName: node linkType: hard -"crc-32@npm:^1.2.0, crc-32@npm:^1.2.2": - version: 1.2.2 - resolution: "crc-32@npm:1.2.2" +"crc-32@npm:^1.2.0": + version: 1.2.0 + resolution: "crc-32@npm:1.2.0" + dependencies: + exit-on-epipe: "npm:~1.0.1" + printj: "npm:~1.1.0" bin: - crc32: bin/crc32.njs - checksum: 10/824f696a5baaf617809aa9cd033313c8f94f12d15ebffa69f10202480396be44aef9831d900ab291638a8022ed91c360696dd5b1ba691eb3f34e60be8835b7c3 + crc32: ./bin/crc32.njs + checksum: 10/10c648c986b005ed0ea8393bb0d1ccb99e7a102505b136d313dee6abe204aa682d9bb9bc6fd180f9cd98ef92aa029964f1cc96a2a85eb50507dedd9ead1a262f languageName: node linkType: hard @@ -16625,6 +16675,13 @@ __metadata: languageName: node linkType: hard +"delimit-stream@npm:0.1.0": + version: 0.1.0 + resolution: "delimit-stream@npm:0.1.0" + checksum: 10/9d179cfb91dfbb0702909dfab33bd837fec67c49f0c81495215af578fb08f262d509d76de7431eb11e64e6e71794b9bfe642e372fd33fabbfaf7e060cf5c044f + languageName: node + linkType: hard + "depcheck@npm:^1.4.3": version: 1.4.3 resolution: "depcheck@npm:1.4.3" @@ -17395,9 +17452,24 @@ __metadata: languageName: node linkType: hard +"elliptic@npm:6.5.4": + version: 6.5.4 + resolution: "elliptic@npm:6.5.4" + dependencies: + bn.js: "npm:^4.11.9" + brorand: "npm:^1.1.0" + hash.js: "npm:^1.0.0" + hmac-drbg: "npm:^1.0.1" + inherits: "npm:^2.0.4" + minimalistic-assert: "npm:^1.0.1" + minimalistic-crypto-utils: "npm:^1.0.1" + checksum: 10/2cd7ff4b69720dbb2ca1ca650b2cf889d1df60c96d4a99d331931e4fe21e45a7f3b8074e86618ca7e56366c4b6258007f234f9d61d9b0c87bbbc8ea990b99e94 + languageName: node + linkType: hard + "elliptic@npm:^6.0.0, elliptic@npm:^6.4.0, elliptic@npm:^6.5.4, elliptic@npm:^6.5.7": - version: 6.5.7 - resolution: "elliptic@npm:6.5.7" + version: 6.6.1 + resolution: "elliptic@npm:6.6.1" dependencies: bn.js: "npm:^4.11.9" brorand: "npm:^1.1.0" @@ -17406,7 +17478,7 @@ __metadata: inherits: "npm:^2.0.4" minimalistic-assert: "npm:^1.0.1" minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10/fbad1fad0a5cc07df83f80cc1f7a784247ef59075194d3e340eaeb2f4dd594825ee24c7e9b0cf279c9f1982efe610503bb3139737926428c4821d4fca1bcf348 + checksum: 10/dc678c9febd89a219c4008ba3a9abb82237be853d9fd171cd602c8fb5ec39927e65c6b5e7a1b2a4ea82ee8e0ded72275e7932bb2da04a5790c2638b818e4e1c5 languageName: node linkType: hard @@ -18589,9 +18661,20 @@ __metadata: linkType: hard "eth-chainlist@npm:~0.0.498": - version: 0.0.519 - resolution: "eth-chainlist@npm:0.0.519" - checksum: 10/c9767c64e58d140d04e6fcca9589c50edab48a5c57a62f2c749279574a9ab3e13784b05ab4c05c7b020fe8421769bc4119bd7a904df040fbb076827aaac3de23 + version: 0.0.498 + resolution: "eth-chainlist@npm:0.0.498" + checksum: 10/a414c0e1f0a877f9ab8bf1cf775556308ddbb66618e368666d4dea9a0b949febedf8ca5440cf57419413404e7661f1e3d040802faf532d0e1618c40ecd334cbf + languageName: node + linkType: hard + +"eth-eip712-util-browser@npm:^0.0.3": + version: 0.0.3 + resolution: "eth-eip712-util-browser@npm:0.0.3" + dependencies: + bn.js: "npm:>4.0.0" + buffer: "npm:^6.0.3" + js-sha3: "npm:^0.8.0" + checksum: 10/f953e553da8326cc7eacffd7edc4c5ca4ba66ddf27546412cbed961900d50bbd8196b44665bd9e8f7d63c3b64df0793a6a8a60cc2f15b340763a78e84c4e7bd4 languageName: node linkType: hard @@ -18663,7 +18746,19 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.1.3, ethereum-cryptography@npm:^2.2.1": +"ethereum-cryptography@npm:^1.1.2": + version: 1.1.2 + resolution: "ethereum-cryptography@npm:1.1.2" + dependencies: + "@noble/hashes": "npm:1.1.2" + "@noble/secp256k1": "npm:1.6.3" + "@scure/bip32": "npm:1.1.0" + "@scure/bip39": "npm:1.1.0" + checksum: 10/abf9288086002a697e0ee0077d77d001c8e1306fa53ea8d7901f9744786f47d073caa6c266bd5b25a283a5c0fbc8beed9fa9cd90d842dc51339e6748aa1ab46a + languageName: node + linkType: hard + +"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.2.1": version: 2.2.1 resolution: "ethereum-cryptography@npm:2.2.1" dependencies: @@ -18955,6 +19050,13 @@ __metadata: languageName: node linkType: hard +"exit-on-epipe@npm:~1.0.1": + version: 1.0.1 + resolution: "exit-on-epipe@npm:1.0.1" + checksum: 10/b180aa277aec5bef2609b34e5876061f421a1f81bf343beb213c4d60b382ddcb6b83012833f0ba329d6bc38042685c8d89b1c52ea495b9b6327948ea80627398 + languageName: node + linkType: hard + "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -20981,29 +21083,29 @@ __metadata: linkType: hard "gridplus-sdk@npm:^2.5.1": - version: 2.7.1 - resolution: "gridplus-sdk@npm:2.7.1" + version: 2.5.1 + resolution: "gridplus-sdk@npm:2.5.1" dependencies: - "@ethereumjs/common": "npm:4.3.0" - "@ethereumjs/rlp": "npm:^5.0.2" - "@ethereumjs/tx": "npm:5.3.0" - "@ethersproject/abi": "npm:^5.7.0" - "@metamask/eth-sig-util": "npm:^7.0.3" - "@types/uuid": "npm:^10.0.0" - aes-js: "npm:^3.1.2" + "@ethereumjs/common": "npm:3.1.1" + "@ethereumjs/tx": "npm:4.1.1" + "@ethersproject/abi": "npm:^5.5.0" + "@types/uuid": "npm:^9.0.0" + aes-js: "npm:^3.1.1" bech32: "npm:^2.0.0" - bignumber.js: "npm:^9.1.2" - bitwise: "npm:^2.2.1" - borc: "npm:^3.0.0" - bs58check: "npm:^4.0.0" - buffer: "npm:^6.0.3" - crc-32: "npm:^1.2.2" - elliptic: "npm:6.5.6" + bignumber.js: "npm:^9.0.1" + bitwise: "npm:^2.0.4" + borc: "npm:^2.1.2" + bs58check: "npm:^2.1.2" + buffer: "npm:^5.6.0" + crc-32: "npm:^1.2.0" + elliptic: "npm:6.5.4" + eth-eip712-util-browser: "npm:^0.0.3" hash.js: "npm:^1.1.7" - js-sha3: "npm:^0.9.3" - secp256k1: "npm:5.0.0" - uuid: "npm:^10.0.0" - checksum: 10/0d81908f69d2972350f4fc6fb721b12f62de643b48dce1d25f4ee2e085899e0cc64605d6cc63590ba870cea72d53f970c05d0fd74979d2c07ad102f3e15b7f82 + js-sha3: "npm:^0.8.0" + rlp: "npm:^3.0.0" + secp256k1: "npm:4.0.2" + uuid: "npm:^9.0.0" + checksum: 10/57deeae78fc5f904309e689054baabaed8b078b896ecfd5d724889c6ea424a113db64c3fd79d4dca7cc5f558167d7af754506df5c0692ee76087822ae60c3873 languageName: node linkType: hard @@ -23303,10 +23405,10 @@ __metadata: languageName: node linkType: hard -"iso-url@npm:^1.1.5": - version: 1.2.1 - resolution: "iso-url@npm:1.2.1" - checksum: 10/87455fd79166c7b269df7711ea0bee896338330fb46164dd3e6d73ba09c294326ae356b60032dc3217c1455b66f57216a44b95ded8fb2c1c2f9e490396060ef9 +"iso-url@npm:~0.4.7": + version: 0.4.7 + resolution: "iso-url@npm:0.4.7" + checksum: 10/355574598d46947f48a63518517bfacf443aae5914991484cdc51c1ebe3f4487d4936ecd0b73a297784d20bf1a4eda3f47975b0fff8022ae20af76b6655e014a languageName: node linkType: hard @@ -24553,12 +24655,12 @@ __metadata: languageName: node linkType: hard -"json-text-sequence@npm:~0.3.0": - version: 0.3.0 - resolution: "json-text-sequence@npm:0.3.0" +"json-text-sequence@npm:~0.1.0": + version: 0.1.1 + resolution: "json-text-sequence@npm:0.1.1" dependencies: - "@sovpro/delimited-stream": "npm:^1.1.0" - checksum: 10/e5dc050aadd626938514363399cf14c409f878628914922c5d470530c3f3473d6b0e16a10338dd7d863aab0291bb0e5e15d71526d14733c22e30cba771b03297 + delimit-stream: "npm:0.1.0" + checksum: 10/540973055e03e3caf55e5e06adf88a5d1a4fbefdee44e4c67bbeb614f0d1edd6ea9207f8f9027b6aa86eb6ed4fca3f0dd1f40c4be13f7396efbc0d2f5c5f1e73 languageName: node linkType: hard @@ -30143,6 +30245,15 @@ __metadata: languageName: node linkType: hard +"printj@npm:~1.1.0": + version: 1.1.2 + resolution: "printj@npm:1.1.2" + bin: + printj: ./bin/printj.njs + checksum: 10/45376a5ee7ef2e0d7ff0b4fecc893d73995a332e63d7e0622a544fe662c8213d22f0c9750e627c6d732a7d7a543266be960e6cd51cf19485cce87cf80468bb41 + languageName: node + linkType: hard + "prismjs@npm:^1.27.0": version: 1.29.0 resolution: "prismjs@npm:1.29.0" @@ -33054,7 +33165,7 @@ __metadata: languageName: node linkType: hard -"secp256k1@npm:^4.0.0, secp256k1@npm:^4.0.1, secp256k1@npm:^4.0.4": +"secp256k1@npm:4.0.4": version: 4.0.4 resolution: "secp256k1@npm:4.0.4" dependencies: @@ -33066,18 +33177,6 @@ __metadata: languageName: node linkType: hard -"secp256k1@npm:^5.0.1": - version: 5.0.1 - resolution: "secp256k1@npm:5.0.1" - dependencies: - elliptic: "npm:^6.5.7" - node-addon-api: "npm:^5.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - checksum: 10/63fbd35624be4fd9cf3d39e5f79c5471b4a8aea6944453b2bea7b100bb1c77a25c55e6e08e2210cdabdf478c4c62d34c408b34214f2afd9367e19a52a3a4236c - languageName: node - linkType: hard - "select-hose@npm:^2.0.0": version: 2.0.0 resolution: "select-hose@npm:2.0.0" @@ -36648,15 +36747,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^10.0.0": - version: 10.0.0 - resolution: "uuid@npm:10.0.0" - bin: - uuid: dist/bin/uuid - checksum: 10/35aa60614811a201ff90f8ca5e9ecb7076a75c3821e17f0f5ff72d44e36c2d35fcbc2ceee9c4ac7317f4cc41895da30e74f3885e30313bee48fda6338f250538 - languageName: node - linkType: hard - "uuid@npm:^3.3.3": version: 3.4.0 resolution: "uuid@npm:3.4.0" From acdf7c6579e2d1ac06e2ab4f2a0917d616df0403 Mon Sep 17 00:00:00 2001 From: OGPoyraz Date: Thu, 12 Dec 2024 13:57:45 +0100 Subject: [PATCH 07/17] fix: Change visibility of `AmountRow` in contract interaction (#29131) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR makes two visibility change on `AmountRow` in transaction details. - Regardless of the amount or simulated value, if transaction details is toggled, it must show `AmountRow` - Whenever the Amount being sent doesn't match with a 5% buffer what we're displaying in the "You send" row of simulations UI for contract interactions, `AmountRow` must be visible. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29131?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3783 ## **Manual testing steps** ### Scenario I 1. Trigger a contract interaction 2. Enable advanced view 3. With this change, you should now see the Amount row on the advanced view displaying the native asset value that is being sent along with the transaction. ### Scenario II 1. Trigger a contract interaction with the below payload (this payload should make the amount being sent don't match "You send" value within simulations) 2. With this change, you should now see the Amount row on the default view displaying the native asset value that is being sent along with the transaction. `{ to: "0x4805a248c9611c22a43ce956489c9aadb6108433", value: "0xDE0B6B3A7640000", data: "0x3158952e", }` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../transaction-details.test.tsx | 116 +++++++++++++++--- .../transaction-details.tsx | 15 ++- .../components/confirm/info/utils.test.ts | 107 +++++++++++++++- .../components/confirm/info/utils.ts | 83 +++++++++++++ 4 files changed, 300 insertions(+), 21 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.test.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.test.tsx index 1263acf08397..f283ee6c4530 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.test.tsx @@ -1,7 +1,8 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import { SimulationErrorCode } from '@metamask/transaction-controller'; +import { Hex } from '@metamask/utils'; +import { toHex } from '@metamask/controller-utils'; import { getMockConfirmState, getMockConfirmStateForTransaction, @@ -44,21 +45,104 @@ describe('', () => { expect(container).toMatchSnapshot(); }); - it('renders component for transaction details with amount', () => { - const simulationDataMock = { - error: { code: SimulationErrorCode.Disabled }, - tokenBalanceChanges: [], - }; - const contractInteraction = genUnapprovedContractInteractionConfirmation({ - simulationData: simulationDataMock, - chainId: CHAIN_IDS.GOERLI, + describe('AmountRow', () => { + describe('should be in the document', () => { + it('when showAdvancedDetails is true', () => { + const contractInteraction = + genUnapprovedContractInteractionConfirmation({ + chainId: CHAIN_IDS.GOERLI, + }); + const state = getMockConfirmStateForTransaction(contractInteraction, { + metamask: { + preferences: { + showConfirmationAdvancedDetails: true, + }, + }, + }); + const mockStore = configureMockStore(middleware)(state); + const { getByTestId } = renderWithConfirmContextProvider( + , + mockStore, + ); + expect( + getByTestId('transaction-details-amount-row'), + ).toBeInTheDocument(); + }); + + it('when value and simulated native balance mismatch', () => { + // Transaction value is set to 0x3782dace9d900000 below mock + const simulationDataMock = { + tokenBalanceChanges: [], + nativeBalanceChange: { + difference: '0x1' as Hex, + isDecrease: false, + previousBalance: '0x2' as Hex, + newBalance: '0x1' as Hex, + }, + }; + const contractInteraction = + genUnapprovedContractInteractionConfirmation({ + simulationData: simulationDataMock, + chainId: CHAIN_IDS.GOERLI, + }); + const state = getMockConfirmStateForTransaction(contractInteraction, { + metamask: { + preferences: { + // Intentionally setting to false to test the condition + showConfirmationAdvancedDetails: false, + }, + }, + }); + const mockStore = configureMockStore(middleware)(state); + const { getByTestId } = renderWithConfirmContextProvider( + , + mockStore, + ); + expect( + getByTestId('transaction-details-amount-row'), + ).toBeInTheDocument(); + }); + }); + + it('should not be in the document when value and simulated native balance mismatch is within threshold', () => { + // Transaction value is set to 0x3782dace9d900000 below mock + const transactionValueInDecimal = 4000000000000000000; + const transactionValueInHex = toHex(transactionValueInDecimal); + const newBalanceInDecimal = 1; + const newBalanceInHex = toHex(newBalanceInDecimal); + const previousBalanceInDecimal = + transactionValueInDecimal + newBalanceInDecimal; + const previousBalanceInHex = toHex(previousBalanceInDecimal); + + const simulationDataMock = { + tokenBalanceChanges: [], + nativeBalanceChange: { + difference: transactionValueInHex, + isDecrease: true, + previousBalance: previousBalanceInHex, + newBalance: newBalanceInHex, + }, + }; + const contractInteraction = genUnapprovedContractInteractionConfirmation({ + simulationData: simulationDataMock, + chainId: CHAIN_IDS.GOERLI, + }); + const state = getMockConfirmStateForTransaction(contractInteraction, { + metamask: { + preferences: { + // Intentionally setting to false to test the condition + showConfirmationAdvancedDetails: false, + }, + }, + }); + const mockStore = configureMockStore(middleware)(state); + const { queryByTestId } = renderWithConfirmContextProvider( + , + mockStore, + ); + expect( + queryByTestId('transaction-details-amount-row'), + ).not.toBeInTheDocument(); }); - const state = getMockConfirmStateForTransaction(contractInteraction); - const mockStore = configureMockStore(middleware)(state); - const { getByTestId } = renderWithConfirmContextProvider( - , - mockStore, - ); - expect(getByTestId('transaction-details-amount-row')).toBeInTheDocument(); }); }); diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx index 79cea5963c45..2cf6426f1975 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx @@ -1,6 +1,6 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import { isValidAddress } from 'ethereumjs-util'; -import React from 'react'; +import React, { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { ConfirmInfoRow, @@ -20,6 +20,7 @@ import { ConfirmInfoRowCurrency } from '../../../../../../../components/app/conf import { PRIMARY } from '../../../../../../../helpers/constants/common'; import { useUserPreferencedCurrency } from '../../../../../../../hooks/useUserPreferencedCurrency'; import { HEX_ZERO } from '../constants'; +import { hasValueAndNativeBalanceMismatch as checkValueAndNativeBalanceMismatch } from '../../utils'; import { SigningInWithRow } from '../sign-in-with-row/sign-in-with-row'; export const OriginRow = () => { @@ -99,9 +100,8 @@ const AmountRow = () => { const { currency } = useUserPreferencedCurrency(PRIMARY); const value = currentConfirmation?.txParams?.value; - const simulationData = currentConfirmation?.simulationData; - if (!value || value === HEX_ZERO || !simulationData?.error) { + if (!value || value === HEX_ZERO) { return null; } @@ -150,6 +150,11 @@ export const TransactionDetails = () => { const showAdvancedDetails = useSelector( selectConfirmationAdvancedDetailsOpen, ); + const { currentConfirmation } = useConfirmContext(); + const hasValueAndNativeBalanceMismatch = useMemo( + () => checkValueAndNativeBalanceMismatch(currentConfirmation), + [currentConfirmation], + ); return ( <> @@ -159,7 +164,9 @@ export const TransactionDetails = () => { {showAdvancedDetails && } - + {(showAdvancedDetails || hasValueAndNativeBalanceMismatch) && ( + + )} ); diff --git a/ui/pages/confirmations/components/confirm/info/utils.test.ts b/ui/pages/confirmations/components/confirm/info/utils.test.ts index e78d06d87622..9c12b9127811 100644 --- a/ui/pages/confirmations/components/confirm/info/utils.test.ts +++ b/ui/pages/confirmations/components/confirm/info/utils.test.ts @@ -1,5 +1,10 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { toHex } from '@metamask/controller-utils'; import { DecodedTransactionDataSource } from '../../../../../../shared/types/transaction-decode'; -import { getIsRevokeSetApprovalForAll } from './utils'; +import { + getIsRevokeSetApprovalForAll, + hasValueAndNativeBalanceMismatch, +} from './utils'; describe('getIsRevokeSetApprovalForAll', () => { it('returns false if no data is passed as an argument', () => { @@ -36,3 +41,103 @@ describe('getIsRevokeSetApprovalForAll', () => { expect(actual).toEqual(true); }); }); + +describe('hasValueAndNativeBalanceMismatch', () => { + it('returns false when transaction value matches simulated balance change', () => { + const transactionValueInDecimal = 10000000000000000; + const transactionValueInHex = toHex(transactionValueInDecimal); + + const transaction = { + txParams: { + value: transactionValueInHex, + }, + simulationData: { + nativeBalanceChange: { + difference: transactionValueInHex, + isDecrease: true, + }, + }, + } as unknown as TransactionMeta; + + expect(hasValueAndNativeBalanceMismatch(transaction)).toBe(false); + }); + + it('returns false when values differ within threshold', () => { + const transactionValueInDecimal = 10000000000000000; + const transactionValueInHex = toHex(transactionValueInDecimal); + + const differenceInDecimal = 10400000000000000; + const differenceInHex = toHex(differenceInDecimal); + + const transaction = { + txParams: { + value: transactionValueInHex, + }, + simulationData: { + nativeBalanceChange: { + difference: differenceInHex, + isDecrease: true, + }, + }, + } as unknown as TransactionMeta; + + expect(hasValueAndNativeBalanceMismatch(transaction)).toBe(false); + }); + + it('returns true when values differ beyond threshold', () => { + const transactionValueInDecimal = 10000000000000000; + const transactionValueInHex = toHex(transactionValueInDecimal); + + const differenceInDecimal = 1000000000; + const muchSmallerDifferenceInHex = toHex(differenceInDecimal); + + const transaction = { + txParams: { + value: transactionValueInHex, + }, + simulationData: { + nativeBalanceChange: { + difference: muchSmallerDifferenceInHex, + isDecrease: true, + }, + }, + } as unknown as TransactionMeta; + + expect(hasValueAndNativeBalanceMismatch(transaction)).toBe(true); + }); + + it('returns true when no simulation data is present', () => { + const transactionValueInDecimal = 10000000000000000; + const transactionValueInHex = toHex(transactionValueInDecimal); + + const transaction = { + txParams: { + value: transactionValueInHex, + }, + } as unknown as TransactionMeta; + + expect(hasValueAndNativeBalanceMismatch(transaction)).toBe(true); + }); + + it('handles case when value is increased in simulation', () => { + const transactionValueInDecimal = 10000000000000000; + const transactionValueInHex = toHex(transactionValueInDecimal); + + const differenceInDecimal = 10000000000000000; + const differenceInHex = toHex(differenceInDecimal); + + const transaction = { + txParams: { + value: transactionValueInHex, + }, + simulationData: { + nativeBalanceChange: { + difference: differenceInHex, + isDecrease: false, + }, + }, + } as unknown as TransactionMeta; + + expect(hasValueAndNativeBalanceMismatch(transaction)).toBe(true); + }); +}); diff --git a/ui/pages/confirmations/components/confirm/info/utils.ts b/ui/pages/confirmations/components/confirm/info/utils.ts index 0ad8479ac7b9..1af918aea74e 100644 --- a/ui/pages/confirmations/components/confirm/info/utils.ts +++ b/ui/pages/confirmations/components/confirm/info/utils.ts @@ -1,9 +1,15 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import type { Hex } from '@metamask/utils'; +import { remove0x } from '@metamask/utils'; +import { BN } from 'bn.js'; import { DecodedTransactionDataResponse } from '../../../../../../shared/types/transaction-decode'; import { BackgroundColor, TextColor, } from '../../../../../helpers/constants/design-system'; +const VALUE_COMPARISON_PERCENT_THRESHOLD = 5; + export function getIsRevokeSetApprovalForAll( value: DecodedTransactionDataResponse | undefined, ): boolean { @@ -27,3 +33,80 @@ export const getAmountColors = (credit?: boolean, debit?: boolean) => { } return { color, backgroundColor }; }; + +/** + * Calculate the absolute percentage change between two values. + * + * @param originalValue - The first value. + * @param newValue - The second value. + * @returns The percentage change from the first value to the second value. + * If the original value is zero and the new value is not, returns 100. + */ +export function getPercentageChange( + originalValue: InstanceType, + newValue: InstanceType, +): number { + const precisionFactor = new BN(10).pow(new BN(18)); + const originalValuePrecision = originalValue.mul(precisionFactor); + const newValuePrecision = newValue.mul(precisionFactor); + + const difference = newValuePrecision.sub(originalValuePrecision); + + if (difference.isZero()) { + return 0; + } + + if (originalValuePrecision.isZero() && !newValuePrecision.isZero()) { + return 100; + } + + return difference.muln(100).div(originalValuePrecision).abs().toNumber(); +} + +/** + * Determine if the percentage change between two values is within a threshold. + * + * @param originalValue - The original value. + * @param newValue - The new value. + * @param newNegative - Whether the new value is negative. + * @returns Whether the percentage change between the two values is within a threshold. + */ +function percentageChangeWithinThreshold( + originalValue: Hex, + newValue: Hex, + newNegative?: boolean, +): boolean { + const originalValueBN = new BN(remove0x(originalValue), 'hex'); + let newValueBN = new BN(remove0x(newValue), 'hex'); + + if (newNegative) { + newValueBN = newValueBN.neg(); + } + + return ( + getPercentageChange(originalValueBN, newValueBN) <= + VALUE_COMPARISON_PERCENT_THRESHOLD + ); +} + +/** + * Determine if a transaction has a value and simulation native balance mismatch. + * + * @param transactionMeta - The transaction metadata. + * @returns Whether the transaction has a value and simulation native balance mismatch. + */ +export function hasValueAndNativeBalanceMismatch( + transactionMeta: TransactionMeta, +): boolean { + const value = transactionMeta?.txParams?.value ?? '0x0'; + const nativeBalanceChange = + transactionMeta?.simulationData?.nativeBalanceChange; + const simulatedNativeBalanceDifference = + nativeBalanceChange?.difference ?? '0x0'; + + return !percentageChangeWithinThreshold( + value as Hex, + simulatedNativeBalanceDifference, + nativeBalanceChange?.isDecrease === false, + ); +} From 717cd8780db00fe953958988d6ccfa6e2a9fb15a Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Thu, 12 Dec 2024 18:32:28 +0530 Subject: [PATCH 08/17] fix: Fix in label displayed for state change in signature decoding section (#29020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We currently displaying multiple "You list" and "Spending cap" for multiple assets. We should be displaying the copy only once similar to how we do it for simulations. ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/28944 ## **Manual testing steps** 1. Submit a typed sign v4 request with multiple NFT listed 2. Check simulation section on page displayed ## **Screenshots/Recordings** Screenshot 2024-12-09 at 6 05 46 PM ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../decoded-simulation.test.tsx | 25 ++++++++++- .../decoded-simulation/decoded-simulation.tsx | 42 ++++++++++++------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.test.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.test.tsx index 26b4c46f26cd..c06cf906e870 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { - DecodingData, DecodingDataChangeType, DecodingDataStateChanges, } from '@metamask/signature-controller'; @@ -11,7 +10,7 @@ import { renderWithConfirmContextProvider } from '../../../../../../../../../tes import { permitSignatureMsg } from '../../../../../../../../../test/data/confirmations/typed_sign'; import PermitSimulation, { getStateChangeToolip } from './decoded-simulation'; -const decodingData: DecodingData = { +const decodingData = { stateChanges: [ { assetType: 'ERC20', @@ -165,4 +164,26 @@ describe('DecodedSimulation', () => { ); expect(tooltip).toBe('signature_decoding_bid_nft_tooltip'); }); + + it('renders label only once if there are multiple state changes of same changeType', async () => { + const state = getMockTypedSignConfirmStateForRequest({ + ...permitSignatureMsg, + decodingLoading: false, + decodingData: { + stateChanges: [ + decodingData.stateChanges[0], + decodingData.stateChanges[0], + decodingData.stateChanges[0], + ], + }, + }); + const mockStore = configureMockStore([])(state); + + const { findAllByText } = renderWithConfirmContextProvider( + , + mockStore, + ); + + expect(await findAllByText('Spending cap')).toHaveLength(1); + }); }); diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.tsx index ec07ae253405..fe2be9d76261 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign-v4-simulation/decoded-simulation/decoded-simulation.tsx @@ -60,10 +60,12 @@ const StateChangeRow = ({ stateChangeList, stateChange, chainId, + shouldDisplayLabel, }: { stateChangeList: DecodingDataStateChanges | null; stateChange: DecodingDataStateChange; chainId: Hex; + shouldDisplayLabel: boolean; }) => { const t = useI18nContext(); const { assetType, changeType, amount, contractAddress, tokenID } = @@ -71,7 +73,7 @@ const StateChangeRow = ({ const tooltip = getStateChangeToolip(stateChangeList, stateChange, t); return ( {(assetType === TokenStandard.ERC20 || @@ -104,19 +106,31 @@ const DecodedSimulation: React.FC = () => { const chainId = currentConfirmation.chainId as Hex; const { decodingLoading, decodingData } = currentConfirmation; - const stateChangeFragment = useMemo( - () => - (decodingData?.stateChanges ?? []).map( - (change: DecodingDataStateChange) => ( - - ), - ), - [decodingData?.stateChanges], - ); + const stateChangeFragment = useMemo(() => { + const stateChangesGrouped: Record = ( + decodingData?.stateChanges ?? [] + ).reduce>( + (result, stateChange) => { + result[stateChange.changeType] = [ + ...(result[stateChange.changeType] ?? []), + stateChange, + ]; + return result; + }, + {}, + ); + + return Object.entries(stateChangesGrouped).flatMap(([_, changeList]) => + changeList.map((change: DecodingDataStateChange, index: number) => ( + + )), + ); + }, [decodingData?.stateChanges]); return ( Date: Thu, 12 Dec 2024 13:46:34 +0000 Subject: [PATCH 09/17] feat: Permission page tour removal (#28966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is to remove product tour from Permissions Page ## **Related issues** Fixes: [https://github.com/MetaMask/MetaMask-planning/issues/3755](https://github.com/MetaMask/MetaMask-planning/issues/3755) ## **Manual testing steps** 1. Run extension with `yarn start` 2. Install a fresh version 3. Go to Permissions Page, check there is no Product Tour ## **Screenshots/Recordings** ### **Before** ![Screenshot 2024-12-05 at 3 53 47 PM](https://github.com/user-attachments/assets/a020cd59-492c-43df-af41-0f7a5ec7f142) ### **After** ![Screenshot 2024-12-05 at 3 54 50 PM](https://github.com/user-attachments/assets/e77251f3-c3c9-433b-bef8-218dceba2bf5) ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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 | 6 ----- app/_locales/el/messages.json | 6 ----- app/_locales/en/messages.json | 6 ----- app/_locales/es/messages.json | 6 ----- app/_locales/fr/messages.json | 6 ----- app/_locales/hi/messages.json | 6 ----- app/_locales/id/messages.json | 6 ----- app/_locales/ja/messages.json | 6 ----- app/_locales/ko/messages.json | 6 ----- app/_locales/pt/messages.json | 6 ----- app/_locales/ru/messages.json | 6 ----- app/_locales/tl/messages.json | 6 ----- app/_locales/tr/messages.json | 6 ----- app/_locales/vi/messages.json | 6 ----- app/_locales/zh_CN/messages.json | 6 ----- .../connections/connect-with-metamask.spec.js | 4 --- .../connections/edit-account-flow.spec.js | 4 --- .../connections/edit-networks-flow.spec.js | 4 --- .../review-permissions-page.spec.js | 8 ------ .../dapp-interactions.spec.js | 5 ---- .../dapp-interactions/permissions.spec.js | 4 --- test/e2e/tests/metrics/dapp-viewed.spec.js | 4 --- .../multichain/all-permissions-page.spec.js | 8 ------ .../tests/multichain/permission-page.spec.js | 8 ------ .../permissions-page/permissions-page.js | 25 +------------------ 25 files changed, 1 insertion(+), 163 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 06d2f690716d..ec9779e4d1af 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Hier können Sie die Genehmigungen sehen, die Sie installierten Snaps oder verbundenen Websites gegeben haben." }, - "permissionsPageTourDescription": { - "message": "Dies ist Ihr Kontrollfeld zum Verwalten der Genehmigungen für verbundene Websites und installierte Snaps." - }, - "permissionsPageTourTitle": { - "message": "Verbundene Websites sind nun Genehmigungen" - }, "permitSimulationDetailInfo": { "message": "Sie erteilen dem Spender die Genehmigung, diese Menge an Tokens von Ihrem Konto auszugeben." }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 8d09e2c6658f..42d08fa2f602 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Εδώ μπορείτε να δείτε τις άδειες χρήσης που έχετε δώσει στα εγκατεστημένα Snaps ή στους συνδεδεμένους ιστότοπους." }, - "permissionsPageTourDescription": { - "message": "Αυτός είναι ο πίνακας ελέγχου για τη διαχείριση των αδειών χρήσης που έχετε δώσει στους συνδεδεμένους ιστότοπους και στα εγκατεστημένα Snaps." - }, - "permissionsPageTourTitle": { - "message": "Οι συνδεδεμένοι ιστότοποι είναι τώρα με άδειες χρήσης" - }, "permitSimulationDetailInfo": { "message": "Δίνετε στον διαθέτη την άδεια να δαπανήσει τα tokens από τον λογαριασμό σας." }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 9d63e212d88c..34afdaab62ed 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -4255,12 +4255,6 @@ "permissionsPageEmptySubContent": { "message": "This is where you can see the permissions you've given to installed Snaps or connected sites." }, - "permissionsPageTourDescription": { - "message": "This is your control panel for managing permissions given to connected sites and installed Snaps." - }, - "permissionsPageTourTitle": { - "message": "Connected sites are now permissions" - }, "permitSimulationChange_approve": { "message": "Spending cap" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 2861d508743d..9d3b9028c734 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Aquí es donde puedes ver los permisos que has otorgado a los Snaps instalados o a los sitios conectados." }, - "permissionsPageTourDescription": { - "message": "Este es su panel de control para administrar los permisos otorgados a los sitios conectados y los Snaps instalados." - }, - "permissionsPageTourTitle": { - "message": "Los sitios conectados ahora tienen permisos" - }, "permitSimulationDetailInfo": { "message": "Le está dando permiso al gastador para gastar esta cantidad de tokens de su cuenta." }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 5ae9377d8a69..6b9f60d35678 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Ici, vous pouvez voir les autorisations que vous avez accordées aux Snaps installés ou aux sites connectés." }, - "permissionsPageTourDescription": { - "message": "C’’est votre panneau de configuration pour gérer les autorisations accordées aux sites connectés et aux Snaps installés." - }, - "permissionsPageTourTitle": { - "message": "Les sites connectés sont maintenant des autorisations" - }, "permitSimulationDetailInfo": { "message": "Vous autorisez la dépenseur à dépenser ce nombre de jetons de votre compte." }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index a036aef959ce..7e4df895fbd8 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "यहां पर आप इंस्टॉल किए गए Snaps या कनेक्टेड साइटों को दी गई अनुमतियां देख सकते हैं।" }, - "permissionsPageTourDescription": { - "message": "कनेक्टेड साइटों और इंस्टॉल किए गए Snaps को दी गई अनुमतियों को मैनेज करने के लिए यह आपका कंट्रोल पैनल है।" - }, - "permissionsPageTourTitle": { - "message": "कनेक्टेड साइटें अब अनुमतियां हैं" - }, "permitSimulationDetailInfo": { "message": "आप खर्च करने वाले को अपने अकाउंट से इतने सारे टोकन खर्च करने की अनुमति दे रहे हैं।" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 5777f05c2322..9cc407f17b1c 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Di sinilah Anda dapat melihat izin yang Anda berikan untuk Snap yang terinstal atau situs yang terhubung." }, - "permissionsPageTourDescription": { - "message": "Ini merupakan panel kontrol Anda untuk mengelola izin yang diberikan ke situs yang terhubung dan Snap yang terinstal." - }, - "permissionsPageTourTitle": { - "message": "Situs yang terhubung kini memiliki izin" - }, "permitSimulationDetailInfo": { "message": "Anda memberikan izin kepada pengguna untuk menggunakan token sebanyak ini dari akun." }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 561411606feb..08b8022108d1 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "ここには、インストールされたSnapや接続されたサイトに付与したアクセス許可が表示されます。" }, - "permissionsPageTourDescription": { - "message": "これは、接続されたサイトやインストールされたSnapに付与したアクセス許可を管理するための、コントロールパネルです。" - }, - "permissionsPageTourTitle": { - "message": "「接続済みのサイト」が「アクセス許可」に変更されました" - }, "permitSimulationDetailInfo": { "message": "この数量のトークンをアカウントから転送する権限を使用者に付与しようとしています。" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 941010db2abe..11c9e64de010 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "여기에서 설치된 Snap 또는 연결된 사이트의 권한을 확인할 수 있습니다." }, - "permissionsPageTourDescription": { - "message": "연결된 사이트 또는 설치된 Snap의 권한을 관리하기 위한 제어판입니다." - }, - "permissionsPageTourTitle": { - "message": "이제 연결된 사이트에 권한이 부여됩니다" - }, "permitSimulationDetailInfo": { "message": "내 계정에서 이만큼의 토큰을 사용할 수 있도록 승인합니다." }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 553b0ad31508..af31962e7066 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Aqui você pode ver as permissões que deu aos snaps instalados ou sites conectados." }, - "permissionsPageTourDescription": { - "message": "Este é o seu painel de controle para gerenciar as permissões dadas aos sites conectados e snaps instalados." - }, - "permissionsPageTourTitle": { - "message": "Sites conectados agora são permissões" - }, "permitSimulationDetailInfo": { "message": "Você está autorizando o consumidor a gastar esta quantidade de tokens de sua conta." }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 1403b6084d27..c8c54df2d25d 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Здесь вы можете увидеть разрешения, которые вы предоставили установленным Snaps или подключенным сайтам." }, - "permissionsPageTourDescription": { - "message": "Это ваша панель управления для управления разрешениями, предоставленными подключенным сайтам и установленным Snaps." - }, - "permissionsPageTourTitle": { - "message": "Подключенные сайты теперь имеют разрешения" - }, "permitSimulationDetailInfo": { "message": "Вы даёте расходующему лицу разрешение потратить именно столько токенов из вашего аккаунта" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 60855b61765d..34f248e7ec8c 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Dito mo makikita ang mga pahintulot na iyong binigay sa mga naka-install na Snap o konektadong site." }, - "permissionsPageTourDescription": { - "message": "Ito ang iyong control panel para pamahalaan ang mga permiso na ibinigay sa mga konektadong Snap." - }, - "permissionsPageTourTitle": { - "message": "Ang mga konektadong site ay pahintulot na ngayon" - }, "permitSimulationDetailInfo": { "message": "Binibigyan mo ang gumagastos ng permiso upang gumastos ng ganito karaming token mula sa iyong account." }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 6bcd1b8a61fc..3bfcbe9812c1 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Burada, yüklü Snap'lere veya bağlı sitelere verdiğiniz izinleri görebilirsiniz." }, - "permissionsPageTourDescription": { - "message": "Burası, bağlı sitelere ve yüklü Snap'lere verilen izinleri yönetebileceğiniz kontrol panelinizdir." - }, - "permissionsPageTourTitle": { - "message": "Bağlı siteler şimdi izinler oldu" - }, "permitSimulationDetailInfo": { "message": "Harcama yapan tarafa hesabınızdan bu kadar çok token'i harcama izni veriyorsunuz." }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 3901eed1fc07..47ca7fad8568 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "Đây là nơi bạn có thể xem các quyền mà bạn đã cấp cho các Snap đã cài đặt hoặc các trang web đã kết nối." }, - "permissionsPageTourDescription": { - "message": "Đây là bảng điều khiển để bạn quản lý các quyền được cấp cho các trang web đã kết nối và các Snap đã cài đặt." - }, - "permissionsPageTourTitle": { - "message": "Các trang web đã kết nối hiện đã được cấp quyền" - }, "permitSimulationDetailInfo": { "message": "Bạn đang cấp cho người chi tiêu quyền chi tiêu số lượng token này từ tài khoản của bạn." }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 4d548221769f..2e8a8ee3a052 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -4105,12 +4105,6 @@ "permissionsPageEmptySubContent": { "message": "您可以在此处查看您授予已安装 Snap 或已连接站点的许可。" }, - "permissionsPageTourDescription": { - "message": "这是您的控制面板,用于管理授予已连接站点和已安装 Snap 的许可。" - }, - "permissionsPageTourTitle": { - "message": "已连接的站点现已获得许可" - }, "permitSimulationDetailInfo": { "message": "您将授予该消费者许可从您的账户中支出这些代币。" }, diff --git a/test/e2e/tests/connections/connect-with-metamask.spec.js b/test/e2e/tests/connections/connect-with-metamask.spec.js index 5611b40346db..b46fc8730d84 100644 --- a/test/e2e/tests/connections/connect-with-metamask.spec.js +++ b/test/e2e/tests/connections/connect-with-metamask.spec.js @@ -55,10 +55,6 @@ describe('Connections page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/connections/edit-account-flow.spec.js b/test/e2e/tests/connections/edit-account-flow.spec.js index 7b05f439714c..1c4899ed8328 100644 --- a/test/e2e/tests/connections/edit-account-flow.spec.js +++ b/test/e2e/tests/connections/edit-account-flow.spec.js @@ -58,10 +58,6 @@ describe('Edit Accounts Flow', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/connections/edit-networks-flow.spec.js b/test/e2e/tests/connections/edit-networks-flow.spec.js index 1db224f0ac0a..95a091f7e504 100644 --- a/test/e2e/tests/connections/edit-networks-flow.spec.js +++ b/test/e2e/tests/connections/edit-networks-flow.spec.js @@ -43,10 +43,6 @@ describe('Edit Networks Flow', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/connections/review-permissions-page.spec.js b/test/e2e/tests/connections/review-permissions-page.spec.js index d411a343b2c9..60b7df8de4e0 100644 --- a/test/e2e/tests/connections/review-permissions-page.spec.js +++ b/test/e2e/tests/connections/review-permissions-page.spec.js @@ -36,10 +36,6 @@ describe('Review Permissions page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', @@ -90,10 +86,6 @@ describe('Review Permissions page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js index 584408134f1a..05d9528ce6b4 100644 --- a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js +++ b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js @@ -83,11 +83,6 @@ describe('Dapp interactions', function () { ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); - const connectedDapp1 = await driver.isElementPresent({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/dapp-interactions/permissions.spec.js b/test/e2e/tests/dapp-interactions/permissions.spec.js index 4b6c210f0a98..b8da733d3160 100644 --- a/test/e2e/tests/dapp-interactions/permissions.spec.js +++ b/test/e2e/tests/dapp-interactions/permissions.spec.js @@ -46,10 +46,6 @@ describe('Permissions', function () { text: 'All Permissions', tag: 'div', }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.waitForSelector({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/metrics/dapp-viewed.spec.js b/test/e2e/tests/metrics/dapp-viewed.spec.js index 668f93e65dc5..a747ea658937 100644 --- a/test/e2e/tests/metrics/dapp-viewed.spec.js +++ b/test/e2e/tests/metrics/dapp-viewed.spec.js @@ -297,10 +297,6 @@ describe('Dapp viewed Event @no-mmi', function () { text: 'All Permissions', tag: 'div', }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/multichain/all-permissions-page.spec.js b/test/e2e/tests/multichain/all-permissions-page.spec.js index 5bb718bd8d20..47601c58bb2f 100644 --- a/test/e2e/tests/multichain/all-permissions-page.spec.js +++ b/test/e2e/tests/multichain/all-permissions-page.spec.js @@ -32,10 +32,6 @@ describe('Permissions Page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); const connectedDapp = await driver.isElementPresent({ text: '127.0.0.1:8080', tag: 'p', @@ -83,10 +79,6 @@ describe('Permissions Page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); const connectedDapp = await driver.isElementPresent({ text: '127.0.0.1:8080', tag: 'p', diff --git a/test/e2e/tests/multichain/permission-page.spec.js b/test/e2e/tests/multichain/permission-page.spec.js index 5ae3f71b6046..e2b7208045e0 100644 --- a/test/e2e/tests/multichain/permission-page.spec.js +++ b/test/e2e/tests/multichain/permission-page.spec.js @@ -32,10 +32,6 @@ describe('Permissions Page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); const connectedDapp = await driver.isElementPresent({ text: '127.0.0.1:8080', tag: 'p', @@ -68,10 +64,6 @@ describe('Permissions Page', function () { '[data-testid ="account-options-menu-button"]', ); await driver.clickElement({ text: 'All Permissions', tag: 'div' }); - await driver.clickElementAndWaitToDisappear({ - text: 'Got it', - tag: 'button', - }); await driver.clickElement({ text: '127.0.0.1:8080', tag: 'p', diff --git a/ui/components/multichain/pages/permissions-page/permissions-page.js b/ui/components/multichain/pages/permissions-page/permissions-page.js index 8cdeae0ed57d..3f4680bf0350 100644 --- a/ui/components/multichain/pages/permissions-page/permissions-page.js +++ b/ui/components/multichain/pages/permissions-page/permissions-page.js @@ -1,4 +1,3 @@ -import classnames from 'classnames'; import React, { useEffect, useRef, useState } from 'react'; import { useHistory } from 'react-router-dom'; import { useSelector } from 'react-redux'; @@ -26,13 +25,7 @@ import { DEFAULT_ROUTE, REVIEW_PERMISSIONS, } from '../../../../helpers/constants/routes'; -import { - getOnboardedInThisUISession, - getShowPermissionsTour, - getConnectedSitesListWithNetworkInfo, -} from '../../../../selectors'; -import { ProductTour } from '../../product-tour-popover'; -import { hidePermissionsTour } from '../../../../store/actions'; +import { getConnectedSitesListWithNetworkInfo } from '../../../../selectors'; import { isSnapId } from '../../../../helpers/utils/snaps'; import { ConnectionListItem } from './connection-list-item'; @@ -44,8 +37,6 @@ export const PermissionsPage = () => { const sitesConnectionsList = useSelector( getConnectedSitesListWithNetworkInfo, ); - const showPermissionsTour = useSelector(getShowPermissionsTour); - const onboardedInThisUISession = useSelector(getOnboardedInThisUISession); useEffect(() => { setTotalConnections(Object.keys(sitesConnectionsList).length); @@ -94,20 +85,6 @@ export const PermissionsPage = () => { {t('permissions')} - {showPermissionsTour && !onboardedInThisUISession ? ( - - ) : null} {totalConnections > 0 ? ( From 49a7c825a2c723a1bf9250066d24567cf43fde54 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Thu, 12 Dec 2024 19:27:24 +0530 Subject: [PATCH 10/17] fix: design related fixes in confirmation pages (#29137) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Small design related fixes in re-designed confirmation pages ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3478 ## **Manual testing steps** 1. Go to test dapp 2. Submit transaction pages and check design fixes ## **Screenshots/Recordings** Screenshot 2024-12-12 at 6 52 03 PM ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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/components/app/confirm/info/row/text.tsx | 26 +++---- .../info/__snapshots__/info.test.tsx.snap | 72 +++++++++---------- .../__snapshots__/approve.test.tsx.snap | 38 +++++----- .../__snapshots__/spending-cap.test.tsx.snap | 14 ++-- .../base-transaction-info.test.tsx.snap | 24 +++---- .../native-transfer.test.tsx.snap | 24 +++---- .../nft-token-transfer.test.tsx.snap | 24 +++---- .../set-approval-for-all-info.test.tsx.snap | 24 +++---- .../edit-gas-fees-row.test.tsx.snap | 26 +++---- .../edit-gas-fees-row/edit-gas-fees-row.tsx | 8 +-- .../gas-fees-details.test.tsx.snap | 24 +++---- .../gas-fees-section.test.tsx.snap | 24 +++---- .../token-transfer.test.tsx.snap | 24 +++---- 13 files changed, 176 insertions(+), 176 deletions(-) diff --git a/ui/components/app/confirm/info/row/text.tsx b/ui/components/app/confirm/info/row/text.tsx index 1f026f53c7d4..0e26b5a75bdc 100644 --- a/ui/components/app/confirm/info/row/text.tsx +++ b/ui/components/app/confirm/info/row/text.tsx @@ -53,18 +53,6 @@ export const ConfirmInfoRowText: React.FC = ({ gap={2} minWidth={BlockSize.Zero} > - {tooltip ? ( - - - - ) : ( - - )} {isEditable ? ( = ({ onClick={onEditClick} size={ButtonIconSize.Sm} // to reset the button padding - style={{ marginLeft: '-4px' }} + style={{ marginRight: '-4px' }} data-testid={editIconDataTestId} /> ) : null} + {tooltip ? ( + + + + ) : ( + + )} ); }; diff --git a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap index a3f98126b093..2ff281c5186e 100644 --- a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap @@ -92,18 +92,6 @@ exports[`Info renders info section for approve request 1`] = `
-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

-

- 0.0001 ETH -

-

- $0.04 -

+

+ 0.0001 ETH +

+

+ $0.04 +

-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

renders component for approve request 1`] = `
-

- 1000 -

+

+ 1000 +

@@ -475,18 +475,6 @@ exports[` renders component for approve request 1`] = `
-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

renders component 1`] = `
-

- 1000 -

+

+ 1000 +

diff --git a/ui/pages/confirmations/components/confirm/info/base-transaction-info/__snapshots__/base-transaction-info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/base-transaction-info/__snapshots__/base-transaction-info.test.tsx.snap index ee15d22e6363..f82c33d3d0f2 100644 --- a/ui/pages/confirmations/components/confirm/info/base-transaction-info/__snapshots__/base-transaction-info.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/base-transaction-info/__snapshots__/base-transaction-info.test.tsx.snap @@ -276,18 +276,6 @@ exports[` renders component for contract interaction requ
-

- 0.0001 ETH -

-

- $0.04 -

+

+ 0.0001 ETH +

+

+ $0.04 +

-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

renders component for approve request 1`] = `
-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

renders component 1`] = `
+

renders component 1`] = `

- diff --git a/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx b/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx index e351516941b8..2d3697c6f949 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx @@ -58,6 +58,10 @@ export const EditGasFeesRow = ({ alignItems={AlignItems.center} textAlign={TextAlign.Center} > + )} - ); diff --git a/ui/pages/confirmations/components/confirm/info/shared/gas-fees-details/__snapshots__/gas-fees-details.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/shared/gas-fees-details/__snapshots__/gas-fees-details.test.tsx.snap index 8cc9a9c3bfb5..081f1038b24b 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/gas-fees-details/__snapshots__/gas-fees-details.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/shared/gas-fees-details/__snapshots__/gas-fees-details.test.tsx.snap @@ -39,18 +39,6 @@ exports[` renders component for gas fees section 1`] = `
-

- 0.0001 ETH -

-

- $0.04 -

+

+ 0.0001 ETH +

+

+ $0.04 +

renders component for gas fees section 1`] = `
-

- 0.0001 ETH -

-

- $0.04 -

+

+ 0.0001 ETH +

+

+ $0.04 +

-

- 0.0001 ETH -

-

- $0.08 -

+

+ 0.0001 ETH +

+

+ $0.08 +

Date: Thu, 12 Dec 2024 15:39:51 +0100 Subject: [PATCH 11/17] test: [POM] Migrate hardware wallet e2e tests to follow Page Object Model (#28768) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - Create base pages for hardware wallet related pages - Migrate hardware wallet e2e tests to Page Object Model - Remove dead code (We should not keep unused functions in the codebase because they can lead to several issues, such as increased maintenance overhead, added complexity, potential bugs, and misleading information.) [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27155?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/28808 ## **Manual testing steps** Check code readability, make sure tests pass. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [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. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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: Harika <153644847+hjetpoluru@users.noreply.github.com> Co-authored-by: Derek Brans --- .../page-objects/pages/account-list-page.ts | 31 +++- .../connect-hardware-wallet-page.ts | 54 ++++++ .../select-trezor-account-page.ts | 94 +++++++++++ .../e2e/page-objects/pages/home/asset-list.ts | 44 ----- .../pages/snap-simple-keyring-page.ts | 5 +- test/e2e/page-objects/pages/test-dapp.ts | 47 ++++-- .../hardware-wallets/lattice-connect.spec.ts | 38 ++--- .../hardware-wallets/trezor-account.spec.js | 156 ------------------ .../hardware-wallets/trezor-account.spec.ts | 117 +++++++++++++ .../hardware-wallets/trezor-send.spec.ts | 27 ++- .../hardware-wallets/trezor-sign.spec.ts | 40 ++--- 11 files changed, 372 insertions(+), 281 deletions(-) create mode 100644 test/e2e/page-objects/pages/hardware-wallet/connect-hardware-wallet-page.ts create mode 100644 test/e2e/page-objects/pages/hardware-wallet/select-trezor-account-page.ts delete mode 100644 test/e2e/tests/hardware-wallets/trezor-account.spec.js create mode 100644 test/e2e/tests/hardware-wallets/trezor-account.spec.ts diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index 955dd5111fe1..bbf25013f607 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; import { Driver } from '../../webdriver/driver'; -import { largeDelayMs } from '../../helpers'; +import { largeDelayMs, regularDelayMs } from '../../helpers'; import messages from '../../../../app/_locales/en/messages.json'; class AccountListPage { @@ -8,6 +8,9 @@ class AccountListPage { private readonly accountAddressText = '.qr-code__address-segments'; + private readonly accountListAddressItem = + '[data-testid="account-list-address"]'; + private readonly accountListBalance = '[data-testid="second-currency-display"]'; @@ -40,6 +43,11 @@ class AccountListPage { private readonly addEthereumAccountButton = '[data-testid="multichain-account-menu-popover-add-account"]'; + private readonly addHardwareWalletButton = { + text: 'Add hardware wallet', + tag: 'button', + }; + private readonly addImportedAccountButton = '[data-testid="multichain-account-menu-popover-add-imported-account"]'; @@ -378,6 +386,15 @@ class AccountListPage { await this.driver.waitForSelector(this.addEthereumAccountButton); } + async openConnectHardwareWalletModal(): Promise { + console.log(`Open connect hardware wallet modal`); + await this.driver.clickElement(this.createAccountButton); + await this.driver.clickElement(this.addHardwareWalletButton); + // This delay is needed to mitigate an existing bug in FF + // See https://github.com/metamask/metamask-extension/issues/25851 + await this.driver.delay(regularDelayMs); + } + async openHiddenAccountOptions(): Promise { console.log(`Open hidden accounts options menu`); await this.driver.clickElement(this.hiddenAccountOptionsMenuButton); @@ -436,6 +453,18 @@ class AccountListPage { await this.driver.clickElement(this.pinUnpinAccountButton); } + async check_accountAddressDisplayedInAccountList( + expectedAddress: string, + ): Promise { + console.log( + `Check that account address ${expectedAddress} is displayed in account list`, + ); + await this.driver.waitForSelector({ + css: this.accountListAddressItem, + text: expectedAddress, + }); + } + /** * Checks that the account balance is displayed in the account list. * diff --git a/test/e2e/page-objects/pages/hardware-wallet/connect-hardware-wallet-page.ts b/test/e2e/page-objects/pages/hardware-wallet/connect-hardware-wallet-page.ts new file mode 100644 index 000000000000..e3b4de3fb522 --- /dev/null +++ b/test/e2e/page-objects/pages/hardware-wallet/connect-hardware-wallet-page.ts @@ -0,0 +1,54 @@ +import { Driver } from '../../../webdriver/driver'; + +/** + * Represents the page for connecting hardware wallets. + * This page allows users to initiate connections with various hardware wallet types. + */ +class ConnectHardwareWalletPage { + private driver: Driver; + + private readonly connectHardwareWalletPageTitle = { + text: 'Connect a hardware wallet', + tag: 'h3', + }; + + private readonly connectLatticeButton = '[data-testid="connect-lattice-btn"]'; + + private readonly connectTrezorButton = '[data-testid="connect-trezor-btn"]'; + + private readonly continueButton = { text: 'Continue', tag: 'button' }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.connectHardwareWalletPageTitle, + this.connectLatticeButton, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for connect hardware wallet page to be loaded', + e, + ); + throw e; + } + console.log('Connect hardware wallet page is loaded'); + } + + async openConnectLatticePage(): Promise { + console.log(`Open connect lattice page`); + await this.driver.clickElement(this.connectLatticeButton); + await this.driver.clickElement(this.continueButton); + } + + async openConnectTrezorPage(): Promise { + console.log(`Open connect trezor page`); + await this.driver.clickElement(this.connectTrezorButton); + await this.driver.clickElement(this.continueButton); + } +} + +export default ConnectHardwareWalletPage; diff --git a/test/e2e/page-objects/pages/hardware-wallet/select-trezor-account-page.ts b/test/e2e/page-objects/pages/hardware-wallet/select-trezor-account-page.ts new file mode 100644 index 000000000000..65a00808c0bb --- /dev/null +++ b/test/e2e/page-objects/pages/hardware-wallet/select-trezor-account-page.ts @@ -0,0 +1,94 @@ +import { Driver } from '../../../webdriver/driver'; + +/** + * Represents the select trezor hardware wallet account page. + * This page allows users to select Trezor accounts to connect. + */ +class SelectTrezorAccountPage { + private driver: Driver; + + private readonly cancelButton = { text: 'Cancel', tag: 'button' }; + + private readonly selectTrezorAccountPageTitle = { + text: 'Select an account', + tag: 'h3', + }; + + private readonly trezorAccountCheckbox = '.hw-account-list__item__checkbox'; + + private readonly unlockButton = { text: 'Unlock', tag: 'button' }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.selectTrezorAccountPageTitle, + this.cancelButton, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for select trezor account page to be loaded', + e, + ); + throw e; + } + console.log('Select trezor account page is loaded'); + } + + async clickUnlockButton(): Promise { + console.log(`Click unlock button on select trezor account page`); + await this.driver.clickElement(this.unlockButton); + } + + async selectTrezorAccount(accountIndex: number): Promise { + console.log(`Select trezor account ${accountIndex}`); + const accountCheckboxes = await this.driver.findElements( + this.trezorAccountCheckbox, + ); + await accountCheckboxes[accountIndex - 1].click(); + } + + async unlockAccount(accountIndex: number): Promise { + console.log(`Unlock trezor account ${accountIndex}`); + await this.selectTrezorAccount(accountIndex); + await this.clickUnlockButton(); + } + + /** + * Check that the specified address is displayed in the list of accounts. + * + * @param address - The address to check for. + */ + async check_addressIsDisplayed(address: string): Promise { + console.log( + `Check that account address ${address} is displayed on select trezor account page`, + ); + await this.driver.waitForSelector({ text: address }); + } + + /** + * This function checks if the specified number of trezor account items is displayed in the trezor account list. + * + * @param expectedNumber - The number of trezor account items expected to be displayed. Defaults to 5. + * @returns A promise that resolves if the expected number of trezor account items is displayed. + */ + async check_trezorAccountNumber(expectedNumber: number = 5): Promise { + console.log( + `Waiting for ${expectedNumber} trezor account items to be displayed`, + ); + await this.driver.wait(async () => { + const trezorAccountItems = await this.driver.findElements( + this.trezorAccountCheckbox, + ); + return trezorAccountItems.length === expectedNumber; + }, 10000); + console.log( + `Expected number of trezor account items ${expectedNumber} is displayed.`, + ); + } +} + +export default SelectTrezorAccountPage; diff --git a/test/e2e/page-objects/pages/home/asset-list.ts b/test/e2e/page-objects/pages/home/asset-list.ts index abc5870ec04a..db9367991bf7 100644 --- a/test/e2e/page-objects/pages/home/asset-list.ts +++ b/test/e2e/page-objects/pages/home/asset-list.ts @@ -81,15 +81,6 @@ class AssetListPage { throw new Error(`${assetName} button not found`); } - async getAllNetworksOptionTotal(): Promise { - console.log(`Retrieving the "All networks" option fiat value`); - const allNetworksValueElement = await this.driver.findElement( - this.allNetworksTotal, - ); - const value = await allNetworksValueElement.getText(); - return value; - } - async getCurrentNetworksOptionTotal(): Promise { console.log(`Retrieving the "Current network" option fiat value`); const allNetworksValueElement = await this.driver.findElement( @@ -156,30 +147,6 @@ class AssetListPage { ); } - async selectNetworkFilterAllNetworks(): Promise { - console.log(`Selecting "All networks" from the network filter`); - await this.driver.clickElement(this.allNetworksOption); - await this.driver.waitUntil( - async () => { - const label = await this.getNetworksFilterLabel(); - return label === 'All networks'; - }, - { timeout: 5000, interval: 100 }, - ); - } - - async selectNetworkFilterCurrentNetwork(): Promise { - console.log(`Selecting "Current network" from the network filter`); - await this.driver.clickElement(this.currentNetworkOption); - await this.driver.waitUntil( - async () => { - const label = await this.getNetworksFilterLabel(); - return label !== 'All networks'; - }, - { timeout: 5000, interval: 100 }, - ); - } - async waitUntilFilterLabelIs(label: string): Promise { console.log(`Waiting until the filter label is ${label}`); await this.driver.waitUntil( @@ -191,17 +158,6 @@ class AssetListPage { ); } - async check_ifAssetIsVisible(assetName: string): Promise { - const assets = await this.driver.findElements(this.tokenListItem); - for (const asset of assets) { - const text = await asset.getText(); - if (text.includes(assetName)) { - return true; - } - } - return false; - } - async check_networkFilterText(expectedText: string): Promise { console.log( `Verify the displayed account label in header is: ${expectedText}`, diff --git a/test/e2e/page-objects/pages/snap-simple-keyring-page.ts b/test/e2e/page-objects/pages/snap-simple-keyring-page.ts index c75adb06da3a..21722cf7b36a 100644 --- a/test/e2e/page-objects/pages/snap-simple-keyring-page.ts +++ b/test/e2e/page-objects/pages/snap-simple-keyring-page.ts @@ -306,7 +306,10 @@ class SnapSimpleKeyringPage { await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await this.driver.clickElement(this.confirmConnectionButton); - await this.driver.waitForSelector(this.addtoMetamaskMessage); + // set a bigger timeout to wait for element as a temporary fix to reduce flakiness + await this.driver.waitForSelector(this.addtoMetamaskMessage, { + timeout: 15000, + }); await this.driver.clickElementSafe(this.snapInstallScrollButton, 200); await this.driver.waitForSelector(this.confirmAddtoMetamask); await this.driver.clickElement(this.confirmAddtoMetamask); diff --git a/test/e2e/page-objects/pages/test-dapp.ts b/test/e2e/page-objects/pages/test-dapp.ts index c31ee497152e..5155707663b6 100644 --- a/test/e2e/page-objects/pages/test-dapp.ts +++ b/test/e2e/page-objects/pages/test-dapp.ts @@ -16,9 +16,15 @@ class TestDapp { private readonly confirmDialogScrollButton = '[data-testid="signature-request-scroll-button"]'; + private readonly confirmScrollToBottomButtonRedesign = + '.confirm-scroll-to-bottom__button'; + private readonly confirmSignatureButton = '[data-testid="page-container-footer-next"]'; + private readonly confirmSignatureButtonRedesign = + '[data-testid="confirm-footer-button"]'; + private readonly connectAccountButton = '#connectButton'; private readonly connectMetaMaskMessage = { @@ -116,6 +122,11 @@ class TestDapp { tag: 'div', }; + private readonly signTypedDataV3V4SignatureRequestMessageRedesign = { + text: 'Hello, Bob!', + tag: 'p', + }; + private readonly signTypedDataV3VerifyButton = '#signTypedDataV3Verify'; private readonly signTypedDataV3VerifyResult = '#signTypedDataV3VerifyResult'; @@ -159,11 +170,6 @@ class TestDapp { tag: 'h2', }; - private readonly updateNetworkButton = { - text: 'Update', - tag: 'button', - }; - private readonly userRejectedRequestMessage = { tag: 'span', text: 'Error: User rejected the request.', @@ -657,18 +663,33 @@ class TestDapp { /** * Sign a message with the signTypedDataV4 method. + * + * @param confirmationRedesign - Indicates whether the redesigned signature confirmation flow is used. Defaults to false. */ - async signTypedDataV4() { + async signTypedDataV4(confirmationRedesign: boolean = false) { console.log('Sign message with signTypedDataV4'); await this.clickSignTypedDatav4(); await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - await this.driver.waitForSelector( - this.signTypedDataV3V4SignatureRequestMessage, - ); - await this.driver.clickElementSafe(this.confirmDialogScrollButton, 200); - await this.driver.clickElementAndWaitForWindowToClose( - this.confirmSignatureButton, - ); + if (confirmationRedesign) { + await this.driver.waitForSelector( + this.signTypedDataV3V4SignatureRequestMessageRedesign, + ); + await this.driver.clickElementSafe( + this.confirmScrollToBottomButtonRedesign, + 200, + ); + await this.driver.clickElementAndWaitForWindowToClose( + this.confirmSignatureButtonRedesign, + ); + } else { + await this.driver.waitForSelector( + this.signTypedDataV3V4SignatureRequestMessage, + ); + await this.driver.clickElementSafe(this.confirmDialogScrollButton, 200); + await this.driver.clickElementAndWaitForWindowToClose( + this.confirmSignatureButton, + ); + } } async pasteIntoEip747ContractAddressInput() { diff --git a/test/e2e/tests/hardware-wallets/lattice-connect.spec.ts b/test/e2e/tests/hardware-wallets/lattice-connect.spec.ts index b8497a9df692..e20e0bd6fb45 100644 --- a/test/e2e/tests/hardware-wallets/lattice-connect.spec.ts +++ b/test/e2e/tests/hardware-wallets/lattice-connect.spec.ts @@ -2,39 +2,33 @@ import { strict as assert } from 'assert'; import { Suite } from 'mocha'; import { Driver } from '../../webdriver/driver'; import FixtureBuilder from '../../fixture-builder'; -import { withFixtures, unlockWallet } from '../../helpers'; +import { withFixtures } from '../../helpers'; import { isManifestV3 } from '../../../../shared/modules/mv3.utils'; +import AccountListPage from '../../page-objects/pages/account-list-page'; +import ConnectHardwareWalletPage from '../../page-objects/pages/hardware-wallet/connect-hardware-wallet-page'; +import HeaderNavbar from '../../page-objects/pages/header-navbar'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; describe('Lattice hardware wallet @no-mmi', function (this: Suite) { - it('connects to lattice hardware wallet', async function () { + it('lattice page rendering validation', async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), title: this.test?.fullTitle(), }, async ({ driver }: { driver: Driver }) => { - await unlockWallet(driver); + await loginWithBalanceValidation(driver); + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.openAccountMenu(); - // choose Connect hardware wallet from the account menu - await driver.clickElement('[data-testid="account-menu-icon"]'); + // Choose connect hardware wallet from the account menu + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.openConnectHardwareWalletModal(); - // Wait until account list is loaded to mitigate race condition - await driver.waitForSelector({ - text: 'Account 1', - tag: 'span', - }); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - await driver.clickElement({ - text: 'Add hardware wallet', - tag: 'button', - }); - await driver.findClickableElement( - '[data-testid="hardware-connect-close-btn"]', - ); - await driver.clickElement('[data-testid="connect-lattice-btn"]'); - await driver.clickElement({ text: 'Continue', tag: 'button' }); + const connectHardwareWalletPage = new ConnectHardwareWalletPage(driver); + await connectHardwareWalletPage.check_pageIsLoaded(); + await connectHardwareWalletPage.openConnectLatticePage(); const allWindows = await driver.waitUntilXWindowHandles(2); assert.equal(allWindows.length, isManifestV3 ? 3 : 2); diff --git a/test/e2e/tests/hardware-wallets/trezor-account.spec.js b/test/e2e/tests/hardware-wallets/trezor-account.spec.js deleted file mode 100644 index 9abf6e67974d..000000000000 --- a/test/e2e/tests/hardware-wallets/trezor-account.spec.js +++ /dev/null @@ -1,156 +0,0 @@ -const { strict: assert } = require('assert'); -const FixtureBuilder = require('../../fixture-builder'); -const { - defaultGanacheOptions, - unlockWallet, - withFixtures, - regularDelayMs, -} = require('../../helpers'); -const { shortenAddress } = require('../../../../ui/helpers/utils/util'); -const { KNOWN_PUBLIC_KEY_ADDRESSES } = require('../../../stub/keyring-bridge'); - -/** - * Connect Trezor hardware wallet without selecting an account - * - * @param {*} driver - Selenium driver - */ -async function connectTrezor(driver) { - // Open add hardware wallet modal - await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement( - '[data-testid="multichain-account-menu-popover-action-button"]', - ); - await driver.clickElement({ text: 'Add hardware wallet' }); - // This delay is needed to mitigate an existing bug in FF - // See https://github.com/metamask/metamask-extension/issues/25851 - await driver.delay(regularDelayMs); - // Select Trezor - await driver.clickElement('[data-testid="connect-trezor-btn"]'); - await driver.clickElement({ text: 'Continue' }); -} - -describe('Trezor Hardware', function () { - it('derives the correct accounts', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await connectTrezor(driver); - - // Check that the first page of accounts is correct - for (const { address, index } of KNOWN_PUBLIC_KEY_ADDRESSES.slice( - 0, - 4, - )) { - const shortenedAddress = `${address.slice(0, 4)}...${address.slice( - -4, - )}`; - assert( - await driver.isElementPresent({ - text: shortenedAddress, - }), - `Known account ${index} not found`, - ); - } - }, - ); - }); - - it('unlocks the first account', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await connectTrezor(driver); - - // Select first account of first page and unlock - await driver.clickElement('.hw-account-list__item__checkbox'); - await driver.clickElement({ text: 'Unlock' }); - - // Check that the correct account has been added - await driver.clickElement('[data-testid="account-menu-icon"]'); - assert( - await driver.isElementPresent({ - text: 'Trezor 1', - }), - 'Trezor account not found', - ); - assert( - await driver.isElementPresent({ - text: shortenAddress(KNOWN_PUBLIC_KEY_ADDRESSES[0].address), - }), - 'Unlocked account is wrong', - ); - }, - ); - }); - - it('unlocks multiple accounts at once and removes one', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await connectTrezor(driver); - - // Unlock 5 Trezor accounts - const accountCheckboxes = await driver.findElements( - '.hw-account-list__item__checkbox', - ); - await accountCheckboxes[0].click(); - await accountCheckboxes[1].click(); - await accountCheckboxes[2].click(); - await accountCheckboxes[3].click(); - await accountCheckboxes[4].click(); - - await driver.clickElement({ text: 'Unlock' }); - - // Check that all 5 Trezor accounts are present - await driver.clickElement('[data-testid="account-menu-icon"]'); - for (let i = 0; i < 5; i++) { - assert( - await driver.isElementPresent({ - text: `Trezor ${i + 1}`, - }), - `Trezor account ${i + 1} not found`, - ); - assert( - await driver.isElementPresent({ - text: shortenAddress(KNOWN_PUBLIC_KEY_ADDRESSES[i].address), - }), - `Unlocked account ${i + 1} is wrong`, - ); - } - - // Remove Trezor account - const accountDetailsButton = await driver.findElements( - '[data-testid="account-list-item-menu-button"', - ); - await accountDetailsButton[1].click(); - await driver.clickElement('[data-testid="account-list-menu-remove"'); - await driver.clickElement({ - text: 'Remove', - tag: 'button', - }); - - // Assert Trezor account is removed - await driver.clickElement('[data-testid="account-menu-icon"]'); - - await driver.assertElementNotPresent({ - text: 'Trezor 1', - }); - }, - ); - }); -}); diff --git a/test/e2e/tests/hardware-wallets/trezor-account.spec.ts b/test/e2e/tests/hardware-wallets/trezor-account.spec.ts new file mode 100644 index 000000000000..44a382023881 --- /dev/null +++ b/test/e2e/tests/hardware-wallets/trezor-account.spec.ts @@ -0,0 +1,117 @@ +import FixtureBuilder from '../../fixture-builder'; +import { withFixtures } from '../../helpers'; +import { shortenAddress } from '../../../../ui/helpers/utils/util'; +import { KNOWN_PUBLIC_KEY_ADDRESSES } from '../../../stub/keyring-bridge'; +import AccountListPage from '../../page-objects/pages/account-list-page'; +import ConnectHardwareWalletPage from '../../page-objects/pages/hardware-wallet/connect-hardware-wallet-page'; +import HeaderNavbar from '../../page-objects/pages/header-navbar'; +import HomePage from '../../page-objects/pages/home/homepage'; +import SelectTrezorAccountPage from '../../page-objects/pages/hardware-wallet/select-trezor-account-page'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; + +describe('Trezor Hardware', function () { + it('derives the correct accounts and unlocks the first account', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.openAccountMenu(); + + // Choose connect hardware wallet from the account menu + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.openConnectHardwareWalletModal(); + + const connectHardwareWalletPage = new ConnectHardwareWalletPage(driver); + await connectHardwareWalletPage.check_pageIsLoaded(); + await connectHardwareWalletPage.openConnectTrezorPage(); + + const selectTrezorAccountPage = new SelectTrezorAccountPage(driver); + await selectTrezorAccountPage.check_pageIsLoaded(); + + // Check that the first page of accounts is correct + await selectTrezorAccountPage.check_trezorAccountNumber(); + for (const { address } of KNOWN_PUBLIC_KEY_ADDRESSES.slice(0, 4)) { + const shortenedAddress = `${address.slice(0, 4)}...${address.slice( + -4, + )}`; + await selectTrezorAccountPage.check_addressIsDisplayed( + shortenedAddress, + ); + } + + // Unlock first account of first page and check that the correct account has been added + await selectTrezorAccountPage.unlockAccount(1); + await headerNavbar.check_pageIsLoaded(); + await new HomePage(driver).check_expectedBalanceIsDisplayed(); + await headerNavbar.openAccountMenu(); + await accountListPage.check_pageIsLoaded(); + await accountListPage.check_accountDisplayedInAccountList('Trezor 1'); + await accountListPage.check_accountAddressDisplayedInAccountList( + shortenAddress(KNOWN_PUBLIC_KEY_ADDRESSES[0].address), + ); + }, + ); + }); + + it('unlocks multiple accounts at once and removes one', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.openAccountMenu(); + + // Choose connect hardware wallet from the account menu + const accountListPage = new AccountListPage(driver); + await accountListPage.check_pageIsLoaded(); + await accountListPage.openConnectHardwareWalletModal(); + + const connectHardwareWalletPage = new ConnectHardwareWalletPage(driver); + await connectHardwareWalletPage.check_pageIsLoaded(); + await connectHardwareWalletPage.openConnectTrezorPage(); + + // Unlock 5 Trezor accounts + const selectTrezorAccountPage = new SelectTrezorAccountPage(driver); + await selectTrezorAccountPage.check_pageIsLoaded(); + await selectTrezorAccountPage.check_trezorAccountNumber(); + for (let i = 1; i <= 5; i++) { + await selectTrezorAccountPage.selectTrezorAccount(i); + } + await selectTrezorAccountPage.clickUnlockButton(); + + // Check that all 5 Trezor accounts are displayed in account list + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + await headerNavbar.openAccountMenu(); + await accountListPage.check_pageIsLoaded(); + for (let i = 0; i < 5; i++) { + await accountListPage.check_accountDisplayedInAccountList( + `Trezor ${i + 1}`, + ); + await accountListPage.check_accountAddressDisplayedInAccountList( + shortenAddress(KNOWN_PUBLIC_KEY_ADDRESSES[i].address), + ); + } + + // Remove Trezor 1 account and check Trezor 1 account is removed + await accountListPage.removeAccount('Trezor 1'); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedBalanceIsDisplayed(); + await headerNavbar.openAccountMenu(); + await accountListPage.check_accountIsNotDisplayedInAccountList( + 'Trezor 1', + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/hardware-wallets/trezor-send.spec.ts b/test/e2e/tests/hardware-wallets/trezor-send.spec.ts index b10269c69ef0..5bb6fcb45220 100644 --- a/test/e2e/tests/hardware-wallets/trezor-send.spec.ts +++ b/test/e2e/tests/hardware-wallets/trezor-send.spec.ts @@ -2,13 +2,11 @@ import { Suite } from 'mocha'; import { Driver } from '../../webdriver/driver'; import { Ganache } from '../../seeder/ganache'; import FixtureBuilder from '../../fixture-builder'; -import { - defaultGanacheOptions, - logInWithBalanceValidation, - sendTransaction, - withFixtures, -} from '../../helpers'; +import { logInWithBalanceValidation, withFixtures } from '../../helpers'; import { KNOWN_PUBLIC_KEY_ADDRESSES } from '../../../stub/keyring-bridge'; +import ActivityListPage from '../../page-objects/pages/home/activity-list'; +import HomePage from '../../page-objects/pages/home/homepage'; +import { sendRedesignedTransactionToAddress } from '../../page-objects/flows/send-transaction.flow'; const RECIPIENT = '0x0Cc5261AB8cE458dc977078A3623E2BaDD27afD3'; @@ -17,7 +15,6 @@ describe('Trezor Hardware', function (this: Suite) { await withFixtures( { fixtures: new FixtureBuilder().withTrezorAccount().build(), - ganacheOptions: defaultGanacheOptions, title: this.test?.fullTitle(), }, async ({ @@ -33,14 +30,16 @@ describe('Trezor Hardware', function (this: Suite) { '0x100000000000000000000', ); await logInWithBalanceValidation(driver); - - await sendTransaction(driver, RECIPIENT, '1'); - - // Wait for transaction to be confirmed - await driver.waitForSelector({ - css: '.transaction-status-label', - text: 'Confirmed', + await sendRedesignedTransactionToAddress({ + driver, + recipientAddress: RECIPIENT, + amount: '1', }); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + const activityList = new ActivityListPage(driver); + await activityList.check_confirmedTxNumberDisplayedInActivity(); + await activityList.check_txAmountInActivity(); }, ); }); diff --git a/test/e2e/tests/hardware-wallets/trezor-sign.spec.ts b/test/e2e/tests/hardware-wallets/trezor-sign.spec.ts index f4cbf87b9dd4..418758a4d426 100644 --- a/test/e2e/tests/hardware-wallets/trezor-sign.spec.ts +++ b/test/e2e/tests/hardware-wallets/trezor-sign.spec.ts @@ -1,15 +1,10 @@ -import { strict as assert } from 'assert'; import { Suite } from 'mocha'; import { Driver } from '../../webdriver/driver'; import FixtureBuilder from '../../fixture-builder'; -import { - defaultGanacheOptions, - openDapp, - unlockWallet, - WINDOW_TITLES, - withFixtures, -} from '../../helpers'; +import { defaultGanacheOptions, withFixtures } from '../../helpers'; import { KNOWN_PUBLIC_KEY_ADDRESSES } from '../../../stub/keyring-bridge'; +import TestDappPage from '../../page-objects/pages/test-dapp'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; describe('Trezor Hardware Signatures', function (this: Suite) { it('sign typed v4', async function () { @@ -26,28 +21,13 @@ describe('Trezor Hardware Signatures', function (this: Suite) { dapp: true, }, async ({ driver }: { driver: Driver }) => { - await unlockWallet(driver); - - await openDapp(driver); - await driver.clickElement('#signTypedDataV4'); - await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - await driver.delay(1000); - - await driver.clickElementSafe('.confirm-scroll-to-bottom__button'); - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.delay(1000); - - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - await driver.clickElement('#signTypedDataV4Verify'); - - const verifyRecoverAddress = await driver.findElement( - '#signTypedDataV4VerifyResult', - ); - - assert.equal( - await verifyRecoverAddress.getText(), - KNOWN_PUBLIC_KEY_ADDRESSES[0].address.toLocaleLowerCase(), + await loginWithBalanceValidation(driver); + const testDappPage = new TestDappPage(driver); + await testDappPage.openTestDappPage(); + await testDappPage.check_pageIsLoaded(); + await testDappPage.signTypedDataV4(true); + await testDappPage.check_successSignTypedDataV4( + KNOWN_PUBLIC_KEY_ADDRESSES[0].address, ); }, ); From 2e941a841a82f50bbc757e349e8e95f2f8ae86e5 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Thu, 12 Dec 2024 14:57:57 +0000 Subject: [PATCH 12/17] feat: Add new metric sending_value to Transaction * events (#29134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Adds a `useSendingValueMetric` hook that uses `updateTransactionEventFragment` to add the `sending_value` property on erc20 and native token transfers. The value is sent as an unformatted decimal javascript number. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29134?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3784 ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** Native token send: Screenshot 2024-12-12 at 11 40 43 ERC20 token send: Screenshot 2024-12-12 at 11 41 47 ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../info/hooks/use-token-values.test.ts | 2 + .../confirm/info/hooks/use-token-values.ts | 1 + .../info/hooks/useSendingValueMetric.test.ts | 104 ++++++++++++++++++ .../info/hooks/useSendingValueMetric.ts | 26 +++++ .../native-send-heading.tsx | 3 + .../info/shared/send-heading/send-heading.tsx | 4 + 6 files changed, 140 insertions(+) create mode 100644 ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.test.ts create mode 100644 ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.ts diff --git a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts index 4489690654d5..f7f9dd25d4b8 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts @@ -76,6 +76,7 @@ describe('useTokenValues', () => { decodedTransferValue: '7', displayTransferValue: '7', fiatDisplayValue: '$6.37', + fiatValue: 6.37, pending: false, }); }); @@ -122,6 +123,7 @@ describe('useTokenValues', () => { decodedTransferValue: '7', displayTransferValue: '7', fiatDisplayValue: null, + fiatValue: null, pending: false, }); }); diff --git a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts index 53987ffd06e6..b53e2842e5e7 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts @@ -89,6 +89,7 @@ export const useTokenValues = (transactionMeta: TransactionMeta) => { decodedTransferValue, displayTransferValue, fiatDisplayValue, + fiatValue, pending: pending || isDecodedTransferValuePending, }; }; diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.test.ts new file mode 100644 index 000000000000..c143dc2879cd --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.test.ts @@ -0,0 +1,104 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { renderHook } from '@testing-library/react-hooks'; +import { useEffect, useState } from 'react'; +import { genUnapprovedTokenTransferConfirmation } from '../../../../../../../test/data/confirmations/token-transfer'; +import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment'; +import { useSendingValueMetric } from './useSendingValueMetric'; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useEffect: jest.fn(), + useState: jest.fn(), +})); + +jest.mock('../../../../hooks/useTransactionEventFragment'); + +describe('useSimulationMetrics', () => { + const useTransactionEventFragmentMock = jest.mocked( + useTransactionEventFragment, + ); + + const useStateMock = jest.mocked(useState); + const useEffectMock = jest.mocked(useEffect); + + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let updateTransactionEventFragmentMock: jest.MockedFunction; + + beforeEach(() => { + jest.resetAllMocks(); + + updateTransactionEventFragmentMock = jest.fn(); + + useTransactionEventFragmentMock.mockReturnValue({ + updateTransactionEventFragment: updateTransactionEventFragmentMock, + }); + + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useStateMock.mockImplementation(((initialValue: any) => [ + initialValue, + jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ]) as any); + + useEffectMock.mockImplementation((fn) => fn()); + }); + + describe('useSendingValueMetric', () => { + it('Updates the event property', async () => { + const MOCK_FIAT_VALUE = 10; + const transactionMeta = genUnapprovedTokenTransferConfirmation( + {}, + ) as TransactionMeta; + const props = { transactionMeta, fiatValue: MOCK_FIAT_VALUE }; + + renderHook(() => useSendingValueMetric(props)); + + expect(updateTransactionEventFragmentMock).toHaveBeenCalledWith( + expect.objectContaining({ + properties: expect.objectContaining({ + sending_value: MOCK_FIAT_VALUE, + }), + }), + '1d7c08c0-fe54-11ee-9243-91b1e533746a', + ); + + jest.restoreAllMocks(); + }); + + it('Does not updates the event property if fiat value is undefined', async () => { + const MOCK_FIAT_VALUE = undefined; + const transactionMeta = genUnapprovedTokenTransferConfirmation( + {}, + ) as TransactionMeta; + const props = { transactionMeta, fiatValue: MOCK_FIAT_VALUE }; + + renderHook(() => useSendingValueMetric(props)); + + expect(updateTransactionEventFragmentMock).not.toHaveBeenCalled(); + + jest.restoreAllMocks(); + }); + + it('Does not updates the event property if fiat value is empty string', async () => { + const MOCK_FIAT_VALUE = '' as const; + const transactionMeta = genUnapprovedTokenTransferConfirmation( + {}, + ) as TransactionMeta; + const props = { transactionMeta, fiatValue: MOCK_FIAT_VALUE }; + + renderHook(() => useSendingValueMetric(props)); + + expect(updateTransactionEventFragmentMock).not.toHaveBeenCalled(); + + jest.restoreAllMocks(); + }); + }); +}); diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.ts b/ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.ts new file mode 100644 index 000000000000..06d7bff39c03 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/hooks/useSendingValueMetric.ts @@ -0,0 +1,26 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { useEffect } from 'react'; +import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment'; + +export type UseSendingValueMetricProps = { + transactionMeta: TransactionMeta; + fiatValue: number | undefined | ''; +}; + +export const useSendingValueMetric = ({ + transactionMeta, + fiatValue, +}: UseSendingValueMetricProps) => { + const { updateTransactionEventFragment } = useTransactionEventFragment(); + + const transactionId = transactionMeta.id; + const properties = { sending_value: fiatValue }; + const sensitiveProperties = {}; + const params = { properties, sensitiveProperties }; + + useEffect(() => { + if (fiatValue !== undefined && fiatValue !== '') { + updateTransactionEventFragment(params, transactionId); + } + }, [updateTransactionEventFragment, transactionId, JSON.stringify(params)]); +}; diff --git a/ui/pages/confirmations/components/confirm/info/shared/native-send-heading/native-send-heading.tsx b/ui/pages/confirmations/components/confirm/info/shared/native-send-heading/native-send-heading.tsx index f3f1f292fa2e..146eb6f169c7 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/native-send-heading/native-send-heading.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/native-send-heading/native-send-heading.tsx @@ -32,6 +32,7 @@ import { import { getMultichainNetwork } from '../../../../../../../selectors/multichain'; import { useConfirmContext } from '../../../../../context/confirm'; import { formatAmount } from '../../../../simulation-details/formatAmount'; +import { useSendingValueMetric } from '../../hooks/useSendingValueMetric'; const NativeSendHeading = () => { const { currentConfirmation: transactionMeta } = @@ -114,6 +115,8 @@ const NativeSendHeading = () => { ); + useSendingValueMetric({ transactionMeta, fiatValue }); + return ( { decodedTransferValue, displayTransferValue, fiatDisplayValue, + fiatValue, pending, } = useTokenValues(transactionMeta); @@ -85,6 +87,8 @@ const SendHeading = () => { ); + useSendingValueMetric({ transactionMeta, fiatValue }); + if (pending) { return ; } From b3c4759639468d889f2248504cb58ae4b449f1dc Mon Sep 17 00:00:00 2001 From: Derek Brans Date: Thu, 12 Dec 2024 10:16:09 -0500 Subject: [PATCH 13/17] chore: Add App Opened Metric Event (#28927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR adds tracking for when the MetaMask app is opened in order to track MAU/MTU. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/28927?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3401 ## **Manual testing steps** 1. Ensure MM is not "fullscreen" in any tabs 2. Open chrome dev tools for service worker 3. Clear the network tab 4. Open metamask (via Dapp or by clicking on extension) 5. There should be one or more new network request for POST https://api.segment.io/v1/batch – One of those should should have event: "App Opened" ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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: Niranjana Binoy <43930900+NiranjanaBinoy@users.noreply.github.com> --- app/scripts/background.js | 44 +++++++++ shared/constants/metametrics.ts | 1 + test/e2e/tests/metrics/app-opened.spec.ts | 104 ++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 test/e2e/tests/metrics/app-opened.spec.ts diff --git a/app/scripts/background.js b/app/scripts/background.js index e9aaf2cab20b..320efbd5c302 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -741,6 +741,49 @@ function trackDappView(remotePort) { } } +/** + * Emit App Opened event + */ +function emitAppOpenedMetricEvent() { + const { metaMetricsId, participateInMetaMetrics } = + controller.metaMetricsController.state; + + // Skip if user hasn't opted into metrics + if (metaMetricsId === null && !participateInMetaMetrics) { + return; + } + + controller.metaMetricsController.trackEvent({ + event: MetaMetricsEventName.AppOpened, + category: MetaMetricsEventCategory.App, + }); +} + +/** + * This function checks if the app is being opened + * and emits an event only if no other UI instances are currently open. + * + * @param {string} environment - The environment type where the app is opening + */ +function trackAppOpened(environment) { + // List of valid environment types to track + const environmentTypeList = [ + ENVIRONMENT_TYPE_POPUP, + ENVIRONMENT_TYPE_NOTIFICATION, + ENVIRONMENT_TYPE_FULLSCREEN, + ]; + + // Check if any UI instances are currently open + const isFullscreenOpen = Object.values(openMetamaskTabsIDs).some(Boolean); + const isAlreadyOpen = + isFullscreenOpen || notificationIsOpen || openPopupCount > 0; + + // Only emit event if no UI is open and environment is valid + if (!isAlreadyOpen && environmentTypeList.includes(environment)) { + emitAppOpenedMetricEvent(); + } +} + /** * Initializes the MetaMask Controller with any initial state and default language. * Configures platform-specific error reporting strategy. @@ -883,6 +926,7 @@ export function setupController( // communication with popup controller.isClientOpen = true; controller.setupTrustedCommunication(portStream, remotePort.sender); + trackAppOpened(processName); initializeRemoteFeatureFlags(); diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index d46bad603a83..700bead89320 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -640,6 +640,7 @@ export enum MetaMetricsEventName { ActivityDetailsClosed = 'Activity Details Closed', AnalyticsPreferenceSelected = 'Analytics Preference Selected', AppInstalled = 'App Installed', + AppOpened = 'App Opened', AppUnlocked = 'App Unlocked', AppUnlockedFailed = 'App Unlocked Failed', AppLocked = 'App Locked', diff --git a/test/e2e/tests/metrics/app-opened.spec.ts b/test/e2e/tests/metrics/app-opened.spec.ts new file mode 100644 index 000000000000..80169e36c369 --- /dev/null +++ b/test/e2e/tests/metrics/app-opened.spec.ts @@ -0,0 +1,104 @@ +import { strict as assert } from 'assert'; +import { Mockttp } from 'mockttp'; +import { + withFixtures, + getEventPayloads, + unlockWallet, + connectToDapp, +} from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import { loginWithoutBalanceValidation } from '../../page-objects/flows/login.flow'; + +/** + * Mocks the segment API for the App Opened event that we expect to see when + * these tests are run. + * + * @param mockServer - The mock server instance. + * @returns The mocked endpoints + */ +async function mockSegment(mockServer: Mockttp) { + return [ + await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'App Opened' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }), + ]; +} + +describe('App Opened metric @no-mmi', function () { + it('should send AppOpened metric when app is opened and metrics are enabled', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-fd20', + participateInMetaMetrics: true, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await loginWithoutBalanceValidation(driver); + + const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 1); + assert.equal(events[0].properties.category, 'App'); + }, + ); + }); + + it('should not send AppOpened metric when metrics are disabled', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-fd20', + participateInMetaMetrics: false, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 0); + }, + ); + }); + + it('should send AppOpened metric when dapp opens MetaMask', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-fd20', + participateInMetaMetrics: true, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // Connect to dapp which will trigger MetaMask to open + await connectToDapp(driver); + + // Wait for events to be tracked + const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 1); + assert.equal(events[0].properties.category, 'App'); + }, + ); + }); +}); From b7aab59d69fe46208be153f2a605f5fdde74349a Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Thu, 12 Dec 2024 15:44:41 +0000 Subject: [PATCH 14/17] feat: Remove scroll to the bottom requirement for all personal sign requests (#29053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Users can now Confirm personal sign requests without scrolling to the bottom of the confirmation. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29053?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3760 ## **Manual testing steps** 1. Go to OpenSea 2. Login 3. See their personal sign request and how the Confirm button is disabled ## **Screenshots/Recordings** ### **Before** ### **After** Screenshot 2024-12-10 at 14 16 32 ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../components/confirm/footer/footer.test.tsx | 25 ++++++++----------- .../components/confirm/footer/footer.tsx | 12 +++++++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/footer/footer.test.tsx b/ui/pages/confirmations/components/confirm/footer/footer.test.tsx index 09d1fdf5753b..bd026848bd95 100644 --- a/ui/pages/confirmations/components/confirm/footer/footer.test.tsx +++ b/ui/pages/confirmations/components/confirm/footer/footer.test.tsx @@ -1,15 +1,10 @@ import React from 'react'; - import { LedgerTransportTypes, WebHIDConnectedStatuses, } from '../../../../../../shared/constants/hardware-wallets'; import { BlockaidResultType } from '../../../../../../shared/constants/security-provider'; -import { - signatureRequestSIWE, - unapprovedPersonalSignMsg, -} from '../../../../../../test/data/confirmations/personal_sign'; -import { permitSignatureMsg } from '../../../../../../test/data/confirmations/typed_sign'; +import { genUnapprovedContractInteractionConfirmation } from '../../../../../../test/data/confirmations/contract-interaction'; import { getMockContractInteractionConfirmState, getMockPersonalSignConfirmState, @@ -17,17 +12,21 @@ import { getMockTypedSignConfirmState, getMockTypedSignConfirmStateForRequest, } from '../../../../../../test/data/confirmations/helper'; +import { + signatureRequestSIWE, + unapprovedPersonalSignMsg, +} from '../../../../../../test/data/confirmations/personal_sign'; +import { permitSignatureMsg } from '../../../../../../test/data/confirmations/typed_sign'; import mockState from '../../../../../../test/data/mock-state.json'; import { fireEvent } from '../../../../../../test/jest'; import { renderWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers'; +import { Alert } from '../../../../../ducks/confirm-alerts/confirm-alerts'; +import { Severity } from '../../../../../helpers/constants/design-system'; import * as MMIConfirmations from '../../../../../hooks/useMMIConfirmations'; import * as Actions from '../../../../../store/actions'; import configureStore from '../../../../../store/store'; -import { Severity } from '../../../../../helpers/constants/design-system'; -import { SignatureRequestType } from '../../../types/confirm'; import * as confirmContext from '../../../context/confirm'; - -import { Alert } from '../../../../../ducks/confirm-alerts/confirm-alerts'; +import { SignatureRequestType } from '../../../types/confirm'; import Footer from './footer'; jest.mock('react-redux', () => ({ @@ -107,13 +106,11 @@ describe('ConfirmFooter', () => { describe('renders disabled "Confirm" Button', () => { it('when isScrollToBottomCompleted is false', () => { jest.spyOn(confirmContext, 'useConfirmContext').mockReturnValue({ - currentConfirmation: unapprovedPersonalSignMsg, + currentConfirmation: genUnapprovedContractInteractionConfirmation(), isScrollToBottomCompleted: false, setIsScrollToBottomCompleted: () => undefined, }); - const mockStateTypedSign = getMockPersonalSignConfirmStateForRequest( - unapprovedPersonalSignMsg, - ); + const mockStateTypedSign = getMockContractInteractionConfirmState(); const { getByText } = render(mockStateTypedSign); const confirmButton = getByText('Confirm'); diff --git a/ui/pages/confirmations/components/confirm/footer/footer.tsx b/ui/pages/confirmations/components/confirm/footer/footer.tsx index a9aea54c03f7..82b10a9511a8 100644 --- a/ui/pages/confirmations/components/confirm/footer/footer.tsx +++ b/ui/pages/confirmations/components/confirm/footer/footer.tsx @@ -1,4 +1,7 @@ -import { TransactionMeta } from '@metamask/transaction-controller'; +import { + TransactionMeta, + TransactionType, +} from '@metamask/transaction-controller'; import { providerErrors, serializeError } from '@metamask/rpc-errors'; import React, { useCallback, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -187,9 +190,14 @@ const Footer = () => { const isSIWE = isSIWESignatureRequest(currentConfirmation); const isPermit = isPermitSignatureRequest(currentConfirmation); const isPermitSimulationShown = isPermit && useTransactionSimulations; + const isPersonalSign = + currentConfirmation?.type === TransactionType.personalSign; const isConfirmDisabled = - (!isScrollToBottomCompleted && !isSIWE && !isPermitSimulationShown) || + (!isScrollToBottomCompleted && + !isSIWE && + !isPermitSimulationShown && + !isPersonalSign) || ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) mmiSubmitDisabled || ///: END:ONLY_INCLUDE_IF From fffb8c67d344acbb100dd6a6c36d88881cf53a66 Mon Sep 17 00:00:00 2001 From: infiniteflower <139582705+infiniteflower@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:02:50 -0500 Subject: [PATCH 15/17] feat: update bridge tx details (#29075) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29075?quickstart=1) This PR update the Bridge tx details screen with: 1. Source/destination chain always visible 2. You sent/received 3. Activity log ## **Related issues** Fixes: ## **Manual testing steps** 1. Do a bridge tx 4. Click on the bridge tx in the activity list 5. Observe changes ## **Screenshots/Recordings** ### **Before** ### **After** ![Screenshot 2024-12-11 at 1 32 49 PM](https://github.com/user-attachments/assets/36879afa-e2ec-4d21-97a9-015d82dd8229) ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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/en/messages.json | 40 +-- .../transaction-list-item.component.js | 1 + ui/hooks/bridge/useBridgeTxHistoryData.ts | 7 +- .../transaction-details.tsx | 268 ++++++++++-------- ui/pages/bridge/types.ts | 7 +- 5 files changed, 174 insertions(+), 149 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 34afdaab62ed..466615b0343a 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -861,9 +861,6 @@ "bridgeCalculatingAmount": { "message": "Calculating..." }, - "bridgeDestination": { - "message": "Destination" - }, "bridgeDontSend": { "message": "Bridge, don't send" }, @@ -888,9 +885,6 @@ "bridgeSelectTokenAndAmount": { "message": "Select token and amount" }, - "bridgeSource": { - "message": "Source" - }, "bridgeStepActionBridgeComplete": { "message": "$1 received on $2", "description": "$1 is the amount of the destination asset, $2 is the name of the destination network" @@ -923,14 +917,8 @@ "bridgeTotalFeesTooltipText": { "message": "This includes gas fees (paid to crypto miners) and relayer fees (paid to power complex services like bridging).\nFees are based on network traffic and transaction complexity. MetaMask does not profit from either fee." }, - "bridgeTxDetailsBaseFee": { - "message": "Base fee (GWEI)" - }, - "bridgeTxDetailsBridgeAmount": { - "message": "Bridge amount" - }, - "bridgeTxDetailsBridgeType": { - "message": "Bridge type" + "bridgeTxDetailsBridging": { + "message": "Bridging" }, "bridgeTxDetailsDelayedDescription": { "message": "Reach out to" @@ -941,21 +929,9 @@ "bridgeTxDetailsDelayedTitle": { "message": "Has it been longer than 3 hours?" }, - "bridgeTxDetailsGasLimit": { - "message": "Gas limit (units)" - }, - "bridgeTxDetailsGasUsed": { - "message": "Gas used (units)" - }, - "bridgeTxDetailsMaxFeePerGas": { - "message": "Max fee per gas" - }, "bridgeTxDetailsNonce": { "message": "Nonce" }, - "bridgeTxDetailsPriorityFee": { - "message": "Priority fee (GWEI)" - }, "bridgeTxDetailsStatus": { "message": "Status" }, @@ -966,14 +942,18 @@ "message": "$1 at $2", "description": "$1 is the date, $2 is the time" }, - "bridgeTxDetailsTotal": { - "message": "Total" + "bridgeTxDetailsTokenAmountOnChain": { + "message": "$1 $2 on", + "description": "$1 is the amount of the token, $2 is the ticker symbol of the token" }, "bridgeTxDetailsTotalGasFee": { "message": "Total gas fee" }, - "bridgeTypeDirectionTo": { - "message": "To" + "bridgeTxDetailsYouReceived": { + "message": "You received" + }, + "bridgeTxDetailsYouSent": { + "message": "You sent" }, "browserNotSupported": { "message": "Your browser is not supported..." 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 fed0f925a3ac..09e8983b9196 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 @@ -99,6 +99,7 @@ function TransactionListItemInner({ const { bridgeTxHistoryItem, isBridgeComplete, showBridgeTxDetails } = useBridgeTxHistoryData({ transactionGroup, + isEarliestNonce, }); const { diff --git a/ui/hooks/bridge/useBridgeTxHistoryData.ts b/ui/hooks/bridge/useBridgeTxHistoryData.ts index dc6db53896ae..0334f822cc16 100644 --- a/ui/hooks/bridge/useBridgeTxHistoryData.ts +++ b/ui/hooks/bridge/useBridgeTxHistoryData.ts @@ -25,10 +25,12 @@ export type TransactionGroup = { export type UseBridgeTxHistoryDataProps = { transactionGroup: TransactionGroup; + isEarliestNonce: boolean; }; export function useBridgeTxHistoryData({ transactionGroup, + isEarliestNonce, }: UseBridgeTxHistoryDataProps) { const history = useHistory(); const bridgeHistory = useSelector(selectBridgeHistoryForAccount); @@ -49,7 +51,10 @@ export function useBridgeTxHistoryData({ ) ? undefined : () => { - history.push(`${CROSS_CHAIN_SWAP_TX_DETAILS_ROUTE}/${srcTxMetaId}`); + history.push({ + pathname: `${CROSS_CHAIN_SWAP_TX_DETAILS_ROUTE}/${srcTxMetaId}`, + state: { transactionGroup, isEarliestNonce }, + }); }; return { diff --git a/ui/pages/bridge/transaction-details/transaction-details.tsx b/ui/pages/bridge/transaction-details/transaction-details.tsx index fe81e8e3b3dd..762e2c1218d9 100644 --- a/ui/pages/bridge/transaction-details/transaction-details.tsx +++ b/ui/pages/bridge/transaction-details/transaction-details.tsx @@ -1,8 +1,9 @@ import React, { useContext } from 'react'; import { useSelector } from 'react-redux'; -import { useHistory, useParams } from 'react-router-dom'; +import { useHistory, useParams, useLocation } from 'react-router-dom'; import { NetworkConfiguration } from '@metamask/network-controller'; import { TransactionMeta } from '@metamask/transaction-controller'; +import { BigNumber } from 'bignumber.js'; import { AvatarNetwork, AvatarNetworkSize, @@ -12,7 +13,9 @@ import { ButtonIcon, ButtonIconSize, ButtonLink, + Icon, IconName, + IconSize, Text, } from '../../../components/component-library'; import { Content, Header } from '../../../components/multichain/pages/page'; @@ -28,7 +31,6 @@ import { PRIMARY, SUPPORT_REQUEST_LINK, } from '../../../helpers/constants/common'; -import CurrencyDisplay from '../../../components/ui/currency-display/currency-display.component'; import { BridgeHistoryItem, StatusTypes, @@ -51,6 +53,10 @@ import { MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics'; +import { formatAmount } from '../../confirmations/components/simulation-details/formatAmount'; +import { getIntlLocale } from '../../../ducks/locale/locale'; +import { TransactionGroup } from '../../../hooks/bridge/useBridgeTxHistoryData'; +import TransactionActivityLog from '../../../components/app/transaction-activity-log'; import TransactionDetailRow from './transaction-detail-row'; import BridgeExplorerLinks from './bridge-explorer-links'; import BridgeStepList from './bridge-step-list'; @@ -77,18 +83,47 @@ const getBlockExplorerUrl = ( /** * @param options0 * @param options0.bridgeHistoryItem + * @param options0.locale * @returns A string representing the bridge amount in decimal form */ -const getBridgeAmount = ({ +const getBridgeAmountSentFormatted = ({ + locale, bridgeHistoryItem, }: { + locale: string; bridgeHistoryItem?: BridgeHistoryItem; }) => { - if (bridgeHistoryItem) { - return bridgeHistoryItem.pricingData?.amountSent; + if (!bridgeHistoryItem?.pricingData?.amountSent) { + return undefined; + } + + return formatAmount( + locale, + new BigNumber(bridgeHistoryItem.pricingData.amountSent), + ); +}; + +const getBridgeAmountReceivedFormatted = ({ + locale, + bridgeHistoryItem, +}: { + locale: string; + bridgeHistoryItem?: BridgeHistoryItem; +}) => { + if (!bridgeHistoryItem) { + return undefined; } - return undefined; + const destAmount = bridgeHistoryItem.status.destChain?.amount; + if (!destAmount) { + return undefined; + } + + const destAssetDecimals = bridgeHistoryItem.quote.destAsset.decimals; + return formatAmount( + locale, + new BigNumber(destAmount).dividedBy(10 ** destAssetDecimals), + ); }; /** @@ -118,9 +153,11 @@ const StatusToColorMap: Record = { const CrossChainSwapTxDetails = () => { const t = useI18nContext(); + const locale = useSelector(getIntlLocale); const trackEvent = useContext(MetaMetricsContext); const rootState = useSelector((state) => state); const history = useHistory(); + const location = useLocation(); const { srcTxMetaId } = useParams<{ srcTxMetaId: string }>(); const bridgeHistory = useSelector(selectBridgeHistoryForAccount); const selectedAddressTxList = useSelector( @@ -131,6 +168,10 @@ const CrossChainSwapTxDetails = () => { getNetworkConfigurationsByChainId, ); + const { transactionGroup, isEarliestNonce } = location.state as { + transactionGroup: TransactionGroup; + isEarliestNonce: boolean; + }; const srcChainTxMeta = selectedAddressTxList.find( (tx) => tx.id === srcTxMetaId, ); @@ -154,12 +195,18 @@ const CrossChainSwapTxDetails = () => { ? bridgeHistoryItem?.status.status : StatusTypes.PENDING; + const srcChainIconUrl = srcNetwork + ? CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP[ + srcNetwork.chainId as keyof typeof CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP + ] + : undefined; + const destChainIconUrl = destNetwork ? CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP[ destNetwork.chainId as keyof typeof CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP ] : undefined; - const bridgeTypeDirection = t('bridgeTypeDirectionTo'); + const srcNetworkName = srcNetwork?.name; const destNetworkName = destNetwork?.name; @@ -171,9 +218,41 @@ const CrossChainSwapTxDetails = () => { }) : undefined; - const bridgeAmount = getBridgeAmount({ bridgeHistoryItem }); + const bridgeAmountSent = getBridgeAmountSentFormatted({ + locale, + bridgeHistoryItem, + }); + const bridgeAmountReceived = getBridgeAmountReceivedFormatted({ + locale, + bridgeHistoryItem, + }); const isDelayed = getIsDelayed(status, bridgeHistoryItem); + const srcNetworkIconName = ( + + {srcNetwork && ( + + )} + {srcNetworkName} + + ); + const destNetworkIconName = ( + + {destNetwork && ( + + )} + {destNetworkName} + + ); + return (
@@ -196,6 +275,7 @@ const CrossChainSwapTxDetails = () => { flexDirection={FlexDirection.Column} gap={4} > + {/* Delayed banner */} {isDelayed && ( { )} + {/* Bridge step list */} {status !== StatusTypes.COMPLETE && (bridgeHistoryItem || srcChainTxMeta) && ( { srcBlockExplorerUrl={srcBlockExplorerUrl} destBlockExplorerUrl={destBlockExplorerUrl} /> + - {/* General tx details */} + {/* Bridge tx details */} { } /> - - {status !== StatusTypes.COMPLETE && ( - - {bridgeTypeDirection}{' '} - {destNetwork && ( - - )} - {destNetworkName} - - } - /> - )} - {status === StatusTypes.COMPLETE && ( - <> - - - - )} + + {srcNetworkIconName} + + {destNetworkIconName} + + } + /> { formatDate(srcChainTxMeta?.time, 'hh:mm a'), ])} /> - + {/* Bridge tx details 2 */} - + {t('bridgeTxDetailsTokenAmountOnChain', [ + bridgeAmountSent, + bridgeHistoryItem?.quote.srcAsset.symbol, + ])} + {srcNetworkIconName} + + } /> + {t('bridgeTxDetailsTokenAmountOnChain', [ + bridgeAmountReceived, + bridgeHistoryItem?.quote.destAsset.symbol, + ])} + {destNetworkIconName} + + } /> - {data?.isEIP1559Transaction && - typeof data?.baseFee !== 'undefined' && ( - - } - /> - )} - {data?.isEIP1559Transaction && - typeof data?.priorityFee !== 'undefined' && ( - - } - /> - )} - { /> } /> - - } - /> - - } - /> + {/* Generic tx details */} + + - + +
diff --git a/ui/pages/bridge/types.ts b/ui/pages/bridge/types.ts index db6d7e8e1394..e753207f1631 100644 --- a/ui/pages/bridge/types.ts +++ b/ui/pages/bridge/types.ts @@ -94,12 +94,11 @@ export type Quote = { requestId: string; srcChainId: ChainId; srcAsset: BridgeAsset; - // This is amount sent - metabridge fee, however, some tokens have a fee of 0 - // So sometimes it's equal to amount sent - srcTokenAmount: string; + // Some tokens have a fee of 0, so sometimes it's equal to amount sent + srcTokenAmount: string; // Atomic amount, the amount sent - fees destChainId: ChainId; destAsset: BridgeAsset; - destTokenAmount: string; + destTokenAmount: string; // Atomic amount, the amount received feeData: Record & Partial>; bridgeId: string; From 4b48ee62e4bd62fcb2981c230f2c2ed383d2ec62 Mon Sep 17 00:00:00 2001 From: Nick Gambino <35090461+gambinish@users.noreply.github.com> Date: Thu, 12 Dec 2024 08:07:35 -0800 Subject: [PATCH 16/17] fix: Use correct selector to pull name from non-popular networks (#29121) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** On token-list-item, we were using the wrong selector to select the network configuration, which included the network name needed for the fallback icon of non-popular networks. `getNetworkConfigurationsByChainId` returns chainId => networkConfiguration mapping, while `getNetworkConfigurationIdByChainId` returns a chainId => string mapping, which could be a networkId (random UUID string) This broke the fallback behavior, as we would render the first letter of the uuid, rather than the first letter of the network name. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29121?quickstart=1) ## **Related issues** Fixes: Incorrect network logo fallback letter ## **Manual testing steps** 1. Add Base Sepolia as custom network: https://chainlist.org/chain/84532 2. Verify that the fallback image on main token-list and token-detail page is `B` and matches the network picker. ## **Screenshots/Recordings** Before Screenshot 2024-12-11 at 5 29 02 PM After Screenshot 2024-12-11 at 5 28 21 PM ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../assets/asset-list/network-filter/network-filter.tsx | 2 +- .../multichain/token-list-item/token-list-item.tsx | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ui/components/app/assets/asset-list/network-filter/network-filter.tsx b/ui/components/app/assets/asset-list/network-filter/network-filter.tsx index d08d01f933ee..a63aef334d11 100644 --- a/ui/components/app/assets/asset-list/network-filter/network-filter.tsx +++ b/ui/components/app/assets/asset-list/network-filter/network-filter.tsx @@ -203,7 +203,7 @@ const NetworkFilter = ({ handleClose }: SortControlProps) => { diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index 76152770dbc9..40b91a001f17 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -44,7 +44,6 @@ import { getParticipateInMetaMetrics, getDataCollectionForMarketing, getMarketData, - getNetworkConfigurationIdByChainId, getCurrencyRates, } from '../../../selectors'; import { getMultichainIsEvm } from '../../../selectors/multichain'; @@ -69,6 +68,7 @@ import { useSafeChains, } from '../../../pages/settings/networks-tab/networks-form/use-safe-chains'; import { NETWORK_TO_SHORT_NETWORK_NAME_MAP } from '../../../../shared/constants/bridge'; +import { getNetworkConfigurationsByChainId } from '../../../../shared/modules/selectors/networks'; import { PercentageChange } from './price/percentage-change/percentage-change'; type TokenListItemProps = { @@ -227,9 +227,7 @@ export const TokenListItem = ({ ); // Used for badge icon - const allNetworks: Record = useSelector( - getNetworkConfigurationIdByChainId, - ); + const allNetworks = useSelector(getNetworkConfigurationsByChainId); const testNetworkBackgroundColor = useSelector(getTestNetworkBackgroundColor); return ( @@ -285,7 +283,7 @@ export const TokenListItem = ({ badge={ Date: Thu, 12 Dec 2024 11:34:19 -0500 Subject: [PATCH 17/17] chore: delay linea bridge tx to make it less flaky (#29109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29109?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** 1. Set network to Linea 2. Bridge an ERC20 to another network 3. Observe loading spinner on quotes page 4. Get redirected to activity list 5. See successful ERC20 approval and bridge tx ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/e6079f43-632e-4bd3-a9e0-54f7c427b541 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] 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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. --- .../hooks/useSubmitBridgeTransaction.ts | 25 ++++++++++++++ ui/pages/bridge/prepare/bridge-cta-button.tsx | 34 ++++++++++++------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/ui/pages/bridge/hooks/useSubmitBridgeTransaction.ts b/ui/pages/bridge/hooks/useSubmitBridgeTransaction.ts index 39e905631e82..847df1204ab3 100644 --- a/ui/pages/bridge/hooks/useSubmitBridgeTransaction.ts +++ b/ui/pages/bridge/hooks/useSubmitBridgeTransaction.ts @@ -2,18 +2,25 @@ import { useDispatch, useSelector } from 'react-redux'; import { zeroAddress } from 'ethereumjs-util'; import { useHistory } from 'react-router-dom'; import { TransactionMeta } from '@metamask/transaction-controller'; +import { createProjectLogger, Hex } from '@metamask/utils'; import { QuoteMetadata, QuoteResponse } from '../types'; import { DEFAULT_ROUTE } from '../../../helpers/constants/routes'; import { setDefaultHomeActiveTabName } from '../../../store/actions'; import { startPollingForBridgeTxStatus } from '../../../ducks/bridge-status/actions'; import { getQuoteRequest } from '../../../ducks/bridge/selectors'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; +import { getCurrentChainId } from '../../../../shared/modules/selectors/networks'; import useAddToken from './useAddToken'; import useHandleApprovalTx from './useHandleApprovalTx'; import useHandleBridgeTx from './useHandleBridgeTx'; +const debugLog = createProjectLogger('bridge'); +const LINEA_DELAY_MS = 5000; + export default function useSubmitBridgeTransaction() { const history = useHistory(); const dispatch = useDispatch(); + const srcChainId = useSelector(getCurrentChainId); const { addSourceToken, addDestToken } = useAddToken(); const { handleApprovalTx } = useHandleApprovalTx(); const { handleBridgeTx } = useHandleBridgeTx(); @@ -33,6 +40,24 @@ export default function useSubmitBridgeTransaction() { }); } + if ( + ( + [ + CHAIN_IDS.LINEA_MAINNET, + CHAIN_IDS.LINEA_GOERLI, + CHAIN_IDS.LINEA_SEPOLIA, + ] as Hex[] + ).includes(srcChainId) + ) { + debugLog( + 'Delaying submitting bridge tx to make Linea confirmation more likely', + ); + const waitPromise = new Promise((resolve) => + setTimeout(resolve, LINEA_DELAY_MS), + ); + await waitPromise; + } + const bridgeTxMeta = await handleBridgeTx({ quoteResponse, approvalTxId: approvalTxMeta?.id, diff --git a/ui/pages/bridge/prepare/bridge-cta-button.tsx b/ui/pages/bridge/prepare/bridge-cta-button.tsx index c8738a6551de..931b6cb4e8ea 100644 --- a/ui/pages/bridge/prepare/bridge-cta-button.tsx +++ b/ui/pages/bridge/prepare/bridge-cta-button.tsx @@ -35,6 +35,7 @@ export const BridgeCTAButton = () => { const { maxRefreshCount, refreshRate } = useSelector(getBridgeQuotesConfig); const { submitBridgeTransaction } = useSubmitBridgeTransaction(); + const [isSubmitting, setIsSubmitting] = useState(false); const { isNoQuotesAvailable, isInsufficientBalance } = useSelector(getValidationErrors); @@ -108,20 +109,29 @@ export const BridgeCTAButton = () => { data-testid="bridge-cta-button" onClick={() => { if (activeQuote && isTxSubmittable) { - quoteRequestProperties && - requestMetadataProperties && - tradeProperties && - trackCrossChainSwapsEvent({ - event: MetaMetricsEventName.ActionSubmitted, - properties: { - ...quoteRequestProperties, - ...requestMetadataProperties, - ...tradeProperties, - }, - }); - submitBridgeTransaction(activeQuote); + try { + // We don't need to worry about setting to true if the tx submission succeeds + // because we route immediately to Activity list page + setIsSubmitting(true); + + quoteRequestProperties && + requestMetadataProperties && + tradeProperties && + trackCrossChainSwapsEvent({ + event: MetaMetricsEventName.ActionSubmitted, + properties: { + ...quoteRequestProperties, + ...requestMetadataProperties, + ...tradeProperties, + }, + }); + submitBridgeTransaction(activeQuote); + } catch (error) { + setIsSubmitting(false); + } } }} + loading={isSubmitting} disabled={!isTxSubmittable || isQuoteExpired} > {label}