From 3188e229012157dd372b806cce59ac4c27c8b6e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n?= Date: Thu, 19 Dec 2024 12:23:03 +0100 Subject: [PATCH 01/41] test: approve erc721 token e2e (#12767) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR is within the scope of the Quality Quest. We're including an e2e test case to approve an ERC721 token. **Test Steps:** Given I am on the test dApp When I tap on the Approve From button under the ERC 721 section Then the transaction bottom sheet should appear When I submit the transaction Then the transaction should appear in the transaction history ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- e2e/pages/Browser/TestDApp.js | 28 +++++++-- e2e/selectors/Browser/TestDapp.selectors.js | 3 +- .../Transactions/ActivitiesView.selectors.js | 1 + .../approve-custom-erc20.spec.js | 2 +- .../approve-default-erc20.spec.js | 2 +- .../confirmations/approve-erc721.spec.js | 61 +++++++++++++++++++ 6 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 e2e/specs/confirmations/approve-erc721.spec.js diff --git a/e2e/pages/Browser/TestDApp.js b/e2e/pages/Browser/TestDApp.js index cdf89c571f8..a09c4b8d5fd 100644 --- a/e2e/pages/Browser/TestDApp.js +++ b/e2e/pages/Browser/TestDApp.js @@ -12,6 +12,7 @@ import Matchers from '../../utils/Matchers'; export const TEST_DAPP_LOCAL_URL = `http://localhost:${getLocalTestDappPort()}`; const CONFIRM_BUTTON_TEXT = enContent.confirmation_modal.confirm_cta; +const APPROVE_BUTTON_TEXT = enContent.transactions.tx_review_approve; class TestDApp { get androidContainer() { @@ -22,6 +23,10 @@ class TestDApp { return Matchers.getElementByText(CONFIRM_BUTTON_TEXT); } + get approveButtonText() { + return Matchers.getElementByText(APPROVE_BUTTON_TEXT); + } + get DappConnectButton() { return Matchers.getElementByWebID( BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, @@ -29,10 +34,17 @@ class TestDApp { ); } - get ApproveButton() { + get ApproveERC20TokensButton() { + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.APPROVE_ERC_20_TOKENS_BUTTON_ID, + ); + } + + get ApproveERC721TokenButton() { return Matchers.getElementByWebID( BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - TestDappSelectorsWebIDs.APPROVE_TOKENS_BUTTON_ID, + TestDappSelectorsWebIDs.APPROVE_ERC_721_TOKEN_BUTTON_ID, ); } // This taps on the transfer tokens button under the "SEND TOKENS section" @@ -104,8 +116,12 @@ class TestDApp { await this.tapButton(this.DappConnectButton); } - async tapApproveButton() { - await this.tapButton(this.ApproveButton); + async tapApproveERC20TokensButton() { + await this.tapButton(this.ApproveERC20TokensButton); + } + + async tapApproveERC721TokenButton() { + await this.tapButton(this.ApproveERC721TokenButton); } async tapIncreaseAllowanceButton() { @@ -150,6 +166,10 @@ class TestDApp { await Gestures.tap(this.confirmButtonText, 0); } + async tapApproveButton() { + await Gestures.tap(this.approveButtonText, 0); + } + async tapButton(elementId) { await Gestures.scrollToWebViewPort(elementId); await Gestures.tapWebElement(elementId); diff --git a/e2e/selectors/Browser/TestDapp.selectors.js b/e2e/selectors/Browser/TestDapp.selectors.js index 0f2b7cad254..4407c27a950 100644 --- a/e2e/selectors/Browser/TestDapp.selectors.js +++ b/e2e/selectors/Browser/TestDapp.selectors.js @@ -1,5 +1,6 @@ export const TestDappSelectorsWebIDs = { - APPROVE_TOKENS_BUTTON_ID: 'approveTokens', + APPROVE_ERC_20_TOKENS_BUTTON_ID: 'approveTokens', + APPROVE_ERC_721_TOKEN_BUTTON_ID: 'approveButton', CONNECT_BUTTON: 'connectButton', ERC_20_SEND_TOKENS_TRANSFER_TOKENS_BUTTON_ID: 'transferTokens', INCREASE_ALLOWANCE_BUTTON_ID: 'increaseTokenAllowance', diff --git a/e2e/selectors/Transactions/ActivitiesView.selectors.js b/e2e/selectors/Transactions/ActivitiesView.selectors.js index 50a3cb95384..4327c397700 100644 --- a/e2e/selectors/Transactions/ActivitiesView.selectors.js +++ b/e2e/selectors/Transactions/ActivitiesView.selectors.js @@ -16,4 +16,5 @@ export const ActivitiesViewSelectorsText = { SET_APPROVAL_FOR_ALL_METHOD: enContent.transactions.set_approval_for_all, SWAP: enContent.swaps.transaction_label.swap, TITLE: enContent.transactions_view.title, + }; diff --git a/e2e/specs/confirmations/approve-custom-erc20.spec.js b/e2e/specs/confirmations/approve-custom-erc20.spec.js index 1c8d9e96383..ed24c9c3c6a 100644 --- a/e2e/specs/confirmations/approve-custom-erc20.spec.js +++ b/e2e/specs/confirmations/approve-custom-erc20.spec.js @@ -48,7 +48,7 @@ describe(SmokeConfirmations('ERC20 tokens'), () => { await TestDApp.navigateToTestDappWithContract({ contractAddress: hstAddress, }); - await TestDApp.tapApproveButton(); + await TestDApp.tapApproveERC20TokensButton(); //Input custom token amount await Assertions.checkIfVisible( diff --git a/e2e/specs/confirmations/approve-default-erc20.spec.js b/e2e/specs/confirmations/approve-default-erc20.spec.js index ed9c02188c5..ca7a2889a0f 100644 --- a/e2e/specs/confirmations/approve-default-erc20.spec.js +++ b/e2e/specs/confirmations/approve-default-erc20.spec.js @@ -50,7 +50,7 @@ describe(SmokeConfirmations('ERC20 tokens'), () => { await TestDApp.navigateToTestDappWithContract({ contractAddress: hstAddress, }); - await TestDApp.tapApproveButton(); + await TestDApp.tapApproveERC20TokensButton(); await Assertions.checkIfVisible( ContractApprovalBottomSheet.approveTokenAmount, diff --git a/e2e/specs/confirmations/approve-erc721.spec.js b/e2e/specs/confirmations/approve-erc721.spec.js new file mode 100644 index 00000000000..d06a16d4909 --- /dev/null +++ b/e2e/specs/confirmations/approve-erc721.spec.js @@ -0,0 +1,61 @@ +'use strict'; + +import { SmokeConfirmations } from '../../tags'; +import TestHelpers from '../../helpers'; +import { loginToApp } from '../../viewHelper'; + +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import TestDApp from '../../pages/Browser/TestDApp'; +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { + withFixtures, + defaultGanacheOptions, +} from '../../fixtures/fixture-helper'; +import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; +import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; +import Assertions from '../../utils/Assertions'; + +describe(SmokeConfirmations('ERC721 tokens'), () => { + const NFT_CONTRACT = SMART_CONTRACTS.NFTS; + + beforeAll(async () => { + jest.setTimeout(150000); + await TestHelpers.reverseServerPort(); + }); + + it('approve an ERC721 token from a dapp', async () => { + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder() + .withGanacheNetwork() + .withPermissionControllerConnectedToTestDapp() + .build(), + restartDevice: true, + ganacheOptions: defaultGanacheOptions, + smartContract: NFT_CONTRACT, + }, + async ({ contractRegistry }) => { + const nftsAddress = await contractRegistry.getContractAddress( + NFT_CONTRACT, + ); + await loginToApp(); + // Navigate to the browser screen + await TabBarComponent.tapBrowser(); + await TestDApp.navigateToTestDappWithContract({ + contractAddress: nftsAddress, + }); + // Approve NFT + await TestDApp.tapApproveERC721TokenButton(); + await TestHelpers.delay(3000); + await TestDApp.tapApproveButton(); + // Navigate to the activity screen + await TabBarComponent.tapActivity(); + // Assert NFT is approved + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.CONFIRM_TEXT, + ); + }, + ); + }); +}); From d2b2b1a14821e54e8d599b10e86b204da3b7706f Mon Sep 17 00:00:00 2001 From: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:09:46 +0300 Subject: [PATCH 02/41] chore: update js.env.example to include examples of chain permissions to true (#12791) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Inluding an example of multichain permissions feature to true in js.env.example ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .js.env.example | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.js.env.example b/.js.env.example index 56c7c1bb865..325ee52559d 100644 --- a/.js.env.example +++ b/.js.env.example @@ -97,7 +97,10 @@ export MM_ENABLE_SETTINGS_PAGE_DEV_OPTIONS="true" # Per dapp selected network (Amon Hen) feature flag export MM_PER_DAPP_SELECTED_NETWORK="" -export MM_CHAIN_PERMISSIONS="" +# Multichain permissions now set to true in production via the CI +# MM_MULTICHAIN_V1_ENABLED is the UI, and MM_CHAIN_PERMISSIONS is the engine +export MM_MULTICHAIN_V1_ENABLED="true" +export MM_CHAIN_PERMISSIONS="true" # Multichain feature flag specific to UI changes export MM_MULTICHAIN_V1_ENABLED="" From dd81987146e2ca66df0f3237eb1a1242ee2c0669 Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Thu, 19 Dec 2024 14:10:25 +0100 Subject: [PATCH 03/41] fix: set default selectedNetworkClientId to 'mainnet' if no matching with entry on network list (#12227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR implements a fix for Migration 60 to handle cases where selectedNetworkClientId does not match any entry within networkConfigurationsByChainId. If no corresponding networkClientId is found, the migration will now set selectedNetworkClientId to 'mainnet' by default. ## **Related issues** Fixes: [#11657](https://github.com/MetaMask/metamask-mobile/issues/11657) ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/store/migrations/064.test.ts | 173 +++++++++++++++++++++++++++++++ app/store/migrations/064.ts | 167 +++++++++++++++++++++++++++++ app/store/migrations/index.ts | 2 + 3 files changed, 342 insertions(+) create mode 100644 app/store/migrations/064.test.ts create mode 100644 app/store/migrations/064.ts diff --git a/app/store/migrations/064.test.ts b/app/store/migrations/064.test.ts new file mode 100644 index 00000000000..680fe4fc378 --- /dev/null +++ b/app/store/migrations/064.test.ts @@ -0,0 +1,173 @@ +import migration from './064'; +import { merge } from 'lodash'; +import initialRootState from '../../util/test/initial-root-state'; +import { captureException } from '@sentry/react-native'; +import { RootState } from '../../reducers'; + +const oldState = { + engine: { + backgroundState: { + NetworkController: { + selectedNetworkClientId: 'unknown-client-id', + networkConfigurationsByChainId: { + '0x1': { + rpcEndpoints: [{ networkClientId: 'mainnet' }], + }, + '0x5': { + rpcEndpoints: [{ networkClientId: 'goerli' }], + }, + }, + }, + }, + }, +}; + +const expectedNewState = { + engine: { + backgroundState: { + NetworkController: { + selectedNetworkClientId: 'mainnet', + networkConfigurationsByChainId: { + '0x1': { + rpcEndpoints: [{ networkClientId: 'mainnet' }], + }, + '0x5': { + rpcEndpoints: [{ networkClientId: 'goerli' }], + }, + }, + }, + }, + }, +}; + +jest.mock('@sentry/react-native', () => ({ + captureException: jest.fn(), +})); +const mockedCaptureException = jest.mocked(captureException); + +describe('Migration #64', () => { + beforeEach(() => { + jest.restoreAllMocks(); + jest.resetAllMocks(); + }); + + const invalidStates = [ + { + state: merge({}, initialRootState, { + engine: { + backgroundState: { + NetworkController: null, + }, + }, + }), + errorMessage: + "Migration 64: Invalid or missing 'NetworkController' in backgroundState: 'object'", + scenario: 'NetworkController state is invalid', + }, + { + state: merge({}, initialRootState, { + engine: { + backgroundState: { + NetworkController: { networkConfigurationsByChainId: null }, + }, + }, + }), + errorMessage: + "Migration 64: Missing or invalid 'networkConfigurationsByChainId' in NetworkController", + scenario: 'networkConfigurationsByChainId is invalid', + }, + ]; + + for (const { errorMessage, scenario, state } of invalidStates) { + it(`should capture exception if ${scenario}`, async () => { + const newState = await migration(state); + + expect(newState).toStrictEqual(state); + expect(mockedCaptureException).toHaveBeenCalledWith(expect.any(Error)); + expect(mockedCaptureException.mock.calls[0][0].message).toBe( + errorMessage, + ); + }); + } + + it('should set selectedNetworkClientId to "mainnet" if it does not exist in networkConfigurationsByChainId', async () => { + const newState = await migration(oldState); + expect(newState).toStrictEqual(expectedNewState); + }); + + it('should keep selectedNetworkClientId unchanged if it exists in networkConfigurationsByChainId', async () => { + const validState = merge({}, oldState, { + engine: { + backgroundState: { + NetworkController: { + selectedNetworkClientId: 'mainnet', + }, + }, + }, + }); + const newState = await migration(validState); + + expect(newState).toStrictEqual(validState); + }); + + it('should set selectedNetworkClientId to the default mainnet client ID if mainnet configuration exists but selectedNetworkClientId is invalid', async () => { + const invalidClientState = merge({}, oldState, { + engine: { + backgroundState: { + NetworkController: { + selectedNetworkClientId: 'invalid-client-id', + }, + }, + }, + }); + + const newState = await migration(invalidClientState); + expect( + (newState as RootState).engine.backgroundState.NetworkController + .selectedNetworkClientId, + ).toBe('mainnet'); + }); + + it('should handle the absence of mainnet configuration gracefully', async () => { + const noMainnetState = merge({}, oldState, { + engine: { + backgroundState: { + NetworkController: { + networkConfigurationsByChainId: { + '0x1': { + chainId: '0x1', + defaultRpcEndpointIndex: 0, + rpcEndpoints: [{ networkClientId: 'another-mainnet' }], + }, + '0x5': { + rpcEndpoints: [{ networkClientId: 'goerli' }], + }, + }, + selectedNetworkClientId: 'unknown-client-id', + }, + }, + }, + }); + + const newState = await migration(noMainnetState); + expect( + (newState as RootState).engine.backgroundState.NetworkController + .selectedNetworkClientId, + ).toBe('another-mainnet'); + }); + + it('should not modify the state if it is already valid', async () => { + const validState = merge({}, oldState, { + engine: { + backgroundState: { + NetworkController: { + selectedNetworkClientId: 'mainnet', + }, + }, + }, + }); + + const newState = await migration(validState); + expect(newState).toStrictEqual(validState); + }); +}); diff --git a/app/store/migrations/064.ts b/app/store/migrations/064.ts new file mode 100644 index 00000000000..048fcbb341c --- /dev/null +++ b/app/store/migrations/064.ts @@ -0,0 +1,167 @@ +import { captureException } from '@sentry/react-native'; +import { isObject, hasProperty, Hex } from '@metamask/utils'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import { + NetworkClientId, + NetworkConfiguration, + NetworkState, +} from '@metamask/network-controller'; +import { ensureValidState } from './util'; +import { RootState } from '../../reducers'; + +/** + * This migration checks if `selectedNetworkClientId` exists in any entry within `networkConfigurationsByChainId`. + * If it does not, or if `selectedNetworkClientId` is undefined or invalid, it sets `selectedNetworkClientId` to `'mainnet'`. + * @param {unknown} stateAsync - Redux state. + * @returns Migrated Redux state. + */ +export default async function migrate(stateAsync: unknown) { + const migrationVersion = 64; + const mainnetChainId = CHAIN_IDS.MAINNET; + + const state = await stateAsync; + + if (!ensureValidState(state, migrationVersion)) { + return state; + } + + const networkControllerState = state.engine.backgroundState + .NetworkController as NetworkState; + + if ( + !isValidNetworkControllerState( + networkControllerState, + state as RootState, + migrationVersion, + ) + ) { + return state; + } + + const { networkConfigurationsByChainId, selectedNetworkClientId } = + networkControllerState; + + const networkClientIdExists = doesNetworkClientIdExist( + selectedNetworkClientId, + networkConfigurationsByChainId, + migrationVersion, + ); + + const isMainnetRpcExists = isMainnetRpcConfigured( + networkConfigurationsByChainId, + ); + + ensureSelectedNetworkClientId( + networkControllerState, + networkClientIdExists, + isMainnetRpcExists, + networkConfigurationsByChainId, + mainnetChainId, + ); + + return state; +} + +function isValidNetworkControllerState( + networkControllerState: NetworkState, + state: RootState, + migrationVersion: number, +) { + if ( + !isObject(networkControllerState) || + !hasProperty(state.engine.backgroundState, 'NetworkController') + ) { + captureException( + new Error( + `Migration ${migrationVersion}: Invalid or missing 'NetworkController' in backgroundState: '${typeof networkControllerState}'`, + ), + ); + return false; + } + + if ( + !hasProperty(networkControllerState, 'networkConfigurationsByChainId') || + !isObject(networkControllerState.networkConfigurationsByChainId) + ) { + captureException( + new Error( + `Migration ${migrationVersion}: Missing or invalid 'networkConfigurationsByChainId' in NetworkController`, + ), + ); + return false; + } + + return true; +} + +function doesNetworkClientIdExist( + selectedNetworkClientId: NetworkClientId, + networkConfigurationsByChainId: Record, + migrationVersion: number, +) { + for (const chainId in networkConfigurationsByChainId) { + const networkConfig = networkConfigurationsByChainId[chainId as Hex]; + + if ( + isObject(networkConfig) && + hasProperty(networkConfig, 'rpcEndpoints') && + Array.isArray(networkConfig.rpcEndpoints) + ) { + if ( + networkConfig.rpcEndpoints.some( + (endpoint) => + isObject(endpoint) && + hasProperty(endpoint, 'networkClientId') && + endpoint.networkClientId === selectedNetworkClientId, + ) + ) { + return true; + } + } else { + captureException( + new Error( + `Migration ${migrationVersion}: Invalid network configuration or missing 'rpcEndpoints' for chainId: '${chainId}'`, + ), + ); + } + } + + return false; +} + +function isMainnetRpcConfigured( + networkConfigurationsByChainId: Record, +) { + return Object.values(networkConfigurationsByChainId).some((networkConfig) => + networkConfig.rpcEndpoints.some( + (endpoint) => endpoint.networkClientId === 'mainnet', + ), + ); +} + +function ensureSelectedNetworkClientId( + networkControllerState: NetworkState, + networkClientIdExists: boolean, + isMainnetRpcExists: boolean, + networkConfigurationsByChainId: Record, + mainnetChainId: Hex, +) { + const setDefaultMainnetClientId = () => { + networkControllerState.selectedNetworkClientId = isMainnetRpcExists + ? 'mainnet' + : networkConfigurationsByChainId[mainnetChainId].rpcEndpoints[ + networkConfigurationsByChainId[mainnetChainId].defaultRpcEndpointIndex + ].networkClientId; + }; + + if ( + !hasProperty(networkControllerState, 'selectedNetworkClientId') || + typeof networkControllerState.selectedNetworkClientId !== 'string' + ) { + setDefaultMainnetClientId(); + } + + if (!networkClientIdExists) { + setDefaultMainnetClientId(); + } +} diff --git a/app/store/migrations/index.ts b/app/store/migrations/index.ts index 06f50319276..44ef0d4f7d2 100644 --- a/app/store/migrations/index.ts +++ b/app/store/migrations/index.ts @@ -64,6 +64,7 @@ import migration60 from './060'; import migration61 from './061'; import migration62 from './062'; import migration63 from './063'; +import migration64 from './064'; type MigrationFunction = (state: unknown) => unknown; type AsyncMigrationFunction = (state: unknown) => Promise; @@ -140,6 +141,7 @@ export const migrationList: MigrationsList = { 61: migration61, 62: migration62, 63: migration63, + 64: migration64, }; // Enable both synchronous and asynchronous migrations From 425669e99d92bc0a5a9a8471ade3f3ebe35595ae Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Thu, 19 Dec 2024 15:01:50 +0100 Subject: [PATCH 04/41] fix: set token network filter when adding network from dapp (#12661) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** PR to setTokenNetworkFilter value when user is adding a new network from dapp ## **Related issues** Fixes: ## **Manual testing steps** 1. Click on current network 2. Add new network from chainlist 3. Confirm switching to this network 4. Go back to wallet and you should see your new network with the correct token list ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/03b43fd3-239e-47e5-a419-2c87a76e84d5 ### **After** https://github.com/user-attachments/assets/c11c4fb4-396f-4db9-b359-2c91108a0b42 ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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: Daniel Cross --- .../SwitchChainApproval.test.tsx | 39 +++++++++++++++++++ .../SwitchChainApproval.tsx | 25 +++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.test.tsx b/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.test.tsx index 4630f1984cc..1b1483b2dcc 100644 --- a/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.test.tsx +++ b/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.test.tsx @@ -5,13 +5,26 @@ import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; import { ApprovalRequest } from '@metamask/approval-controller'; import SwitchChainApproval from './SwitchChainApproval'; import { networkSwitched } from '../../../actions/onboardNetwork'; +// eslint-disable-next-line import/no-namespace +import * as networks from '../../../util/networks'; +import Engine from '../../../core/Engine'; +const { PreferencesController } = Engine.context; jest.mock('../../Views/confirmations/hooks/useApprovalRequest'); jest.mock('../../../actions/onboardNetwork'); +jest.mock('../../../core/Engine', () => ({ + context: { + PreferencesController: { + setTokenNetworkFilter: jest.fn(), + }, + }, +})); + jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), useDispatch: () => jest.fn(), + useSelector: jest.fn(), })); const URL_MOCK = 'test.com'; @@ -32,6 +45,7 @@ const mockApprovalRequest = (approvalRequest?: ApprovalRequest) => { describe('SwitchChainApproval', () => { beforeEach(() => { jest.resetAllMocks(); + jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(false); }); it('renders', () => { @@ -81,4 +95,29 @@ describe('SwitchChainApproval', () => { networkStatus: true, }); }); + + it('invokes network switched on confirm when portfolio view is enabled', () => { + jest.spyOn(networks, 'isPortfolioViewEnabled').mockReturnValue(true); + const tokenNetworkFilterSpy = jest.spyOn( + PreferencesController, + 'setTokenNetworkFilter', + ); + mockApprovalRequest({ + type: ApprovalTypes.SWITCH_ETHEREUM_CHAIN, + requestData: { + rpcUrl: URL_MOCK, + }, + } as ApprovalRequest<{ + rpcUrl: string; + }>); + + const wrapper = shallow(); + wrapper.find('SwitchCustomNetwork').simulate('confirm'); + expect(tokenNetworkFilterSpy).toHaveBeenCalledTimes(1); + expect(networkSwitched).toHaveBeenCalledTimes(1); + expect(networkSwitched).toHaveBeenCalledWith({ + networkUrl: URL_MOCK, + networkStatus: true, + }); + }); }); diff --git a/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.tsx b/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.tsx index 9a3310addf9..ff4a9814ce1 100644 --- a/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.tsx +++ b/app/components/Approvals/SwitchChainApproval/SwitchChainApproval.tsx @@ -4,7 +4,11 @@ import { ApprovalTypes } from '../../../core/RPCMethods/RPCMethodMiddleware'; import ApprovalModal from '../ApprovalModal'; import SwitchCustomNetwork from '../../UI/SwitchCustomNetwork'; import { networkSwitched } from '../../../actions/onboardNetwork'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; +import Engine from '../../../core/Engine'; +import { selectIsAllNetworks } from '../../../selectors/networkController'; +import { selectTokenNetworkFilter } from '../../../selectors/preferencesController'; +import { isPortfolioViewEnabled } from '../../../util/networks'; const SwitchChainApproval = () => { const { @@ -15,17 +19,34 @@ const SwitchChainApproval = () => { } = useApprovalRequest(); const dispatch = useDispatch(); + const isAllNetworks = useSelector(selectIsAllNetworks); + const tokenNetworkFilter = useSelector(selectTokenNetworkFilter); const onConfirm = useCallback(() => { defaultOnConfirm(); + // If portfolio view is enabled should set network filter + if (isPortfolioViewEnabled()) { + const { PreferencesController } = Engine.context; + PreferencesController.setTokenNetworkFilter({ + ...(isAllNetworks ? tokenNetworkFilter : {}), + [approvalRequest?.requestData?.chainId]: true, + }); + } + dispatch( networkSwitched({ networkUrl: approvalRequest?.requestData?.rpcUrl, networkStatus: true, }), ); - }, [approvalRequest, defaultOnConfirm, dispatch]); + }, [ + approvalRequest, + defaultOnConfirm, + dispatch, + isAllNetworks, + tokenNetworkFilter, + ]); if (approvalRequest?.type !== ApprovalTypes.SWITCH_ETHEREUM_CHAIN) return null; From 48a86c7c535111a1c7f33cecaa179d6eb354a90d Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Thu, 19 Dec 2024 15:12:02 +0100 Subject: [PATCH 05/41] fix: filter token activity when clicking on native token (#12732) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR filters out token related activity from activity list when clicking on a native token. ## **Related issues** Fixes: https://github.com/MetaMask/metamask-mobile/issues/6164 ## **Manual testing steps** 1. Create an ERC20 token 2. Add the new token to your wallet 3. Send some tokens to another wallet 4. Send ETH to another account 5. Click on the native token and scroll down to see activity, you should not see ERC2O related activity 6. Click on the token; you should see the activity related to token ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/ceb7f311-6163-4bb1-ba4e-1a29255b83a6 ### **After** https://github.com/user-attachments/assets/66827a01-6ce5-4c7b-9d93-8a9c551ad830 ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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: salimtb --- app/components/UI/TransactionElement/utils.js | 13 ++- app/components/Views/Asset/index.js | 11 ++- app/components/Views/Asset/index.test.js | 82 ++++++++++++++++++- 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/app/components/UI/TransactionElement/utils.js b/app/components/UI/TransactionElement/utils.js index 22b0e562005..4f9c30e6bbc 100644 --- a/app/components/UI/TransactionElement/utils.js +++ b/app/components/UI/TransactionElement/utils.js @@ -32,7 +32,10 @@ import { swapsUtils } from '@metamask/swaps-controller'; import { isSwapsNativeAsset } from '../Swaps/utils'; import { toLowerCaseEquals } from '../../../util/general'; import Engine from '../../../core/Engine'; -import { isEIP1559Transaction } from '@metamask/transaction-controller'; +import { + isEIP1559Transaction, + TransactionType, +} from '@metamask/transaction-controller'; const { getSwapsContractAddress } = swapsUtils; @@ -920,3 +923,11 @@ export default async function decodeTransaction(args) { } return [transactionElement, transactionDetails]; } + +export const TOKEN_CATEGORY_HASH = { + [TransactionType.tokenMethodApprove]: true, + [TransactionType.tokenMethodSetApprovalForAll]: true, + [TransactionType.tokenMethodTransfer]: true, + [TransactionType.tokenMethodTransferFrom]: true, + [TransactionType.tokenMethodIncreaseAllowance]: true, +}; diff --git a/app/components/Views/Asset/index.js b/app/components/Views/Asset/index.js index 4610949677e..65e1fa1341c 100644 --- a/app/components/Views/Asset/index.js +++ b/app/components/Views/Asset/index.js @@ -61,6 +61,7 @@ import { withMetricsAwareness } from '../../../components/hooks/useMetrics'; import { store } from '../../../store'; import { toChecksumHexAddress } from '@metamask/controller-utils'; import { selectSwapsTransactions } from '../../../selectors/transactionController'; +import { TOKEN_CATEGORY_HASH } from '../../UI/TransactionElement/utils'; const createStyles = (colors) => StyleSheet.create({ @@ -248,6 +249,7 @@ class Asset extends PureComponent { }); this.navSymbol = (this.props.route.params?.symbol ?? '').toLowerCase(); this.navAddress = (this.props.route.params?.address ?? '').toLowerCase(); + if (this.navSymbol.toUpperCase() !== 'ETH' && this.navAddress !== '') { this.filter = this.noEthFilter; } else { @@ -287,6 +289,7 @@ class Asset extends PureComponent { txParams: { from, to }, isTransfer, transferInformation, + type, } = tx; if ( @@ -295,10 +298,15 @@ class Asset extends PureComponent { (chainId === tx.chainId || (!tx.chainId && networkId === tx.networkID)) && tx.status !== 'unapproved' ) { - if (isTransfer) + if (TOKEN_CATEGORY_HASH[type]) { + return false; + } + if (isTransfer) { return this.props.tokens.find(({ address }) => toLowerCaseEquals(address, transferInformation.contractAddress), ); + } + return true; } return false; @@ -493,7 +501,6 @@ class Asset extends PureComponent { const displayBuyButton = asset.isETH ? this.props.isNetworkBuyNativeTokenSupported : this.props.isNetworkRampSupported; - return ( {loading ? ( diff --git a/app/components/Views/Asset/index.test.js b/app/components/Views/Asset/index.test.js index a7461510901..c67129f7409 100644 --- a/app/components/Views/Asset/index.test.js +++ b/app/components/Views/Asset/index.test.js @@ -1,10 +1,25 @@ import React from 'react'; +import { TransactionType } from '@metamask/transaction-controller'; import renderWithProvider from '../../../util/test/renderWithProvider'; import { backgroundState } from '../../../util/test/initial-root-state'; import Asset from './'; import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../util/test/accountsControllerTestUtils'; const mockInitialState = { + swaps: { '0x1': { isLive: true }, hasOnboarded: false, isLive: true }, + fiatOrders: { + networks: [ + { + active: true, + chainId: '1', + chainName: 'Ethereum Mainnet', + nativeTokenSupported: true, + }, + ], + }, + inpageProvider: { + networkId: '0x1', + }, engine: { backgroundState: { ...backgroundState, @@ -16,10 +31,58 @@ const mockInitialState = { }, }, }, + NetworkController: { + selectedNetworkClientId: 'selectedNetworkClientId', + networkConfigurationsByChainId: { + '0x1': { + chainId: '0x1', + rpcEndpoints: [ + { + networkClientId: 'selectedNetworkClientId', + }, + ], + defaultRpcEndpointIndex: 0, + defaultBlockExplorerUrl: 0, + blockExplorerUrls: ['https://block.com'], + }, + '0x89': { + chainId: '0x89', + rpcEndpoints: [ + { + networkClientId: 'otherNetworkClientId', + }, + ], + defaultRpcEndpointIndex: 0, + }, + }, + }, + TransactionController: { + transactions: [ + { + txParams: { + from: '0xC4966c0D659D99699BFD7EB54D8fafEE40e4a756', + to: '0x0000000000000000000000000000000000000000', + }, + hash: '0x3148', + status: 'confirmed', + chainId: '0x1', + networkID: '0x1', + type: TransactionType.simpleSend, + }, + ], + }, }, }, }; +jest.mock('../../../store', () => ({ + store: { + getState: () => mockInitialState, + }, +})); + +jest.unmock('react-native/Libraries/Interaction/InteractionManager'); + jest.mock('../../../core/Engine', () => { const { MOCK_ADDRESS_1, @@ -48,9 +111,8 @@ describe('Asset', () => { it('should render correctly', () => { const { toJSON } = renderWithProvider( null }} + navigation={{ setOptions: jest.fn() }} route={{ params: { symbol: 'ETH', address: 'something', isETH: true } }} - transactions={[]} />, { state: mockInitialState, @@ -58,4 +120,20 @@ describe('Asset', () => { ); expect(toJSON()).toMatchSnapshot(); }); + + it('should call navigation.setOptions on mount', () => { + const mockSetOptions = jest.fn(); + renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + expect(mockSetOptions).toHaveBeenCalled(); + }); }); From f96fb4ea2eeaaf14226d7479c0e9257151047eb2 Mon Sep 17 00:00:00 2001 From: tommasini <46944231+tommasini@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:10:14 +0000 Subject: [PATCH 06/41] chore: remove duplicated dependencies (#12722) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** remove eth-json-rpc-filters and eth-json-rpc-middleware duplicated deps ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- package.json | 2 - yarn.lock | 114 +++++---------------------------------------------- 2 files changed, 10 insertions(+), 106 deletions(-) diff --git a/package.json b/package.json index db621739117..be591d65c21 100644 --- a/package.json +++ b/package.json @@ -162,8 +162,6 @@ "@metamask/eth-json-rpc-filters": "^9.0.0", "@metamask/eth-json-rpc-middleware": "^15.0.0", "@metamask/eth-hd-keyring": "^9.0.0", - "@metamask/eth-json-rpc-filters": "^8.0.0", - "@metamask/eth-json-rpc-middleware": "^11.0.2", "@metamask/eth-ledger-bridge-keyring": "^8.0.0", "@metamask/eth-query": "^4.0.0", "@metamask/eth-sig-util": "^8.0.0", diff --git a/yarn.lock b/yarn.lock index 1b9e5218c5a..d3ab8f8bdbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4360,14 +4360,6 @@ resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.8.0.tgz#fc32e07746689459c4b049dc581d1dbda5545686" integrity sha512-+70fkgjhVJeJ+nJqnburIM3UAsfvxat1Low9HMPobLbv64FIdB4Nzu5ct3qojNQ58r5sK01tg5UoFIJYslaVrg== -"@metamask/abi-utils@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-1.2.0.tgz#068e1b0f5e423dfae96961e0e5276a7c1babc03a" - integrity sha512-Hf7fnBDM9ptCPDtq/wQffWbw859CdVGMwlpWUEsTH6gLXhXONGrRXHA2piyYPRuia8YYTdJvRC/zSK1/nyLvYg== - dependencies: - "@metamask/utils" "^3.4.1" - superstruct "^1.0.3" - "@metamask/abi-utils@^2.0.3", "@metamask/abi-utils@^2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.4.tgz#20908c1d910f7a17a89fdf5778a5c59d5cb8b8be" @@ -4555,13 +4547,13 @@ "@metamask/utils" "^9.2.1" ethereum-cryptography "^2.1.2" -"@metamask/eth-json-rpc-filters@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-filters/-/eth-json-rpc-filters-8.0.0.tgz#fd0ca224dc198e270e142c1f2007e05cacb5f16a" - integrity sha512-kDwSoas8gYWtN79AO4vvyKvaL8bIMstpuwZdsWTSc1goBFTOJEscCD6zUX+MOQFnQohFoC512mNeA5tPLRV46A== +"@metamask/eth-json-rpc-filters@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-filters/-/eth-json-rpc-filters-9.0.0.tgz#9efe770d12f7d1d8289d9f2ed601911c642c31b9" + integrity sha512-mn3clrrNF1zl3E729IgNHV9ia6wvRl+eRwc98e38GM+Se2EcDqBvx1oa9e3oo6BTlqmzzIwdeTvF4/jHU1CDWQ== dependencies: "@metamask/eth-query" "^4.0.0" - "@metamask/json-rpc-engine" "^9.0.0" + "@metamask/json-rpc-engine" "^10.0.0" "@metamask/safe-event-emitter" "^3.0.0" async-mutex "^0.5.0" pify "^5.0.0" @@ -4576,21 +4568,6 @@ "@metamask/rpc-errors" "^7.0.0" "@metamask/utils" "^9.1.0" -"@metamask/eth-json-rpc-middleware@^11.0.2": - version "11.0.2" - resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-middleware/-/eth-json-rpc-middleware-11.0.2.tgz#85e6639f5d159a3277d13609dea9f12ebfb5b4e8" - integrity sha512-/HqtuK/6E8sIJmzg0O3Ey5JsgK6O/VbDqg5R9thHFQMi9EtKXnnZFc8Blir7IOQraGVJFiZQIKZMHRTNQRyreg== - dependencies: - "@metamask/eth-json-rpc-provider" "^1.0.0" - "@metamask/eth-sig-util" "^6.0.0" - "@metamask/utils" "^5.0.1" - clone "^2.1.1" - eth-block-tracker "^7.0.1" - eth-rpc-errors "^4.0.3" - json-rpc-engine "^6.1.0" - pify "^3.0.0" - safe-stable-stringify "^2.3.2" - "@metamask/eth-json-rpc-middleware@^15.0.0": version "15.0.0" resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-middleware/-/eth-json-rpc-middleware-15.0.0.tgz#167288ad4618438af9d1bda75d238cb0facfde3f" @@ -4608,15 +4585,6 @@ pify "^5.0.0" safe-stable-stringify "^2.4.3" -"@metamask/eth-json-rpc-provider@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz#3fd5316c767847f4ca107518b611b15396a5a32c" - integrity sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA== - dependencies: - "@metamask/json-rpc-engine" "^7.0.0" - "@metamask/safe-event-emitter" "^3.0.0" - "@metamask/utils" "^5.0.1" - "@metamask/eth-json-rpc-provider@^4.1.5", "@metamask/eth-json-rpc-provider@^4.1.6": version "4.1.6" resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-4.1.6.tgz#5d86ee7db6ff94b0abe1f00ef02aeffa60536497" @@ -4648,19 +4616,6 @@ json-rpc-random-id "^1.0.0" xtend "^4.0.1" -"@metamask/eth-sig-util@^6.0.0": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-6.0.2.tgz#d81dc87e0cd5a6580010911501976b48821746ad" - integrity sha512-D6IIefM2vS+4GUGGtezdBbkwUYQC4bCosYx/JteUuF0zfe6lyxR4cruA8+2QHoUg7F7edNH1xymYpqYq1BeOkw== - dependencies: - "@ethereumjs/util" "^8.1.0" - "@metamask/abi-utils" "^1.2.0" - "@metamask/utils" "^5.0.2" - ethereum-cryptography "^2.1.2" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" - "@metamask/eth-sig-util@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-7.0.3.tgz#be9e444fe0b8474c04e2ff42fd983173767f6ac0" @@ -4801,15 +4756,6 @@ "@metamask/safe-event-emitter" "^3.0.0" "@metamask/utils" "^10.0.0" -"@metamask/json-rpc-engine@^7.0.0": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.3.tgz#f2b30a2164558014bfcca45db10f5af291d989af" - integrity sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg== - dependencies: - "@metamask/rpc-errors" "^6.2.1" - "@metamask/safe-event-emitter" "^3.0.0" - "@metamask/utils" "^8.3.0" - "@metamask/json-rpc-engine@^8.0.1": version "8.0.2" resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-8.0.2.tgz#29510a871a8edef892f838ee854db18de0bf0d14" @@ -4819,15 +4765,6 @@ "@metamask/safe-event-emitter" "^3.0.0" "@metamask/utils" "^8.3.0" -"@metamask/json-rpc-engine@^9.0.0": - version "9.0.3" - resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-9.0.3.tgz#491eb6085b63b040979d4c65f2a01107d22a162a" - integrity sha512-efeRXW7KaL0BJcAeudSGhzu6sD3hMpxx9nl3V+Yemm1bsyc66yVUhYPR+XH+Y6ZvB2p05ywgvd1Ev5PBwFzr/g== - dependencies: - "@metamask/rpc-errors" "^6.3.1" - "@metamask/safe-event-emitter" "^3.0.0" - "@metamask/utils" "^9.1.0" - "@metamask/json-rpc-middleware-stream@^7.0.1": version "7.0.1" resolved "https://registry.yarnpkg.com/@metamask/json-rpc-middleware-stream/-/json-rpc-middleware-stream-7.0.1.tgz#3e10c93c88507b1a55eea5d125ebf87db0f8fead" @@ -5200,7 +5137,7 @@ "@metamask/utils" "^10.0.0" cockatiel "^3.1.2" -"@metamask/rpc-errors@7.0.1", "@metamask/rpc-errors@^6.2.1", "@metamask/rpc-errors@^6.3.1", "@metamask/rpc-errors@^7.0.0", "@metamask/rpc-errors@^7.0.1": +"@metamask/rpc-errors@7.0.1", "@metamask/rpc-errors@^6.2.1", "@metamask/rpc-errors@^7.0.0", "@metamask/rpc-errors@^7.0.1": version "7.0.1" resolved "https://registry.yarnpkg.com/@metamask/rpc-errors/-/rpc-errors-7.0.1.tgz#0eb2231a1d5e6bb102df5ac07f365c695bf70055" integrity sha512-EeQGYioq845w2iBmiR9LHYqHhYIaeDTmxprHpPE3BTlkLB74P0xLv/TivOn4snNLowiC5ekOXfcUzCQszTDmSg== @@ -5470,7 +5407,7 @@ lodash "^4.17.21" uuid "^8.3.2" -"@metamask/utils@^10.0.0", "@metamask/utils@^10.0.1", "@metamask/utils@^3.4.1", "@metamask/utils@^5.0.1", "@metamask/utils@^5.0.2", "@metamask/utils@^8.2.0", "@metamask/utils@^8.3.0", "@metamask/utils@^9.0.0", "@metamask/utils@^9.1.0", "@metamask/utils@^9.2.1": +"@metamask/utils@^10.0.0", "@metamask/utils@^10.0.1", "@metamask/utils@^8.2.0", "@metamask/utils@^8.3.0", "@metamask/utils@^9.0.0", "@metamask/utils@^9.1.0", "@metamask/utils@^9.2.1": version "10.0.1" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-10.0.1.tgz#a765f96c20e35fc51c068fb9f88a3332b40b215e" integrity sha512-zHgAitJtRwviVVFnRUA2PLRMaAwatr3jiHgiH7mPicJaeSK4ma01aGR4fHy0iy5tlVo1ZiioTmJ1Hbp8FZ6pSg== @@ -13683,7 +13620,7 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= -clone@^2.1.1, clone@^2.1.2: +clone@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== @@ -16346,17 +16283,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eth-block-tracker@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz#dfc16085c6817cc30caabba381deb8d204c1c766" - integrity sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg== - dependencies: - "@metamask/eth-json-rpc-provider" "^1.0.0" - "@metamask/safe-event-emitter" "^3.0.0" - "@metamask/utils" "^5.0.1" - json-rpc-random-id "^1.0.1" - pify "^3.0.0" - eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" @@ -16388,13 +16314,6 @@ eth-phishing-detect@^1.2.0: dependencies: fast-levenshtein "^2.0.6" -eth-rpc-errors@^4.0.2, eth-rpc-errors@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" - integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg== - dependencies: - fast-safe-stringify "^2.0.6" - eth-url-parser@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/eth-url-parser/-/eth-url-parser-1.0.4.tgz#310a99f331abdb8d603c74131568fb773e609cd8" @@ -16620,7 +16539,7 @@ ethjs-util@0.1.3: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: +ethjs-util@0.1.6, ethjs-util@^0.1.3: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -20428,14 +20347,6 @@ json-pointer@^0.6.2: dependencies: foreach "^2.0.4" -json-rpc-engine@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" - integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - eth-rpc-errors "^4.0.2" - json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" @@ -26124,7 +26035,7 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1, safe-stable-stringify@^2.3.2, safe-stable-stringify@^2.4.3: +safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1, safe-stable-stringify@^2.4.3: version "2.5.0" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== @@ -27949,11 +27860,6 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" From 9708fe6ec853fa7b13fb546af8d2806b941e889b Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Thu, 19 Dec 2024 16:20:37 +0100 Subject: [PATCH 07/41] fix: fix swap flow (#12788) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** ## **Related issues** Fixes: #12757 ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/480510e9-b2fe-4e92-9bd0-3a30d0d2ae07 ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .../Asset/__snapshots__/index.test.js.snap | 39 ++++++++++++++++++ app/components/Views/Asset/index.js | 40 +++++++++++++++++- app/components/Views/Asset/index.test.js | 41 ++++++++++++++++++- 3 files changed, 116 insertions(+), 4 deletions(-) diff --git a/app/components/Views/Asset/__snapshots__/index.test.js.snap b/app/components/Views/Asset/__snapshots__/index.test.js.snap index 627aedf5a32..333565b0718 100644 --- a/app/components/Views/Asset/__snapshots__/index.test.js.snap +++ b/app/components/Views/Asset/__snapshots__/index.test.js.snap @@ -1,5 +1,44 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Asset should not display swaps button if the asset is not allowed 1`] = ` + + + + + + + +`; + exports[`Asset should render correctly 1`] = ` @@ -169,6 +172,10 @@ class Asset extends PureComponent { * Boolean that indicates if native token is supported to buy */ isNetworkBuyNativeTokenSupported: PropTypes.bool, + /** + * Function to set the swaps liveness + */ + setLiveness: PropTypes.func, }; state = { @@ -241,8 +248,27 @@ class Asset extends PureComponent { this.updateNavBar(contentOffset); }; + checkLiveness = async (chainId) => { + try { + const featureFlags = await swapsUtils.fetchSwapsFeatureFlags( + getFeatureFlagChainId(chainId), + AppConstants.SWAPS.CLIENT_ID, + ); + this.props.setLiveness(chainId, featureFlags); + } catch (error) { + Logger.error(error, 'Swaps: error while fetching swaps liveness'); + this.props.setLiveness(chainId, null); + } + }; + componentDidMount() { this.updateNavBar(); + + const tokenChainId = this.props.route?.params?.chainId; + if (tokenChainId) { + this.checkLiveness(tokenChainId); + } + InteractionManager.runAfterInteractions(() => { this.normalizeTransactions(); this.mounted = true; @@ -490,7 +516,9 @@ class Asset extends PureComponent { : isSwapsAllowed(chainId); const isAssetAllowed = - asset.isETH || asset.address?.toLowerCase() in this.props.swapsTokens; + asset.isETH || + asset.isNative || + asset.address?.toLowerCase() in this.props.swapsTokens; const displaySwapsButton = isSwapsFeatureLive && @@ -566,4 +594,12 @@ const mapStateToProps = (state, { route }) => ({ networkClientId: selectNetworkClientId(state), }); -export default connect(mapStateToProps)(withMetricsAwareness(Asset)); +const mapDispatchToProps = (dispatch) => ({ + setLiveness: (chainId, featureFlags) => + dispatch(setSwapsLiveness(chainId, featureFlags)), +}); + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(withMetricsAwareness(Asset)); diff --git a/app/components/Views/Asset/index.test.js b/app/components/Views/Asset/index.test.js index c67129f7409..23ab4e6da7b 100644 --- a/app/components/Views/Asset/index.test.js +++ b/app/components/Views/Asset/index.test.js @@ -1,5 +1,6 @@ import React from 'react'; import { TransactionType } from '@metamask/transaction-controller'; +import { swapsUtils } from '@metamask/swaps-controller/'; import renderWithProvider from '../../../util/test/renderWithProvider'; import { backgroundState } from '../../../util/test/initial-root-state'; import Asset from './'; @@ -112,7 +113,14 @@ describe('Asset', () => { const { toJSON } = renderWithProvider( , { state: mockInitialState, @@ -126,7 +134,14 @@ describe('Asset', () => { renderWithProvider( , { @@ -136,4 +151,26 @@ describe('Asset', () => { expect(mockSetOptions).toHaveBeenCalled(); }); + + it('should not display swaps button if the asset is not allowed', () => { + jest.spyOn(swapsUtils, 'fetchSwapsFeatureFlags').mockRejectedValue('error'); + const { toJSON } = renderWithProvider( + , + { + state: mockInitialState, + }, + ); + + expect(toJSON()).toMatchSnapshot(); + }); }); From d3e0771e37aefb4ed5a23c25e47a801bc3bbb9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n?= Date: Thu, 19 Dec 2024 17:00:31 +0100 Subject: [PATCH 08/41] test: ERC1155 set approval for all e2e (#12774) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR is within the scope of the Quality Quest. We're including an e2e test case to check the set approval for all for ERC1155 in test dApp. **Test steps:** Given I am on the test dapp When I tap on the Set Approval for All button under the ERC 1155 section Then the transaction bottom sheet should appear When I submit the transaction Then the transaction should appear in the transaction history ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- e2e/pages/Browser/TestDApp.js | 13 +++- e2e/selectors/Browser/TestDapp.selectors.js | 3 +- .../set-approval-for-all-erc1155.spec.js | 73 +++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 e2e/specs/confirmations/set-approval-for-all-erc1155.spec.js diff --git a/e2e/pages/Browser/TestDApp.js b/e2e/pages/Browser/TestDApp.js index a09c4b8d5fd..ab411415955 100644 --- a/e2e/pages/Browser/TestDApp.js +++ b/e2e/pages/Browser/TestDApp.js @@ -101,7 +101,7 @@ class TestDApp { get nftSetApprovalForAllButton() { return Matchers.getElementByWebID( BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - TestDappSelectorsWebIDs.SET_APPROVAL_FOR_ALL_BUTTON_ID, + TestDappSelectorsWebIDs.SET_APPROVAL_FOR_ALL_NFT_BUTTON_ID, ); } @@ -112,6 +112,13 @@ class TestDApp { ); } + get erc1155SetApprovalForAllButton() { + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.SET_APPROVAL_FOR_ALL_ERC1155_BUTTON_ID, + ); + } + async connect() { await this.tapButton(this.DappConnectButton); } @@ -162,6 +169,10 @@ class TestDApp { await this.tapButton(this.nftSetApprovalForAllButton); } + async tapERC1155SetApprovalForAllButton() { + await this.tapButton(this.erc1155SetApprovalForAllButton); + } + async tapConfirmButton() { await Gestures.tap(this.confirmButtonText, 0); } diff --git a/e2e/selectors/Browser/TestDapp.selectors.js b/e2e/selectors/Browser/TestDapp.selectors.js index 4407c27a950..4725a436c92 100644 --- a/e2e/selectors/Browser/TestDapp.selectors.js +++ b/e2e/selectors/Browser/TestDapp.selectors.js @@ -6,7 +6,8 @@ export const TestDappSelectorsWebIDs = { INCREASE_ALLOWANCE_BUTTON_ID: 'increaseTokenAllowance', NFT_TRANSFER_FROM_BUTTON_ID: 'transferFromButton', PERSONAL_SIGN: 'personalSign', - SET_APPROVAL_FOR_ALL_BUTTON_ID: 'setApprovalForAllButton', + SET_APPROVAL_FOR_ALL_NFT_BUTTON_ID: 'setApprovalForAllButton', + SET_APPROVAL_FOR_ALL_ERC1155_BUTTON_ID: 'setApprovalForAllERC1155Button', SIGN_TYPE_DATA: 'signTypedData', SIGN_TYPE_DATA_V3: 'signTypedDataV3', SIGN_TYPE_DATA_V4: 'signTypedDataV4', diff --git a/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.js b/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.js new file mode 100644 index 00000000000..8e646db9efd --- /dev/null +++ b/e2e/specs/confirmations/set-approval-for-all-erc1155.spec.js @@ -0,0 +1,73 @@ +'use strict'; + +import { SmokeConfirmations } from '../../tags'; +import TestHelpers from '../../helpers'; +import { loginToApp } from '../../viewHelper'; + +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import TestDApp from '../../pages/Browser/TestDApp'; +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { + withFixtures, + defaultGanacheOptions, +} from '../../fixtures/fixture-helper'; +import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; +import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; +import Assertions from '../../utils/Assertions'; +import { ContractApprovalBottomSheetSelectorsText } from '../../selectors/Browser/ContractApprovalBottomSheet.selectors'; +import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; + +describe(SmokeConfirmations('ERC1155 token'), () => { + const ERC1155_CONTRACT = SMART_CONTRACTS.ERC1155; + + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + it('approve all ERC1155 tokens', async () => { + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder() + .withGanacheNetwork() + .withPermissionControllerConnectedToTestDapp() + .build(), + restartDevice: true, + ganacheOptions: defaultGanacheOptions, + smartContract: ERC1155_CONTRACT, + }, + async ({ contractRegistry }) => { + const erc1155Address = await contractRegistry.getContractAddress( + ERC1155_CONTRACT, + ); + await loginToApp(); + + // Navigate to the browser screen + await TabBarComponent.tapBrowser(); + await TestDApp.navigateToTestDappWithContract({ + contractAddress: erc1155Address, + }); + + // Set approval for all ERC1155 tokens + await TestDApp.tapERC1155SetApprovalForAllButton(); + await Assertions.checkIfTextIsDisplayed( + ContractApprovalBottomSheetSelectorsText.APPROVE, + ); + + // Tap approve button + await ContractApprovalBottomSheet.tapApproveButton(); + + // Navigate to the activity screen + await TabBarComponent.tapActivity(); + + // Assert that the ERC1155 activity is an set approve for all and it is confirmed + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.SET_APPROVAL_FOR_ALL_METHOD, + ); + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.CONFIRM_TEXT, + ); + }, + ); + }); +}); From 77931ab29e4c903b44dc4bef5c0872241ca94857 Mon Sep 17 00:00:00 2001 From: Curtis David Date: Thu, 19 Dec 2024 11:01:17 -0500 Subject: [PATCH 09/41] test: E2E Send to Contract Address (#12777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The purpose of this PR is to add e2e coverage for sending to a contract address. The scenario is as follows: ``` Given I am on the Send View And I input a contract address When I proceed to send the transaction Then the transaction is submitted ``` ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .../Transactions/ActivitiesView.selectors.js | 1 + .../send-to-contract-address.spec.js | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 e2e/specs/confirmations/send-to-contract-address.spec.js diff --git a/e2e/selectors/Transactions/ActivitiesView.selectors.js b/e2e/selectors/Transactions/ActivitiesView.selectors.js index 4327c397700..1aba946d5ec 100644 --- a/e2e/selectors/Transactions/ActivitiesView.selectors.js +++ b/e2e/selectors/Transactions/ActivitiesView.selectors.js @@ -10,6 +10,7 @@ export const ActivitiesViewSelectorsIDs = { export const ActivitiesViewSelectorsText = { CONFIRM_TEXT: enContent.transaction.confirmed, + SMART_CONTRACT_INTERACTION: enContent.transactions.smart_contract_interaction, INCREASE_ALLOWANCE_METHOD: enContent.transactions.increase_allowance, SENT_COLLECTIBLE_MESSAGE_TEXT: enContent.transactions.sent_collectible, SENT_TOKENS_MESSAGE_TEXT: (unit) => getSentUnitMessage(unit), diff --git a/e2e/specs/confirmations/send-to-contract-address.spec.js b/e2e/specs/confirmations/send-to-contract-address.spec.js new file mode 100644 index 00000000000..ddcbad62bc9 --- /dev/null +++ b/e2e/specs/confirmations/send-to-contract-address.spec.js @@ -0,0 +1,70 @@ +'use strict'; + +import { SmokeConfirmations } from '../../tags'; +import AmountView from '../../pages/Send/AmountView'; +import SendView from '../../pages/Send/SendView'; +import TransactionConfirmationView from '../../pages/Send/TransactionConfirmView'; +import { loginToApp } from '../../viewHelper'; +import WalletActionsBottomSheet from '../../pages/wallet/WalletActionsBottomSheet'; + +import TestHelpers from '../../helpers'; +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { + withFixtures, + defaultGanacheOptions, +} from '../../fixtures/fixture-helper'; +import { + SMART_CONTRACTS, + contractConfiguration, +} from '../../../app/util/test/smart-contracts'; +import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; + +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import Assertions from '../../utils/Assertions'; + +const HST_CONTRACT = SMART_CONTRACTS.HST; + +describe(SmokeConfirmations('Send to contract address'), () => { + beforeAll(async () => { + jest.setTimeout(170000); + await TestHelpers.reverseServerPort(); + }); + + it('should send ETH to a contract from inside the wallet', async () => { + const AMOUNT = '12'; + + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder().withGanacheNetwork().build(), + restartDevice: true, + ganacheOptions: defaultGanacheOptions, + smartContract: HST_CONTRACT, + }, + async ({ contractRegistry }) => { + const hstAddress = await contractRegistry.getContractAddress( + HST_CONTRACT, + ); + await loginToApp(); + + await TabBarComponent.tapActions(); + await WalletActionsBottomSheet.tapSendButton(); + + await SendView.inputAddress(hstAddress); + await SendView.tapNextButton(); + + await Assertions.checkIfVisible(AmountView.title); + + await AmountView.typeInTransactionAmount(AMOUNT); + await AmountView.tapNextButton(); + + await TransactionConfirmationView.tapConfirmButton(); + await TabBarComponent.tapActivity(); + + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.SMART_CONTRACT_INTERACTION, + ); + }, + ); + }); +}); From 1670ada53ec51ea2702ea584162bc8416f2fdf18 Mon Sep 17 00:00:00 2001 From: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:03:11 +0100 Subject: [PATCH 10/41] chore: remove duplicate `@metamask/swaps-controller` in `package.json` (#12795) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This pr remove duplicate `@metamask/swaps-controller` in `package.json` ## **Related issues** Fixes: ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index be591d65c21..e27ea614e5e 100644 --- a/package.json +++ b/package.json @@ -209,7 +209,6 @@ "@metamask/swaps-controller": "^11.0.0", "@metamask/transaction-controller": "^42.0.0", "@metamask/utils": "^10.0.1", - "@metamask/swaps-controller": "^11.0.0", "@ngraveio/bc-ur": "^1.1.6", "@notifee/react-native": "^9.0.0", "@react-native-async-storage/async-storage": "^1.23.1", From 7a75c4a12ae4ad1c23fc4e7c6bb6c7feb0b3cd79 Mon Sep 17 00:00:00 2001 From: Amitabh Aggarwal Date: Thu, 19 Dec 2024 12:07:37 -0600 Subject: [PATCH 11/41] fix: improve error handling in staking eligibility hook (#12799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR improves loose error handling in the eligibility hook when Staking API service is not available by moving the check to the existing try catch block. ## **Related issues** Fixes: https://github.com/MetaMask/metamask-mobile/issues/12759 [STAKE-910](https://consensyssoftware.atlassian.net/browse/STAKE-910) ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. [STAKE-910]: https://consensyssoftware.atlassian.net/browse/STAKE-910?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- .../hooks/useStakingEligibility.test.tsx | 29 +++++++++++++++++-- .../UI/Stake/hooks/useStakingEligibility.ts | 12 ++++---- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/app/components/UI/Stake/hooks/useStakingEligibility.test.tsx b/app/components/UI/Stake/hooks/useStakingEligibility.test.tsx index ac3b6739b78..ae15901fd82 100644 --- a/app/components/UI/Stake/hooks/useStakingEligibility.test.tsx +++ b/app/components/UI/Stake/hooks/useStakingEligibility.test.tsx @@ -27,10 +27,13 @@ const mockStakingApiService: Partial = { getPooledStakingEligibility: jest.fn(), }; -const mockSdkContext: Stake = { +const createMockStakeContext = (overrides?: Partial) => ({ setSdkType: jest.fn(), stakingApiService: mockStakingApiService as StakingApiService, -}; + ...overrides, +}); + +let mockSdkContext = createMockStakeContext(); // Mock the context jest.mock('./useStakeContext', () => ({ @@ -38,6 +41,10 @@ jest.mock('./useStakeContext', () => ({ })); describe('useStakingEligibility', () => { + beforeEach(() => { + mockSdkContext = createMockStakeContext(); + }); + afterEach(() => { jest.clearAllMocks(); }); @@ -125,4 +132,22 @@ describe('useStakingEligibility', () => { }); }); }); + + describe('when stakingApiService is undefined', () => { + it('handles undefined stakingApiService gracefully', async () => { + // Override the mock context with undefined stakingApiService + mockSdkContext = createMockStakeContext({ + stakingApiService: undefined, + }); + + const { result } = renderHookWithProvider(() => useStakingEligibility(), { + state: mockInitialState, + }); + + await waitFor(() => { + expect(result.current.isLoadingEligibility).toBe(false); + expect(result.current.isEligible).toBe(false); + }); + }); + }); }); diff --git a/app/components/UI/Stake/hooks/useStakingEligibility.ts b/app/components/UI/Stake/hooks/useStakingEligibility.ts index 6ba2c0add8a..a04f0a4f490 100644 --- a/app/components/UI/Stake/hooks/useStakingEligibility.ts +++ b/app/components/UI/Stake/hooks/useStakingEligibility.ts @@ -19,14 +19,12 @@ const useStakingEligibility = () => { const [error, setError] = useState(null); const fetchStakingEligibility = useCallback(async () => { - if (!stakingApiService) { - throw new Error('Staking API service is unavailable'); - } - - setIsLoading(true); - setError(null); - try { + if (!stakingApiService) { + return { isEligible: false }; + } + setIsLoading(true); + setError(null); const { eligible } = await stakingApiService.getPooledStakingEligibility([ selectedAddress, ]); From 4b9ea55044e8f8744c8185635a96253cf76550f1 Mon Sep 17 00:00:00 2001 From: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:13:53 +0100 Subject: [PATCH 12/41] chore: bump `@metamask/smart-transactions-controller` to `16.0.0` (#12790) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR bumps `@metamask/smart-transactions-controller` to `16.0.0` [CHANGELOG](https://github.com/MetaMask/smart-transactions-controller/blob/main/CHANGELOG.md#1600) - `@metamask/transaction-controller` has been bumped to `42.0.0` which match the current version used in the client. ## **Related issues** Fixes: ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- package.json | 2 +- yarn.lock | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index e27ea614e5e..b6b74ef38a3 100644 --- a/package.json +++ b/package.json @@ -198,7 +198,7 @@ "@metamask/selected-network-controller": "^19.0.0", "@metamask/signature-controller": "^23.1.0", "@metamask/slip44": "^4.1.0", - "@metamask/smart-transactions-controller": "^15.0.0", + "@metamask/smart-transactions-controller": "^16.0.0", "@metamask/snaps-controllers": "^9.15.0", "@metamask/snaps-execution-environments": "^6.10.0", "@metamask/snaps-rpc-methods": "^11.7.0", diff --git a/yarn.lock b/yarn.lock index d3ab8f8bdbc..1c291169aa3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5202,10 +5202,10 @@ resolved "https://registry.yarnpkg.com/@metamask/slip44/-/slip44-4.1.0.tgz#6f2702de7ba64dad3ab6586ea3ac4e5647804b0a" integrity sha512-RQ2MJO0X3QLnJo0rFlb83h2tNAkqqx/VNOPLc3/S2CvY3/cXy3UAEw/xRM/475BeAAkWI93yiIn/FoGUy3E0Ig== -"@metamask/smart-transactions-controller@^15.0.0": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@metamask/smart-transactions-controller/-/smart-transactions-controller-15.0.0.tgz#d9a3c2b3e3b1c5d9ddf68c03c0a537d348119fab" - integrity sha512-IN3mtNDt6YZZBlBn0hk5M+9ShUVD+I4IhAkwbKGp5aom1NdGqVqvl/N0axuhFCqgjBG9JM4zt+orvXIDIhDLXw== +"@metamask/smart-transactions-controller@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@metamask/smart-transactions-controller/-/smart-transactions-controller-16.0.0.tgz#d5f26e3f25945dc695c7e7152f8ab4c9ffa85ac9" + integrity sha512-NfX4yvWlB5MQvkpp+1hsInom1+f0D+xK6b3n/csGJgsDuTWXIS+C3hdYBMS5bpZIrjobFRBG1LH+YQBBsndPHg== dependencies: "@babel/runtime" "^7.24.1" "@ethereumjs/tx" "^5.2.1" @@ -5217,7 +5217,6 @@ "@metamask/eth-query" "^4.0.0" "@metamask/polling-controller" "^12.0.0" bignumber.js "^9.0.1" - events "^3.3.0" fast-json-patch "^3.1.0" lodash "^4.17.21" From 3b17cd311c16742cc3866ac1a23cc35a07465ad0 Mon Sep 17 00:00:00 2001 From: Frank von Hoven <141057783+frankvonhoven@users.noreply.github.com> Date: Thu, 19 Dec 2024 13:29:12 -0600 Subject: [PATCH 13/41] fix: use correct import for MetricsEventBuilder (#12798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Fixes correct import for MetricsEventBuilder ## **Related issues** Fixes: [12530](https://github.com/MetaMask/metamask-mobile/issues/12530) [Related Slack message](https://consensys.slack.com/archives/C8RSKCNCD/p1734622035414719?thread_ts=1734535680.397999&cid=C8RSKCNCD) ## **Manual testing steps** 1. Go to this [dapp ](https://metamask.github.io/metamask-sdk/chore-update-vuejs-build/packages/examples/react-demo/build/index.html)in the inapp browser with a debug build 2. Check the console logs for the dapp 3. Switch chains -> See console ## **Screenshots/Recordings** [Link to zoom recording](https://consensys.zoom.us/rec/share/AJr-gv8tqRuEZx0PorROKgux41aYESIZ3k_PHRMoYTwh6EHIcZU40oliXHa28bYU.wYfZYWsUupmI5hQo) ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/core/RPCMethods/wallet_switchEthereumChain.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/core/RPCMethods/wallet_switchEthereumChain.js b/app/core/RPCMethods/wallet_switchEthereumChain.js index 69a7d85cee4..7d9d3163545 100644 --- a/app/core/RPCMethods/wallet_switchEthereumChain.js +++ b/app/core/RPCMethods/wallet_switchEthereumChain.js @@ -1,6 +1,7 @@ import Engine from '../Engine'; import { providerErrors, rpcErrors } from '@metamask/rpc-errors'; import { MetaMetricsEvents, MetaMetrics } from '../../core/Analytics'; +import { MetricsEventBuilder } from '../../core/Analytics/MetricsEventBuilder'; import { selectNetworkConfigurations } from '../../selectors/networkController'; import { store } from '../../store'; import { @@ -74,8 +75,7 @@ const wallet_switchEthereumChain = async ({ }); MetaMetrics.getInstance().trackEvent( - MetaMetrics.getInstance() - .createEventBuilder(MetaMetricsEvents.NETWORK_SWITCHED) + MetricsEventBuilder.createEventBuilder(MetaMetricsEvents.NETWORK_SWITCHED) .addProperties(analyticsParams) .build(), ); From e9c1617fc00dbfc7c80c1c047fa4998654a8f089 Mon Sep 17 00:00:00 2001 From: OGPoyraz Date: Fri, 20 Dec 2024 08:29:16 +0100 Subject: [PATCH 14/41] fix: Sanitize `signTypedDatav3v4` params before calling security API (#12789) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR aims to filter request params before calling security API call if method is `signTypedDatav3v4` ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3830 ## **Manual testing steps** 1. Use following payload in the local test-dapp sign typed data v3/v4 ``` // Request the current account addresses from the Ethereum provider const addresses = await window.ethereum.request({ "method": "eth_accounts" }); // Construct the JSON string for eth_signTypedData_v4, including the dynamic owner address const jsonData = { domain: { name: "USD Coin", version: "2", chainId: "1", verifyingContract: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, types: { EIP712Domain: [ { name: "name", type: "string" }, { name: "version", type: "string" }, { name: "chainId", type: "uint256" }, { name: "verifyingContract", type: "address" } ], Permit: [ { name: "owner", type: "address" }, { name: "spender", type: "address" }, { name: "value", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" } ] }, primaryType: "Permit", message: { owner: addresses[0], spender: "0xa2d86c5ff6fbf5f455b1ba2737938776c24d7a58", value: "115792089237316195423570985008687907853269984665640564039457584007913129639935", nonce: "0", deadline: "115792089237316195423570985008687907853269984665640564039457584007913129639935" } }; ``` 2. Notice that the transaction is considered as malicious (which was not flagged before) ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [X] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/lib/ppom/ppom-util.test.ts | 42 +++++++++++++++++++++++++++++++++- app/lib/ppom/ppom-util.ts | 27 +++++++++++++++++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/app/lib/ppom/ppom-util.test.ts b/app/lib/ppom/ppom-util.test.ts index 89faa23a585..6d0ab6bc03d 100644 --- a/app/lib/ppom/ppom-util.test.ts +++ b/app/lib/ppom/ppom-util.test.ts @@ -3,7 +3,10 @@ import * as SignatureRequestActions from '../../actions/signatureRequest'; // es import * as TransactionActions from '../../actions/transaction'; // eslint-disable-line import/no-namespace import * as NetworkControllerSelectors from '../../selectors/networkController'; // eslint-disable-line import/no-namespace import Engine from '../../core/Engine'; -import PPOMUtil from './ppom-util'; +import PPOMUtil, { + METHOD_SIGN_TYPED_DATA_V3, + METHOD_SIGN_TYPED_DATA_V4, +} from './ppom-util'; // eslint-disable-next-line import/no-namespace import * as securityAlertAPI from './security-alerts-api'; import { isBlockaidFeatureEnabled } from '../../util/blockaid'; @@ -22,6 +25,10 @@ import Logger from '../../util/Logger'; const CHAIN_ID_MOCK = '0x1'; +const SIGN_TYPED_DATA_PARAMS_MOCK_1 = '0x123'; +const SIGN_TYPED_DATA_PARAMS_MOCK_2 = + '{"primaryType":"Permit","domain":{},"types":{}}'; + jest.mock('./security-alerts-api'); jest.mock('../../util/blockaid'); @@ -439,5 +446,38 @@ describe('PPOM Utils', () => { source: SecurityAlertSource.Local, }); }); + + it.each([METHOD_SIGN_TYPED_DATA_V3, METHOD_SIGN_TYPED_DATA_V4])( + 'sanitizes request params if method is %s', + async (method: string) => { + isSecurityAlertsEnabledMock.mockReturnValue(true); + getSupportedChainIdsMock.mockResolvedValue([CHAIN_ID_MOCK]); + + const firstTwoParams = [ + SIGN_TYPED_DATA_PARAMS_MOCK_1, + SIGN_TYPED_DATA_PARAMS_MOCK_2, + ]; + + const unwantedParams = [{}, undefined, 1, null]; + + const params = [...firstTwoParams, ...unwantedParams]; + + const request = { + ...mockRequest, + method, + params, + }; + await PPOMUtil.validateRequest(request, CHAIN_ID_MOCK); + + expect(validateWithSecurityAlertsAPIMock).toHaveBeenCalledTimes(1); + expect(validateWithSecurityAlertsAPIMock).toHaveBeenCalledWith( + CHAIN_ID_MOCK, + { + ...request, + params: firstTwoParams, + }, + ); + }, + ); }); }); diff --git a/app/lib/ppom/ppom-util.ts b/app/lib/ppom/ppom-util.ts index 3a7716eb87f..b76d4bf8f4b 100644 --- a/app/lib/ppom/ppom-util.ts +++ b/app/lib/ppom/ppom-util.ts @@ -34,6 +34,8 @@ export interface PPOMRequest { const TRANSACTION_METHOD = 'eth_sendTransaction'; const TRANSACTION_METHODS = [TRANSACTION_METHOD, 'eth_sendRawTransaction']; +export const METHOD_SIGN_TYPED_DATA_V3 = 'eth_signTypedData_v3'; +export const METHOD_SIGN_TYPED_DATA_V4 = 'eth_signTypedData_v4'; const CONFIRMATION_METHODS = Object.freeze([ 'eth_sendRawTransaction', @@ -155,7 +157,7 @@ async function validateWithController( ppomController: PPOMController, request: PPOMRequest, ): Promise { - try{ + try { const response = (await ppomController.usePPOM((ppom) => ppom.validateJsonRpc(request as unknown as Record), )) as SecurityAlertResponse; @@ -166,7 +168,10 @@ async function validateWithController( }; } catch (e) { Logger.log(`Error validating request with PPOM: ${e}`); - return {...SECURITY_ALERT_RESPONSE_FAILED, source: SecurityAlertSource.Local,}; + return { + ...SECURITY_ALERT_RESPONSE_FAILED, + source: SecurityAlertSource.Local, + }; } } @@ -212,9 +217,25 @@ function isTransactionRequest(request: PPOMRequest) { return TRANSACTION_METHODS.includes(request.method); } +function sanitizeRequest(request: PPOMRequest): PPOMRequest { + // This is a temporary fix to prevent a PPOM bypass + if ( + request.method === METHOD_SIGN_TYPED_DATA_V4 || + request.method === METHOD_SIGN_TYPED_DATA_V3 + ) { + if (Array.isArray(request.params)) { + return { + ...request, + params: request.params.slice(0, 2), + }; + } + } + return request; +} + function normalizeRequest(request: PPOMRequest): PPOMRequest { if (request.method !== TRANSACTION_METHOD) { - return request; + return sanitizeRequest(request); } request.origin = request.origin From c87ac200f6663d891ccb2fd918e7b45e4b0d3eaa Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Fri, 20 Dec 2024 12:10:32 +0000 Subject: [PATCH 15/41] refactor: remove global network usage from transaction simulation (#12743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Remove any usage of the global network from transaction simulation. This requires using the `chainId` from the `TransactionMeta`, and so the `SimulationDetails` properties have been simplified to accept `TransactionMeta` directly to minimise the number of tightly coupled properties. ## **Related issues** Fixes: [#2011](https://github.com/MetaMask/mobile-planning/issues/2011) ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .eslintrc.js | 1 + .../AmountPill/AmountPill.test.tsx | 12 ++- .../AssetPill/AssetPill.test.tsx | 51 ++++++----- .../SimulationDetails/AssetPill/AssetPill.tsx | 29 +++---- .../BalanceChangeList.test.tsx | 4 + .../BalanceChangeRow.test.tsx | 8 +- .../SimulationDetails.stories.tsx | 58 ++++++++----- .../SimulationDetails.test.tsx | 86 +++++++++++++------ .../SimulationDetails/SimulationDetails.tsx | 11 ++- app/components/UI/SimulationDetails/types.ts | 10 +-- .../useBalanceChanges.test.ts | 41 +++++++-- .../UI/SimulationDetails/useBalanceChanges.ts | 31 +++++-- .../useSimulationMetrics.test.ts | 4 - .../SimulationDetails/useSimulationMetrics.ts | 8 +- .../confirmations/SendFlow/Confirm/index.js | 21 ++--- .../components/TransactionReview/index.js | 13 +-- 16 files changed, 243 insertions(+), 145 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 21a0949d4ea..70565eb4945 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -76,6 +76,7 @@ module.exports = { { files: [ 'app/components/UI/Name/**/*.{js,ts,tsx}', + 'app/components/UI/SimulationDetails/**/*.{js,ts,tsx}', 'app/components/hooks/DisplayName/**/*.{js,ts,tsx}' ], rules: { diff --git a/app/components/UI/SimulationDetails/AmountPill/AmountPill.test.tsx b/app/components/UI/SimulationDetails/AmountPill/AmountPill.test.tsx index 012f050320d..bf87cb1a899 100644 --- a/app/components/UI/SimulationDetails/AmountPill/AmountPill.test.tsx +++ b/app/components/UI/SimulationDetails/AmountPill/AmountPill.test.tsx @@ -5,25 +5,33 @@ import AmountPill from './AmountPill'; import { AssetIdentifier, AssetType, - NATIVE_ASSET_IDENTIFIER, + NativeAssetIdentifier, TokenAssetIdentifier, } from '../types'; const TOKEN_ID_MOCK = '0xabc'; +const CHAIN_ID_MOCK = '0x123'; const ERC20_ASSET_MOCK: TokenAssetIdentifier = { type: AssetType.ERC20, address: '0x456', + chainId: CHAIN_ID_MOCK, }; const ERC721_ASSET_MOCK: TokenAssetIdentifier = { type: AssetType.ERC721, address: '0x123', tokenId: TOKEN_ID_MOCK, + chainId: CHAIN_ID_MOCK, }; const ERC1155_ASSET_MOCK: TokenAssetIdentifier = { type: AssetType.ERC1155, address: '0x789', tokenId: TOKEN_ID_MOCK, + chainId: CHAIN_ID_MOCK, +}; +const NATIVE_ASSET_MOCK: NativeAssetIdentifier = { + type: AssetType.Native, + chainId: CHAIN_ID_MOCK, }; const renderAndExpect = ( @@ -83,7 +91,7 @@ describe('AmountPill', () => { it.each(nativeAndErc20Cases)( 'renders the correct sign and amount for $amount', ({ amount, expected }) => { - renderAndExpect(NATIVE_ASSET_IDENTIFIER, amount, expected); + renderAndExpect(NATIVE_ASSET_MOCK, amount, expected); }, ); }); diff --git a/app/components/UI/SimulationDetails/AssetPill/AssetPill.test.tsx b/app/components/UI/SimulationDetails/AssetPill/AssetPill.test.tsx index 220dad70717..291d2087c78 100644 --- a/app/components/UI/SimulationDetails/AssetPill/AssetPill.test.tsx +++ b/app/components/UI/SimulationDetails/AssetPill/AssetPill.test.tsx @@ -1,18 +1,10 @@ import React from 'react'; -import { render } from '@testing-library/react-native'; import AssetPill from './AssetPill'; -import { - selectChainId, - selectTicker, -} from '../../../../selectors/networkController'; import { AssetType, AssetIdentifier } from '../types'; +import renderWithProvider from '../../../../util/test/renderWithProvider'; +import { mockNetworkState } from '../../../../util/test/network'; -jest.mock('react-redux', () => ({ - ...jest.requireActual('react-redux'), - useSelector: jest.fn().mockImplementation((selector) => selector()), -})); -jest.mock('../../../../selectors/networkController'); jest.mock( '../../../../component-library/components/Avatars/Avatar/variants/AvatarNetwork', () => 'AvatarNetwork', @@ -22,18 +14,33 @@ jest.mock('../../../hooks/useStyles', () => ({ useStyles: () => ({ styles: {} }), })); -describe('AssetPill', () => { - const selectChainIdMock = jest.mocked(selectChainId); - const selectTickerMock = jest.mocked(selectTicker); +const CHAIN_ID_MOCK = '0x123'; - beforeAll(() => { - selectChainIdMock.mockReturnValue('0x1'); - selectTickerMock.mockReturnValue('ETH'); - }); +const STATE_MOCK = { + engine: { + backgroundState: { + NetworkController: { + ...mockNetworkState({ + chainId: CHAIN_ID_MOCK, + }), + }, + }, + }, +}; +describe('AssetPill', () => { it('renders correctly for native assets', () => { - const asset = { type: AssetType.Native } as AssetIdentifier; - const { getByText, getByTestId } = render(); + const asset = { + type: AssetType.Native, + chainId: CHAIN_ID_MOCK, + } as AssetIdentifier; + + const { getByText, getByTestId } = renderWithProvider( + , + { + state: STATE_MOCK, + }, + ); expect( getByTestId('simulation-details-asset-pill-avatar-network'), @@ -45,8 +52,12 @@ describe('AssetPill', () => { const asset = { type: AssetType.ERC20, address: '0xabc123', + chainId: CHAIN_ID_MOCK, } as AssetIdentifier; - const { getByTestId } = render(); + + const { getByTestId } = renderWithProvider(, { + state: STATE_MOCK, + }); expect(getByTestId('simulation-details-asset-pill-name')).toBeTruthy(); }); diff --git a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx index 3399ed8b0d6..13e829b3795 100644 --- a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx +++ b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx @@ -9,16 +9,13 @@ import Text, { } from '../../../../component-library/components/Texts/Text'; import AvatarNetwork from '../../../../component-library/components/Avatars/Avatar/variants/AvatarNetwork'; import { AvatarSize } from '../../../../component-library/components/Avatars/Avatar/Avatar.types'; -import { - selectChainId, - selectTicker, -} from '../../../../selectors/networkController'; import { NetworkList } from '../../../../util/networks'; import { useStyles } from '../../../hooks/useStyles'; import Name from '../../Name/Name'; import { NameType } from '../../Name/Name.types'; import { AssetIdentifier, AssetType } from '../types'; import styleSheet from './AssetPill.styles'; +import { selectNetworkConfigurations } from '../../../../selectors/networkController'; interface AssetPillProperties extends ViewProps { asset: AssetIdentifier; @@ -35,21 +32,26 @@ const getNetworkImage = (chainId: Hex) => { return network?.imageSource || null; }; -const NativeAssetPill: React.FC = () => { +const NativeAssetPill: React.FC = ({ asset }) => { const { styles } = useStyles(styleSheet, {}); - const ticker = useSelector(selectTicker); - const chainId = useSelector(selectChainId); - const imageSource = getNetworkImage(chainId); + const imageSource = getNetworkImage(asset.chainId); + + const networkConfigurationsByChainId = useSelector( + selectNetworkConfigurations, + ); + + const { nativeCurrency } = + networkConfigurationsByChainId[asset.chainId] || {}; return ( - {ticker} + {nativeCurrency} ); }; @@ -57,20 +59,17 @@ const NativeAssetPill: React.FC = () => { const AssetPill: React.FC = ({ asset }) => { const { styles } = useStyles(styleSheet, {}); - // TODO: Remove global network selector usage once simulations refactored. - const chainId = useSelector(selectChainId); - return ( {asset.type === AssetType.Native ? ( - + ) : ( )} diff --git a/app/components/UI/SimulationDetails/BalanceChangeList/BalanceChangeList.test.tsx b/app/components/UI/SimulationDetails/BalanceChangeList/BalanceChangeList.test.tsx index dacf4df7de4..70ef9cb1116 100644 --- a/app/components/UI/SimulationDetails/BalanceChangeList/BalanceChangeList.test.tsx +++ b/app/components/UI/SimulationDetails/BalanceChangeList/BalanceChangeList.test.tsx @@ -14,11 +14,14 @@ jest.mock('../FiatDisplay/FiatDisplay', () => ({ TotalFiatDisplay: 'TotalFiatDisplay', })); +const CHAIN_ID_MOCK = '0x123'; + const balanceChangesMock = [ { asset: { type: 'ERC20', address: '0xabc123', + chainId: CHAIN_ID_MOCK, }, amount: new BigNumber(100), fiatAmount: 100, @@ -68,6 +71,7 @@ describe('BalanceChangeList', () => { asset: { type: 'ERC20', address: '0xabc123', + chainId: CHAIN_ID_MOCK, }, amount: new BigNumber(100), fiatAmount: 100, diff --git a/app/components/UI/SimulationDetails/BalanceChangeRow/BalanceChangeRow.test.tsx b/app/components/UI/SimulationDetails/BalanceChangeRow/BalanceChangeRow.test.tsx index ede8373ed23..3d95d368876 100644 --- a/app/components/UI/SimulationDetails/BalanceChangeRow/BalanceChangeRow.test.tsx +++ b/app/components/UI/SimulationDetails/BalanceChangeRow/BalanceChangeRow.test.tsx @@ -5,22 +5,24 @@ import { BigNumber } from 'bignumber.js'; import BalanceChangeRow from './BalanceChangeRow'; import { AssetType, BalanceChange } from '../types'; +jest.mock('../AmountPill/AmountPill', () => 'AmountPill'); +jest.mock('../AssetPill/AssetPill', () => 'AssetPill'); jest.mock('../FiatDisplay/FiatDisplay', () => ({ IndividualFiatDisplay: 'IndividualFiatDisplay', })); +const CHAIN_ID_MOCK = '0x123'; + const balanceChangeMock: BalanceChange = { asset: { type: AssetType.ERC20, address: '0xabc123', + chainId: CHAIN_ID_MOCK, }, amount: new BigNumber(100), fiatAmount: 0, } as BalanceChange; -jest.mock('../AmountPill/AmountPill', () => 'AmountPill'); -jest.mock('../AssetPill/AssetPill', () => 'AssetPill'); - describe('BalanceChangeList', () => { it('renders a balance change row', () => { const { getByText, getByTestId } = render( diff --git a/app/components/UI/SimulationDetails/SimulationDetails.stories.tsx b/app/components/UI/SimulationDetails/SimulationDetails.stories.tsx index b5d8994e194..97a826f55f6 100644 --- a/app/components/UI/SimulationDetails/SimulationDetails.stories.tsx +++ b/app/components/UI/SimulationDetails/SimulationDetails.stories.tsx @@ -9,6 +9,8 @@ import { SimulationErrorCode, SimulationTokenStandard, CHAIN_IDS, + TransactionMeta, + SimulationData, } from '@metamask/transaction-controller'; import { @@ -145,8 +147,20 @@ const meta: Meta = { }; export default meta; +function buildArgs({ + simulationData, +}: { + simulationData?: SimulationData; +}): Partial { + return { + transaction: { + simulationData, + } as TransactionMeta, + }; +} + export const MultipleTokens: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { ...DUMMY_BALANCE_CHANGE, @@ -193,11 +207,11 @@ export const MultipleTokens: Story = { }, ], }, - }, + }), }; export const SendSmallAmount: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { ...DUMMY_BALANCE_CHANGE, @@ -206,11 +220,11 @@ export const SendSmallAmount: Story = { }, tokenBalanceChanges: [], }, - }, + }), }; export const LongValuesAndNames: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { ...DUMMY_BALANCE_CHANGE, @@ -234,11 +248,11 @@ export const LongValuesAndNames: Story = { }, ], }, - }, + }), }; export const PolygonNativeAsset: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { ...DUMMY_BALANCE_CHANGE, @@ -247,14 +261,14 @@ export const PolygonNativeAsset: Story = { }, tokenBalanceChanges: [], }, - }, + }), decorators: [ (story) => {story()}, ], }; export const ArbitrumNativeAsset: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { ...DUMMY_BALANCE_CHANGE, @@ -263,14 +277,14 @@ export const ArbitrumNativeAsset: Story = { }, tokenBalanceChanges: [], }, - }, + }), decorators: [ (story) => {story()}, ], }; export const ReceiveOnly: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { previousBalance: '0x2', @@ -280,11 +294,11 @@ export const ReceiveOnly: Story = { }, tokenBalanceChanges: [], }, - }, + }), }; export const SendOnly: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: { previousBalance: '0x1', @@ -294,40 +308,40 @@ export const SendOnly: Story = { }, tokenBalanceChanges: [], }, - }, + }), }; export const NoBalanceChanges: Story = { - args: { + args: buildArgs({ simulationData: { nativeBalanceChange: undefined, tokenBalanceChanges: [], }, - }, + }), }; export const Loading: Story = { - args: { + args: buildArgs({ simulationData: undefined, - }, + }), }; export const TransactionReverted: Story = { - args: { + args: buildArgs({ simulationData: { error: { code: SimulationErrorCode.Reverted }, nativeBalanceChange: undefined, tokenBalanceChanges: [], }, - }, + }), }; export const GenericError: Story = { - args: { + args: buildArgs({ simulationData: { error: {}, nativeBalanceChange: undefined, tokenBalanceChanges: [], }, - }, + }), }; diff --git a/app/components/UI/SimulationDetails/SimulationDetails.test.tsx b/app/components/UI/SimulationDetails/SimulationDetails.test.tsx index e4054925201..3b64269f9f3 100644 --- a/app/components/UI/SimulationDetails/SimulationDetails.test.tsx +++ b/app/components/UI/SimulationDetails/SimulationDetails.test.tsx @@ -6,6 +6,7 @@ import { SimulationData, SimulationErrorCode, SimulationTokenStandard, + TransactionMeta, } from '@metamask/transaction-controller'; import AnimatedSpinner from '../AnimatedSpinner'; @@ -21,6 +22,7 @@ const DUMMY_BALANCE_CHANGE = { previousBalance: '0xIGNORED' as Hex, newBalance: '0xIGNORED' as Hex, }; +const CHAIN_ID_MOCK = '0x123'; const mockTransactionId = '0x1234567890'; const simulationDataMock = { nativeBalanceChange: { @@ -81,8 +83,12 @@ describe('SimulationDetails', () => { render( , ); @@ -95,11 +101,15 @@ describe('SimulationDetails', () => { expect( render( , ).toJSON(), @@ -110,11 +120,15 @@ describe('SimulationDetails', () => { expect( render( , ).toJSON(), @@ -126,11 +140,15 @@ describe('SimulationDetails', () => { it('if transaction will be reverted', () => { const { getByText } = render( , ); @@ -141,11 +159,15 @@ describe('SimulationDetails', () => { it('if simulation is failed', () => { const { getByText } = render( , ); @@ -159,8 +181,12 @@ describe('SimulationDetails', () => { it('renders if no balance change', () => { const { getByText } = render( , ); @@ -175,7 +201,7 @@ describe('SimulationDetails', () => { { amount: new BigNumber('0x1', 16).times(-1), fiatAmount: 10, - asset: { type: AssetType.Native }, + asset: { type: AssetType.Native, chainId: CHAIN_ID_MOCK }, }, { amount: new BigNumber('0x123456', 16).times(1), @@ -184,6 +210,7 @@ describe('SimulationDetails', () => { address: FIRST_PARTY_CONTRACT_ADDRESS_1_MOCK, tokenId: undefined, type: AssetType.ERC20, + chainId: CHAIN_ID_MOCK, }, }, { @@ -193,6 +220,7 @@ describe('SimulationDetails', () => { address: FIRST_PARTY_CONTRACT_ADDRESS_2_MOCK, tokenId: undefined, type: AssetType.ERC20, + chainId: CHAIN_ID_MOCK, }, }, ], @@ -200,8 +228,12 @@ describe('SimulationDetails', () => { const { getByTestId } = render( , ); diff --git a/app/components/UI/SimulationDetails/SimulationDetails.tsx b/app/components/UI/SimulationDetails/SimulationDetails.tsx index 474bafc3ebe..04c8406b5e3 100644 --- a/app/components/UI/SimulationDetails/SimulationDetails.tsx +++ b/app/components/UI/SimulationDetails/SimulationDetails.tsx @@ -2,9 +2,9 @@ import React, { useState } from 'react'; import { View, Pressable } from 'react-native'; import { - SimulationData, SimulationErrorCode, SimulationError, + TransactionMeta, } from '@metamask/transaction-controller'; import { strings } from '../../../../locales/i18n'; @@ -25,8 +25,7 @@ import styleSheet from './SimulationDetails.styles'; import { useSimulationMetrics } from './useSimulationMetrics'; export interface SimulationDetailsProps { - simulationData?: SimulationData; - transactionId: string; + transaction: TransactionMeta; enableMetrics: boolean; } @@ -140,12 +139,12 @@ const SimulationDetailsLayout: React.FC<{ * @returns The simulation details. */ export const SimulationDetails: React.FC = ({ - simulationData, + transaction, enableMetrics = false, - transactionId, }: SimulationDetailsProps) => { const { styles } = useStyles(styleSheet, {}); - const balanceChangesResult = useBalanceChanges(simulationData); + const { chainId, id: transactionId, simulationData } = transaction; + const balanceChangesResult = useBalanceChanges({ chainId, simulationData }); const loading = !simulationData || balanceChangesResult.pending; useSimulationMetrics({ diff --git a/app/components/UI/SimulationDetails/types.ts b/app/components/UI/SimulationDetails/types.ts index 9b87ad84af3..93468745472 100644 --- a/app/components/UI/SimulationDetails/types.ts +++ b/app/components/UI/SimulationDetails/types.ts @@ -8,10 +8,6 @@ export enum AssetType { ERC1155 = 'ERC1155', } -export const NATIVE_ASSET_IDENTIFIER: NativeAssetIdentifier = { - type: AssetType.Native, -}; - /** * Describes an amount of fiat. */ @@ -23,18 +19,20 @@ export type FiatAmount = FiatAmountAvailable | typeof FIAT_UNAVAILABLE; * Identifies the native asset of a chain. */ export interface NativeAssetIdentifier { - type: AssetType.Native; address?: undefined; + chainId: Hex; tokenId?: undefined; + type: AssetType.Native; } /** * Uniquely identifies a token asset on a chain. */ export interface TokenAssetIdentifier { - type: Exclude; address: Hex; + chainId: Hex; tokenId?: Hex; + type: Exclude; } export type AssetIdentifier = Readonly< diff --git a/app/components/UI/SimulationDetails/useBalanceChanges.test.ts b/app/components/UI/SimulationDetails/useBalanceChanges.test.ts index 720c09c5397..16fe3af39e9 100644 --- a/app/components/UI/SimulationDetails/useBalanceChanges.test.ts +++ b/app/components/UI/SimulationDetails/useBalanceChanges.test.ts @@ -61,6 +61,8 @@ const DIFFERENCE_1_MOCK: Hex = '0x11'; const DIFFERENCE_2_MOCK: Hex = '0x2'; const DIFFERENCE_ETH_MOCK: Hex = '0x1234567890123456789'; +const CHAIN_ID_MOCK = '0x123'; + const dummyBalanceChange = { previousBalance: '0xIGNORE' as Hex, newBalance: '0xIGNORE' as Hex, @@ -98,7 +100,10 @@ describe('useBalanceChanges', () => { describe('pending states', () => { it('returns pending=true if no simulation data', async () => { const { result, waitForNextUpdate } = renderHook(() => - useBalanceChanges(undefined), + useBalanceChanges({ + chainId: CHAIN_ID_MOCK, + simulationData: undefined, + }), ); expect(result.current).toEqual({ pending: true, value: [] }); await waitForNextUpdate(); @@ -119,7 +124,10 @@ describe('useBalanceChanges', () => { ], }; const { result, unmount, waitForNextUpdate } = renderHook(() => - useBalanceChanges(simulationData), + useBalanceChanges({ + chainId: CHAIN_ID_MOCK, + simulationData, + }), ); await waitForNextUpdate(); @@ -143,7 +151,10 @@ describe('useBalanceChanges', () => { ], }; const { result, unmount } = renderHook(() => - useBalanceChanges(simulationData), + useBalanceChanges({ + chainId: CHAIN_ID_MOCK, + simulationData, + }), ); expect(result.current).toEqual({ pending: true, value: [] }); @@ -159,7 +170,12 @@ describe('useBalanceChanges', () => { nativeBalanceChange: undefined, tokenBalanceChanges, }; - return renderHook(() => useBalanceChanges(simulationData)); + return renderHook(() => + useBalanceChanges({ + chainId: CHAIN_ID_MOCK, + simulationData, + }), + ); }; it('maps token balance changes correctly', async () => { @@ -182,6 +198,7 @@ describe('useBalanceChanges', () => { address: ERC20_TOKEN_ADDRESS_1_MOCK, type: AssetType.ERC20, tokenId: undefined, + chainId: CHAIN_ID_MOCK, }, amount: new BigNumber('-0.017'), fiatAmount: -0.0255, @@ -238,6 +255,7 @@ describe('useBalanceChanges', () => { address: NFT_TOKEN_ADDRESS_MOCK, type: AssetType.ERC721, tokenId: TOKEN_ID_1_MOCK, + chainId: CHAIN_ID_MOCK, }, amount: new BigNumber('-1'), fiatAmount: FIAT_UNAVAILABLE, @@ -305,7 +323,12 @@ describe('useBalanceChanges', () => { nativeBalanceChange, tokenBalanceChanges: [], }; - return renderHook(() => useBalanceChanges(simulationData)); + return renderHook(() => + useBalanceChanges({ + chainId: CHAIN_ID_MOCK, + simulationData, + }), + ); }; it('maps native balance change correctly', async () => { @@ -322,6 +345,7 @@ describe('useBalanceChanges', () => { { asset: { type: AssetType.Native, + chainId: CHAIN_ID_MOCK, }, amount: new BigNumber('-5373.003641998677469065'), fiatAmount: Number('-16119.010925996032'), @@ -367,7 +391,10 @@ describe('useBalanceChanges', () => { ], }; const { result, waitForNextUpdate } = renderHook(() => - useBalanceChanges(simulationData), + useBalanceChanges({ + chainId: CHAIN_ID_MOCK, + simulationData, + }), ); await waitForNextUpdate(); @@ -376,6 +403,7 @@ describe('useBalanceChanges', () => { expect(changes).toHaveLength(2); expect(changes[0].asset).toEqual({ type: AssetType.Native, + chainId: CHAIN_ID_MOCK, }); expect(changes[0].amount).toEqual( new BigNumber('-5373.003641998677469065'), @@ -384,6 +412,7 @@ describe('useBalanceChanges', () => { expect(changes[1].asset).toEqual({ address: ERC20_TOKEN_ADDRESS_1_MOCK, type: AssetType.ERC20, + chainId: CHAIN_ID_MOCK, }); expect(changes[1].amount).toEqual(new BigNumber('0.002')); }); diff --git a/app/components/UI/SimulationDetails/useBalanceChanges.ts b/app/components/UI/SimulationDetails/useBalanceChanges.ts index faa7aeb14bf..e383058c0c4 100644 --- a/app/components/UI/SimulationDetails/useBalanceChanges.ts +++ b/app/components/UI/SimulationDetails/useBalanceChanges.ts @@ -15,17 +15,16 @@ import { import { BalanceChange, - NATIVE_ASSET_IDENTIFIER, TokenAssetIdentifier, AssetType, FIAT_UNAVAILABLE, + NativeAssetIdentifier, } from './types'; import { getTokenDetails } from '../../../util/address'; import { selectConversionRate, selectCurrentCurrency, } from '../../../selectors/currencyRateController'; -import { selectChainId } from '../../../selectors/networkController'; import { useAsyncResultOrThrow } from '../../hooks/useAsyncResult'; const NATIVE_DECIMALS = 18; @@ -132,14 +131,20 @@ async function fetchTokenFiatRates( function getNativeBalanceChange( nativeBalanceChange: SimulationBalanceChange | undefined, nativeFiatRate: number, + chainId: Hex, ): BalanceChange | undefined { if (!nativeBalanceChange) { return undefined; } - const asset = NATIVE_ASSET_IDENTIFIER; - const amount = getAssetAmount(nativeBalanceChange, NATIVE_DECIMALS); + const asset: NativeAssetIdentifier = { + type: AssetType.Native, + chainId, + }; + + const amount = getAssetAmount(nativeBalanceChange, NATIVE_DECIMALS); const fiatAmount = amount.times(nativeFiatRate).toNumber(); + return { asset, amount, fiatAmount }; } @@ -148,12 +153,14 @@ function getTokenBalanceChanges( tokenBalanceChanges: SimulationTokenBalanceChange[], erc20Decimals: Record, erc20FiatRates: Partial>, + chainId: Hex, ): BalanceChange[] { return tokenBalanceChanges.map((tokenBc) => { const asset: TokenAssetIdentifier = { type: convertStandard(tokenBc.standard), address: tokenBc.address.toLowerCase() as Hex, tokenId: tokenBc.id, + chainId, }; const decimals = @@ -172,12 +179,15 @@ function getTokenBalanceChanges( } // Compiles a list of balance changes from simulation data -export default function useBalanceChanges( - simulationData: SimulationData | undefined, -): { pending: boolean; value: BalanceChange[] } { +export default function useBalanceChanges({ + chainId, + simulationData, +}: { + chainId: Hex; + simulationData?: SimulationData; +}): { pending: boolean; value: BalanceChange[] } { const nativeFiatRate = useSelector(selectConversionRate) as number; const fiatCurrency = useSelector(selectCurrentCurrency); - const chainId = useSelector(selectChainId); const { nativeBalanceChange, tokenBalanceChanges = [] } = simulationData ?? {}; @@ -200,18 +210,21 @@ export default function useBalanceChanges( [JSON.stringify(erc20TokenAddresses), chainId, fiatCurrency], ); - if (erc20Decimals.pending || erc20FiatRates.pending || !simulationData ) { + if (erc20Decimals.pending || erc20FiatRates.pending || !simulationData) { return { pending: true, value: [] }; } const nativeChange = getNativeBalanceChange( nativeBalanceChange, nativeFiatRate, + chainId, ); + const tokenChanges = getTokenBalanceChanges( tokenBalanceChanges, erc20Decimals.value, erc20FiatRates.value, + chainId, ); const balanceChanges: BalanceChange[] = [ diff --git a/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts b/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts index cf9eacf54a6..920aded4148 100644 --- a/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts +++ b/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react'; import { - CHAIN_IDS, SimulationData, SimulationErrorCode, } from '@metamask/transaction-controller'; @@ -23,7 +22,6 @@ import { useSimulationMetrics, } from './useSimulationMetrics'; import useLoadingTime from './useLoadingTime'; -import { selectChainId } from '../../../selectors/networkController'; import { MetricsEventBuilder } from '../../../core/Analytics/MetricsEventBuilder'; jest.mock('react-redux', () => ({ @@ -89,7 +87,6 @@ describe('useSimulationMetrics', () => { const useDisplayNamesMock = jest.mocked(useDisplayNames); const useLoadingTimeMock = jest.mocked(useLoadingTime); const setLoadingCompleteMock = jest.fn(); - const selectChainIdMock = jest.mocked(selectChainId); function expectUpdateTransactionMetricsCalled( { @@ -141,7 +138,6 @@ describe('useSimulationMetrics', () => { loadingTime: LOADING_TIME_MOCK, setLoadingComplete: setLoadingCompleteMock, }); - selectChainIdMock.mockReturnValue(CHAIN_IDS.MAINNET); }); describe('updates transaction simulation metrics', () => { diff --git a/app/components/UI/SimulationDetails/useSimulationMetrics.ts b/app/components/UI/SimulationDetails/useSimulationMetrics.ts index ed7e7f2f4c9..0d16524d9ff 100644 --- a/app/components/UI/SimulationDetails/useSimulationMetrics.ts +++ b/app/components/UI/SimulationDetails/useSimulationMetrics.ts @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { SimulationData, SimulationErrorCode, @@ -17,7 +17,6 @@ import { NameType } from '../../UI/Name/Name.types'; import useLoadingTime from './useLoadingTime'; import { calculateTotalFiat } from './FiatDisplay/FiatDisplay'; import { BalanceChange } from './types'; -import { selectChainId } from '../../../selectors/networkController'; export interface UseSimulationMetricsProps { balanceChanges: BalanceChange[]; @@ -50,9 +49,6 @@ export function useSimulationMetrics({ const { loadingTime, setLoadingComplete } = useLoadingTime(); const dispatch = useDispatch(); - // TODO: Remove global network selector usage once simulations refactored. - const chainId = useSelector(selectChainId); - if (!loading) { setLoadingComplete(); } @@ -62,7 +58,7 @@ export function useSimulationMetrics({ value: asset.address ?? '', type: NameType.EthereumAddress, preferContractSymbol: true, - variation: chainId, + variation: asset.chainId, }), ); diff --git a/app/components/Views/confirmations/SendFlow/Confirm/index.js b/app/components/Views/confirmations/SendFlow/Confirm/index.js index 8c06868102f..7aa29a398e1 100644 --- a/app/components/Views/confirmations/SendFlow/Confirm/index.js +++ b/app/components/Views/confirmations/SendFlow/Confirm/index.js @@ -264,16 +264,14 @@ class Confirm extends PureComponent { * Boolean that indicates if smart transaction should be used */ shouldUseSmartTransaction: PropTypes.bool, - /** * Object containing transaction metrics by id */ transactionMetricsById: PropTypes.object, - /** - * Object containing the transaction simulation data + * Transaction metadata from the transaction controller */ - transactionSimulationData: PropTypes.object, + transactionMetadata: PropTypes.object, /** * Update transaction metrics */ @@ -915,9 +913,12 @@ class Confirm extends PureComponent { resetTransaction, gasEstimateType, shouldUseSmartTransaction, - transactionSimulationData: { isUpdatedAfterSecurityCheck } = {}, + transactionMetadata, } = this.props; + const transactionSimulationData = transactionMetadata?.simulationData; + const { isUpdatedAfterSecurityCheck } = transactionSimulationData ?? {}; + const { legacyGasTransaction, transactionConfirmed, @@ -1326,7 +1327,7 @@ class Confirm extends PureComponent { gasEstimateType, isNativeTokenBuySupported, shouldUseSmartTransaction, - transactionSimulationData, + transactionMetadata, transactionState, useTransactionSimulations, } = this.props; @@ -1359,6 +1360,7 @@ class Confirm extends PureComponent { const isLedgerAccount = isHardwareAccount(fromSelectedAddress, [ ExtendedKeyringTypes.ledger, ]); + const transactionSimulationData = transactionMetadata?.simulationData; const isTestNetwork = isTestNet(chainId); @@ -1430,9 +1432,8 @@ class Confirm extends PureComponent { {useTransactionSimulations && transactionState?.id && ( )} @@ -1575,8 +1576,8 @@ const mapStateToProps = (state) => ({ ), shouldUseSmartTransaction: selectShouldUseSmartTransaction(state), transactionMetricsById: selectTransactionMetrics(state), - transactionSimulationData: - selectCurrentTransactionMetadata(state)?.simulationData, + transactionMetadata: + selectCurrentTransactionMetadata(state), useTransactionSimulations: selectUseTransactionSimulations(state), securityAlertResponse: selectCurrentTransactionSecurityAlertResponse(state), }); diff --git a/app/components/Views/confirmations/components/TransactionReview/index.js b/app/components/Views/confirmations/components/TransactionReview/index.js index c548b692d6c..6c43963b376 100644 --- a/app/components/Views/confirmations/components/TransactionReview/index.js +++ b/app/components/Views/confirmations/components/TransactionReview/index.js @@ -261,10 +261,6 @@ class TransactionReview extends PureComponent { * Boolean that indicates if smart transaction should be used */ shouldUseSmartTransaction: PropTypes.bool, - /** - * Transaction simulation data - */ - transactionSimulationData: PropTypes.object, /** * Boolean that indicates if transaction simulations should be enabled */ @@ -523,10 +519,12 @@ class TransactionReview extends PureComponent { transaction, transaction: { to, origin, from, ensRecipient, id: transactionId }, error, - transactionSimulationData, + transactionMetadata, useTransactionSimulations, } = this.props; + const transactionSimulationData = transactionMetadata?.simulationData; + const { actionKey, assetAmount, @@ -619,9 +617,8 @@ class TransactionReview extends PureComponent { {useTransactionSimulations && transactionSimulationData && ( )} @@ -720,8 +717,6 @@ const mapStateToProps = (state) => ({ primaryCurrency: state.settings.primaryCurrency, tokenList: selectTokenList(state), shouldUseSmartTransaction: selectShouldUseSmartTransaction(state), - transactionSimulationData: - selectCurrentTransactionMetadata(state)?.simulationData, useTransactionSimulations: selectUseTransactionSimulations(state), securityAlertResponse: selectCurrentTransactionSecurityAlertResponse(state), transactionMetadata: selectCurrentTransactionMetadata(state), From c7eee9c2f8d88da24914e50c8d1e6cbf1575e580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n?= Date: Fri, 20 Dec 2024 13:55:39 +0100 Subject: [PATCH 16/41] test: erc 1155 batch transfer (#12800) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR is within the scope of the Quality Quest. We're including an e2e test case to check the batch transfer for ERC1155 in test dApp. **Steps:** Given I am on the test dapp When I tap on the batch transfer button in the ERC-1155 section Then the contract bottom sheet should appear When I submit the transaction Then the transaction should appear in the transaction history ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .../Browser/ContractApprovalBottomSheet.js | 8 ++ e2e/pages/Browser/TestDApp.js | 11 +++ .../ContractApprovalBottomSheet.selectors.js | 1 + e2e/selectors/Browser/TestDapp.selectors.js | 1 + .../batch-transfer-erc1155.spec.js | 73 +++++++++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 e2e/specs/confirmations/batch-transfer-erc1155.spec.js diff --git a/e2e/pages/Browser/ContractApprovalBottomSheet.js b/e2e/pages/Browser/ContractApprovalBottomSheet.js index e99985f84c4..489fe6a83c0 100644 --- a/e2e/pages/Browser/ContractApprovalBottomSheet.js +++ b/e2e/pages/Browser/ContractApprovalBottomSheet.js @@ -48,6 +48,10 @@ class ContractApprovalBottomSheet { ); } + get confirmButton() { + return Matchers.getElementByText(ContractApprovalBottomSheetSelectorsText.CONFIRM); + } + async tapAddNickName() { await Gestures.waitAndTap(this.addNickName); } @@ -63,6 +67,10 @@ class ContractApprovalBottomSheet { await Gestures.waitAndTap(this.approveButton); } + async tapConfirmButton() { + await Gestures.waitAndTap(this.confirmButton); + } + async tapToCopyContractAddress() { await Gestures.waitAndTap(this.contractAddress); } diff --git a/e2e/pages/Browser/TestDApp.js b/e2e/pages/Browser/TestDApp.js index ab411415955..a9bc65d01d6 100644 --- a/e2e/pages/Browser/TestDApp.js +++ b/e2e/pages/Browser/TestDApp.js @@ -119,6 +119,13 @@ class TestDApp { ); } + get erc1155BatchTransferButton() { + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.BATCH_TRANSFER_ERC1155_BUTTON_ID, + ); + } + async connect() { await this.tapButton(this.DappConnectButton); } @@ -181,6 +188,10 @@ class TestDApp { await Gestures.tap(this.approveButtonText, 0); } + async tapERC1155BatchTransferButton() { + await this.tapButton(this.erc1155BatchTransferButton); + } + async tapButton(elementId) { await Gestures.scrollToWebViewPort(elementId); await Gestures.tapWebElement(elementId); diff --git a/e2e/selectors/Browser/ContractApprovalBottomSheet.selectors.js b/e2e/selectors/Browser/ContractApprovalBottomSheet.selectors.js index 39ee13229f7..d469fbfed79 100644 --- a/e2e/selectors/Browser/ContractApprovalBottomSheet.selectors.js +++ b/e2e/selectors/Browser/ContractApprovalBottomSheet.selectors.js @@ -6,6 +6,7 @@ export const ContractApprovalBottomSheetSelectorsText = { APPROVE: enContent.transactions.tx_review_approve, REJECT: enContent.transaction.reject, NEXT: enContent.transaction.next, + CONFIRM: enContent.transaction.confirm, }; export const ContractApprovalBottomSheetSelectorsIDs = { diff --git a/e2e/selectors/Browser/TestDapp.selectors.js b/e2e/selectors/Browser/TestDapp.selectors.js index 4725a436c92..e0995aa10f0 100644 --- a/e2e/selectors/Browser/TestDapp.selectors.js +++ b/e2e/selectors/Browser/TestDapp.selectors.js @@ -13,4 +13,5 @@ export const TestDappSelectorsWebIDs = { SIGN_TYPE_DATA_V4: 'signTypedDataV4', ETHEREUM_SIGN: 'siwe', ADD_TOKENS_TO_WALLET_BUTTON: 'watchAssets', + BATCH_TRANSFER_ERC1155_BUTTON_ID: 'batchTransferFromButton', }; diff --git a/e2e/specs/confirmations/batch-transfer-erc1155.spec.js b/e2e/specs/confirmations/batch-transfer-erc1155.spec.js new file mode 100644 index 00000000000..b7ed8494d16 --- /dev/null +++ b/e2e/specs/confirmations/batch-transfer-erc1155.spec.js @@ -0,0 +1,73 @@ +'use strict'; + +import { SmokeConfirmations } from '../../tags'; +import TestHelpers from '../../helpers'; +import { loginToApp } from '../../viewHelper'; + +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import TestDApp from '../../pages/Browser/TestDApp'; +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { + withFixtures, + defaultGanacheOptions, +} from '../../fixtures/fixture-helper'; +import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; +import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; +import Assertions from '../../utils/Assertions'; +import { ContractApprovalBottomSheetSelectorsText } from '../../selectors/Browser/ContractApprovalBottomSheet.selectors'; +import ContractApprovalBottomSheet from '../../pages/Browser/ContractApprovalBottomSheet'; + +describe(SmokeConfirmations('ERC1155 token'), () => { + const ERC1155_CONTRACT = SMART_CONTRACTS.ERC1155; + + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + it('batch transfer ERC1155 tokens', async () => { + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder() + .withGanacheNetwork() + .withPermissionControllerConnectedToTestDapp() + .build(), + restartDevice: true, + ganacheOptions: defaultGanacheOptions, + smartContract: ERC1155_CONTRACT, + }, + async ({ contractRegistry }) => { + const erc1155Address = await contractRegistry.getContractAddress( + ERC1155_CONTRACT, + ); + await loginToApp(); + + // Navigate to the browser screen + await TabBarComponent.tapBrowser(); + await TestDApp.navigateToTestDappWithContract({ + contractAddress: erc1155Address, + }); + + // Send batch transfer for ERC1155 tokens + await TestDApp.tapERC1155BatchTransferButton(); + await Assertions.checkIfTextIsDisplayed( + ContractApprovalBottomSheetSelectorsText.CONFIRM, + ); + + // Tap confirm button + await ContractApprovalBottomSheet.tapConfirmButton(); + + // Navigate to the activity screen + await TabBarComponent.tapActivity(); + + // Assert that the ERC1155 activity is an smart contract interaction and it is confirmed + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.SMART_CONTRACT_INTERACTION, + ); + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.CONFIRM_TEXT, + ); + }, + ); + }); +}); From 89b61d359a4193c5b6916dcec3161e826591b183 Mon Sep 17 00:00:00 2001 From: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:07:19 +0300 Subject: [PATCH 17/41] chore(tests): move multichain assets test so it runs as part of the assets bitrise workflow (#12807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This moves the mutlichain assets test to the assets workflow. The multichain workflow still has 6 more tests to add and already reached over 20 minutes run, which is close to or over the expected length, while assets workflow was using only 7min of it's workflow. ## **Related issues** Fixes: ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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 => assets/multichain}/asset-list.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename e2e/specs/{multichain/assets => assets/multichain}/asset-list.spec.js (98%) diff --git a/e2e/specs/multichain/assets/asset-list.spec.js b/e2e/specs/assets/multichain/asset-list.spec.js similarity index 98% rename from e2e/specs/multichain/assets/asset-list.spec.js rename to e2e/specs/assets/multichain/asset-list.spec.js index d33360a7f6f..042723d44d9 100644 --- a/e2e/specs/multichain/assets/asset-list.spec.js +++ b/e2e/specs/assets/multichain/asset-list.spec.js @@ -1,6 +1,6 @@ // 'persists the preferred asset list preference when changing networks' -import { SmokeMultiChain } from '../../../tags'; +import { SmokeAssets } from '../../../tags'; import WalletView from '../../../pages/wallet/WalletView'; import FixtureBuilder from '../../../fixtures/fixture-builder'; import { @@ -26,7 +26,7 @@ const ETHEREUM_NAME = 'Ethereum'; const AVAX_NAME = 'AVAX'; const BNB_NAME = 'BNB'; -describe(SmokeMultiChain('Import Tokens'), () => { +describe(SmokeAssets('Import Tokens'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder().withPopularNetworks().build(); From bea70f16d3bc1d7d78049ce5a21433735cc395b3 Mon Sep 17 00:00:00 2001 From: Curtis David Date: Fri, 20 Dec 2024 10:15:39 -0500 Subject: [PATCH 18/41] test: Add ramps URL scheme deeplinking e2e (#12747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The purpose of this PR is to add e2e coverage for the URL schema deeplinks in the ramps flow. The goal here is to ensure that we properly test the URL scheme deep linking in these flows. ### Sell Deep link ``` Scenario 1 Given I open a sell ETH deeplink for mainnet Then the app should launch with the ramps build quotes page And the token I want to sell is displayed correctly And the amount i want to send is displayed correctly Scenario 2 Given I open a sell deeplink on an unsupported network Then the app should launch with the ramps build quotes page And I am prompted to add the network When I add the network Then the Quotes page should be displayed ``` ### Buy deeplink Flow ``` Scenario 3 Given i deeplink to the buy eth flow on mainnet Then the app should launch with the ramps build quotes page And the token I want to sell is displayed correctly And the amount i want to send is displayed correctly Scenario 4 Given i deeplink to the buy eth flow on a popular network Then the app should launch with the ramps build quotes page And the token I want to sell is displayed correctly And the amount i want to send is displayed correctly ``` ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- e2e/fixtures/fixture-builder.js | 65 ++++++++++---- e2e/pages/Ramps/BuildQuoteView.js | 4 + e2e/pages/Ramps/TokenSelectBottomSheet.js | 12 +++ e2e/resources/blacklistURLs.json | 6 +- e2e/specs/networks/add-custom-rpc.spec.js | 2 +- ...-buy-flow-with-unsupported-network.spec.js | 57 ++++++++++++ e2e/specs/ramps/deeplink-to-buy-flow.spec.js | 55 ++++++++++++ e2e/specs/ramps/deeplink-to-sell-flow.spec.js | 89 +++++++++++++++++++ 8 files changed, 269 insertions(+), 21 deletions(-) create mode 100644 e2e/pages/Ramps/TokenSelectBottomSheet.js create mode 100644 e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js create mode 100644 e2e/specs/ramps/deeplink-to-buy-flow.spec.js create mode 100644 e2e/specs/ramps/deeplink-to-sell-flow.spec.js diff --git a/e2e/fixtures/fixture-builder.js b/e2e/fixtures/fixture-builder.js index 024f90a6c1a..01da16759e2 100644 --- a/e2e/fixtures/fixture-builder.js +++ b/e2e/fixtures/fixture-builder.js @@ -5,7 +5,8 @@ import { merge } from 'lodash'; import { CustomNetworks, PopularNetworksList } from '../resources/networks.e2e'; import { CHAIN_IDS } from '@metamask/transaction-controller'; -export const DEFAULT_FIXTURE_ACCOUNT = '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3'; +export const DEFAULT_FIXTURE_ACCOUNT = + '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3'; const DAPP_URL = 'localhost'; @@ -627,6 +628,7 @@ class FixtureBuilder { selectedRegionAgg: null, selectedPaymentMethodAgg: null, getStartedAgg: false, + getStartedSell: false, authenticationUrls: [], activationKeys: [], }, @@ -696,8 +698,9 @@ class FixtureBuilder { const { providerConfig } = data; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(networkController.networkConfigurationsByChainId).length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(networkController.networkConfigurationsByChainId).length + 1 + }`; // Define the network configuration const networkConfig = { @@ -776,6 +779,30 @@ class FixtureBuilder { return this; } + withRampsSelectedRegion(region = null) { + const defaultRegion = { + currencies: ['/currencies/fiat/xcd'], + emoji: '🇱🇨', + id: '/regions/lc', + name: 'Saint Lucia', + support: { buy: true, sell: true, recurringBuy: true }, + unsupported: false, + recommended: false, + detected: false, + }; + + // Use the provided region or fallback to the default + this.fixture.state.fiatOrders.selectedRegionAgg = region ?? defaultRegion; + return this; + } + withRampsSelectedPaymentMethod() { + const paymentType = '/payments/debit-credit-card'; + + // Use the provided region or fallback to the default + this.fixture.state.fiatOrders.selectedPaymentMethodAgg = paymentType; + return this; + } + /** * Adds chain switching permission for specific chains. * @param {string[]} chainIds - Array of chain IDs to permit (defaults to ['0x1']), other nexts like linea mainnet 0xe708 @@ -818,9 +845,10 @@ class FixtureBuilder { const fixtures = this.fixture.state.engine.backgroundState; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) - .length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) + .length + 1 + }`; // Define the Ganache network configuration const ganacheNetworkConfig = { @@ -856,9 +884,10 @@ class FixtureBuilder { const sepoliaConfig = CustomNetworks.Sepolia.providerConfig; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) - .length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(fixtures.NetworkController.networkConfigurationsByChainId) + .length + 1 + }`; // Define the Sepolia network configuration const sepoliaNetworkConfig = { @@ -908,8 +937,9 @@ class FixtureBuilder { } = network.providerConfig; // Generate a unique key for the new network client ID - const newNetworkClientId = `networkClientId${Object.keys(networkConfigurationsByChainId).length + 1 - }`; + const newNetworkClientId = `networkClientId${ + Object.keys(networkConfigurationsByChainId).length + 1 + }`; // Define the network configuration const networkConfig = { @@ -988,19 +1018,16 @@ class FixtureBuilder { allTokens: { [CHAIN_IDS.MAINNET]: { [DEFAULT_FIXTURE_ACCOUNT]: tokens, - } - } + }, + }, }); return this; } withIncomingTransactionPreferences(incomingTransactionPreferences) { - merge( - this.fixture.state.engine.backgroundState.PreferencesController, - { - showIncomingTransactions: incomingTransactionPreferences, - }, - ); + merge(this.fixture.state.engine.backgroundState.PreferencesController, { + showIncomingTransactions: incomingTransactionPreferences, + }); return this; } diff --git a/e2e/pages/Ramps/BuildQuoteView.js b/e2e/pages/Ramps/BuildQuoteView.js index 407abb8177d..e7bcd2f1ba1 100644 --- a/e2e/pages/Ramps/BuildQuoteView.js +++ b/e2e/pages/Ramps/BuildQuoteView.js @@ -22,6 +22,10 @@ class BuildQuoteView { async tapCancelButton() { await Gestures.waitAndTap(this.cancelButton); } + async tapDefaultToken(token) { + const tokenName = await Matchers.getElementByText(token); + await Gestures.waitAndTap(tokenName); + } } export default new BuildQuoteView(); diff --git a/e2e/pages/Ramps/TokenSelectBottomSheet.js b/e2e/pages/Ramps/TokenSelectBottomSheet.js new file mode 100644 index 00000000000..0625e6bcf0c --- /dev/null +++ b/e2e/pages/Ramps/TokenSelectBottomSheet.js @@ -0,0 +1,12 @@ +import Matchers from '../../utils/Matchers'; +import Gestures from '../../utils/Gestures'; + +class TokenSelectBottomSheet { + async tapTokenByName(token) { + const tokenName = await Matchers.getElementByText(token); + + await Gestures.waitAndTap(tokenName); + } +} + +export default new TokenSelectBottomSheet(); diff --git a/e2e/resources/blacklistURLs.json b/e2e/resources/blacklistURLs.json index e8b620c8ca8..f337d71278b 100644 --- a/e2e/resources/blacklistURLs.json +++ b/e2e/resources/blacklistURLs.json @@ -14,6 +14,10 @@ ".*phishing-detection.cx.metamask.io/.*", ".*eth.llamarpc.com/.*", ".*token-api.metaswap.codefi.network/.*", - ".*gas.api.cx.metamask.io/networks/*" + ".*gas.api.cx.metamask.io/networks/.*", + ".*clients3.google.com/generate_204.*", + ".*pulse.walletconnect.org/batch.*", + ".*accounts.api.cx.metamask.io/v2/accounts/.*", + ".*exp.host/--/api/v2/development-sessions/.*" ] } diff --git a/e2e/specs/networks/add-custom-rpc.spec.js b/e2e/specs/networks/add-custom-rpc.spec.js index cd8269aa2d2..d0d53ce26a5 100644 --- a/e2e/specs/networks/add-custom-rpc.spec.js +++ b/e2e/specs/networks/add-custom-rpc.spec.js @@ -20,7 +20,7 @@ import { CustomNetworks } from '../../resources/networks.e2e'; const fixtureServer = new FixtureServer(); -describe(SmokeCore('Custom RPC Tests'), () => { +describe('Custom RPC Tests', () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder().build(); diff --git a/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js b/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js new file mode 100644 index 00000000000..a999cb28548 --- /dev/null +++ b/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js @@ -0,0 +1,57 @@ +'use strict'; +import TestHelpers from '../../helpers'; + +import { loginToApp } from '../../viewHelper'; +import { withFixtures } from '../../fixtures/fixture-helper'; +import { SmokeCore } from '../../tags'; +import FixtureBuilder from '../../fixtures/fixture-builder'; + +import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; +import BuyGetStartedView from '../../pages/Ramps/BuyGetStartedView'; + +import Assertions from '../../utils/Assertions'; +import NetworkAddedBottomSheet from '../../pages/Network/NetworkAddedBottomSheet'; +import NetworkApprovalBottomSheet from '../../pages/Network/NetworkApprovalBottomSheet'; +import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; + +describe(SmokeCore('Buy Crypto Deeplinks'), () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + beforeEach(async () => { + jest.setTimeout(150000); + }); + + it('should deep link to onramp on Base network', async () => { + const BuyDeepLink = + 'metamask://buy?chainId=8453&address=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&amount=12'; + + await withFixtures( + { + fixture: new FixtureBuilder().withRampsSelectedRegion().build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + await device.sendToHome(); + await device.launchApp({ + url: BuyDeepLink, + }); + + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await BuyGetStartedView.tapGetStartedButton(); + + await Assertions.checkIfVisible(NetworkApprovalBottomSheet.container); + await NetworkApprovalBottomSheet.tapApproveButton(); + await NetworkAddedBottomSheet.tapSwitchToNetwork(); + await Assertions.checkIfVisible(NetworkEducationModal.container); + await NetworkEducationModal.tapGotItButton(); + await Assertions.checkIfTextIsDisplayed('USD Coin'); + }, + ); + }); +}); diff --git a/e2e/specs/ramps/deeplink-to-buy-flow.spec.js b/e2e/specs/ramps/deeplink-to-buy-flow.spec.js new file mode 100644 index 00000000000..0817a1949fa --- /dev/null +++ b/e2e/specs/ramps/deeplink-to-buy-flow.spec.js @@ -0,0 +1,55 @@ +'use strict'; +import TestHelpers from '../../helpers'; + +import { loginToApp } from '../../viewHelper'; +import { withFixtures } from '../../fixtures/fixture-helper'; +import { SmokeCore } from '../../tags'; +import FixtureBuilder from '../../fixtures/fixture-builder'; + +import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; +import BuyGetStartedView from '../../pages/Ramps/BuyGetStartedView'; + +import BuildQuoteView from '../../pages/Ramps/BuildQuoteView'; +import TokenSelectBottomSheet from '../../pages/Ramps/TokenSelectBottomSheet'; +import Assertions from '../../utils/Assertions'; + +describe(SmokeCore('Buy Crypto Deeplinks'), () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + beforeEach(async () => { + jest.setTimeout(150000); + }); + it('should deep link to onramp ETH', async () => { + const buyLink = 'metamask://buy?chainId=1&amount=275'; + + await withFixtures( + { + fixture: new FixtureBuilder() + .withRampsSelectedPaymentMethod() + .withRampsSelectedRegion() + .build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + await device.sendToHome(); + await device.launchApp({ + url: buyLink, + }); + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await BuyGetStartedView.tapGetStartedButton(); + await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); + await BuildQuoteView.tapDefaultToken('Ethereum'); + + await TokenSelectBottomSheet.tapTokenByName('DAI'); + await Assertions.checkIfTextIsDisplayed('Dai Stablecoin'); + await Assertions.checkIfTextIsDisplayed('$275'); + }, + ); + }); +}); diff --git a/e2e/specs/ramps/deeplink-to-sell-flow.spec.js b/e2e/specs/ramps/deeplink-to-sell-flow.spec.js new file mode 100644 index 00000000000..49b43b58cf2 --- /dev/null +++ b/e2e/specs/ramps/deeplink-to-sell-flow.spec.js @@ -0,0 +1,89 @@ +'use strict'; +import { loginToApp } from '../../viewHelper'; + +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { withFixtures } from '../../fixtures/fixture-helper'; + +import TestHelpers from '../../helpers'; +import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; +import { SmokeCore } from '../../tags'; + +import BuildQuoteView from '../../pages/Ramps/BuildQuoteView'; +import Assertions from '../../utils/Assertions'; +import NetworkApprovalBottomSheet from '../../pages/Network/NetworkApprovalBottomSheet'; +import NetworkAddedBottomSheet from '../../pages/Network/NetworkAddedBottomSheet'; +import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; + +describe(SmokeCore('Sell Crypto Deeplinks'), () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + beforeEach(async () => { + jest.setTimeout(150000); + }); + it('should deep link to offramp ETH', async () => { + const sellDeepLinkURL = + 'metamask://sell?chainId=1&address=0x0000000000000000000000000000000000000000&amount=50'; + const franceRegion = { + currencies: ['/currencies/fiat/eur'], + emoji: '🇫🇷', + id: '/regions/fr', + name: 'France', + support: { buy: true, sell: true, recurringBuy: true }, + unsupported: false, + recommended: false, + detected: false, + }; + await withFixtures( + { + fixture: new FixtureBuilder() + .withRampsSelectedRegion(franceRegion) + .build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + + await device.openURL({ + url: sellDeepLinkURL, + }); + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await SellGetStartedView.tapGetStartedButton(); + await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); + + await Assertions.checkIfTextIsDisplayed('50 ETH'); + }, + ); + }); + it('Should deep link to an unsupported network in the off-ramp flow', async () => { + const unsupportedNetworkSellDeepLink = 'metamask://sell?chainId=56'; + + await withFixtures( + { + fixture: new FixtureBuilder().withRampsSelectedRegion().build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + + await device.openURL({ + url: unsupportedNetworkSellDeepLink, + }); + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await SellGetStartedView.tapGetStartedButton(); + + await NetworkApprovalBottomSheet.tapApproveButton(); + await NetworkAddedBottomSheet.tapSwitchToNetwork(); + await Assertions.checkIfVisible(NetworkEducationModal.container); + await NetworkEducationModal.tapGotItButton(); + }, + ); + }); +}); From cb049605ede232b7b23cd2482f3282ff7991a63b Mon Sep 17 00:00:00 2001 From: Brian August Nguyen Date: Fri, 20 Dec 2024 07:39:21 -0800 Subject: [PATCH 19/41] fix: Update layout of "Network added" BottomSheet (#12778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - This PR updates the layout of the `Network added` `BottomSheet` to align with DS's `BottomSheet` ## **Related issues** Fixes: #10910 ## **Manual testing steps** 1. Go to Wallet 2. Click on Network Picker 3. Scroll down and add a new network 4. Add new network 5. Observe change to `Add new network` `BottomSheet` ## **Screenshots/Recordings** ### **Before** ### **After** ![Simulator Screenshot - iPhone 15 Pro Max - 2024-12-18 at 11 35 12](https://github.com/user-attachments/assets/33480430-f76a-4cfe-9c4f-a8701a38d7aa) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/NetworkModal/NetworkAdded/index.tsx | 97 ++++++++++--------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/app/components/UI/NetworkModal/NetworkAdded/index.tsx b/app/components/UI/NetworkModal/NetworkAdded/index.tsx index 299781879c2..8a00786072f 100644 --- a/app/components/UI/NetworkModal/NetworkAdded/index.tsx +++ b/app/components/UI/NetworkModal/NetworkAdded/index.tsx @@ -1,15 +1,30 @@ import React from 'react'; import { StyleSheet, View } from 'react-native'; -import StyledButton from '../../StyledButton'; import { strings } from '../../../../../locales/i18n'; -import Text from '../../../Base/Text'; -import { useTheme } from '../../../../util/theme'; import { NetworkAddedBottomSheetSelectorsIDs } from '../../../../../e2e/selectors/Network/NetworkAddedBottomSheet.selectors'; +import BottomSheetHeader from '../../../../component-library/components/BottomSheets/BottomSheetHeader'; +import Text, { + TextVariant, +} from '../../../../component-library/components/Texts/Text'; +import BottomSheetFooter, { + ButtonsAlignment, +} from '../../../../component-library/components/BottomSheets/BottomSheetFooter'; +import { + ButtonProps, + ButtonVariants, + ButtonSize, +} from '../../../../component-library/components/Buttons/Button/Button.types'; // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any -const createStyles = (colors: any) => +const createStyles = () => StyleSheet.create({ + header: { + padding: 0, + }, + content: { + paddingVertical: 16, + }, buttonView: { flexDirection: 'row', paddingVertical: 16, @@ -17,19 +32,6 @@ const createStyles = (colors: any) => base: { padding: 16, }, - button: { - flex: 1, - }, - cancel: { - marginRight: 8, - backgroundColor: colors.background.default, - borderColor: colors.border.default, - - borderWidth: 1, - }, - confirm: { - marginLeft: 8, - }, }); interface NetworkAddedProps { @@ -40,38 +42,45 @@ interface NetworkAddedProps { const NetworkAdded = (props: NetworkAddedProps) => { const { nickname, closeModal, switchNetwork } = props; - const { colors } = useTheme(); - const styles = createStyles(colors); + const styles = createStyles(); + const buttonProps: ButtonProps[] = [ + { + variant: ButtonVariants.Secondary, + size: ButtonSize.Lg, + onPress: closeModal, + label: strings('networks.close'), + testID: NetworkAddedBottomSheetSelectorsIDs.CLOSE_NETWORK_BUTTON, + }, + { + variant: ButtonVariants.Primary, + size: ButtonSize.Lg, + onPress: switchNetwork, + label: strings('networks.switch_network'), + testID: NetworkAddedBottomSheetSelectorsIDs.SWITCH_NETWORK_BUTTON, + }, + ]; return ( - + {strings('networks.new_network')} - - - {`"${strings('networks.network_name', { - networkName: nickname ?? '', - })}"`} - {strings('networks.network_added')} - - - - {strings('networks.close')} - - - {strings('networks.switch_network')} - + + + + + {`"${strings('networks.network_name', { + networkName: nickname ?? '', + })}"`} + + + {strings('networks.network_added')} + + + ); }; From 920302f0bb1e09e6ed41c063c827c9a2c620c2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n?= Date: Fri, 20 Dec 2024 16:46:00 +0100 Subject: [PATCH 20/41] test: send failing contract (#12802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR is within the scope of the Quality Quest. We're including an e2e test case that send a failing contract in the test dApp. **Steps:** Given I am on the test dapp When I tap on the Send failing transaction button in the Failing Contract section Then the transaction bottom sheet should appear _And I should see a warning "this transaction will likely fail"_ <- This message is not present When I submit the transaction Then the transaction should appear in the transaction history ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- e2e/pages/Browser/TestDApp.js | 11 +++ e2e/selectors/Browser/TestDapp.selectors.js | 1 + .../Transactions/ActivitiesView.selectors.js | 1 + .../send-failing-contract.spec.js | 77 +++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 e2e/specs/confirmations/send-failing-contract.spec.js diff --git a/e2e/pages/Browser/TestDApp.js b/e2e/pages/Browser/TestDApp.js index a9bc65d01d6..1a1f35cbf51 100644 --- a/e2e/pages/Browser/TestDApp.js +++ b/e2e/pages/Browser/TestDApp.js @@ -119,6 +119,13 @@ class TestDApp { ); } + get sendFailingTransactionButton() { + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.SEND_FAILING_TRANSACTION_BUTTON_ID, + ); + } + get erc1155BatchTransferButton() { return Matchers.getElementByWebID( BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, @@ -188,6 +195,10 @@ class TestDApp { await Gestures.tap(this.approveButtonText, 0); } + async tapSendFailingTransactionButton() { + await this.tapButton(this.sendFailingTransactionButton); + } + async tapERC1155BatchTransferButton() { await this.tapButton(this.erc1155BatchTransferButton); } diff --git a/e2e/selectors/Browser/TestDapp.selectors.js b/e2e/selectors/Browser/TestDapp.selectors.js index e0995aa10f0..f2449607808 100644 --- a/e2e/selectors/Browser/TestDapp.selectors.js +++ b/e2e/selectors/Browser/TestDapp.selectors.js @@ -13,5 +13,6 @@ export const TestDappSelectorsWebIDs = { SIGN_TYPE_DATA_V4: 'signTypedDataV4', ETHEREUM_SIGN: 'siwe', ADD_TOKENS_TO_WALLET_BUTTON: 'watchAssets', + SEND_FAILING_TRANSACTION_BUTTON_ID: 'sendFailingButton', BATCH_TRANSFER_ERC1155_BUTTON_ID: 'batchTransferFromButton', }; diff --git a/e2e/selectors/Transactions/ActivitiesView.selectors.js b/e2e/selectors/Transactions/ActivitiesView.selectors.js index 1aba946d5ec..b7e9c7f1fe5 100644 --- a/e2e/selectors/Transactions/ActivitiesView.selectors.js +++ b/e2e/selectors/Transactions/ActivitiesView.selectors.js @@ -10,6 +10,7 @@ export const ActivitiesViewSelectorsIDs = { export const ActivitiesViewSelectorsText = { CONFIRM_TEXT: enContent.transaction.confirmed, + FAILED_TEXT: enContent.transaction.failed, SMART_CONTRACT_INTERACTION: enContent.transactions.smart_contract_interaction, INCREASE_ALLOWANCE_METHOD: enContent.transactions.increase_allowance, SENT_COLLECTIBLE_MESSAGE_TEXT: enContent.transactions.sent_collectible, diff --git a/e2e/specs/confirmations/send-failing-contract.spec.js b/e2e/specs/confirmations/send-failing-contract.spec.js new file mode 100644 index 00000000000..dac0b112d01 --- /dev/null +++ b/e2e/specs/confirmations/send-failing-contract.spec.js @@ -0,0 +1,77 @@ +'use strict'; + +import { SmokeConfirmations } from '../../tags'; +import TestHelpers from '../../helpers'; +import { loginToApp } from '../../viewHelper'; + +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import TestDApp from '../../pages/Browser/TestDApp'; +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { + withFixtures, + defaultGanacheOptions, +} from '../../fixtures/fixture-helper'; +import { SMART_CONTRACTS } from '../../../app/util/test/smart-contracts'; +import { ActivitiesViewSelectorsText } from '../../selectors/Transactions/ActivitiesView.selectors'; +import Assertions from '../../utils/Assertions'; +import { mockEvents } from '../../api-mocking/mock-config/mock-events'; + +describe(SmokeConfirmations('Failing contracts'), () => { + const FAILING_CONTRACT = SMART_CONTRACTS.FAILING; + + beforeAll(async () => { + jest.setTimeout(150000); + await TestHelpers.reverseServerPort(); + }); + + it('sends a failing contract transaction', async () => { + + const testSpecificMock = { + GET: [ + mockEvents.GET.suggestedGasFeesApiGanache + ], + }; + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder() + .withGanacheNetwork() + .withPermissionControllerConnectedToTestDapp() + .build(), + restartDevice: true, + ganacheOptions: defaultGanacheOptions, + smartContract: FAILING_CONTRACT, + testSpecificMock, + }, + async ({ contractRegistry }) => { + const failingAddress = await contractRegistry.getContractAddress( + FAILING_CONTRACT, + ); + await loginToApp(); + + // Navigate to the browser screen + await TabBarComponent.tapBrowser(); + await TestDApp.navigateToTestDappWithContract({ + contractAddress: failingAddress, + }); + + // Send a failing transaction + await TestDApp.tapSendFailingTransactionButton(); + await TestHelpers.delay(3000); + + await TestDApp.tapConfirmButton(); + + // Navigate to the activity screen + await TabBarComponent.tapActivity(); + + // Assert the failed transaction is displayed + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.SMART_CONTRACT_INTERACTION + ); + await Assertions.checkIfTextIsDisplayed( + ActivitiesViewSelectorsText.FAILED_TEXT + ); + }, + ); + }); +}); From bde605fe4280c27940eb24bdab3a29eac6e71c39 Mon Sep 17 00:00:00 2001 From: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:50:00 +0300 Subject: [PATCH 21/41] refactor: rename multichain e2e pipeline (#12809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR renames the multichain e2e pipeline to be more specific about permissions and adds a new pipeline for multichain assets testing. Changes were made in a hierarchical order: 1. Renamed existing pipeline for clarity: - `multichain_e2e_pipeline` → `multichain_permissions_e2e_pipeline` - Renamed stages to include "permissions": - `build_multichain_e2e_ios_android_stage` → `build_multichain_permissions_e2e_ios_android_stage` - `run_multichain_e2e_ios_android_stage` → `run_multichain_permissions_e2e_ios_android_stage` - Renamed build workflows: - `build_ios_multichain_e2e` → `build_ios_multichain_permissions_e2e` - `build_android_multichain_e2e` → `build_android_multichain_permissions_e2e` - Renamed test workflows: - `run_tag_multichain_ios` → `run_tag_multichain_permissions_ios` - `run_tag_multichain_android` → `run_tag_multichain_permissions_android` ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to bitrise mobile project 2. Run the smoke e2e pipeline 3. At the bottom of the list of workflows, you should now see multichain permissions rather than multichain. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- bitrise.yml | 36 +++++++++---------- .../permission-system-revoke-multiple.spec.js | 4 +-- .../permission-system-revoke-single.spec.js | 4 +-- ...ermission-system-add-non-permitted.spec.js | 4 +-- .../permission-system-discard-changes.spec.js | 4 +-- ...rmission-system-initial-connection.spec.js | 4 +-- .../chains/permission-system-remove.spec.js | 4 +-- .../permission-system-revoke-single.spec.js | 4 +-- ...rmission-system-update-permissions.spec.js | 4 +-- e2e/tags.js | 7 ++-- 10 files changed, 38 insertions(+), 37 deletions(-) diff --git a/bitrise.yml b/bitrise.yml index 44878376bba..bbd5b1a6149 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -71,10 +71,10 @@ pipelines: stages: - create_build_qa_android: {} - app_upgrade_test_stage: {} - multichain_e2e_pipeline: + multichain_permissions_e2e_pipeline: stages: - - build_multichain_e2e_ios_android_stage: {} - - run_multichain_e2e_ios_android_stage: {} + - build_multichain_permissions_e2e_ios_android_stage: {} + - run_multichain_permissions_e2e_ios_android_stage: {} # Pipeline for Flask create_flask_release_builds_pipeline: stages: @@ -140,15 +140,15 @@ stages: workflows: - ios_e2e_build: {} - android_e2e_build: {} - build_multichain_e2e_ios_android_stage: + build_multichain_permissions_e2e_ios_android_stage: abort_on_fail: true workflows: - - build_ios_multichain_e2e: {} - - build_android_multichain_e2e: {} - run_multichain_e2e_ios_android_stage: + - build_ios_multichain_permissions_e2e: {} + - build_android_multichain_permissions_e2e: {} + run_multichain_permissions_e2e_ios_android_stage: workflows: - - run_tag_multichain_ios: {} - - run_tag_multichain_android: {} + - run_tag_multichain_permissions_ios: {} + - run_tag_multichain_permissions_android: {} run_smoke_e2e_ios_android_stage: workflows: - run_ios_api_specs: {} @@ -164,8 +164,8 @@ stages: # - run_tag_smoke_swaps_android: {} - run_tag_smoke_core_ios: {} - run_tag_smoke_core_android: {} - - run_tag_multichain_ios: {} - - run_tag_multichain_android: {} + - run_tag_multichain_permissions_ios: {} + - run_tag_multichain_permissions_android: {} build_regression_e2e_ios_android_stage: workflows: - ios_build_regression_tests: {} @@ -539,11 +539,11 @@ workflows: - TEST_TYPE: 'upgrade' after_run: - wdio_android_e2e_test - build_ios_multichain_e2e: + build_ios_multichain_permissions_e2e: after_run: - ios_e2e_build # - android_e2e_build - build_android_multichain_e2e: + build_android_multichain_permissions_e2e: meta: bitrise.io: stack: linux-docker-android-22.04 @@ -683,20 +683,20 @@ workflows: - TEST_SUITE_TAG: '.*SmokeCore.*' after_run: - android_e2e_test - run_tag_multichain_ios: + run_tag_multichain_permissions_ios: envs: - TEST_SUITE_FOLDER: './e2e/specs/multichain/*' - - TEST_SUITE_TAG: '.*SmokeMultiChain.*' + - TEST_SUITE_TAG: '.*SmokeMultiChainPermissions.*' after_run: - ios_e2e_test - run_tag_multichain_android: + run_tag_multichain_permissions_android: meta: bitrise.io: stack: linux-docker-android-22.04 machine_type_id: elite-xl envs: - TEST_SUITE_FOLDER: './e2e/specs/multichain/*' - - TEST_SUITE_TAG: '.*SmokeMultiChain.*' + - TEST_SUITE_TAG: '.*SmokeMultiChainPermissions.*' after_run: - android_e2e_test android_e2e_build: @@ -1831,4 +1831,4 @@ trigger_map: - tag: 'v*.*.*-RC-*' pipeline: release_e2e_pipeline - push_branch: detox/address-regression-tests-slowdown - pipeline: multichain_e2e_pipeline + pipeline: multichain_permissions_e2e_pipeline diff --git a/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js b/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js index 5a77d78a195..039452344a3 100644 --- a/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js +++ b/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js @@ -11,11 +11,11 @@ import { loginToApp } from '../../../../viewHelper'; import FixtureBuilder from '../../../../fixtures/fixture-builder'; import { withFixtures } from '../../../../fixtures/fixture-helper'; import Assertions from '../../../../utils/Assertions'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; const AccountTwoText = 'Account 2'; -describe(SmokeMultiChain('Account Permission Management'), () => { +describe(SmokeMultiChainPermissions('Account Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/accounts/permission-system-revoke-single.spec.js b/e2e/specs/multichain/permissions/accounts/permission-system-revoke-single.spec.js index f2435342826..d1c5a2f8002 100644 --- a/e2e/specs/multichain/permissions/accounts/permission-system-revoke-single.spec.js +++ b/e2e/specs/multichain/permissions/accounts/permission-system-revoke-single.spec.js @@ -1,6 +1,6 @@ 'use strict'; import TestHelpers from '../../../../helpers'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import Browser from '../../../../pages/Browser/BrowserView'; import TabBarComponent from '../../../../pages/wallet/TabBarComponent'; import NetworkListModal from '../../../../pages/Network/NetworkListModal'; @@ -10,7 +10,7 @@ import { withFixtures } from '../../../../fixtures/fixture-helper'; import { loginToApp } from '../../../../viewHelper'; import Assertions from '../../../../utils/Assertions'; -describe(SmokeMultiChain('Account Permission Management'), () => { +describe(SmokeMultiChainPermissions('Account Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/chains/permission-system-add-non-permitted.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-add-non-permitted.spec.js index 1553600b2c6..36af037bba8 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-add-non-permitted.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-add-non-permitted.spec.js @@ -1,4 +1,4 @@ -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import { loginToApp } from '../../../../viewHelper'; import WalletView from '../../../../pages/wallet/WalletView'; import NetworkListModal from '../../../../pages/Network/NetworkListModal'; @@ -22,7 +22,7 @@ const fixtureServer = new FixtureServer(); const SEPOLIA = CustomNetworks.Sepolia.providerConfig.nickname; describe( - SmokeMultiChain('Chain Permission System, non-permitted chain, '), + SmokeMultiChainPermissions('Chain Permission System, non-permitted chain, '), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/chains/permission-system-discard-changes.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-discard-changes.spec.js index 5bcebcdc82a..fdbdcc39402 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-discard-changes.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-discard-changes.spec.js @@ -1,6 +1,6 @@ 'use strict'; import TestHelpers from '../../../../helpers'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import Browser from '../../../../pages/Browser/BrowserView'; import TabBarComponent from '../../../../pages/wallet/TabBarComponent'; import ConnectedAccountsModal from '../../../../pages/Browser/ConnectedAccountsModal'; @@ -11,7 +11,7 @@ import Assertions from '../../../../utils/Assertions'; import NetworkConnectMultiSelector from '../../../../pages/Browser/NetworkConnectMultiSelector'; import NetworkNonPemittedBottomSheet from '../../../../pages/Network/NetworkNonPemittedBottomSheet'; -describe(SmokeMultiChain('Chain Permission Management'), () => { +describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/chains/permission-system-initial-connection.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-initial-connection.spec.js index a6773893814..5e0659c1e57 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-initial-connection.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-initial-connection.spec.js @@ -1,6 +1,6 @@ 'use strict'; import TestHelpers from '../../../../helpers'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import Browser from '../../../../pages/Browser/BrowserView'; import TabBarComponent from '../../../../pages/wallet/TabBarComponent'; import TestDApp from '../../../../pages/Browser/TestDApp'; @@ -13,7 +13,7 @@ import ConnectBottomSheet from '../../../../pages/Browser/ConnectBottomSheet'; import NetworkNonPemittedBottomSheet from '../../../../pages/Network/NetworkNonPemittedBottomSheet'; import NetworkConnectMultiSelector from '../../../../pages/Browser/NetworkConnectMultiSelector'; -describe(SmokeMultiChain('Chain Permission Management'), () => { +describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/chains/permission-system-remove.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-remove.spec.js index e3e7ab3af4c..6c927a02e8f 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-remove.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-remove.spec.js @@ -1,6 +1,6 @@ 'use strict'; import TestHelpers from '../../../../helpers'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import Browser from '../../../../pages/Browser/BrowserView'; import TabBarComponent from '../../../../pages/wallet/TabBarComponent'; @@ -18,7 +18,7 @@ import NetworkEducationModal from '../../../../pages/Network/NetworkEducationMod import ConnectBottomSheet from '../../../../pages/Browser/ConnectBottomSheet'; import PermissionSummaryBottomSheet from '../../../../pages/Browser/PermissionSummaryBottomSheet'; -describe(SmokeMultiChain('Chain Permission Management'), () => { +describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/chains/permission-system-revoke-single.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-revoke-single.spec.js index 720c8db2cb7..5129d70bdaa 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-revoke-single.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-revoke-single.spec.js @@ -1,6 +1,6 @@ 'use strict'; import TestHelpers from '../../../../helpers'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import Browser from '../../../../pages/Browser/BrowserView'; import TabBarComponent from '../../../../pages/wallet/TabBarComponent'; import NetworkListModal from '../../../../pages/Network/NetworkListModal'; @@ -10,7 +10,7 @@ import { withFixtures } from '../../../../fixtures/fixture-helper'; import { loginToApp } from '../../../../viewHelper'; import Assertions from '../../../../utils/Assertions'; -describe(SmokeMultiChain('Chain Permission Management'), () => { +describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js index a4b50516810..dd6967759f1 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js @@ -1,6 +1,6 @@ 'use strict'; import TestHelpers from '../../../../helpers'; -import { SmokeMultiChain } from '../../../../tags'; +import { SmokeMultiChainPermissions } from '../../../../tags'; import Browser from '../../../../pages/Browser/BrowserView'; import TabBarComponent from '../../../../pages/wallet/TabBarComponent'; import ConnectedAccountsModal from '../../../../pages/Browser/ConnectedAccountsModal'; @@ -15,7 +15,7 @@ import WalletView from '../../../../pages/wallet/WalletView'; import NetworkEducationModal from '../../../../pages/Network/NetworkEducationModal'; import PermissionSummaryBottomSheet from '../../../../pages/Browser/PermissionSummaryBottomSheet'; -describe(SmokeMultiChain('Chain Permission Management'), () => { +describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { beforeAll(async () => { jest.setTimeout(150000); await TestHelpers.reverseServerPort(); diff --git a/e2e/tags.js b/e2e/tags.js index 2c7e0950126..9d2eade9368 100644 --- a/e2e/tags.js +++ b/e2e/tags.js @@ -7,7 +7,7 @@ const tags = { SmokeRest: 'SmokeRest:', smokeAssets: 'smokeAssets:', smokeIdentity: 'smokeIdentity:', - smokeMultiChain: 'SmokeMultiChain:', + smokeMultiChainPermissions: 'SmokeMultiChainPermissions:', }; const Regression = (testName) => `${tags.regression} ${testName}`; @@ -19,7 +19,8 @@ const SmokeSwaps = (testName) => `${tags.SmokeSwaps} ${testName}`; const SmokeAssets = (testName) => `${tags.smokeAssets} ${testName}`; const SmokeIdentity = (testName) => `${tags.smokeIdentity} ${testName}`; -const SmokeMultiChain = (testName) => `${tags.smokeMultiChain} ${testName}`; +const SmokeMultiChainPermissions = (testName) => + `${tags.smokeMultiChainPermissions} ${testName}`; export { Regression, SmokeAccounts, @@ -28,5 +29,5 @@ export { SmokeSwaps, SmokeAssets, SmokeIdentity, - SmokeMultiChain, + SmokeMultiChainPermissions, }; From 4b09d4831614da90f62d10dfa9ac8e593bb353ec Mon Sep 17 00:00:00 2001 From: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:56:24 +0300 Subject: [PATCH 22/41] test(3615): add ability to check if chain permission is checked (#12762) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Needed a way to check if the permissions checkbox was checked. Note: existing tests were already using an indirect method to test this: Since we knew that the disconnect all button would should when unchecking the checkboxes, we unchecked the expected checkbox and confirmed the disconnect all button would show, this allowed to test that all and only expected checkboxes were checked. That being said, using this method new makes the test more specialized and decoupled from the disconnect all button, which already has it's own test. It aslo makes it shorter, which is also important. ## **Related issues** Contributes to: https://github.com/MetaMask/MetaMask-planning/issues/3615 ## **Manual testing steps** 1. `yarn watch:clean` 2. `yarn test:e2e:ios:debug:build` 3. `yarn test:e2e:ios:debug:run ` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .../NetworkSelectorList.tsx | 35 ++++++++++--------- .../Browser/NetworkConnectMultiSelector.js | 20 ++++++++++- .../permission-system-revoke-multiple.spec.js | 2 +- ...rmission-system-update-permissions.spec.js | 14 ++++---- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx b/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx index 551146856e0..7fa0acdcb58 100644 --- a/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx +++ b/app/components/UI/NetworkSelectorList/NetworkSelectorList.tsx @@ -1,6 +1,6 @@ // Third party dependencies. import React, { useCallback, useRef } from 'react'; -import { ListRenderItem, ImageSourcePropType } from 'react-native'; +import { ListRenderItem, ImageSourcePropType, View } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; // External dependencies. @@ -53,23 +53,26 @@ const NetworkSelectorList = ({ if (selectedChainIds) { isSelectedNetwork = selectedChainIds.includes(id); } - return ( - onSelectNetwork?.(id, isSelectedNetwork)} - avatarProps={{ - variant: AvatarVariant.Network, - name, - imageSource: imageSource as ImageSourcePropType, - size: AvatarSize.Sm, - }} - disabled={isDisabled} + - {renderRightAccessory?.(id, name)} - + onSelectNetwork?.(id, isSelectedNetwork)} + avatarProps={{ + variant: AvatarVariant.Network, + name, + imageSource: imageSource as ImageSourcePropType, + size: AvatarSize.Sm, + }} + disabled={isDisabled} + > + {renderRightAccessory?.(id, name)} + + ); }, [ diff --git a/e2e/pages/Browser/NetworkConnectMultiSelector.js b/e2e/pages/Browser/NetworkConnectMultiSelector.js index 36a9d8f1b02..9eaf39f8ebd 100644 --- a/e2e/pages/Browser/NetworkConnectMultiSelector.js +++ b/e2e/pages/Browser/NetworkConnectMultiSelector.js @@ -1,7 +1,7 @@ import { NetworkConnectMultiSelectorSelectorsIDs } from '../../selectors/Browser/NetworkConnectMultiSelector.selectors'; import Matchers from '../../utils/Matchers'; import Gestures from '../../utils/Gestures'; - +import { waitFor } from 'detox'; class NetworkConnectMultiSelector { get updateButton() { return Matchers.getElementByID( @@ -22,6 +22,24 @@ class NetworkConnectMultiSelector { async tapBackButton() { await Gestures.waitAndTap(this.backButton); } + + async isNetworkChainPermissionSelected(chainName) { + const chainPermissionTestId = `${chainName}-selected`; + + const element = await Matchers.getElementByID(chainPermissionTestId); + await waitFor(element).toBeVisible().withTimeout(10000); + + return expect(element).toExist(); + } + + async isNetworkChainPermissionNotSelected(chainName) { + const chainPermissionTestId = `${chainName}-not-selected`; + + const element = await Matchers.getElementByID(chainPermissionTestId); + await waitFor(element).toBeVisible().withTimeout(10000); + + return expect(element).toExist(); + } } export default new NetworkConnectMultiSelector(); diff --git a/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js b/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js index 039452344a3..b73885b0910 100644 --- a/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js +++ b/e2e/specs/multichain/permissions/accounts/permission-system-revoke-multiple.spec.js @@ -21,7 +21,7 @@ describe(SmokeMultiChainPermissions('Account Permission Management'), () => { await TestHelpers.reverseServerPort(); }); - it('allows connecting multiple accounts and revoking all permissions simultaneously', async () => { + it('revokes all account permissions simultaneously', async () => { await withFixtures( { dapp: true, diff --git a/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js b/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js index dd6967759f1..53ebea8166b 100644 --- a/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js +++ b/e2e/specs/multichain/permissions/chains/permission-system-update-permissions.spec.js @@ -14,6 +14,7 @@ import { CustomNetworks } from '../../../../resources/networks.e2e'; import WalletView from '../../../../pages/wallet/WalletView'; import NetworkEducationModal from '../../../../pages/Network/NetworkEducationModal'; import PermissionSummaryBottomSheet from '../../../../pages/Browser/PermissionSummaryBottomSheet'; +import { NetworkNonPemittedBottomSheetSelectorsText } from '../../../../selectors/Network/NetworkNonPemittedBottomSheet.selectors'; describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { beforeAll(async () => { @@ -54,14 +55,11 @@ describe(SmokeMultiChainPermissions('Chain Permission Management'), () => { // Verify changes were saved by checking chain permissions again await ConnectedAccountsModal.tapNavigateToEditNetworksPermissionsButton(); - - // Deselect both networks to verify they were the only ones selected - await NetworkNonPemittedBottomSheet.tapEthereumMainNetNetworkName(); - await NetworkNonPemittedBottomSheet.tapLineaSepoliaNetworkName(); - - // Verify the disconnect all button appears (indicating no chains are selected) - await Assertions.checkIfVisible( - ConnectedAccountsModal.disconnectNetworksButton, + await NetworkConnectMultiSelector.isNetworkChainPermissionSelected( + NetworkNonPemittedBottomSheetSelectorsText.ETHEREUM_MAIN_NET_NETWORK_NAME, + ); + await NetworkConnectMultiSelector.isNetworkChainPermissionSelected( + NetworkNonPemittedBottomSheetSelectorsText.LINEA_SEPOLIA_NETWORK_NAME, ); }, ); From 9e11cf640e0f86bec715b404c769597191d1970d Mon Sep 17 00:00:00 2001 From: Curtis David Date: Fri, 20 Dec 2024 11:06:05 -0500 Subject: [PATCH 23/41] test: E2E to reveal SRP on error boundary screen (#12805) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** To catch any regressions in the crash screen’s reveal SRP flow, we should add an end-to-end (e2e) test. Since revealing the Secret Recovery Phrase is the user’s last chance to view and securely save it, this test will check that each step in the flow works smoothly: from entering your password to viewing your SRP. ``` Scenario: A user can reveal their SRP while on the crash screen Given I encounter the crash screen When I tap linked text to reveal my SRP And I enter an invalid password Then I should see the appropriate error When I enter the correct password Then I can see my SRP ``` ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/components/Views/ErrorBoundary/index.js | 11 +++- .../Login/__snapshots__/index.test.tsx.snap | 22 ++++++++ e2e/pages/Browser/TestDApp.js | 10 +++- .../ErrorBoundaryView/ErrorBoundaryView.js | 21 +++++++ .../Network/NetworkApprovalBottomSheet.js | 12 +++- .../ErrorBoundaryView.selectors.js | 9 +++ .../error-boundary-srp-backup.spec.js | 56 +++++++++++++++++++ 7 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 e2e/pages/ErrorBoundaryView/ErrorBoundaryView.js create mode 100644 e2e/selectors/ErrorBoundary/ErrorBoundaryView.selectors.js create mode 100644 e2e/specs/accounts/error-boundary-srp-backup.spec.js diff --git a/app/components/Views/ErrorBoundary/index.js b/app/components/Views/ErrorBoundary/index.js index a0c7af42270..603ebc4f312 100644 --- a/app/components/Views/ErrorBoundary/index.js +++ b/app/components/Views/ErrorBoundary/index.js @@ -40,7 +40,7 @@ import { } from '../../../components/hooks/useMetrics'; import AppConstants from '../../../core/AppConstants'; import { useSelector } from 'react-redux'; - +import { isTest } from '../../../util/test/utils'; // eslint-disable-next-line import/no-commonjs const WarningIcon = require('./warning-icon.png'); @@ -246,7 +246,6 @@ export const Fallback = (props) => { captureSentryFeedback({ sentryId: props.sentryId, comments: feedback }); Alert.alert(strings('error_screen.bug_report_thanks')); }; - return ( @@ -270,6 +269,14 @@ export const Fallback = (props) => { } /> + + {isTest && ( + + + {strings('error_screen.save_seedphrase_2')} + + + )} {strings('error_screen.error_message')} diff --git a/app/components/Views/Login/__snapshots__/index.test.tsx.snap b/app/components/Views/Login/__snapshots__/index.test.tsx.snap index 4beae542b9e..599cee47dee 100644 --- a/app/components/Views/Login/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/Login/__snapshots__/index.test.tsx.snap @@ -186,6 +186,28 @@ exports[`Login should render correctly 1`] = ` + + + save your Secret Recovery Phrase + + { + beforeAll(async () => { + jest.setTimeout(2500000); + await TestHelpers.reverseServerPort(); + }); + + it('should trigger error boundary screen to reveal SRP', async () => { + await withFixtures( + { + dapp: true, + fixture: new FixtureBuilder() + .withGanacheNetwork() + .withPermissionControllerConnectedToTestDapp() + .build(), + restartDevice: true, + ganacheOptions: defaultGanacheOptions, + }, + async () => { + await loginToApp(); + + await TabBarComponent.tapBrowser(); + await Browser.navigateToTestDApp(); + + await TestDApp.tapInvalidSigButton(); + await Assertions.checkIfVisible(ErrorBoundaryView.title); + await ErrorBoundaryView.tapSRPLinkText(); + + await RevealSecretRecoveryPhrase.enterPasswordToRevealSecretCredential( + PASSWORD, + ); + // If the following step fails, ensure you are using a test build with tap and hold to reveal animation disabled + await RevealSecretRecoveryPhrase.tapToReveal(); + await Assertions.checkIfVisible(RevealSecretRecoveryPhrase.container); + + await Assertions.checkIfTextIsDisplayed(defaultGanacheOptions.mnemonic); + }, + ); + }); +}); From 59d72d8a63c7bf3a794ac612ffdcdd6dd4bc944c Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Fri, 20 Dec 2024 17:29:43 +0100 Subject: [PATCH 24/41] fix: fix ramp flow (#12796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** ## **Related issues** Fixes: #11783 ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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: Pedro Pablo Aste Kompen --- .../NetworkSwitcher/NetworkSwitcher.test.tsx | 6 +++-- .../Views/NetworkSwitcher/NetworkSwitcher.tsx | 23 ++++++++++++++----- .../CustomNetworkView/CustomNetwork.tsx | 3 ++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.test.tsx b/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.test.tsx index f9921440bd4..5ae44ae8a59 100644 --- a/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.test.tsx +++ b/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.test.tsx @@ -181,6 +181,7 @@ const mockuseRampSDKInitialValues: Partial = { isBuy: true, isSell: false, rampType: RampType.BUY, + setIntent: jest.fn(), }; let mockUseRampSDKValues: Partial = { @@ -275,12 +276,12 @@ describe('NetworkSwitcher View', () => { expect(cancelButtons3.length).toBe(1); }); - it('switches network by calling setProviderType', async () => { + it('switches network by calling setActiveNetwork', async () => { render(NetworkSwitcher); const lineaNetworkText = screen.getByText('Linea Main Network'); fireEvent.press(lineaNetworkText); expect( - (Engine.context.NetworkController.setProviderType as jest.Mock).mock + (Engine.context.NetworkController.setActiveNetwork as jest.Mock).mock .calls, ).toMatchInlineSnapshot(` [ @@ -290,6 +291,7 @@ describe('NetworkSwitcher View', () => { ] `); + jest.clearAllMocks(); render(NetworkSwitcher); const polygonNetworkTest = screen.getByText('Polygon Mainnet'); fireEvent.press(polygonNetworkTest); diff --git a/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.tsx b/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.tsx index bd41a45d241..6dbf9289fb9 100644 --- a/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.tsx +++ b/app/components/UI/Ramp/Views/NetworkSwitcher/NetworkSwitcher.tsx @@ -59,7 +59,7 @@ function NetworkSwitcher() { } = useRampNetworksDetail(); const supportedNetworks = useSelector(getRampNetworks); const [isCurrentNetworkRampSupported] = useRampNetwork(); - const { selectedChainId, isBuy, intent } = useRampSDK(); + const { selectedChainId, isBuy, intent, setIntent } = useRampSDK(); const networkConfigurations = useSelector(selectNetworkConfigurations); const [networkToBeAdded, setNetworkToBeAdded] = useState(); @@ -145,7 +145,7 @@ function NetworkSwitcher() { const switchToMainnet = useCallback( (type: 'mainnet' | 'linea-mainnet') => { const { NetworkController } = Engine.context; - NetworkController.setProviderType(type); + NetworkController.setActiveNetwork(type); navigateToGetStarted(); }, [navigateToGetStarted], @@ -173,13 +173,23 @@ function NetworkSwitcher() { const handleNetworkPress = useCallback( (networkConfiguration) => { + setIntent((prevIntent) => ({ + ...prevIntent, + chainId: networkConfiguration.chainId, + })); + + const networkConfigurationWithHexChainId = { + ...networkConfiguration, + chainId: toHex(networkConfiguration.chainId), + }; + if (networkConfiguration.isAdded) { - switchNetwork(networkConfiguration); + switchNetwork(networkConfigurationWithHexChainId); } else { - setNetworkToBeAdded(networkConfiguration); + setNetworkToBeAdded(networkConfigurationWithHexChainId); } }, - [switchNetwork], + [setIntent, switchNetwork], ); const handleIntentChainId = useCallback( @@ -199,7 +209,8 @@ function NetworkSwitcher() { (networkConfiguration) => { const isAdded = Object.values(networkConfigurations).some( (savedNetwork) => - savedNetwork.chainId === networkConfiguration.chainId, + toHex(savedNetwork.chainId) === + toHex(networkConfiguration.chainId), ); return { ...networkConfiguration, diff --git a/app/components/Views/Settings/NetworksSettings/NetworkSettings/CustomNetworkView/CustomNetwork.tsx b/app/components/Views/Settings/NetworksSettings/NetworkSettings/CustomNetworkView/CustomNetwork.tsx index fa297b73a7b..afb9f8421e8 100644 --- a/app/components/Views/Settings/NetworksSettings/NetworkSettings/CustomNetworkView/CustomNetwork.tsx +++ b/app/components/Views/Settings/NetworksSettings/NetworkSettings/CustomNetworkView/CustomNetwork.tsx @@ -3,6 +3,7 @@ import NetworkModals from '../../../../../UI/NetworkModal'; import { View, TouchableOpacity } from 'react-native'; import { useSelector } from 'react-redux'; import WarningIcon from 'react-native-vector-icons/FontAwesome'; +import { toHex } from '@metamask/controller-utils'; import CustomText from '../../../../../Base/Text'; import EmptyPopularList from '../emptyList'; import { useNavigation } from '@react-navigation/native'; @@ -46,7 +47,7 @@ const CustomNetwork = ({ // TODO: Replace "any" with type // eslint-disable-next-line @typescript-eslint/no-explicit-any (savedNetwork: any) => - savedNetwork.chainId === networkConfiguration.chainId, + toHex(savedNetwork.chainId) === toHex(networkConfiguration.chainId), ); return { ...networkConfiguration, From 442d33181f46cadf42a7d97b80aa25de00c01d60 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:06:42 +0000 Subject: [PATCH 25/41] feat: @lavamoat/git-safe-dependencies (#12814) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Quality Quest 2024 ft. @naugtur and @tommasini b2b TODO - [x] add package - [x] integrate in CI - [x] update depcheck - [x] socket ## **Related issues** - Fixes: https://github.com/MetaMask/mobile-planning/issues/2079 ## **Manual testing steps** 1. Locally update package.json to `"react-native-tcp": "aprock/react-native-tcp#11/head"` 2. Run `yarn git-safe-dependencies` 3. There should be an error message 4. Revert package.json to the correct `"react-native-tcp": "aprock/react-native-tcp#98fbc801f0586297f16730b2f4c75eef15dfabcd",` 5. Run `yarn git-safe-dependencies` 6. great 7. success ## **Screenshots/Recordings** ### **Before** e.g. package.json > `"react-native-tcp": "aprock/react-native-tcp#11/head",` ![image](https://github.com/user-attachments/assets/f054cda3-ce19-4b64-a84d-e1f92397d2be) ### **After** fixed to: package.json > `"react-native-tcp": "aprock/react-native-tcp#98fbc801f0586297f16730b2f4c75eef15dfabcd",` in https://github.com/MetaMask/metamask-mobile/pull/12595 ![image](https://github.com/user-attachments/assets/a3340650-743f-48f8-a4bc-b1dcfd81d243) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .depcheckrc.yml | 1 + .github/workflows/ci.yml | 13 ++++++- package.json | 5 ++- yarn.lock | 79 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/.depcheckrc.yml b/.depcheckrc.yml index babe74bcd3a..df73bd5e8ad 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -6,6 +6,7 @@ ignores: - '@react-native-community/slider' - 'patch-package' - '@lavamoat/allow-scripts' + - '@lavamoat/git-safe-dependencies' - 'babel-plugin-inline-import' # This is used on the patch for TokenRatesController of Assets controllers, for we to be able to use the last version of it - cockatiel diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c453cc01200..71c11d98d64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,17 @@ jobs: echo "Duplicate dependencies detected; run 'yarn deduplicate' to remove them" exit 1 fi + git-safe-dependencies: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: yarn + - run: yarn setup --node + - name: Run @lavamoat/git-safe-dependencies + run: yarn git-safe-dependencies scripts: runs-on: ubuntu-20.04 strategy: @@ -323,4 +334,4 @@ jobs: else echo "All jobs passed step skipped. Block PR." exit 1 - fi \ No newline at end of file + fi diff --git a/package.json b/package.json index b6b74ef38a3..62afebe29a0 100644 --- a/package.json +++ b/package.json @@ -159,9 +159,9 @@ "@metamask/composable-controller": "^10.0.0", "@metamask/controller-utils": "^11.3.0", "@metamask/design-tokens": "^4.0.0", + "@metamask/eth-hd-keyring": "^9.0.0", "@metamask/eth-json-rpc-filters": "^9.0.0", "@metamask/eth-json-rpc-middleware": "^15.0.0", - "@metamask/eth-hd-keyring": "^9.0.0", "@metamask/eth-ledger-bridge-keyring": "^8.0.0", "@metamask/eth-query": "^4.0.0", "@metamask/eth-sig-util": "^8.0.0", @@ -170,8 +170,8 @@ "@metamask/ethjs-contract": "^0.4.1", "@metamask/ethjs-query": "^0.7.1", "@metamask/ethjs-unit": "^0.3.0", - "@metamask/json-rpc-engine": "^10.0.0", "@metamask/gas-fee-controller": "^22.0.2", + "@metamask/json-rpc-engine": "^10.0.0", "@metamask/json-rpc-middleware-stream": "^8.0.2", "@metamask/key-tree": "^9.0.0", "@metamask/keyring-api": "^10.1.0", @@ -383,6 +383,7 @@ "@ethersproject/contracts": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@lavamoat/allow-scripts": "^3.0.4", + "@lavamoat/git-safe-dependencies": "^0.1.0", "@metamask/browser-passworder": "^5.0.0", "@metamask/build-utils": "^1.0.0", "@metamask/eslint-config-typescript": "^9.0.0", diff --git a/yarn.lock b/yarn.lock index 1c291169aa3..0634bd37f44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4219,6 +4219,15 @@ npm-normalize-package-bin "3.0.1" yargs "17.7.2" +"@lavamoat/git-safe-dependencies@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@lavamoat/git-safe-dependencies/-/git-safe-dependencies-0.1.0.tgz#5896d4e3972964f900f74809b207a03bbcbb90c5" + integrity sha512-KhtdqJkOroMyiqfFJbyKOYxLkay+ZoXeNaPcjty5rLSJ2Yy0Bwhuk2twQF3C3IRAR0FF36KVzTsAA4281imMKA== + dependencies: + glob "11.0.0" + hosted-git-info "8.0.2" + lockfile-lint-api "^5.9.1" + "@ledgerhq/cryptoassets-evm-signatures@^13.5.0": version "13.5.0" resolved "https://registry.yarnpkg.com/@ledgerhq/cryptoassets-evm-signatures/-/cryptoassets-evm-signatures-13.5.0.tgz#19ad9c567fe40efa822b9f5a8d3968210024e704" @@ -11293,6 +11302,14 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== +"@yarnpkg/parsers@^3.0.0-rc.48.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.2.tgz#48a1517a0f49124827f4c37c284a689c607b2f32" + integrity sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA== + dependencies: + js-yaml "^3.10.0" + tslib "^2.4.0" + Base64@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028" @@ -18024,6 +18041,18 @@ glob@10.4.5, glob@^10.0.0, glob@^10.2.2, glob@^10.3.10, glob@^10.3.4, glob@^10.4 package-json-from-dist "^1.0.0" path-scurry "^1.11.1" +glob@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e" + integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^4.0.1" + minimatch "^10.0.0" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + glob@7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -18491,6 +18520,13 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +hosted-git-info@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-8.0.2.tgz#5bd7d8b5395616e41cc0d6578381a32f669b14b2" + integrity sha512-sYKnA7eGln5ov8T8gnYlkSOxFJvywzEx9BueN6xo/GKO8PGiI6uK6xx+DIGe45T3bdVjLAQDQW1aicT8z8JwQg== + dependencies: + lru-cache "^10.0.1" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -19667,6 +19703,13 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jackspeak@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015" + integrity sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw== + dependencies: + "@isaacs/cliui" "^8.0.2" + jake@^10.8.5: version "10.8.5" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46" @@ -20227,7 +20270,7 @@ js-sha3@^0.9.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.12.1, js-yaml@^3.13.1, js-yaml@^3.14.1: +js-yaml@^3.10.0, js-yaml@^3.12.1, js-yaml@^3.13.1, js-yaml@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -20982,6 +21025,15 @@ locate-path@^7.1.0: dependencies: p-locate "^6.0.0" +lockfile-lint-api@^5.9.1: + version "5.9.1" + resolved "https://registry.yarnpkg.com/lockfile-lint-api/-/lockfile-lint-api-5.9.1.tgz#12b10434792fa8b8dd0e332ddfbac55ea70a9e08" + integrity sha512-us5IT1bGA6KXbq1WrhrSzk9mtPgHKz5nhvv3S4hwcYnhcVOKW2uK0W8+PN9oIgv4pI49WsD5wBdTQFTpNChF/Q== + dependencies: + "@yarnpkg/parsers" "^3.0.0-rc.48.1" + debug "^4.3.4" + object-hash "^3.0.0" + lockfile@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" @@ -21236,6 +21288,11 @@ lru-cache@10.4.3, lru-cache@^10.0.0, lru-cache@^10.0.1, lru-cache@^10.0.2, lru-c resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^11.0.0: + version "11.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39" + integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA== + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -21908,6 +21965,13 @@ minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" +minimatch@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + minimatch@^5.0.0, minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" @@ -22738,6 +22802,11 @@ object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1 resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + object-inspect@^1.10.3, object-inspect@^1.13.1, object-inspect@^1.6.0: version "1.13.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" @@ -23390,6 +23459,14 @@ path-scurry@^1.10.1, path-scurry@^1.11.1, path-scurry@^1.6.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + path-to-regexp@0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" From ec8804c3fbbb1cf62e8f23ba3e712f0f3337a169 Mon Sep 17 00:00:00 2001 From: Brian August Nguyen Date: Fri, 20 Dec 2024 09:24:07 -0800 Subject: [PATCH 26/41] fix: Updated display format for asset currency dif (#12775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - This PR updates the format of the change in currency for negative cases to be `-$123.45` instead of `$-123.45` ## **Related issues** Fixes: #10922 ## **Manual testing steps** 1. Go to Assets 2. Look at the amount changed in dollars 3. ## **Screenshots/Recordings** ### **Before** ### **After** ![Simulator Screenshot - iPhone 15 Pro Max - 2024-12-18 at 11 57 50](https://github.com/user-attachments/assets/df7fc031-2152-4f72-878e-4be41d0e0d0c) ![Screenshot_1734563249](https://github.com/user-attachments/assets/d713ddee-cfcf-4e68-b08c-566e448a12a1) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/util/number/index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/util/number/index.js b/app/util/number/index.js index 28027c52b7a..894716562aa 100644 --- a/app/util/number/index.js +++ b/app/util/number/index.js @@ -482,6 +482,7 @@ export function addCurrencySymbol( currencyCode, extendDecimals = false, ) { + const prefix = parseFloat(amount) < 0 ? '-' : ''; if (extendDecimals) { if (isNumberScientificNotationWhenString(amount)) { amount = amount.toFixed(18); @@ -512,17 +513,22 @@ export function addCurrencySymbol( amount = parseFloat(amount).toFixed(2); } + const amountString = amount.toString(); + const absAmountStr = amountString.startsWith('-') + ? amountString.slice(1) // Remove the first character if it's a '-' + : amountString; + if (currencySymbols[currencyCode]) { - return `${currencySymbols[currencyCode]}${amount}`; + return `${prefix}${currencySymbols[currencyCode]}${absAmountStr}`; } const lowercaseCurrencyCode = currencyCode?.toLowerCase(); if (currencySymbols[lowercaseCurrencyCode]) { - return `${currencySymbols[lowercaseCurrencyCode]}${amount}`; + return `${prefix}${currencySymbols[lowercaseCurrencyCode]}${absAmountStr}`; } - return `${amount} ${currencyCode}`; + return `${prefix}${absAmountStr} ${currencyCode}`; } /** From 754f4f90b064eb26475de0db9a9776efebf09306 Mon Sep 17 00:00:00 2001 From: Brian August Nguyen Date: Fri, 20 Dec 2024 10:50:40 -0800 Subject: [PATCH 27/41] [Design Quality] Updated navbar title to remove green dot (#12773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - This PR updates the navbar title to remove the green dot - Also updated the navbar title in Receive flow ## **Related issues** Fixes: #12768 ## **Manual testing steps** 1. Go to wallet 2. Click on asset 3. Observe change in header 4. Go to receive 5. Observe change in header ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/84d7e1c0-a9a9-4c26-9584-6d83cd1614bd ![Screenshot_1734556451](https://github.com/user-attachments/assets/0e294a97-5234-4b4b-bd8c-a1b250d0f9f3) ![Screenshot_1734557087](https://github.com/user-attachments/assets/fbe5baac-6859-413e-9a27-6cd9ea6c1be6) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .../BottomSheetHeader.test.tsx.snap | 1 - .../HeaderBase/HeaderBase.styles.ts | 1 - .../__snapshots__/HeaderBase.test.tsx.snap | 1 - app/components/UI/NavbarTitle/index.js | 46 +-- .../__snapshots__/index.test.tsx.snap | 1 - .../NetworkVerificationInfo.test.tsx.snap | 1 - .../__snapshots__/BuildQuote.test.tsx.snap | 364 ++++-------------- .../__snapshots__/GetStarted.test.tsx.snap | 104 +---- .../NetworkSwitcher.test.tsx.snap | 235 +++-------- .../__snapshots__/OrderDetails.test.tsx.snap | 286 +++----------- .../PaymentMethods.test.tsx.snap | 260 +++---------- .../Quotes/__snapshots__/Quotes.test.tsx.snap | 184 ++------- .../__snapshots__/Regions.test.tsx.snap | 234 +++-------- .../SendTransaction.test.tsx.snap | 78 +--- .../GasImpactModal.test.tsx.snap | 1 - .../__snapshots__/MaxInputModal.test.tsx.snap | 1 - .../__snapshots__/QuotesView.test.ts.snap | 28 +- ...tPermissionsConfirmRevokeAll.test.tsx.snap | 1 - .../RpcSelectionModal.test.tsx.snap | 1 - .../Views/QRTabSwitcher/QRTabSwitcher.tsx | 37 +- app/components/Views/QRTabSwitcher/styles.ts | 8 +- .../Send/__snapshots__/index.test.tsx.snap | 26 +- .../Confirm/__snapshots__/index.test.tsx.snap | 26 +- 23 files changed, 380 insertions(+), 1545 deletions(-) diff --git a/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap b/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap index bda8377bdd9..03389274972 100644 --- a/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap +++ b/app/component-library/components/BottomSheets/BottomSheetHeader/__snapshots__/BottomSheetHeader.test.tsx.snap @@ -4,7 +4,6 @@ exports[`BottomSheetHeader should render snapshot correctly 1`] = ` @@ -21,38 +22,11 @@ const createStyles = (colors) => wrapper: { justifyContent: 'center', alignItems: 'center', - flex: 1, }, network: { flexDirection: 'row', alignItems: 'center', }, - networkName: { - fontSize: 11, - color: colors.text.alternative, - ...fontStyles.normal, - }, - networkIcon: { - width: 5, - height: 5, - borderRadius: 100, - marginRight: 5, - }, - title: { - fontSize: scale(14), - ...fontStyles.normal, - color: colors.text.default, - }, - children: { - ...fontStyles.normal, - color: colors.text.default, - fontWeight: 'bold', - }, - otherNetworkIcon: { - backgroundColor: importedColors.transparent, - borderColor: colors.border.default, - borderWidth: 1, - }, }); /** @@ -163,26 +137,22 @@ class NavbarTitle extends PureComponent { activeOpacity={this.props.disableNetwork ? 1 : 0.2} > {title ? ( - + {realTitle} ) : null} {typeof children === 'string' ? ( - - {strings(children)} - + {strings(children)} ) : ( children )} {showSelectedNetwork ? ( - - + {name} diff --git a/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap b/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap index fb2c30e33a1..343d6450187 100644 --- a/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/NetworkModal/__snapshots__/index.test.tsx.snap @@ -146,7 +146,6 @@ exports[`NetworkDetails renders correctly 1`] = ` - @@ -858,7 +842,6 @@ exports[`BuildQuote View Crypto Currency Data renders a special error page if cr style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -869,9 +852,9 @@ exports[`BuildQuote View Crypto Currency Data renders a special error page if cr style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -887,21 +870,6 @@ exports[`BuildQuote View Crypto Currency Data renders a special error page if cr } } > - @@ -1559,7 +1527,6 @@ exports[`BuildQuote View Crypto Currency Data renders an error page when there i style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1570,9 +1537,9 @@ exports[`BuildQuote View Crypto Currency Data renders an error page when there i style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1588,21 +1555,6 @@ exports[`BuildQuote View Crypto Currency Data renders an error page when there i } } > - @@ -2231,7 +2183,6 @@ exports[`BuildQuote View Crypto Currency Data renders the loading page when cryp style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -2242,9 +2193,9 @@ exports[`BuildQuote View Crypto Currency Data renders the loading page when cryp style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -2260,21 +2211,6 @@ exports[`BuildQuote View Crypto Currency Data renders the loading page when cryp } } > - @@ -3179,7 +3115,6 @@ exports[`BuildQuote View Fiat Currency Data renders an error page when there is style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -3190,9 +3125,9 @@ exports[`BuildQuote View Fiat Currency Data renders an error page when there is style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -3208,21 +3143,6 @@ exports[`BuildQuote View Fiat Currency Data renders an error page when there is } } > - @@ -3851,7 +3771,6 @@ exports[`BuildQuote View Fiat Currency Data renders the loading page when fiats style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -3862,9 +3781,9 @@ exports[`BuildQuote View Fiat Currency Data renders the loading page when fiats style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -3880,21 +3799,6 @@ exports[`BuildQuote View Fiat Currency Data renders the loading page when fiats } } > - @@ -4799,7 +4703,6 @@ exports[`BuildQuote View Payment Method Data renders an error page when there is style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -4810,9 +4713,9 @@ exports[`BuildQuote View Payment Method Data renders an error page when there is style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -4828,21 +4731,6 @@ exports[`BuildQuote View Payment Method Data renders an error page when there is } } > - @@ -5471,7 +5359,6 @@ exports[`BuildQuote View Payment Method Data renders the loading page when payme style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -5482,9 +5369,9 @@ exports[`BuildQuote View Payment Method Data renders the loading page when payme style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -5500,21 +5387,6 @@ exports[`BuildQuote View Payment Method Data renders the loading page when payme } } > - @@ -6419,7 +6291,6 @@ exports[`BuildQuote View Regions data renders an error page when there is a regi style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -6430,9 +6301,9 @@ exports[`BuildQuote View Regions data renders an error page when there is a regi style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -6448,21 +6319,6 @@ exports[`BuildQuote View Regions data renders an error page when there is a regi } } > - @@ -7091,7 +6947,6 @@ exports[`BuildQuote View Regions data renders the loading page when regions are style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -7102,9 +6957,9 @@ exports[`BuildQuote View Regions data renders the loading page when regions are style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -7120,21 +6975,6 @@ exports[`BuildQuote View Regions data renders the loading page when regions are } } > - @@ -8039,7 +7879,6 @@ exports[`BuildQuote View renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -8050,9 +7889,9 @@ exports[`BuildQuote View renders correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -8068,21 +7907,6 @@ exports[`BuildQuote View renders correctly 1`] = ` } } > - @@ -11094,7 +10918,6 @@ exports[`BuildQuote View renders correctly 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -11105,9 +10928,9 @@ exports[`BuildQuote View renders correctly 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -11123,21 +10946,6 @@ exports[`BuildQuote View renders correctly 2`] = ` } } > - @@ -14129,7 +13937,6 @@ exports[`BuildQuote View renders correctly when sdkError is present 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -14140,9 +13947,9 @@ exports[`BuildQuote View renders correctly when sdkError is present 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -14158,21 +13965,6 @@ exports[`BuildQuote View renders correctly when sdkError is present 1`] = ` } } > - @@ -14801,7 +14593,6 @@ exports[`BuildQuote View renders correctly when sdkError is present 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -14812,9 +14603,9 @@ exports[`BuildQuote View renders correctly when sdkError is present 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -14830,21 +14621,6 @@ exports[`BuildQuote View renders correctly when sdkError is present 2`] = ` } } > - diff --git a/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap b/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap index 747b1d55068..c19b71c5914 100644 --- a/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap +++ b/app/components/UI/Ramp/Views/GetStarted/__snapshots__/GetStarted.test.tsx.snap @@ -134,7 +134,6 @@ exports[`GetStarted renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -145,9 +144,9 @@ exports[`GetStarted renders correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -163,21 +162,6 @@ exports[`GetStarted renders correctly 1`] = ` } } > - @@ -807,7 +791,6 @@ exports[`GetStarted renders correctly 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -818,9 +801,9 @@ exports[`GetStarted renders correctly 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -836,21 +819,6 @@ exports[`GetStarted renders correctly 2`] = ` } } > - @@ -1480,7 +1448,6 @@ exports[`GetStarted renders correctly when getStarted is true 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1491,9 +1458,9 @@ exports[`GetStarted renders correctly when getStarted is true 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1509,21 +1476,6 @@ exports[`GetStarted renders correctly when getStarted is true 1`] = ` } } > - @@ -1923,7 +1875,6 @@ exports[`GetStarted renders correctly when sdkError is present 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1934,9 +1885,9 @@ exports[`GetStarted renders correctly when sdkError is present 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1952,21 +1903,6 @@ exports[`GetStarted renders correctly when sdkError is present 1`] = ` } } > - diff --git a/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap b/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap index a55851ee09d..90a5e588c9f 100644 --- a/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap +++ b/app/components/UI/Ramp/Views/NetworkSwitcher/__snapshots__/NetworkSwitcher.test.tsx.snap @@ -134,7 +134,6 @@ exports[`NetworkSwitcher View renders and dismisses network modal when pressing style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -145,9 +144,9 @@ exports[`NetworkSwitcher View renders and dismisses network modal when pressing style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -163,21 +162,6 @@ exports[`NetworkSwitcher View renders and dismisses network modal when pressing } } > - @@ -978,7 +962,6 @@ exports[`NetworkSwitcher View renders and dismisses network modal when pressing - @@ -3037,7 +3004,6 @@ exports[`NetworkSwitcher View renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -3048,9 +3014,9 @@ exports[`NetworkSwitcher View renders correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -3066,21 +3032,6 @@ exports[`NetworkSwitcher View renders correctly 1`] = ` } } > - @@ -4192,7 +4143,6 @@ exports[`NetworkSwitcher View renders correctly 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -4203,9 +4153,9 @@ exports[`NetworkSwitcher View renders correctly 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -4221,21 +4171,6 @@ exports[`NetworkSwitcher View renders correctly 2`] = ` } } > - @@ -5347,7 +5282,6 @@ exports[`NetworkSwitcher View renders correctly while loading 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -5358,9 +5292,9 @@ exports[`NetworkSwitcher View renders correctly while loading 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -5376,21 +5310,6 @@ exports[`NetworkSwitcher View renders correctly while loading 1`] = ` } } > - @@ -6690,7 +6609,6 @@ exports[`NetworkSwitcher View renders correctly while loading 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -6701,9 +6619,9 @@ exports[`NetworkSwitcher View renders correctly while loading 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -6719,21 +6637,6 @@ exports[`NetworkSwitcher View renders correctly while loading 2`] = ` } } > - @@ -8033,7 +7936,6 @@ exports[`NetworkSwitcher View renders correctly with errors 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -8044,9 +7946,9 @@ exports[`NetworkSwitcher View renders correctly with errors 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -8062,21 +7964,6 @@ exports[`NetworkSwitcher View renders correctly with errors 1`] = ` } } > - @@ -8682,7 +8569,6 @@ exports[`NetworkSwitcher View renders correctly with errors 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -8693,9 +8579,9 @@ exports[`NetworkSwitcher View renders correctly with errors 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -8711,21 +8597,6 @@ exports[`NetworkSwitcher View renders correctly with errors 2`] = ` } } > - @@ -9331,7 +9202,6 @@ exports[`NetworkSwitcher View renders correctly with no data 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -9342,9 +9212,9 @@ exports[`NetworkSwitcher View renders correctly with no data 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -9360,21 +9230,6 @@ exports[`NetworkSwitcher View renders correctly with no data 1`] = ` } } > - diff --git a/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap b/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap index 9d129bacdfa..f25e42498a0 100644 --- a/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap +++ b/app/components/UI/Ramp/Views/OrderDetails/__snapshots__/OrderDetails.test.tsx.snap @@ -157,7 +157,6 @@ exports[`OrderDetails renders a cancelled order 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -168,9 +167,9 @@ exports[`OrderDetails renders a cancelled order 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -186,21 +185,6 @@ exports[`OrderDetails renders a cancelled order 1`] = ` } } > - @@ -1659,7 +1643,6 @@ exports[`OrderDetails renders a completed order 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1670,9 +1653,9 @@ exports[`OrderDetails renders a completed order 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1688,21 +1671,6 @@ exports[`OrderDetails renders a completed order 1`] = ` } } > - @@ -3172,7 +3140,6 @@ exports[`OrderDetails renders a created order 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -3183,9 +3150,9 @@ exports[`OrderDetails renders a created order 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -3201,21 +3168,6 @@ exports[`OrderDetails renders a created order 1`] = ` } } > - @@ -4646,7 +4598,6 @@ exports[`OrderDetails renders a failed order 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -4657,9 +4608,9 @@ exports[`OrderDetails renders a failed order 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -4675,21 +4626,6 @@ exports[`OrderDetails renders a failed order 1`] = ` } } > - @@ -6148,7 +6084,6 @@ exports[`OrderDetails renders a pending order 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -6159,9 +6094,9 @@ exports[`OrderDetails renders a pending order 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -6177,21 +6112,6 @@ exports[`OrderDetails renders a pending order 1`] = ` } } > - @@ -7622,7 +7542,6 @@ exports[`OrderDetails renders an empty screen layout if there is no order 1`] = style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -7633,9 +7552,9 @@ exports[`OrderDetails renders an empty screen layout if there is no order 1`] = style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -7651,21 +7570,6 @@ exports[`OrderDetails renders an empty screen layout if there is no order 1`] = } } > - @@ -8065,7 +7969,6 @@ exports[`OrderDetails renders an error screen if a CREATED order cannot be polle style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -8076,9 +7979,9 @@ exports[`OrderDetails renders an error screen if a CREATED order cannot be polle style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -8094,21 +7997,6 @@ exports[`OrderDetails renders an error screen if a CREATED order cannot be polle } } > - @@ -8714,7 +8602,6 @@ exports[`OrderDetails renders non-transacted orders 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -8725,9 +8612,9 @@ exports[`OrderDetails renders non-transacted orders 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -8743,21 +8630,6 @@ exports[`OrderDetails renders non-transacted orders 1`] = ` } } > - @@ -10270,7 +10142,6 @@ exports[`OrderDetails renders the support links if the provider has them 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -10281,9 +10152,9 @@ exports[`OrderDetails renders the support links if the provider has them 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -10299,21 +10170,6 @@ exports[`OrderDetails renders the support links if the provider has them 1`] = ` } } > - @@ -11831,7 +11687,6 @@ exports[`OrderDetails renders transacted orders that do not have timeDescription style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -11842,9 +11697,9 @@ exports[`OrderDetails renders transacted orders that do not have timeDescription style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -11860,21 +11715,6 @@ exports[`OrderDetails renders transacted orders that do not have timeDescription } } > - @@ -13305,7 +13145,6 @@ exports[`OrderDetails renders transacted orders that have timeDescriptionPending style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -13316,9 +13155,9 @@ exports[`OrderDetails renders transacted orders that have timeDescriptionPending style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -13334,21 +13173,6 @@ exports[`OrderDetails renders transacted orders that have timeDescriptionPending } } > - diff --git a/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap b/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap index 8137c427852..2e25a8d696d 100644 --- a/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap +++ b/app/components/UI/Ramp/Views/PaymentMethods/__snapshots__/PaymentMethods.test.tsx.snap @@ -157,7 +157,6 @@ exports[`PaymentMethods View renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -168,9 +167,9 @@ exports[`PaymentMethods View renders correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -186,21 +185,6 @@ exports[`PaymentMethods View renders correctly 1`] = ` } } > - @@ -1620,7 +1604,6 @@ exports[`PaymentMethods View renders correctly for sell 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1631,9 +1614,9 @@ exports[`PaymentMethods View renders correctly for sell 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1649,21 +1632,6 @@ exports[`PaymentMethods View renders correctly for sell 1`] = ` } } > - @@ -3083,7 +3051,6 @@ exports[`PaymentMethods View renders correctly while loading 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -3094,9 +3061,9 @@ exports[`PaymentMethods View renders correctly while loading 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -3112,21 +3079,6 @@ exports[`PaymentMethods View renders correctly while loading 1`] = ` } } > - @@ -4324,7 +4276,6 @@ exports[`PaymentMethods View renders correctly with empty data 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -4335,9 +4286,9 @@ exports[`PaymentMethods View renders correctly with empty data 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -4353,21 +4304,6 @@ exports[`PaymentMethods View renders correctly with empty data 1`] = ` } } > - @@ -4998,7 +4934,6 @@ exports[`PaymentMethods View renders correctly with empty data for sell 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -5009,9 +4944,9 @@ exports[`PaymentMethods View renders correctly with empty data for sell 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -5027,21 +4962,6 @@ exports[`PaymentMethods View renders correctly with empty data for sell 1`] = ` } } > - @@ -5672,7 +5592,6 @@ exports[`PaymentMethods View renders correctly with error 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -5683,9 +5602,9 @@ exports[`PaymentMethods View renders correctly with error 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -5701,21 +5620,6 @@ exports[`PaymentMethods View renders correctly with error 1`] = ` } } > - @@ -6344,7 +6248,6 @@ exports[`PaymentMethods View renders correctly with null data 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -6355,9 +6258,9 @@ exports[`PaymentMethods View renders correctly with null data 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -6373,21 +6276,6 @@ exports[`PaymentMethods View renders correctly with null data 1`] = ` } } > - @@ -7585,7 +7473,6 @@ exports[`PaymentMethods View renders correctly with payment method with disclaim style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -7596,9 +7483,9 @@ exports[`PaymentMethods View renders correctly with payment method with disclaim style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -7614,21 +7501,6 @@ exports[`PaymentMethods View renders correctly with payment method with disclaim } } > - @@ -9106,7 +8978,6 @@ exports[`PaymentMethods View renders correctly with sdkError 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -9117,9 +8988,9 @@ exports[`PaymentMethods View renders correctly with sdkError 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -9135,21 +9006,6 @@ exports[`PaymentMethods View renders correctly with sdkError 1`] = ` } } > - @@ -9755,7 +9611,6 @@ exports[`PaymentMethods View renders correctly with show back button false 1`] = style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -9766,9 +9621,9 @@ exports[`PaymentMethods View renders correctly with show back button false 1`] = style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -9784,21 +9639,6 @@ exports[`PaymentMethods View renders correctly with show back button false 1`] = } } > - diff --git a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap index 9240f96c2a9..3ad1e4f304e 100644 --- a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap @@ -681,7 +681,6 @@ exports[`Quotes renders animation on first fetching 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -692,9 +691,9 @@ exports[`Quotes renders animation on first fetching 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -710,21 +709,6 @@ exports[`Quotes renders animation on first fetching 1`] = ` } } > - @@ -2920,7 +2904,6 @@ exports[`Quotes renders correctly after animation with quotes 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -2931,9 +2914,9 @@ exports[`Quotes renders correctly after animation with quotes 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -2949,21 +2932,6 @@ exports[`Quotes renders correctly after animation with quotes 1`] = ` } } > - @@ -3315,7 +3283,6 @@ exports[`Quotes renders correctly after animation with quotes 1`] = ` - @@ -4667,7 +4618,6 @@ exports[`Quotes renders correctly after animation with quotes and expanded 2`] = - @@ -6804,7 +6738,6 @@ exports[`Quotes renders correctly when fetching quotes errors 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -6815,9 +6748,9 @@ exports[`Quotes renders correctly when fetching quotes errors 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -6833,21 +6766,6 @@ exports[`Quotes renders correctly when fetching quotes errors 1`] = ` } } > - @@ -7562,7 +7480,6 @@ exports[`Quotes renders correctly with sdkError 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -7573,9 +7490,9 @@ exports[`Quotes renders correctly with sdkError 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -7591,21 +7508,6 @@ exports[`Quotes renders correctly with sdkError 1`] = ` } } > - @@ -8320,7 +8222,6 @@ exports[`Quotes renders quotes expired screen 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -8331,9 +8232,9 @@ exports[`Quotes renders quotes expired screen 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -8349,21 +8250,6 @@ exports[`Quotes renders quotes expired screen 1`] = ` } } > - diff --git a/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap b/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap index 5a5c62b514f..d181f8b8542 100644 --- a/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Regions/__snapshots__/Regions.test.tsx.snap @@ -134,7 +134,6 @@ exports[`Regions View renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -145,9 +144,9 @@ exports[`Regions View renders correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -163,21 +162,6 @@ exports[`Regions View renders correctly 1`] = ` } } > - @@ -950,7 +934,6 @@ exports[`Regions View renders correctly while loading 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -961,9 +944,9 @@ exports[`Regions View renders correctly while loading 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -979,21 +962,6 @@ exports[`Regions View renders correctly while loading 1`] = ` } } > - @@ -1561,7 +1529,6 @@ exports[`Regions View renders correctly with error 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1572,9 +1539,9 @@ exports[`Regions View renders correctly with error 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1590,21 +1557,6 @@ exports[`Regions View renders correctly with error 1`] = ` } } > - @@ -2210,7 +2162,6 @@ exports[`Regions View renders correctly with no data 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -2221,9 +2172,9 @@ exports[`Regions View renders correctly with no data 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -2239,21 +2190,6 @@ exports[`Regions View renders correctly with no data 1`] = ` } } > - @@ -2821,7 +2757,6 @@ exports[`Regions View renders correctly with sdkError 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -2832,9 +2767,9 @@ exports[`Regions View renders correctly with sdkError 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -2850,21 +2785,6 @@ exports[`Regions View renders correctly with sdkError 1`] = ` } } > - @@ -3470,7 +3390,6 @@ exports[`Regions View renders correctly with selectedRegion 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -3481,9 +3400,9 @@ exports[`Regions View renders correctly with selectedRegion 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -3499,21 +3418,6 @@ exports[`Regions View renders correctly with selectedRegion 1`] = ` } } > - @@ -4284,7 +4188,6 @@ exports[`Regions View renders correctly with unsupportedRegion 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -4295,9 +4198,9 @@ exports[`Regions View renders correctly with unsupportedRegion 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -4313,21 +4216,6 @@ exports[`Regions View renders correctly with unsupportedRegion 1`] = ` } } > - @@ -5473,7 +5361,6 @@ exports[`Regions View renders correctly with unsupportedRegion 2`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -5484,9 +5371,9 @@ exports[`Regions View renders correctly with unsupportedRegion 2`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -5502,21 +5389,6 @@ exports[`Regions View renders correctly with unsupportedRegion 2`] = ` } } > - @@ -6662,7 +6534,6 @@ exports[`Regions View renders regions modal when pressing select button 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -6673,9 +6544,9 @@ exports[`Regions View renders regions modal when pressing select button 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -6691,21 +6562,6 @@ exports[`Regions View renders regions modal when pressing select button 1`] = ` } } > - diff --git a/app/components/UI/Ramp/Views/SendTransaction/__snapshots__/SendTransaction.test.tsx.snap b/app/components/UI/Ramp/Views/SendTransaction/__snapshots__/SendTransaction.test.tsx.snap index f3ad57c5056..2b0c2a89da8 100644 --- a/app/components/UI/Ramp/Views/SendTransaction/__snapshots__/SendTransaction.test.tsx.snap +++ b/app/components/UI/Ramp/Views/SendTransaction/__snapshots__/SendTransaction.test.tsx.snap @@ -157,7 +157,6 @@ exports[`SendTransaction View renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -168,9 +167,9 @@ exports[`SendTransaction View renders correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -186,21 +185,6 @@ exports[`SendTransaction View renders correctly 1`] = ` } } > - @@ -972,7 +956,6 @@ exports[`SendTransaction View renders correctly for custom action payment method style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -983,9 +966,9 @@ exports[`SendTransaction View renders correctly for custom action payment method style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1001,21 +984,6 @@ exports[`SendTransaction View renders correctly for custom action payment method } } > - @@ -1703,7 +1671,6 @@ exports[`SendTransaction View renders correctly for token 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -1714,9 +1681,9 @@ exports[`SendTransaction View renders correctly for token 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -1732,21 +1699,6 @@ exports[`SendTransaction View renders correctly for token 1`] = ` } } > - diff --git a/app/components/UI/Stake/components/GasImpactModal/__snapshots__/GasImpactModal.test.tsx.snap b/app/components/UI/Stake/components/GasImpactModal/__snapshots__/GasImpactModal.test.tsx.snap index 4050753f14d..1643b96b393 100644 --- a/app/components/UI/Stake/components/GasImpactModal/__snapshots__/GasImpactModal.test.tsx.snap +++ b/app/components/UI/Stake/components/GasImpactModal/__snapshots__/GasImpactModal.test.tsx.snap @@ -136,7 +136,6 @@ exports[`GasImpactModal render matches snapshot 1`] = ` - diff --git a/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/__snapshots__/AccountPermissionsConfirmRevokeAll.test.tsx.snap b/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/__snapshots__/AccountPermissionsConfirmRevokeAll.test.tsx.snap index 470bc9a07c3..efa598a9fbf 100644 --- a/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/__snapshots__/AccountPermissionsConfirmRevokeAll.test.tsx.snap +++ b/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/__snapshots__/AccountPermissionsConfirmRevokeAll.test.tsx.snap @@ -126,7 +126,6 @@ exports[`AccountPermissionsConfirmRevokeAll renders correctly 1`] = ` { ) : null} - {selectedIndex === QRTabSwitcherScreens.Receive ? ( - - ) : null} - + + } + > + {selectedIndex === QRTabSwitcherScreens.Receive ? ( + + ) : null} + {disableTabber ? null : ( diff --git a/app/components/Views/QRTabSwitcher/styles.ts b/app/components/Views/QRTabSwitcher/styles.ts index 46e09f4c5cc..7a2eb38654f 100644 --- a/app/components/Views/QRTabSwitcher/styles.ts +++ b/app/components/Views/QRTabSwitcher/styles.ts @@ -21,16 +21,10 @@ const createStyles = (theme: Theme) => { justifyContent: 'flex-start', }, overlay: { - flexDirection: 'row', - justifyContent: 'flex-end', position: 'absolute', width: '100%', top: navbarTop, - }, - closeIcon: { - position: 'absolute', - top: 0, - right: 15, + paddingHorizontal: 16, }, segmentedControlContainer: { position: 'absolute', diff --git a/app/components/Views/confirmations/Send/__snapshots__/index.test.tsx.snap b/app/components/Views/confirmations/Send/__snapshots__/index.test.tsx.snap index e0f712f62e0..3fa1e08f901 100644 --- a/app/components/Views/confirmations/Send/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/confirmations/Send/__snapshots__/index.test.tsx.snap @@ -157,7 +157,6 @@ exports[`Accounts should render correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -168,9 +167,9 @@ exports[`Accounts should render correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -186,21 +185,6 @@ exports[`Accounts should render correctly 1`] = ` } } > - diff --git a/app/components/Views/confirmations/SendFlow/Confirm/__snapshots__/index.test.tsx.snap b/app/components/Views/confirmations/SendFlow/Confirm/__snapshots__/index.test.tsx.snap index 910a960a2c1..375f22756fe 100644 --- a/app/components/Views/confirmations/SendFlow/Confirm/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/confirmations/SendFlow/Confirm/__snapshots__/index.test.tsx.snap @@ -155,7 +155,6 @@ exports[`Confirm should render correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "justifyContent": "center", } } @@ -166,9 +165,9 @@ exports[`Confirm should render correctly 1`] = ` style={ { "color": "#141618", - "fontFamily": "EuclidCircularB-Regular", - "fontSize": 30, - "fontWeight": "400", + "fontFamily": "EuclidCircularB-Bold", + "fontSize": 14, + "fontWeight": "700", "letterSpacing": 0, "lineHeight": 22, } @@ -184,21 +183,6 @@ exports[`Confirm should render correctly 1`] = ` } } > - From c37adbebf6ae5fa70602c361058955510f3c6256 Mon Sep 17 00:00:00 2001 From: sethkfman <10342624+sethkfman@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:58:23 -0700 Subject: [PATCH 28/41] chore: 7.37.1 & main sync (#12817) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR sync stable and main together from the 7.37.1 release. ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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: metamaskbot Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com> Co-authored-by: Nico MASSART Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com> Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com> Co-authored-by: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Co-authored-by: Salim TOUBAL Co-authored-by: Daniel <80175477+dan437@users.noreply.github.com> Co-authored-by: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ android/app/build.gradle | 4 ++-- bitrise.yml | 10 +++++----- ios/MetaMask.xcodeproj/project.pbxproj | 24 ++++++++++++------------ package.json | 2 +- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 155b760639f..0cfee4c59bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Current Main Branch +## 7.37.1 - Dec 16, 2024 +### Fixed +- [#12577](https://github.com/MetaMask/metamask-mobile/pull/12577): chore: bump {gas-fee,network,selected-network,notification-services,profile-sync,signature}-controller (#12577) +- [#12694](https://github.com/MetaMask/metamask-mobile/pull/12694): fix: small refactoring of the latest migration script + add a new migration case (#12694) +- [#12664](https://github.com/MetaMask/metamask-mobile/pull/12664): fix: mark transactions as failed for cancelled / unknown smart transactions (#12664) + ## 7.37.0 - Nov 28, 2024 ### Added - [#12091](https://github.com/MetaMask/metamask-mobile/pull/12091): feat: 2020 Add a performance test for iOS in Bitrise (#12091) diff --git a/android/app/build.gradle b/android/app/build.gradle index c856cc0492f..5692a52de02 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -178,8 +178,8 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionName "7.37.0" - versionCode 1512 + versionName "7.37.1" + versionCode 1520 testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/bitrise.yml b/bitrise.yml index bbd5b1a6149..f02e4b3e711 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -970,7 +970,7 @@ workflows: inputs: - content: |- #!/usr/bin/env bash - brew install ccache with HOMEBREW_NO_DEPENDENTS_CHECK=1 + brew install ccache with HOMEBREW_NO_DEPENDENTS_CHECK=1 ln -s $(which ccache) /usr/local/bin/gcc ln -s $(which ccache) /usr/local/bin/g++ ln -s $(which ccache) /usr/local/bin/cc @@ -1781,16 +1781,16 @@ app: PROJECT_LOCATION_IOS: ios - opts: is_expand: false - VERSION_NAME: 7.37.0 + VERSION_NAME: 7.37.1 - opts: is_expand: false - VERSION_NUMBER: 1512 + VERSION_NUMBER: 1520 - opts: is_expand: false - FLASK_VERSION_NAME: 7.37.0 + FLASK_VERSION_NAME: 7.37.1 - opts: is_expand: false - FLASK_VERSION_NUMBER: 1512 + FLASK_VERSION_NUMBER: 1520 - opts: is_expand: false ANDROID_APK_LINK: '' diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index 604be1574b1..fde045b95df 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -1380,7 +1380,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1512; + CURRENT_PROJECT_VERSION = 1520; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1418,7 +1418,7 @@ "${inherited}", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.37.0; + MARKETING_VERSION = 7.37.1; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1449,7 +1449,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1512; + CURRENT_PROJECT_VERSION = 1520; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1484,7 +1484,7 @@ "${inherited}", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.37.0; + MARKETING_VERSION = 7.37.1; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1514,7 +1514,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1512; + CURRENT_PROJECT_VERSION = 1520; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1547,7 +1547,7 @@ ); LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)"; LLVM_LTO = YES; - MARKETING_VERSION = 7.37.0; + MARKETING_VERSION = 7.37.1; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1576,7 +1576,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1512; + CURRENT_PROJECT_VERSION = 1520; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1607,7 +1607,7 @@ ); LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)"; LLVM_LTO = YES; - MARKETING_VERSION = 7.37.0; + MARKETING_VERSION = 7.37.1; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1731,7 +1731,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1512; + CURRENT_PROJECT_VERSION = 1520; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1768,7 +1768,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.37.0; + MARKETING_VERSION = 7.37.1; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "$(inherited)", @@ -1800,7 +1800,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1512; + CURRENT_PROJECT_VERSION = 1520; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1835,7 +1835,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.37.0; + MARKETING_VERSION = 7.37.1; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", diff --git a/package.json b/package.json index 62afebe29a0..2eeeb68a5a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask", - "version": "7.37.0", + "version": "7.37.1", "private": true, "scripts": { "audit:ci": "./scripts/yarn-audit.sh", From 5fe6aceffcf4c80ed1f3530282640aebcd201935 Mon Sep 17 00:00:00 2001 From: Curtis David Date: Fri, 20 Dec 2024 18:50:07 -0500 Subject: [PATCH 29/41] test: Enhance ramps deeplink e2e (#12821) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR updates some actions in the ramps deep-linking e2e tests to reflect changes from an earlier PR that fixed a few edge case bugs. It also sets up an Android-only CI workflow for the ramps tests. ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- bitrise.yml | 12 ++++++ e2e/pages/Network/NetworkAddedBottomSheet.js | 20 +++------- e2e/resources/networks.e2e.js | 4 +- ...-buy-flow-with-unsupported-network.spec.js | 21 ++++++---- e2e/specs/ramps/deeplink-to-buy-flow.spec.js | 40 ++++++++++++++++++- e2e/specs/ramps/deeplink-to-sell-flow.spec.js | 29 +++++++++----- e2e/specs/ramps/offramp.spec.js | 4 +- e2e/specs/ramps/onramp.spec.js | 4 +- e2e/tags.js | 3 ++ 9 files changed, 97 insertions(+), 40 deletions(-) diff --git a/bitrise.yml b/bitrise.yml index f02e4b3e711..e46fa35dea7 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -160,6 +160,7 @@ stages: - run_tag_smoke_assets_android: {} - run_tag_smoke_confirmations_ios: {} - run_tag_smoke_confirmations_android: {} + - run_tag_smoke_ramps_android: {} # - run_tag_smoke_swaps_ios: {} # - run_tag_smoke_swaps_android: {} - run_tag_smoke_core_ios: {} @@ -182,6 +183,7 @@ stages: - run_tag_smoke_confirmations_android: {} - run_tag_smoke_accounts_ios: {} - run_tag_smoke_accounts_android: {} + - run_tag_smoke_ramps_android: {} # - run_tag_smoke_identity_ios: {} # - run_tag_smoke_identity_android: {} # - run_tag_smoke_assets_ios: {} @@ -699,6 +701,16 @@ workflows: - TEST_SUITE_TAG: '.*SmokeMultiChainPermissions.*' after_run: - android_e2e_test + run_tag_smoke_ramps_android: + meta: + bitrise.io: + stack: linux-docker-android-22.04 + machine_type_id: elite-xl + envs: + - TEST_SUITE_FOLDER: './e2e/specs/ramps/*' + - TEST_SUITE_TAG: '.*SmokeRamps.*' + after_run: + - android_e2e_test android_e2e_build: before_run: - code_setup diff --git a/e2e/pages/Network/NetworkAddedBottomSheet.js b/e2e/pages/Network/NetworkAddedBottomSheet.js index 0bb721b3ccc..ca841c6fb2d 100644 --- a/e2e/pages/Network/NetworkAddedBottomSheet.js +++ b/e2e/pages/Network/NetworkAddedBottomSheet.js @@ -13,23 +13,15 @@ class NetworkAddedBottomSheet { } get switchNetworkButton() { - return device.getPlatform() === 'android' - ? Matchers.getElementByLabel( - NetworkAddedBottomSheetSelectorsIDs.SWITCH_NETWORK_BUTTON, - ) - : Matchers.getElementByID( - NetworkAddedBottomSheetSelectorsIDs.SWITCH_NETWORK_BUTTON, - ); + return Matchers.getElementByID( + NetworkAddedBottomSheetSelectorsIDs.SWITCH_NETWORK_BUTTON, + ); } get closeNetworkButton() { - return device.getPlatform() === 'android' - ? Matchers.getElementByLabel( - NetworkAddedBottomSheetSelectorsIDs.CLOSE_NETWORK_BUTTON, - ) - : Matchers.getElementByID( - NetworkAddedBottomSheetSelectorsIDs.CLOSE_NETWORK_BUTTON, - ); + return Matchers.getElementByID( + NetworkAddedBottomSheetSelectorsIDs.CLOSE_NETWORK_BUTTON, + ); } async tapSwitchToNetwork() { diff --git a/e2e/resources/networks.e2e.js b/e2e/resources/networks.e2e.js index 1cd7b4eb927..8480ea55e74 100644 --- a/e2e/resources/networks.e2e.js +++ b/e2e/resources/networks.e2e.js @@ -10,7 +10,7 @@ const PopularNetworksList = { type: 'rpc', chainId: toHex('43114'), rpcUrl: 'https://api.avax.network/ext/bc/C/rpc', - nickname: 'Avalanche Mainnet C-Chain', + nickname: 'Avalanche C-Chain', ticker: 'AVAX', }, }, @@ -46,7 +46,7 @@ const PopularNetworksList = { type: 'rpc', chainId: toHex('10'), rpcUrl: `https://optimism-mainnet.infura.io/v3/${infuraProjectId}`, - nickname: 'Optimism', + nickname: 'OP Mainnet', ticker: 'ETH', }, }, diff --git a/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js b/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js index a999cb28548..329df8acd11 100644 --- a/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js +++ b/e2e/specs/ramps/deeplink-to-buy-flow-with-unsupported-network.spec.js @@ -3,7 +3,7 @@ import TestHelpers from '../../helpers'; import { loginToApp } from '../../viewHelper'; import { withFixtures } from '../../fixtures/fixture-helper'; -import { SmokeCore } from '../../tags'; +import { SmokeRamps } from '../../tags'; import FixtureBuilder from '../../fixtures/fixture-builder'; import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; @@ -13,8 +13,10 @@ import Assertions from '../../utils/Assertions'; import NetworkAddedBottomSheet from '../../pages/Network/NetworkAddedBottomSheet'; import NetworkApprovalBottomSheet from '../../pages/Network/NetworkApprovalBottomSheet'; import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; +import NetworkListModal from '../../pages/Network/NetworkListModal'; +import { PopularNetworksList } from '../../resources/networks.e2e'; -describe(SmokeCore('Buy Crypto Deeplinks'), () => { +describe(SmokeRamps('Buy Crypto Deeplinks'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); }); @@ -23,9 +25,8 @@ describe(SmokeCore('Buy Crypto Deeplinks'), () => { jest.setTimeout(150000); }); - it('should deep link to onramp on Base network', async () => { - const BuyDeepLink = - 'metamask://buy?chainId=8453&address=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&amount=12'; + it('should deep link to onramp to unsupported network', async () => { + const BuyDeepLink = 'metamask://buy?chainId=2'; await withFixtures( { @@ -45,12 +46,16 @@ describe(SmokeCore('Buy Crypto Deeplinks'), () => { await BuyGetStartedView.tapGetStartedButton(); - await Assertions.checkIfVisible(NetworkApprovalBottomSheet.container); + await Assertions.checkIfTextIsDisplayed('Unsupported buy Network'); + await NetworkListModal.changeNetworkTo( + PopularNetworksList.Avalanche.providerConfig.nickname, + ); await NetworkApprovalBottomSheet.tapApproveButton(); - await NetworkAddedBottomSheet.tapSwitchToNetwork(); + await NetworkAddedBottomSheet.tapCloseButton(); await Assertions.checkIfVisible(NetworkEducationModal.container); await NetworkEducationModal.tapGotItButton(); - await Assertions.checkIfTextIsDisplayed('USD Coin'); + await Assertions.checkIfTextIsNotDisplayed('Unsupported buy Network'); + await Assertions.checkIfTextIsDisplayed('Avalanche'); }, ); }); diff --git a/e2e/specs/ramps/deeplink-to-buy-flow.spec.js b/e2e/specs/ramps/deeplink-to-buy-flow.spec.js index 0817a1949fa..df9a62b634e 100644 --- a/e2e/specs/ramps/deeplink-to-buy-flow.spec.js +++ b/e2e/specs/ramps/deeplink-to-buy-flow.spec.js @@ -3,7 +3,7 @@ import TestHelpers from '../../helpers'; import { loginToApp } from '../../viewHelper'; import { withFixtures } from '../../fixtures/fixture-helper'; -import { SmokeCore } from '../../tags'; +import { SmokeRamps } from '../../tags'; import FixtureBuilder from '../../fixtures/fixture-builder'; import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; @@ -13,7 +13,9 @@ import BuildQuoteView from '../../pages/Ramps/BuildQuoteView'; import TokenSelectBottomSheet from '../../pages/Ramps/TokenSelectBottomSheet'; import Assertions from '../../utils/Assertions'; -describe(SmokeCore('Buy Crypto Deeplinks'), () => { +import { PopularNetworksList } from '../../resources/networks.e2e'; +import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; +describe(SmokeRamps('Buy Crypto Deeplinks'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); }); @@ -52,4 +54,38 @@ describe(SmokeCore('Buy Crypto Deeplinks'), () => { }, ); }); + it('should deep link to onramp on Base network', async () => { + const BuyDeepLink = + 'metamask://buy?chainId=8453&address=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&amount=12'; + + await withFixtures( + { + fixture: new FixtureBuilder() + .withPopularNetworks() + .withRampsSelectedRegion() + .build(), + restartDevice: true, + }, + async () => { + await loginToApp(); + await device.sendToHome(); + await device.launchApp({ + url: BuyDeepLink, + }); + + await Assertions.checkIfVisible( + await SellGetStartedView.getStartedButton, + ); + + await BuyGetStartedView.tapGetStartedButton(); + + await Assertions.checkIfVisible(NetworkEducationModal.container); + await NetworkEducationModal.tapGotItButton(); + await Assertions.checkIfTextIsDisplayed('USD Coin'); + await Assertions.checkIfTextIsDisplayed( + PopularNetworksList.Base.providerConfig.nickname, + ); + }, + ); + }); }); diff --git a/e2e/specs/ramps/deeplink-to-sell-flow.spec.js b/e2e/specs/ramps/deeplink-to-sell-flow.spec.js index 49b43b58cf2..279968e5902 100644 --- a/e2e/specs/ramps/deeplink-to-sell-flow.spec.js +++ b/e2e/specs/ramps/deeplink-to-sell-flow.spec.js @@ -6,15 +6,17 @@ import { withFixtures } from '../../fixtures/fixture-helper'; import TestHelpers from '../../helpers'; import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; -import { SmokeCore } from '../../tags'; +import { SmokeRamps } from '../../tags'; import BuildQuoteView from '../../pages/Ramps/BuildQuoteView'; import Assertions from '../../utils/Assertions'; import NetworkApprovalBottomSheet from '../../pages/Network/NetworkApprovalBottomSheet'; import NetworkAddedBottomSheet from '../../pages/Network/NetworkAddedBottomSheet'; import NetworkEducationModal from '../../pages/Network/NetworkEducationModal'; +import NetworkListModal from '../../pages/Network/NetworkListModal'; +import { PopularNetworksList } from '../../resources/networks.e2e'; -describe(SmokeCore('Sell Crypto Deeplinks'), () => { +describe(SmokeRamps('Sell Crypto Deeplinks'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); }); @@ -59,8 +61,8 @@ describe(SmokeCore('Sell Crypto Deeplinks'), () => { }, ); }); - it('Should deep link to an unsupported network in the off-ramp flow', async () => { - const unsupportedNetworkSellDeepLink = 'metamask://sell?chainId=56'; + it('should deep link to offramp with Base but switch network to OP Mainnet', async () => { + const SellDeepLink = 'metamask://sell?chainId=8453'; await withFixtures( { @@ -69,20 +71,27 @@ describe(SmokeCore('Sell Crypto Deeplinks'), () => { }, async () => { await loginToApp(); - - await device.openURL({ - url: unsupportedNetworkSellDeepLink, + await device.sendToHome(); + await device.launchApp({ + url: SellDeepLink, }); await Assertions.checkIfVisible( await SellGetStartedView.getStartedButton, ); - await SellGetStartedView.tapGetStartedButton(); - + await Assertions.checkIfVisible(NetworkApprovalBottomSheet.container); + await NetworkApprovalBottomSheet.tapCancelButton(); + await NetworkListModal.changeNetworkTo( + PopularNetworksList.Optimism.providerConfig.nickname, + ); await NetworkApprovalBottomSheet.tapApproveButton(); - await NetworkAddedBottomSheet.tapSwitchToNetwork(); + await NetworkAddedBottomSheet.tapCloseButton(); await Assertions.checkIfVisible(NetworkEducationModal.container); await NetworkEducationModal.tapGotItButton(); + await Assertions.checkIfTextIsDisplayed('Ethereum'); + await Assertions.checkIfTextIsDisplayed( + PopularNetworksList.Optimism.providerConfig.nickname, + ); }, ); }); diff --git a/e2e/specs/ramps/offramp.spec.js b/e2e/specs/ramps/offramp.spec.js index b352a696427..027c6051f29 100644 --- a/e2e/specs/ramps/offramp.spec.js +++ b/e2e/specs/ramps/offramp.spec.js @@ -12,7 +12,7 @@ import { CustomNetworks } from '../../resources/networks.e2e'; import TestHelpers from '../../helpers'; import FixtureServer from '../../fixtures/fixture-server'; import { getFixturesServerPort } from '../../fixtures/utils'; -import { SmokeCore } from '../../tags'; +import { SmokeRamps } from '../../tags'; import Assertions from '../../utils/Assertions'; import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; import SelectRegionView from '../../pages/Ramps/SelectRegionView'; @@ -34,7 +34,7 @@ const PaymentMethods = { ACH_BANK_TRANSFER: 'ACH Bank Transfer', }; -describe(SmokeCore('Off-Ramp'), () => { +describe(SmokeRamps('Off-Ramp'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder() diff --git a/e2e/specs/ramps/onramp.spec.js b/e2e/specs/ramps/onramp.spec.js index 6ce7d152291..be78ab9d9e9 100644 --- a/e2e/specs/ramps/onramp.spec.js +++ b/e2e/specs/ramps/onramp.spec.js @@ -11,7 +11,7 @@ import { import TestHelpers from '../../helpers'; import FixtureServer from '../../fixtures/fixture-server'; import { getFixturesServerPort } from '../../fixtures/utils'; -import { SmokeCore } from '../../tags'; +import { SmokeRamps } from '../../tags'; import BuyGetStartedView from '../../pages/Ramps/BuyGetStartedView'; import SelectRegionView from '../../pages/Ramps/SelectRegionView'; import SelectPaymentMethodView from '../../pages/Ramps/SelectPaymentMethodView'; @@ -20,7 +20,7 @@ import Assertions from '../../utils/Assertions'; const fixtureServer = new FixtureServer(); -describe(SmokeCore('Buy Crypto'), () => { +describe(SmokeRamps('Buy Crypto'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder().build(); diff --git a/e2e/tags.js b/e2e/tags.js index 9d2eade9368..2d23561e08e 100644 --- a/e2e/tags.js +++ b/e2e/tags.js @@ -8,6 +8,7 @@ const tags = { smokeAssets: 'smokeAssets:', smokeIdentity: 'smokeIdentity:', smokeMultiChainPermissions: 'SmokeMultiChainPermissions:', + smokeRamps: 'SmokeRamps:', }; const Regression = (testName) => `${tags.regression} ${testName}`; @@ -18,6 +19,7 @@ const SmokeConfirmations = (testName) => const SmokeSwaps = (testName) => `${tags.SmokeSwaps} ${testName}`; const SmokeAssets = (testName) => `${tags.smokeAssets} ${testName}`; const SmokeIdentity = (testName) => `${tags.smokeIdentity} ${testName}`; +const SmokeRamps = (testName) => `${tags.smokeRamps} ${testName}`; const SmokeMultiChainPermissions = (testName) => `${tags.smokeMultiChainPermissions} ${testName}`; @@ -30,4 +32,5 @@ export { SmokeAssets, SmokeIdentity, SmokeMultiChainPermissions, + SmokeRamps, }; From d0942f523f506ee7eca210fab8136b6221df5c48 Mon Sep 17 00:00:00 2001 From: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:22:34 +0000 Subject: [PATCH 30/41] fix: hide `ApprovalTagUrl` when origins is internal (#12629) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR aims to omit the origin pill when the origin is internal. ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3777 ## **Manual testing steps** 1. On your wallet view, click on "Earn" 2. Go through the staking flow 3. See no origin pill on the confirmation ## **Screenshots/Recordings** https://github.com/user-attachments/assets/518a5253-49a1-40e2-a6fb-6b8239dc2c59 ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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/ApprovalTagUrl/ApprovalTagUrl.test.tsx | 21 +++++++++++++++++-- .../UI/ApprovalTagUrl/ApprovalTagUrl.tsx | 5 ++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.test.tsx b/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.test.tsx index 415cff34f01..0b260915412 100644 --- a/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.test.tsx +++ b/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.test.tsx @@ -1,10 +1,12 @@ import React from 'react'; import renderWithProvider from '../../../util/test/renderWithProvider'; -import ApprovalTagUrl from './ApprovalTagUrl'; +import ApprovalTagUrl, { APPROVAL_TAG_URL_ORIGIN_PILL } from './ApprovalTagUrl'; import { backgroundState } from '../../../util/test/initial-root-state'; +import { INTERNAL_ORIGINS } from '../../../constants/transaction'; const ADDRESS_MOCK = '0x1234567890abcdef1234567890abcdef12345678'; const DOMAIN_MOCK = 'metamask.github.io'; + const mockInitialState = { settings: {}, engine: { @@ -19,7 +21,7 @@ const mockInitialState = { describe('ApprovalTagUrl', () => { it('renders correctly', () => { - const { toJSON } = renderWithProvider( + const { toJSON, getByTestId } = renderWithProvider( { ); expect(toJSON()).toMatchSnapshot(); + expect(getByTestId(APPROVAL_TAG_URL_ORIGIN_PILL)).toBeDefined(); + }); + + it('does not render when origin is an internal origin', () => { + const { queryByTestId } = renderWithProvider( + , + { state: mockInitialState }, + ); + + expect(queryByTestId(APPROVAL_TAG_URL_ORIGIN_PILL)).toBeNull(); }); }); diff --git a/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx b/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx index 48ca00125da..dc7ebc8aa2d 100644 --- a/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx +++ b/app/components/UI/ApprovalTagUrl/ApprovalTagUrl.tsx @@ -11,6 +11,7 @@ import { selectAccountsByChainId } from '../../../selectors/accountTrackerContro import { getHost, prefixUrlWithProtocol } from '../../../util/browser'; import useFavicon from '../../hooks/useFavicon/useFavicon'; import stylesheet from './ApprovalTagUrl.styles'; +import { INTERNAL_ORIGINS } from '../../../constants/transaction'; const { ORIGIN_DEEPLINK, ORIGIN_QR_CODE } = AppConstants.DEEPLINKS; export const APPROVAL_TAG_URL_ORIGIN_PILL = 'APPROVAL_TAG_URL_ORIGIN_PILL'; @@ -76,7 +77,9 @@ const ApprovalTagUrl = ({ uri: '', }; - if (origin && !isOriginDeepLink) { + const showOrigin = origin && !isOriginDeepLink && !INTERNAL_ORIGINS.includes(origin); + + if (showOrigin) { return ( Date: Mon, 6 Jan 2025 16:31:03 -0500 Subject: [PATCH 31/41] test: change browser homepage for e2e (#12839) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** In an effort to mitigate flakiness introduced by https://github.com/MetaMask/metamask-mobile/issues/12019, the purpose of this PR is to change the default browser home page from the portfolio dapp to the test dapp. ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- e2e/fixtures/fixture-builder.js | 2 +- e2e/pages/Browser/ConnectedAccountsModal.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/fixtures/fixture-builder.js b/e2e/fixtures/fixture-builder.js index 01da16759e2..1f7fcf30f89 100644 --- a/e2e/fixtures/fixture-builder.js +++ b/e2e/fixtures/fixture-builder.js @@ -448,7 +448,7 @@ class FixtureBuilder { whitelist: [], tabs: [ { - url: 'https://portfolio.metamask.io/explore?MetaMaskEntry=mobile/', + url: 'https://metamask.github.io/test-dapp/', id: 1692550481062, }, ], diff --git a/e2e/pages/Browser/ConnectedAccountsModal.js b/e2e/pages/Browser/ConnectedAccountsModal.js index 1297622507a..7940907e56b 100644 --- a/e2e/pages/Browser/ConnectedAccountsModal.js +++ b/e2e/pages/Browser/ConnectedAccountsModal.js @@ -89,7 +89,7 @@ class ConnectedAccountsModal { } async tapManagePermissionsButton() { - await TestHelpers.delay(3000); + await TestHelpers.delay(4000); await Gestures.waitAndTap(this.managePermissionsButton); } From 3bb796f0bc9ae6b9f5dd19ed41a7aaa760b2ea3c Mon Sep 17 00:00:00 2001 From: sethkfman <10342624+sethkfman@users.noreply.github.com> Date: Mon, 6 Jan 2025 14:47:17 -0700 Subject: [PATCH 32/41] chore: assign CODEOWNERS to BrowserTab (#12823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The BrowserTab is a piece of critical functionality and it should only be update in certain scenarios. This PR add the maintainers of the browser to the BrowserTab ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9576fde1dd0..8364dd78891 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -23,6 +23,7 @@ app/store/migrations/ @MetaMask/mobile-pla bitrise.yml @MetaMask/mobile-platform yarn.lock @MetaMask/mobile-platform ios/Podfile.lock @MetaMask/mobile-platform +app/components/Views/BrowserTab/BrowserTab.tsx @MetaMask/mobile-platform # Ramps Team app/components/UI/Ramp/ @MetaMask/ramp From 724ec84cb6af6fae63bf5f48bd5e553a0c757f6e Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Mon, 6 Jan 2025 16:07:27 -0600 Subject: [PATCH 33/41] chore: Add Wallet API Platform Team as `CODEOWNER` for the `RPCMethods/` directory (#10716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Update RPCMethods directory CODEOWNER to the Wallet API Platform Team. ## **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 Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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: sethkfman <10342624+sethkfman@users.noreply.github.com> --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8364dd78891..58ceabd2486 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -77,6 +77,9 @@ patches/react-native+0.*.patch @MetaMask/supply-chain **/snaps/** @MetaMask/snaps-devs **/Snaps/** @MetaMask/snaps-devs +# Wallet API Platform Team + app/core/RPCMethods/ @MetaMask/wallet-api-platform-engineers + # Staking Team app/components/UI/Stake @MetaMask/metamask-staking From 82d7f873cbadb1e3307f174e4b66206906248711 Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Tue, 7 Jan 2025 13:21:47 +0100 Subject: [PATCH 34/41] fix: fix add network form when addMode is true (#12833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** fix the add network form when addMode is true ## **Related issues** Fixes: #12836 ## **Manual testing steps** 1. Go to settings 2. Go to networks 3. Go to add networks then custom networls ## **Screenshots/Recordings** ### **Before** Screenshot 2025-01-02 at 23 40 52 ### **After** Screenshot 2025-01-02 at 23 41 43 ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/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. --- .../NetworksSettings/NetworkSettings/index.js | 68 ++++++++++--------- .../NetworkSettings/index.test.tsx | 27 ++++++++ 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js index f937c9130ac..757e41ff5e7 100644 --- a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js +++ b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js @@ -541,7 +541,7 @@ export class NetworkSettings extends PureComponent { editable = false; blockExplorerUrl = networkConfigurations?.[chainId]?.blockExplorerUrls[ - networkConfigurations?.[chainId]?.defaultBlockExplorerUrlIndex + networkConfigurations?.[chainId]?.defaultBlockExplorerUrlIndex ]; rpcUrl = networkConfigurations?.[chainId]?.rpcEndpoints[ @@ -563,13 +563,13 @@ export class NetworkSettings extends PureComponent { ({ rpcEndpoints, defaultRpcEndpointIndex }) => rpcEndpoints[defaultRpcEndpointIndex].url === networkTypeOrRpcUrl || rpcEndpoints[defaultRpcEndpointIndex].networkClientId === - networkTypeOrRpcUrl, + networkTypeOrRpcUrl, ); nickname = networkConfiguration?.name; chainId = networkConfiguration?.chainId; blockExplorerUrl = networkConfiguration?.blockExplorerUrls[ - networkConfiguration?.defaultBlockExplorerUrlIndex + networkConfiguration?.defaultBlockExplorerUrlIndex ]; ticker = networkConfiguration?.nativeCurrency; editable = true; @@ -854,8 +854,8 @@ export class NetworkSettings extends PureComponent { networkConfig, existingNetwork.chainId === chainId ? { - replacementSelectedRpcEndpointIndex: indexRpc, - } + replacementSelectedRpcEndpointIndex: indexRpc, + } : undefined, ); } else { @@ -867,8 +867,8 @@ export class NetworkSettings extends PureComponent { isCustomMainnet ? navigation.navigate('OptinMetrics') : shouldNetworkSwitchPopToWallet - ? navigation.navigate('WalletView') - : navigation.goBack(); + ? navigation.navigate('WalletView') + : navigation.goBack(); }; /** @@ -1534,7 +1534,7 @@ export class NetworkSettings extends PureComponent { const { networkClientId } = networkConfigurations?.rpcEndpoints?.[ - networkConfigurations.defaultRpcEndpointIndex + networkConfigurations.defaultRpcEndpointIndex ] ?? {}; NetworkController.setActiveNetwork(networkClientId); @@ -1950,15 +1950,15 @@ export class NetworkSettings extends PureComponent { // Conditionally include secondaryText only if rpcName exists {...(rpcName ? { - secondaryText: - hideKeyFromUrl(rpcUrl) ?? - hideKeyFromUrl( - networkConfigurations?.[chainId]?.rpcEndpoints?.[ - networkConfigurations?.[chainId] - ?.defaultRpcEndpointIndex - ]?.url, - ), - } + secondaryText: + hideKeyFromUrl(rpcUrl) ?? + hideKeyFromUrl( + networkConfigurations?.[chainId]?.rpcEndpoints?.[ + networkConfigurations?.[chainId] + ?.defaultRpcEndpointIndex + ]?.url, + ), + } : {})} isSelected={false} withAvatar={false} @@ -1993,17 +1993,17 @@ export class NetworkSettings extends PureComponent { {!isNetworkUiRedesignEnabled() ? warningRpcUrl && ( - - {warningRpcUrl} - - ) + + {warningRpcUrl} + + ) : null} @@ -2268,10 +2268,12 @@ export class NetworkSettings extends PureComponent { ) : null} {isNetworkUiRedesignEnabled() && - showMultiBlockExplorerAddModal.isVisible ? ( + showMultiBlockExplorerAddModal.isVisible ? ( 0 ? styles.sheet : styles.sheetSmall + blockExplorerUrls.length > 0 || addMode + ? styles.sheet + : styles.sheetSmall } onDismiss={this.closeBlockExplorerModal} shouldGoBack={false} @@ -2338,7 +2340,9 @@ export class NetworkSettings extends PureComponent { {isNetworkUiRedesignEnabled() && showMultiRpcAddModal.isVisible ? ( 0 ? styles.sheet : styles.sheetSmall} + style={ + rpcUrls.length > 0 || addMode ? styles.sheet : styles.sheetSmall + } onDismiss={this.closeRpcModal} shouldGoBack={false} > @@ -2478,7 +2482,7 @@ export class NetworkSettings extends PureComponent { > {(isNetworkUiRedesignEnabled() && !shouldShowPopularNetworks) || - networkTypeOrRpcUrl ? ( + networkTypeOrRpcUrl ? ( this.customNetwork() ) : ( { expect(wrapper.state('rpcUrls')[0].name).toBe('New RPC'); }); + it('adds add RPC URL through modal and update state when addMode is true', async () => { + wrapper.setState({ addMode: true }); + + const instance = wrapper.instance(); + + await instance.onRpcItemAdd('https://new-rpc-url.com', 'New RPC'); + + expect(wrapper.state('rpcUrls').length).toBe(1); + expect(wrapper.state('rpcUrls')[0].url).toBe('https://new-rpc-url.com'); + expect(wrapper.state('rpcUrls')[0].name).toBe('New RPC'); + }); + it('should correctly add Block Explorer URL through modal and update state', async () => { const instance = wrapper.instance(); @@ -828,6 +840,21 @@ describe('NetworkSettings', () => { ); }); + it('adds correctly add Block Explorer URL through modal and update state when addMode is true', async () => { + wrapper.setState({ addMode: true }); + + const instance = wrapper.instance(); + + // Open Block Explorer form modal and add a new URL + instance.openAddBlockExplorerForm(); + await instance.onBlockExplorerItemAdd('https://new-blockexplorer.com'); + + expect(wrapper.state('blockExplorerUrls').length).toBe(1); + expect(wrapper.state('blockExplorerUrls')[0]).toBe( + 'https://new-blockexplorer.com', + ); + }); + it('should not add an empty Block Explorer URL and should return early', async () => { const instance = wrapper.instance(); From edb523ad746123e4ac4303e73c222b1e1c23fa42 Mon Sep 17 00:00:00 2001 From: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:40:48 -0500 Subject: [PATCH 35/41] fix: updated default button label text variant to bodyMDMedium (#12816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Updated the `