diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 12df50e257d7..1ff278090f61 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -883,6 +883,9 @@ "bridgeExplorerLinkViewOn": { "message": "View on $1" }, + "bridgeFetchNewQuotes": { + "message": "Fetch a new one?" + }, "bridgeFrom": { "message": "Bridge from" }, @@ -897,7 +900,7 @@ "message": "Net cost" }, "bridgeQuoteExpired": { - "message": "Quotes expired - please request again" + "message": "Your quote timed out." }, "bridgeSelectNetwork": { "message": "Select network" diff --git a/app/scripts/controllers/permissions/background-api.js b/app/scripts/controllers/permissions/background-api.js index b778ff42385d..8a0942667f17 100644 --- a/app/scripts/controllers/permissions/background-api.js +++ b/app/scripts/controllers/permissions/background-api.js @@ -1,4 +1,4 @@ -import nanoid from 'nanoid'; +import { nanoid } from 'nanoid'; import { CaveatTypes, RestrictedMethods, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index e3a223da4e02..8ab78f2c7e92 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -47,7 +47,7 @@ import { rawChainData } from 'eth-chainlist'; import { MetaMaskKeyring as QRHardwareKeyring } from '@keystonehq/metamask-airgapped-keyring'; import EthQuery from '@metamask/eth-query'; import EthJSQuery from '@metamask/ethjs-query'; -import nanoid from 'nanoid'; +import { nanoid } from 'nanoid'; import { captureException } from '@sentry/browser'; import { AddressBookController } from '@metamask/address-book-controller'; import { diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index ab0210c4f2c8..542d38004de3 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -637,9 +637,9 @@ "console.info": true }, "packages": { - "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, - "@metamask/rpc-errors": true + "@metamask/rpc-errors": true, + "nanoid": true } }, "@metamask/approval-controller>nanoid": { @@ -1970,11 +1970,11 @@ "@metamask/base-controller": true, "@metamask/controller-utils": true, "@metamask/json-rpc-engine": true, - "@metamask/permission-controller>nanoid": true, "@metamask/rpc-errors": true, "@metamask/utils": true, "deep-freeze-strict": true, - "immer": true + "immer": true, + "nanoid": true } }, "@metamask/permission-controller>nanoid": { @@ -2434,7 +2434,6 @@ "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, - "@metamask/snaps-controllers>nanoid": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2445,6 +2444,7 @@ "browserify>browserify-zlib": true, "eslint>fast-deep-equal": true, "immer": true, + "nanoid": true, "readable-stream": true, "semver": true } @@ -4502,9 +4502,7 @@ }, "nanoid": { "globals": { - "crypto": true, - "msCrypto": true, - "navigator": true + "crypto.getRandomValues": true } }, "nock>debug": { diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index ab0210c4f2c8..542d38004de3 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -637,9 +637,9 @@ "console.info": true }, "packages": { - "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, - "@metamask/rpc-errors": true + "@metamask/rpc-errors": true, + "nanoid": true } }, "@metamask/approval-controller>nanoid": { @@ -1970,11 +1970,11 @@ "@metamask/base-controller": true, "@metamask/controller-utils": true, "@metamask/json-rpc-engine": true, - "@metamask/permission-controller>nanoid": true, "@metamask/rpc-errors": true, "@metamask/utils": true, "deep-freeze-strict": true, - "immer": true + "immer": true, + "nanoid": true } }, "@metamask/permission-controller>nanoid": { @@ -2434,7 +2434,6 @@ "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, - "@metamask/snaps-controllers>nanoid": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2445,6 +2444,7 @@ "browserify>browserify-zlib": true, "eslint>fast-deep-equal": true, "immer": true, + "nanoid": true, "readable-stream": true, "semver": true } @@ -4502,9 +4502,7 @@ }, "nanoid": { "globals": { - "crypto": true, - "msCrypto": true, - "navigator": true + "crypto.getRandomValues": true } }, "nock>debug": { diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index ab0210c4f2c8..542d38004de3 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -637,9 +637,9 @@ "console.info": true }, "packages": { - "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, - "@metamask/rpc-errors": true + "@metamask/rpc-errors": true, + "nanoid": true } }, "@metamask/approval-controller>nanoid": { @@ -1970,11 +1970,11 @@ "@metamask/base-controller": true, "@metamask/controller-utils": true, "@metamask/json-rpc-engine": true, - "@metamask/permission-controller>nanoid": true, "@metamask/rpc-errors": true, "@metamask/utils": true, "deep-freeze-strict": true, - "immer": true + "immer": true, + "nanoid": true } }, "@metamask/permission-controller>nanoid": { @@ -2434,7 +2434,6 @@ "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, - "@metamask/snaps-controllers>nanoid": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2445,6 +2444,7 @@ "browserify>browserify-zlib": true, "eslint>fast-deep-equal": true, "immer": true, + "nanoid": true, "readable-stream": true, "semver": true } @@ -4502,9 +4502,7 @@ }, "nanoid": { "globals": { - "crypto": true, - "msCrypto": true, - "navigator": true + "crypto.getRandomValues": true } }, "nock>debug": { diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 334efa0681d7..8c76cb6df139 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -729,9 +729,9 @@ "console.info": true }, "packages": { - "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, - "@metamask/rpc-errors": true + "@metamask/rpc-errors": true, + "nanoid": true } }, "@metamask/approval-controller>nanoid": { @@ -2062,11 +2062,11 @@ "@metamask/base-controller": true, "@metamask/controller-utils": true, "@metamask/json-rpc-engine": true, - "@metamask/permission-controller>nanoid": true, "@metamask/rpc-errors": true, "@metamask/utils": true, "deep-freeze-strict": true, - "immer": true + "immer": true, + "nanoid": true } }, "@metamask/permission-controller>nanoid": { @@ -2526,7 +2526,6 @@ "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, - "@metamask/snaps-controllers>nanoid": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2537,6 +2536,7 @@ "browserify>browserify-zlib": true, "eslint>fast-deep-equal": true, "immer": true, + "nanoid": true, "readable-stream": true, "semver": true } @@ -4594,9 +4594,7 @@ }, "nanoid": { "globals": { - "crypto": true, - "msCrypto": true, - "navigator": true + "crypto.getRandomValues": true } }, "nock>debug": { diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 9874c5915d8e..59a807e7313f 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -6510,7 +6510,7 @@ "process.env.NODE_ENV": true }, "packages": { - "postcss>nanoid": true, + "nanoid": true, "postcss>picocolors": true, "postcss>source-map-js": true } diff --git a/package.json b/package.json index 45d0950abf8b..0cc3222a7d1d 100644 --- a/package.json +++ b/package.json @@ -400,7 +400,7 @@ "loglevel": "^1.8.1", "lottie-web": "^5.12.2", "luxon": "^3.2.1", - "nanoid": "^2.1.6", + "nanoid": "^3.3.8", "pify": "^5.0.0", "promise-to-callback": "^1.0.0", "prop-types": "^15.6.1", diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index bbf25013f607..981955eb19cd 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -547,6 +547,19 @@ class AccountListPage { }); } + /** + * Verifies that all occurrences of the account balance value and symbol are displayed as private. + * + */ + async check_balanceIsPrivateEverywhere(): Promise { + console.log(`Verify all account balance occurrences are private`); + const balanceSelectors = { + tag: 'span', + text: '••••••', + }; + await this.driver.elementCountBecomesN(balanceSelectors, 6); + } + async check_currentAccountIsImported(): Promise { console.log(`Check that current account is an imported account`); await this.driver.waitForSelector({ diff --git a/test/e2e/page-objects/pages/header-navbar.ts b/test/e2e/page-objects/pages/header-navbar.ts index 5c0808eea93a..65d4cbd48358 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -80,13 +80,6 @@ class HeaderNavbar { await this.driver.clickElement(this.switchNetworkDropDown); } - async check_currentSelectedNetwork(networkName: string): Promise { - console.log(`Validate the Switch network to ${networkName}`); - await this.driver.waitForSelector( - `button[data-testid="network-display"][aria-label="Network Menu ${networkName}"]`, - ); - } - /** * Verifies that the displayed account label in header matches the expected label. * @@ -101,6 +94,18 @@ class HeaderNavbar { text: expectedLabel, }); } + + /** + * Validates that the currently selected network matches the expected network name. + * + * @param networkName - The expected name of the currently selected network. + */ + async check_currentSelectedNetwork(networkName: string): Promise { + console.log(`Validate the Switch network to ${networkName}`); + await this.driver.waitForSelector( + `button[data-testid="network-display"][aria-label="Network Menu ${networkName}"]`, + ); + } } export default HeaderNavbar; diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index 8240e51f736c..6b3f7c9f2a87 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -8,8 +8,9 @@ class HomePage { public headerNavbar: HeaderNavbar; - private readonly activityTab = - '[data-testid="account-overview__activity-tab"]'; + private readonly activityTab = { + testId: 'account-overview__activity-tab', + }; private readonly balance = '[data-testid="eth-overview__primary-currency"]'; @@ -23,19 +24,35 @@ class HomePage { tag: 'h6', }; - private readonly erc20TokenDropdown = '[data-testid="import-token-button"]'; + private readonly erc20TokenDropdown = { + testId: 'import-token-button', + }; - private readonly nftTab = '[data-testid="account-overview__nfts-tab"]'; + private readonly nftTab = { + testId: 'account-overview__nfts-tab', + }; private readonly popoverBackground = '.popover-bg'; - private readonly popoverCloseButton = '[data-testid="popover-close"]'; + private readonly popoverCloseButton = { + testId: 'popover-close', + }; - private readonly refreshErc20Tokens = '[data-testid="refreshList"]'; + private readonly privacyBalanceToggle = { + testId: 'sensitive-toggle', + }; - private readonly sendButton = '[data-testid="eth-overview-send"]'; + private readonly refreshErc20Tokens = { + testId: 'refreshList', + }; - private readonly tokensTab = '[data-testid="account-overview__asset-tab"]'; + private readonly sendButton = { + testId: 'eth-overview-send', + }; + + private readonly tokensTab = { + testId: 'account-overview__asset-tab', + }; constructor(driver: Driver) { this.driver = driver; @@ -93,6 +110,10 @@ class HomePage { await this.driver.clickElement(this.sendButton); } + async togglePrivacyBalance(): Promise { + await this.driver.clickElement(this.privacyBalanceToggle); + } + /** * Checks if the toaster message for adding a network is displayed on the homepage. * diff --git a/test/e2e/page-objects/pages/test-dapp.ts b/test/e2e/page-objects/pages/test-dapp.ts index 5155707663b6..ef5aca0c6bf7 100644 --- a/test/e2e/page-objects/pages/test-dapp.ts +++ b/test/e2e/page-objects/pages/test-dapp.ts @@ -321,6 +321,26 @@ class TestDapp { }); } + /** + * Verifies the accounts connected to the test dapp. + * + * @param connectedAccounts - The expected connected accounts separated by a comma. If no accounts are connected we can omit the param. + */ + async check_connectedAccounts(connectedAccounts: string = '') { + console.log('Verify connected accounts'); + if (connectedAccounts) { + await this.driver.waitForSelector({ + css: this.connectedAccount, + text: connectedAccounts, + }); + } else { + await this.driver.waitForSelector({ + css: this.connectedAccount, + text: ' ', + }); + } + } + /** * Verify the failed personal sign signature. * diff --git a/test/e2e/tests/privacy-mode/privacy-mode.spec.js b/test/e2e/tests/privacy-mode/privacy-mode.spec.js deleted file mode 100644 index ede37f900e66..000000000000 --- a/test/e2e/tests/privacy-mode/privacy-mode.spec.js +++ /dev/null @@ -1,106 +0,0 @@ -const { strict: assert } = require('assert'); -const { - withFixtures, - unlockWallet, - defaultGanacheOptions, -} = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); - -describe('Privacy Mode', function () { - it('should activate privacy mode, then deactivate it', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder().withPreferencesController().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - async function checkForHeaderValue(value) { - const balanceElement = await driver.findElement( - '[data-testid="account-value-and-suffix"]', - ); - const surveyText = await balanceElement.getText(); - assert.equal( - surveyText, - value, - `Header balance should be "${value}"`, - ); - } - - async function checkForTokenValue(value) { - const balanceElement = await driver.findElement( - '[data-testid="multichain-token-list-item-value"]', - ); - const surveyText = await balanceElement.getText(); - assert.equal(surveyText, value, `Token balance should be "${value}"`); - } - - async function checkForPrivacy() { - await checkForHeaderValue('••••••'); - await checkForTokenValue('••••••'); - } - - async function checkForNoPrivacy() { - await checkForHeaderValue('25'); - await checkForTokenValue('25 ETH'); - } - - async function togglePrivacy() { - const balanceElement = await driver.findElement( - '[data-testid="account-value-and-suffix"]', - ); - const initialText = await balanceElement.getText(); - - await driver.clickElement('[data-testid="sensitive-toggle"]'); - await driver.wait(async () => { - const currentText = await balanceElement.getText(); - return currentText !== initialText; - }, 2e3); - } - - await unlockWallet(driver); - await checkForNoPrivacy(); - await togglePrivacy(); - await checkForPrivacy(); - await togglePrivacy(); - await checkForNoPrivacy(); - }, - ); - }); - - it('should hide fiat balance and token balance when privacy mode is activated', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().withPreferencesController().build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - async function togglePrivacy() { - const balanceElement = await driver.findElement( - '[data-testid="account-value-and-suffix"]', - ); - const initialText = await balanceElement.getText(); - - await driver.clickElement('[data-testid="sensitive-toggle"]'); - await driver.wait(async () => { - const currentText = await balanceElement.getText(); - return currentText !== initialText; - }, 2e3); - } - - await togglePrivacy(); - await driver.clickElement('[data-testid="account-menu-icon"]'); - const valueText = await driver.findElement( - '[data-testid="account-value-and-suffix"]', - ); - const valueTextContent = await valueText.getText(); - - assert.equal(valueTextContent, '••••••'); - }, - ); - }); -}); diff --git a/test/e2e/tests/privacy-mode/privacy-mode.spec.ts b/test/e2e/tests/privacy-mode/privacy-mode.spec.ts new file mode 100644 index 000000000000..60d9faedc080 --- /dev/null +++ b/test/e2e/tests/privacy-mode/privacy-mode.spec.ts @@ -0,0 +1,74 @@ +import { Driver } from '../../webdriver/driver'; +import { defaultGanacheOptions, withFixtures } from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import AccountListPage from '../../page-objects/pages/account-list-page'; +import HeaderNavbar from '../../page-objects/pages/header-navbar'; +import HomePage from '../../page-objects/pages/home/homepage'; +import { + loginWithBalanceValidation, + loginWithoutBalanceValidation, +} from '../../page-objects/flows/login.flow'; +import { Ganache } from '../../seeder/ganache'; + +describe('Privacy Mode', function () { + it('should hide fiat balance and token balance when privacy mode is activated', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: Ganache; + }) => { + await loginWithBalanceValidation(driver, ganacheServer); + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.togglePrivacyBalance(); + await homePage.check_expectedBalanceIsDisplayed('••••••', '••••••'); + + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.openAccountMenu(); + + const accountList = new AccountListPage(driver); + await accountList.check_pageIsLoaded(); + await accountList.check_balanceIsPrivateEverywhere(); + }, + ); + }); + + it('should show fiat balance and token balance when privacy mode is deactivated', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesController({ + preferences: { + privacyMode: true, + }, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithoutBalanceValidation(driver); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.togglePrivacyBalance(); + await homePage.check_expectedBalanceIsDisplayed('25 ETH'); + + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.openAccountMenu(); + + const accountList = new AccountListPage(driver); + await accountList.check_pageIsLoaded(); + await accountList.check_accountBalanceDisplayed('25'); + }, + ); + }); +}); diff --git a/test/e2e/tests/request-queuing/sendTx-revokePermissions.spec.js b/test/e2e/tests/request-queuing/sendTx-revokePermissions.spec.js deleted file mode 100644 index 363f7c94cc74..000000000000 --- a/test/e2e/tests/request-queuing/sendTx-revokePermissions.spec.js +++ /dev/null @@ -1,58 +0,0 @@ -const FixtureBuilder = require('../../fixture-builder'); -const { - withFixtures, - openDapp, - unlockWallet, - DAPP_URL, - defaultGanacheOptions, -} = require('../../helpers'); -const { PAGES } = require('../../webdriver/driver'); - -describe('Request Queuing', function () { - it('should clear tx confirmation when revokePermission is called from origin dapp', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .withPreferencesControllerUseRequestQueueEnabled() - .withSelectedNetworkControllerPerDomain() - .build(), - ganacheOptions: { - ...defaultGanacheOptions, - }, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - // Navigate to extension home screen - await driver.navigate(PAGES.HOME); - - // Open Dapp One - await openDapp(driver, undefined, DAPP_URL); - - // wallet_revokePermissions request - const revokePermissionsRequest = JSON.stringify({ - jsonrpc: '2.0', - method: 'wallet_revokePermissions', - params: [ - { - eth_accounts: {}, - }, - ], - }); - - await driver.executeScript( - `return window.ethereum.request(${revokePermissionsRequest})`, - ); - - // Should have cleared the tx confirmation - await driver.waitUntilXWindowHandles(2); - - // Cleared eth_accounts account label - await driver.findElement({ xpath: '//span[@id="accounts"][.=""]' }); - }, - ); - }); -}); diff --git a/test/e2e/tests/request-queuing/sendTx-revokePermissions.spec.ts b/test/e2e/tests/request-queuing/sendTx-revokePermissions.spec.ts new file mode 100644 index 000000000000..c5ff864df99c --- /dev/null +++ b/test/e2e/tests/request-queuing/sendTx-revokePermissions.spec.ts @@ -0,0 +1,78 @@ +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; +import TestDapp from '../../page-objects/pages/test-dapp'; +import TransactionConfirmation from '../../page-objects/pages/confirmations/redesign/transaction-confirmation'; +import { Ganache } from '../../seeder/ganache'; +import { Driver } from '../../webdriver/driver'; +import { DEFAULT_FIXTURE_ACCOUNT } from '../../constants'; +import FixtureBuilder from '../../fixture-builder'; +import { + withFixtures, + defaultGanacheOptions, + WINDOW_TITLES, +} from '../../helpers'; + +describe('Request Queuing', function () { + // TODO: add a new spec which checks that after revoking and connecting again + // a pending tx is still closed when using revokePermissions. + // To be done once this bug is fixed: #29272 + it('should clear tx confirmation when revokePermission is called from origin dapp', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesControllerUseRequestQueueEnabled() + .withSelectedNetworkControllerPerDomain() + .build(), + ganacheOptions: { + ...defaultGanacheOptions, + }, + title: this.test?.fullTitle(), + }, + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer?: Ganache; + }) => { + await loginWithBalanceValidation(driver, ganacheServer); + + // Open test dapp + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_connectedAccounts( + DEFAULT_FIXTURE_ACCOUNT.toLowerCase(), + ); + + // Trigger a tx + await testDapp.clickSimpleSendButton(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + const transactionConfirmation = new TransactionConfirmation(driver); + await transactionConfirmation.check_dappInitiatedHeadingTitle(); + + // wallet_revokePermissions request + const revokePermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_revokePermissions', + params: [ + { + eth_accounts: {}, + }, + ], + }); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.executeScript( + `return window.ethereum.request(${revokePermissionsRequest})`, + ); + + // Should have cleared the tx confirmation + await driver.waitUntilXWindowHandles(2); + + // Cleared eth_accounts account label + await testDapp.check_connectedAccounts(); + }, + ); + }); +}); diff --git a/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts index 7e7c94e9e1dc..1aa86f3af337 100644 --- a/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts +++ b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts @@ -8,10 +8,10 @@ import { getMultichainShouldShowFiat, } from '../../../../../selectors/multichain'; import { - getCurrentCurrency, getPreferences, getSelectedInternalAccount, } from '../../../../../selectors'; +import { getCurrentCurrency } from '../../../../../ducks/metamask/metamask'; import { useIsOriginalNativeTokenSymbol } from '../../../../../hooks/useIsOriginalNativeTokenSymbol'; import { PRIMARY, SECONDARY } from '../../../../../helpers/constants/common'; import { useUserPreferencedCurrency } from '../../../../../hooks/useUserPreferencedCurrency'; diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.test.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.test.tsx index 4aac598bd838..a74adca65ce9 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.test.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.test.tsx @@ -4,7 +4,8 @@ import { useSelector } from 'react-redux'; import { setTokenSortConfig } from '../../../../../store/actions'; import { renderWithProvider } from '../../../../../../test/lib/render-helpers'; import { MetaMetricsContext } from '../../../../../contexts/metametrics'; -import { getCurrentCurrency, getPreferences } from '../../../../../selectors'; +import { getPreferences } from '../../../../../selectors'; +import { getCurrentCurrency } from '../../../../../ducks/metamask/metamask'; import SortControl from './sort-control'; // Mock the sortAssets utility diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index cf7285c9115b..ddded6c1c027 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -18,7 +18,8 @@ import { MetaMetricsEventName, MetaMetricsUserTrait, } from '../../../../../../shared/constants/metametrics'; -import { getCurrentCurrency, getPreferences } from '../../../../../selectors'; +import { getPreferences } from '../../../../../selectors'; +import { getCurrentCurrency } from '../../../../../ducks/metamask/metamask'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { getCurrencySymbol } from '../../../../../helpers/utils/common.util'; diff --git a/ui/components/app/assets/nfts/nft-details/nft-details.tsx b/ui/components/app/assets/nfts/nft-details/nft-details.tsx index 49408dfd5fa4..3f421615c3cf 100644 --- a/ui/components/app/assets/nfts/nft-details/nft-details.tsx +++ b/ui/components/app/assets/nfts/nft-details/nft-details.tsx @@ -21,11 +21,7 @@ import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { shortenAddress } from '../../../../../helpers/utils/util'; import { getNftImageAlt } from '../../../../../helpers/utils/nfts'; import { getCurrentChainId } from '../../../../../../shared/modules/selectors/networks'; -import { - getCurrentCurrency, - getCurrentNetwork, - getIpfsGateway, -} from '../../../../../selectors'; +import { getCurrentNetwork, getIpfsGateway } from '../../../../../selectors'; import { ASSET_ROUTE, DEFAULT_ROUTE, @@ -67,7 +63,10 @@ import { Content, Footer, Page } from '../../../../multichain/pages/page'; import { formatCurrency } from '../../../../../helpers/utils/confirm-tx.util'; import { getShortDateFormatterV2 } from '../../../../../pages/asset/util'; import { CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP } from '../../../../../../shared/constants/common'; -import { getConversionRate } from '../../../../../ducks/metamask/metamask'; +import { + getConversionRate, + getCurrentCurrency, +} from '../../../../../ducks/metamask/metamask'; import { Numeric } from '../../../../../../shared/modules/Numeric'; // TODO: Remove restricted import // eslint-disable-next-line import/no-restricted-paths diff --git a/ui/components/app/assets/token-cell/token-cell.test.tsx b/ui/components/app/assets/token-cell/token-cell.test.tsx index 285c3dfac778..d80996776c49 100644 --- a/ui/components/app/assets/token-cell/token-cell.test.tsx +++ b/ui/components/app/assets/token-cell/token-cell.test.tsx @@ -5,10 +5,10 @@ import { fireEvent } from '@testing-library/react'; import { useSelector } from 'react-redux'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import { useTokenFiatAmount } from '../../../../hooks/useTokenFiatAmount'; +import { getCurrentCurrency } from '../../../../ducks/metamask/metamask'; import { getTokenList, getPreferences, - getCurrentCurrency, getCurrencyRates, } from '../../../../selectors'; import { diff --git a/ui/components/app/assets/token-cell/token-cell.tsx b/ui/components/app/assets/token-cell/token-cell.tsx index d470ef3dc21a..c194bdca485c 100644 --- a/ui/components/app/assets/token-cell/token-cell.tsx +++ b/ui/components/app/assets/token-cell/token-cell.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { BigNumber } from 'bignumber.js'; +import { getCurrentCurrency } from '../../../../ducks/metamask/metamask'; import { - getCurrentCurrency, getTokenList, selectERC20TokensByChain, getNativeCurrencyForChain, diff --git a/ui/components/app/currency-input/currency-input.js b/ui/components/app/currency-input/currency-input.js index 83bd3c2edce8..e16d95b8bfb7 100644 --- a/ui/components/app/currency-input/currency-input.js +++ b/ui/components/app/currency-input/currency-input.js @@ -5,12 +5,15 @@ import { Box } from '../../component-library'; import { BlockSize } from '../../../helpers/constants/design-system'; import UnitInput from '../../ui/unit-input'; import CurrencyDisplay from '../../ui/currency-display'; -import { getNativeCurrency } from '../../../ducks/metamask/metamask'; +import { + getNativeCurrency, + getCurrentCurrency, +} from '../../../ducks/metamask/metamask'; import { getProviderConfig, getCurrentChainId, } from '../../../../shared/modules/selectors/networks'; -import { getCurrentCurrency, getShouldShowFiat } from '../../../selectors'; +import { getShouldShowFiat } from '../../../selectors'; import { EtherDenomination } from '../../../../shared/constants/common'; import { Numeric } from '../../../../shared/modules/Numeric'; import { useIsOriginalNativeTokenSymbol } from '../../../hooks/useIsOriginalNativeTokenSymbol'; diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.test.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.test.tsx index 72b2e89e49c6..5f6926f5f616 100644 --- a/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.test.tsx +++ b/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.test.tsx @@ -3,7 +3,6 @@ import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { getIntlLocale } from '../../../ducks/locale/locale'; import { - getCurrentCurrency, getSelectedAccount, getShouldHideZeroBalanceTokens, getPreferences, @@ -11,6 +10,7 @@ import { getAllTokens, getChainIdsToPoll, } from '../../../selectors'; +import { getCurrentCurrency } from '../../../ducks/metamask/metamask'; import { useAccountTotalCrossChainFiatBalance } from '../../../hooks/useAccountTotalCrossChainFiatBalance'; import { getNetworkConfigurationsByChainId } from '../../../../shared/modules/selectors/networks'; import { AggregatedPercentageOverviewCrossChains } from './aggregated-percentage-overview-cross-chains'; @@ -31,7 +31,6 @@ jest.mock('../../../ducks/locale/locale', () => ({ })); jest.mock('../../../selectors', () => ({ - getCurrentCurrency: jest.fn(), getSelectedAccount: jest.fn(), getPreferences: jest.fn(), getShouldHideZeroBalanceTokens: jest.fn(), @@ -40,6 +39,10 @@ jest.mock('../../../selectors', () => ({ getChainIdsToPoll: jest.fn(), })); +jest.mock('../../../ducks/metamask/metamask', () => ({ + getCurrentCurrency: jest.fn(), +})); + jest.mock('../../../../shared/modules/selectors/networks', () => ({ getNetworkConfigurationsByChainId: jest.fn(), })); diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.tsx index 6f7de0c95c7c..5a321c35cf0f 100644 --- a/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.tsx +++ b/ui/components/app/wallet-overview/aggregated-percentage-overview-cross-chains.tsx @@ -5,13 +5,13 @@ import { toChecksumAddress } from 'ethereumjs-util'; import { getNativeTokenAddress } from '@metamask/assets-controllers'; import { Hex } from '@metamask/utils'; import { - getCurrentCurrency, getSelectedAccount, getShouldHideZeroBalanceTokens, getPreferences, getMarketData, getChainIdsToPoll, } from '../../../selectors'; +import { getCurrentCurrency } from '../../../ducks/metamask/metamask'; // TODO: Remove restricted import // eslint-disable-next-line import/no-restricted-paths diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx index 10fd24ec550c..cb6efa2516a9 100644 --- a/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx +++ b/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx @@ -2,8 +2,8 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { getIntlLocale } from '../../../ducks/locale/locale'; +import { getCurrentCurrency } from '../../../ducks/metamask/metamask'; import { - getCurrentCurrency, getSelectedAccount, getShouldHideZeroBalanceTokens, getTokensMarketData, @@ -21,8 +21,11 @@ jest.mock('../../../ducks/locale/locale', () => ({ getIntlLocale: jest.fn(), })); -jest.mock('../../../selectors', () => ({ +jest.mock('../../../ducks/metamask/metamask', () => ({ getCurrentCurrency: jest.fn(), +})); + +jest.mock('../../../selectors', () => ({ getSelectedAccount: jest.fn(), getPreferences: jest.fn(), getShouldHideZeroBalanceTokens: jest.fn(), diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx index d50feebbbd74..ad837ccd322c 100644 --- a/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx +++ b/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx @@ -3,8 +3,8 @@ import { useSelector } from 'react-redux'; import { toChecksumAddress } from 'ethereumjs-util'; import { getNativeTokenAddress } from '@metamask/assets-controllers'; +import { getCurrentCurrency } from '../../../ducks/metamask/metamask'; import { - getCurrentCurrency, getSelectedAccount, getShouldHideZeroBalanceTokens, getTokensMarketData, diff --git a/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.tsx b/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.tsx index 67def7ee82b1..e5197d50b6b0 100644 --- a/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.tsx @@ -4,10 +4,8 @@ import { Text } from '../../../component-library'; import UserPreferencedCurrencyDisplay from '../../../app/user-preferenced-currency-display'; import { PRIMARY } from '../../../../helpers/constants/common'; import { Asset } from '../../../../ducks/send'; -import { - getCurrentCurrency, - getSelectedAccountCachedBalance, -} from '../../../../selectors'; +import { getSelectedAccountCachedBalance } from '../../../../selectors'; +import { getCurrentCurrency } from '../../../../ducks/metamask/metamask'; import { AssetType } from '../../../../../shared/constants/transaction'; import { TextColor, diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/Asset.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/Asset.tsx index 5561af182dc0..e247409f848e 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/Asset.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/Asset.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { BigNumber } from 'bignumber.js'; +import { getCurrentCurrency } from '../../../../ducks/metamask/metamask'; import { - getCurrentCurrency, getNetworkConfigurationIdByChainId, getTokenList, } from '../../../../selectors'; diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx index ece3d7046fde..740425114ab6 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx @@ -7,11 +7,13 @@ import { } from '@metamask/network-controller'; import { getCurrentChainId } from '../../../../../shared/modules/selectors/networks'; import { - getCurrentCurrency, getCurrentNetwork, getSelectedAccountCachedBalance, } from '../../../../selectors'; -import { getNativeCurrency } from '../../../../ducks/metamask/metamask'; +import { + getCurrentCurrency, + getNativeCurrency, +} from '../../../../ducks/metamask/metamask'; import { useCurrencyDisplay } from '../../../../hooks/useCurrencyDisplay'; import { AssetType } from '../../../../../shared/constants/transaction'; import { Box } from '../../../component-library'; diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal-network.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal-network.tsx index 7d6963240619..862e8e842b8d 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal-network.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal-network.tsx @@ -32,7 +32,7 @@ import { useI18nContext } from '../../../../hooks/useI18nContext'; ///: END:ONLY_INCLUDE_IF import { NetworkListItem } from '../../network-list-item'; import { getNetworkConfigurationsByChainId } from '../../../../../shared/modules/selectors/networks'; -import { getCurrentCurrency } from '../../../../selectors'; +import { getCurrentCurrency } from '../../../../ducks/metamask/metamask'; import { formatCurrency } from '../../../../helpers/utils/confirm-tx.util'; import { useMultichainBalances } from '../../../../hooks/useMultichainBalances'; import { NETWORK_TO_SHORT_NETWORK_NAME_MAP } from '../../../../../shared/constants/bridge'; diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx index 8fb933ed2fbb..dfff37c45ad1 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx @@ -12,7 +12,6 @@ import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import mockState from '../../../../../test/data/mock-send-state.json'; import { AssetType } from '../../../../../shared/constants/transaction'; import { - getCurrentCurrency, getNativeCurrencyImage, getSelectedAccountCachedBalance, getSelectedInternalAccount, @@ -24,6 +23,7 @@ import { getConversionRate, getNativeCurrency, getTokens, + getCurrentCurrency, } from '../../../../ducks/metamask/metamask'; import { getTopAssets } from '../../../../ducks/swaps/swaps'; import { getRenderableTokenData } from '../../../../hooks/useTokensToSearch'; diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx index b8bf0a70d7f5..d3daf33afc84 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx @@ -36,7 +36,6 @@ import { } from '../../../../../shared/modules/selectors/networks'; import { getAllTokens, - getCurrentCurrency, getNativeCurrencyImage, getSelectedAccountCachedBalance, getSelectedInternalAccount, @@ -46,6 +45,7 @@ import { } from '../../../../selectors'; import { getConversionRate, + getCurrentCurrency, getNativeCurrency, } from '../../../../ducks/metamask/metamask'; import { useTokenTracker } from '../../../../hooks/useTokenTracker'; diff --git a/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.test.tsx b/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.test.tsx index 1ef3347e3133..9fa58e610bba 100644 --- a/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.test.tsx +++ b/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.test.tsx @@ -4,10 +4,10 @@ import { getNativeCurrency, getConversionRate, getGasFeeEstimates, + getCurrentCurrency, } from '../../../../../../../ducks/metamask/metamask'; import { getUsedSwapsGasPrice } from '../../../../../../../ducks/swaps/swaps'; import { - getCurrentCurrency, checkNetworkAndAccountSupports1559, getIsSwapsChain, } from '../../../../../../../selectors'; diff --git a/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.tsx b/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.tsx index 04fa59ce072a..f08ab47086a9 100644 --- a/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.tsx +++ b/ui/components/multichain/pages/send/components/quote-card/hooks/useEthFeeData.tsx @@ -6,10 +6,10 @@ import { getConversionRate, getGasFeeEstimates, getNativeCurrency, + getCurrentCurrency, } from '../../../../../../../ducks/metamask/metamask'; import { EtherDenomination } from '../../../../../../../../shared/constants/common'; import { - getCurrentCurrency, checkNetworkAndAccountSupports1559, getIsSwapsChain, } from '../../../../../../../selectors/selectors'; diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx index f157afa64d8b..53ff99bd5d06 100644 --- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx +++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx @@ -5,13 +5,13 @@ import { zeroAddress } from 'ethereumjs-util'; import { MarketDataDetails } from '@metamask/assets-controllers'; import { getIntlLocale } from '../../../../../ducks/locale/locale'; import { - getCurrentCurrency, getSelectedAccountCachedBalance, getTokensMarketData, } from '../../../../../selectors'; import { getCurrentChainId } from '../../../../../../shared/modules/selectors/networks'; import { getConversionRate, + getCurrentCurrency, getNativeCurrency, } from '../../../../../ducks/metamask/metamask'; import { PercentageAndAmountChange } from './percentage-and-amount-change'; @@ -25,7 +25,6 @@ jest.mock('../../../../../ducks/locale/locale', () => ({ })); jest.mock('../../../../../selectors', () => ({ - getCurrentCurrency: jest.fn(), getSelectedAccountCachedBalance: jest.fn(), getTokensMarketData: jest.fn(), })); @@ -35,6 +34,7 @@ jest.mock('../../../../../../shared/modules/selectors/networks', () => ({ })); jest.mock('../../../../../ducks/metamask/metamask', () => ({ + getCurrentCurrency: jest.fn(), getConversionRate: jest.fn(), getNativeCurrency: jest.fn(), })); diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx index dc0aeaa5a25c..c0c3e83addb7 100644 --- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx +++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx @@ -11,7 +11,6 @@ import { } from '../../../../../helpers/constants/design-system'; import { getCurrentChainId } from '../../../../../../shared/modules/selectors/networks'; import { - getCurrentCurrency, getSelectedAccountCachedBalance, getTokensMarketData, } from '../../../../../selectors'; @@ -20,6 +19,7 @@ import { EtherDenomination } from '../../../../../../shared/constants/common'; import { Numeric } from '../../../../../../shared/modules/Numeric'; import { getConversionRate, + getCurrentCurrency, getNativeCurrency, } from '../../../../../ducks/metamask/metamask'; import { diff --git a/ui/components/ui/button-group/__snapshots__/button-group-component.test.js.snap b/ui/components/ui/button-group/__snapshots__/button-group-component.test.js.snap index 7e8116227458..b04aa2fbd4f1 100644 --- a/ui/components/ui/button-group/__snapshots__/button-group-component.test.js.snap +++ b/ui/components/ui/button-group/__snapshots__/button-group-component.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ButtonGroup Component should match snapshot 1`] = ` +exports[`ButtonGroup Component should match snapshot with default variant 1`] = `
`; + +exports[`ButtonGroup Component should match snapshot with radiogroup variant 1`] = ` +
+
+ +
+
+`; diff --git a/ui/components/ui/button-group/button-group-component.test.js b/ui/components/ui/button-group/button-group-component.test.js index 2aaccad78a0c..584042491867 100644 --- a/ui/components/ui/button-group/button-group-component.test.js +++ b/ui/components/ui/button-group/button-group-component.test.js @@ -16,15 +16,25 @@ describe('ButtonGroup Component', () => { , - , - , +
diff --git a/ui/pages/bridge/prepare/__snapshots__/bridge-cta-button.test.tsx.snap b/ui/pages/bridge/prepare/__snapshots__/bridge-cta-button.test.tsx.snap index 0b46d2764523..6014dbaddb23 100644 --- a/ui/pages/bridge/prepare/__snapshots__/bridge-cta-button.test.tsx.snap +++ b/ui/pages/bridge/prepare/__snapshots__/bridge-cta-button.test.tsx.snap @@ -2,9 +2,13 @@ exports[`BridgeCTAButton should disable the component when quotes are loading and there are no existing quotes 1`] = `
-

+

+

+

`; @@ -23,20 +27,28 @@ exports[`BridgeCTAButton should enable the component when quotes are loading and exports[`BridgeCTAButton should render the component when amount and dest token is missing 1`] = `
-

- Select token and amount -

+

+ Select token and amount +

+
`; exports[`BridgeCTAButton should render the component's initial state 1`] = `
-

- Select token -

+

+ Select token +

+
`; diff --git a/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap b/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap index d5b980d13fd6..c69368d0b88e 100644 --- a/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap +++ b/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap @@ -172,11 +172,15 @@ exports[`PrepareBridgePage should render the component, with initial state 1`] = @@ -357,11 +361,15 @@ exports[`PrepareBridgePage should render the component, with inputs set 1`] = ` diff --git a/ui/pages/bridge/prepare/bridge-cta-button.test.tsx b/ui/pages/bridge/prepare/bridge-cta-button.test.tsx index d4e0fd0855c5..5dc368043d3a 100644 --- a/ui/pages/bridge/prepare/bridge-cta-button.test.tsx +++ b/ui/pages/bridge/prepare/bridge-cta-button.test.tsx @@ -23,7 +23,7 @@ describe('BridgeCTAButton', () => { bridgeSliceOverrides: { fromTokenInputValue: 1 }, }); const { container, getByText } = renderWithProvider( - , + , configureStore(mockStore), ); @@ -54,7 +54,7 @@ describe('BridgeCTAButton', () => { }, }); const { getByText } = renderWithProvider( - , + , configureStore(mockStore), ); @@ -83,7 +83,7 @@ describe('BridgeCTAButton', () => { }, }); const { getByText, container } = renderWithProvider( - , + , configureStore(mockStore), ); @@ -118,7 +118,7 @@ describe('BridgeCTAButton', () => { }, }); const { getByText, getByRole } = renderWithProvider( - , + , configureStore(mockStore), ); @@ -159,7 +159,7 @@ describe('BridgeCTAButton', () => { }, }); const { container } = renderWithProvider( - , + , configureStore(mockStore), ); @@ -199,7 +199,7 @@ describe('BridgeCTAButton', () => { }, }); const { getByText, getByRole, container } = renderWithProvider( - , + , configureStore(mockStore), ); diff --git a/ui/pages/bridge/prepare/bridge-cta-button.tsx b/ui/pages/bridge/prepare/bridge-cta-button.tsx index 8812e26eb099..8e45f90cd1db 100644 --- a/ui/pages/bridge/prepare/bridge-cta-button.tsx +++ b/ui/pages/bridge/prepare/bridge-cta-button.tsx @@ -1,6 +1,7 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; import { + ButtonLink, ButtonPrimary, ButtonPrimarySize, Text, @@ -18,7 +19,9 @@ import { import { useI18nContext } from '../../../hooks/useI18nContext'; import useSubmitBridgeTransaction from '../hooks/useSubmitBridgeTransaction'; import { + AlignItems, BlockSize, + JustifyContent, TextAlign, TextColor, TextVariant, @@ -32,8 +35,14 @@ import { useTradeProperties } from '../../../hooks/bridge/events/useTradePropert import { MetaMetricsEventName } from '../../../../shared/constants/metametrics'; import { SWAPS_CHAINID_DEFAULT_TOKEN_MAP } from '../../../../shared/constants/swaps'; import { getNativeCurrency } from '../../../ducks/metamask/metamask'; - -export const BridgeCTAButton = () => { +import { Row } from '../layout'; +import { isQuoteExpired as isQuoteExpiredUtil } from '../utils/quote'; + +export const BridgeCTAButton = ({ + onFetchNewQuotes, +}: { + onFetchNewQuotes: () => void; +}) => { const t = useI18nContext(); const fromToken = useSelector(getFromToken); @@ -43,9 +52,14 @@ export const BridgeCTAButton = () => { const fromAmount = useSelector(getFromAmount); - const { isLoading, activeQuote, isQuoteGoingToRefresh, quotesRefreshCount } = + const { isLoading, activeQuote, isQuoteGoingToRefresh, quotesLastFetchedMs } = useSelector(getBridgeQuotes); - const { maxRefreshCount, refreshRate } = useSelector(getBridgeQuotesConfig); + const { refreshRate } = useSelector(getBridgeQuotesConfig); + const isQuoteExpired = isQuoteExpiredUtil( + isQuoteGoingToRefresh, + refreshRate, + quotesLastFetchedMs, + ); const { submitBridgeTransaction } = useSubmitBridgeTransaction(); const [isSubmitting, setIsSubmitting] = useState(false); @@ -76,7 +90,6 @@ export const BridgeCTAButton = () => { const tradeProperties = useTradeProperties(); const ticker = useSelector(getNativeCurrency); - const [isQuoteExpired, setIsQuoteExpired] = useState(false); const isInsufficientBalance = isInsufficientBalance_(balanceAmount); @@ -85,28 +98,12 @@ export const BridgeCTAButton = () => { const isInsufficientGasForQuote = isInsufficientGasForQuote_(nativeAssetBalance); - useEffect(() => { - let timeout: NodeJS.Timeout; - // Reset the isQuoteExpired if quote fethching restarts - if (quotesRefreshCount === 0) { - setIsQuoteExpired(false); - return () => clearTimeout(timeout); - } - // After the last quote refresh, set a timeout to expire the quote and disable the CTA - if (quotesRefreshCount >= maxRefreshCount && !isQuoteGoingToRefresh) { - timeout = setTimeout(() => { - setIsQuoteExpired(true); - }, refreshRate); - } - return () => clearTimeout(timeout); - }, [isQuoteGoingToRefresh, quotesRefreshCount]); - const label = useMemo(() => { if (wasTxDeclined) { return t('youDeclinedTheTransaction'); } - if (isQuoteExpired && !isNoQuotesAvailable) { + if (isQuoteExpired) { return t('bridgeQuoteExpired'); } @@ -149,7 +146,15 @@ export const BridgeCTAButton = () => { isQuoteExpired, ]); - return activeQuote && !wasTxDeclined ? ( + // Label for the secondary button that re-starts quote fetching + const secondaryButtonLabel = useMemo(() => { + if (wasTxDeclined || isQuoteExpired) { + return t('bridgeFetchNewQuotes'); + } + return undefined; + }, [wasTxDeclined, isQuoteExpired]); + + return activeQuote && !secondaryButtonLabel ? ( { {label} ) : ( - - {label} - + + {label} + + {secondaryButtonLabel && ( + + {secondaryButtonLabel} + + )} + ); }; diff --git a/ui/pages/bridge/prepare/bridge-input-group.tsx b/ui/pages/bridge/prepare/bridge-input-group.tsx index c4502725c1ea..1734624b7dcc 100644 --- a/ui/pages/bridge/prepare/bridge-input-group.tsx +++ b/ui/pages/bridge/prepare/bridge-input-group.tsx @@ -14,7 +14,8 @@ import { import { AssetPicker } from '../../../components/multichain/asset-picker-amount/asset-picker'; import { TabName } from '../../../components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal-tabs'; import { useI18nContext } from '../../../hooks/useI18nContext'; -import { getCurrentCurrency, getLocale } from '../../../selectors'; +import { getLocale } from '../../../selectors'; +import { getCurrentCurrency } from '../../../ducks/metamask/metamask'; import { formatCurrencyAmount, formatTokenAmount } from '../utils/quote'; import { Column, Row, Tooltip } from '../layout'; import { diff --git a/ui/pages/bridge/prepare/prepare-bridge-page.tsx b/ui/pages/bridge/prepare/prepare-bridge-page.tsx index b4774ec5489a..fc076b73629b 100644 --- a/ui/pages/bridge/prepare/prepare-bridge-page.tsx +++ b/ui/pages/bridge/prepare/prepare-bridge-page.tsx @@ -67,7 +67,11 @@ import { hexToDecimal } from '../../../../shared/modules/conversion.utils'; import { QuoteRequest } from '../types'; import { calcTokenValue } from '../../../../shared/lib/swaps-utils'; import { BridgeQuoteCard } from '../quotes/bridge-quote-card'; -import { formatTokenAmount, isValidQuoteRequest } from '../utils/quote'; +import { + formatTokenAmount, + isQuoteExpired as isQuoteExpiredUtil, + isValidQuoteRequest, +} from '../utils/quote'; import { getProviderConfig } from '../../../../shared/modules/selectors/networks'; import { CrossChainSwapsEventProperties, @@ -121,12 +125,24 @@ const PrepareBridgePage = () => { const slippage = useSelector(getSlippage); const quoteRequest = useSelector(getQuoteRequest); - const { isLoading, activeQuote, isQuoteGoingToRefresh } = - useSelector(getBridgeQuotes); - + const { + isLoading, + activeQuote: activeQuote_, + isQuoteGoingToRefresh, + quotesLastFetchedMs, + } = useSelector(getBridgeQuotes); const { refreshRate } = useSelector(getBridgeQuotesConfig); const wasTxDeclined = useSelector(getWasTxDeclined); + // If latest quote is expired and user has sufficient balance + // set activeQuote to undefined to hide stale quotes but keep inputs filled + const isQuoteExpired = isQuoteExpiredUtil( + isQuoteGoingToRefresh, + refreshRate, + quotesLastFetchedMs, + ); + const activeQuote = + isQuoteExpired && !quoteRequest.insufficientBal ? undefined : activeQuote_; const keyring = useSelector(getCurrentKeyring); // @ts-expect-error keyring type is wrong maybe? @@ -533,9 +549,13 @@ const PrepareBridgePage = () => { backgroundColor={BackgroundColor.primaryMuted} /> )} - {!wasTxDeclined && } + {!wasTxDeclined && activeQuote && }