From 94b2520d0de66866de7da0aedc14025a6ab2728e Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 6 Jun 2024 15:08:49 -0230 Subject: [PATCH 001/281] Fix auto lock timer call --- app/scripts/controllers/app-state.js | 8 +++++--- ui/pages/settings/advanced-tab/advanced-tab.component.js | 2 +- ui/store/actions.ts | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index c871fd739ed2..bdb3a4ba4618 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -288,10 +288,12 @@ export default class AppStateController extends EventEmitter { return; } + const timeoutToSet = Number(timeoutMinutes); + if (isManifestV3) { this.extension.alarms.create(AUTO_LOCK_TIMEOUT_ALARM, { - delayInMinutes: timeoutMinutes, - periodInMinutes: timeoutMinutes, + delayInMinutes: timeoutToSet, + periodInMinutes: timeoutToSet, }); this.extension.alarms.onAlarm.addListener((alarmInfo) => { if (alarmInfo.name === AUTO_LOCK_TIMEOUT_ALARM) { @@ -302,7 +304,7 @@ export default class AppStateController extends EventEmitter { } else { this.timer = setTimeout( () => this.onInactiveTimeout(), - timeoutMinutes * MINUTE, + timeoutToSet * MINUTE, ); } } diff --git a/ui/pages/settings/advanced-tab/advanced-tab.component.js b/ui/pages/settings/advanced-tab/advanced-tab.component.js index 33e0443d4570..2a2a759d5a96 100644 --- a/ui/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/pages/settings/advanced-tab/advanced-tab.component.js @@ -613,7 +613,7 @@ export default class AdvancedTab extends PureComponent { if (autoLockTimeLimitBeforeNormalization === '') { this.setState({ autoLockTimeLimitBeforeNormalization, - autoLockTimeLimit: DEFAULT_AUTO_LOCK_TIME_LIMIT.toString(), + autoLockTimeLimit: DEFAULT_AUTO_LOCK_TIME_LIMIT, lockTimeError: '', }); return; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 9e1a2ac68969..d40ae8b071a8 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -3119,7 +3119,7 @@ export function setShowTokenAutodetectModal(value: boolean) { return setPreference('showTokenAutodetectModal', value); } -export function setAutoLockTimeLimit(value: boolean) { +export function setAutoLockTimeLimit(value: number) { return setPreference('autoLockTimeLimit', value); } From fb30e431d6d79d4af6037d2cc9348f0f6dc72fa1 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 6 Jun 2024 15:24:11 -0230 Subject: [PATCH 002/281] Add unit test --- .../advanced-tab.component.test.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ui/pages/settings/advanced-tab/advanced-tab.component.test.js b/ui/pages/settings/advanced-tab/advanced-tab.component.test.js index c50a32a7bd26..3982485b5178 100644 --- a/ui/pages/settings/advanced-tab/advanced-tab.component.test.js +++ b/ui/pages/settings/advanced-tab/advanced-tab.component.test.js @@ -6,13 +6,13 @@ import mockState from '../../../../test/data/mock-state.json'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import AdvancedTab from '.'; -const mockSetAutoLockTimeLimit = jest.fn(); +const mockSetAutoLockTimeLimit = jest.fn().mockReturnValue({ type: 'TYPE' }); const mockSetShowTestNetworks = jest.fn(); const mockSetStxOptIn = jest.fn(); jest.mock('../../../store/actions.ts', () => { return { - setAutoLockTimeLimit: () => mockSetAutoLockTimeLimit, + setAutoLockTimeLimit: (...args) => mockSetAutoLockTimeLimit(...args), setShowTestNetworks: () => mockSetShowTestNetworks, setSmartTransactionsOptInStatus: () => mockSetStxOptIn, }; @@ -60,6 +60,20 @@ describe('AdvancedTab Component', () => { expect(mockSetAutoLockTimeLimit).toHaveBeenCalled(); }); + it('should update the auto-lockout time to 0 if the input field is set to empty', () => { + const { queryByTestId } = renderWithProvider(, mockStore); + const autoLockoutTime = queryByTestId('auto-lockout-time'); + const autoLockoutButton = queryByTestId('auto-lockout-button'); + + fireEvent.change(autoLockoutTime, { target: { value: '' } }); + + expect(autoLockoutTime).toHaveValue(''); + + fireEvent.click(autoLockoutButton); + + expect(mockSetAutoLockTimeLimit).toHaveBeenCalledWith(0); + }); + it('should toggle show test networks', () => { const { queryAllByRole } = renderWithProvider(, mockStore); From b8ff5cd26e73a52e71049f5102e0e613081dc0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Fri, 7 Jun 2024 10:23:06 +0100 Subject: [PATCH 003/281] chore: only runs when RUN_MMI_OPTIONAL is true (#25103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The mmi step should only run when RUN_MMI_OPTIONAL is true. ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 915d29f65de5..5cc5d84e9da0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,7 +72,7 @@ aliases: name: Check if MMI Optional tests should run command: | RUN_MMI_OPTIONAL=$(cat ./RUN_MMI_OPTIONAL) - if [[ "${CIRCLE_BRANCH}" == "develop" || "${RUN_MMI_OPTIONAL}" == "true" ]]; then + if [[ "${RUN_MMI_OPTIONAL}" == "true" ]]; then echo "Running MMI Optional tests" else echo "Skipping MMI Optional tests" From 4a3897c4dbb142c170949e25251a6ca8c92a4904 Mon Sep 17 00:00:00 2001 From: Gauthier Petetin Date: Fri, 7 Jun 2024 11:36:39 +0200 Subject: [PATCH 004/281] fix: bug report template - remove reference to recordit (#25108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Remove reference to recordit as the tool is deprecated. ## **Related issues** - None ## **Manual testing steps** - None ## **Screenshots/Recordings** - None ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs/blob/main/docs/pull-requests.md) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] 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. --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index fde8387b1336..cec32fc26969 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -29,7 +29,7 @@ body: id: screenshot-recording attributes: label: Screenshots/Recordings - description: Please include screenshots/recordings if applicable! (https://recordit.co/ is recommended) + description: Please include screenshots/recordings if applicable! - type: textarea id: reproduce attributes: From 348ab2f822a57161c5df348b451fd9cc2e4e2faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Oliv=C3=A9?= Date: Fri, 7 Jun 2024 11:46:51 +0200 Subject: [PATCH 005/281] feat(mmi): improve custody icons when dark/light mode (#25088) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The padding at the moment for icons is 1px → to make it look better, let’s add 4px. If it is light theme, change background to be transparent. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MMI-5089 ## **Manual testing steps** 1. Go to this page accounts page 2. Select an account, see that there isn't any background color white 3. Change system settings theme 4. See that the custody icon background color now is white ## **Screenshots/Recordings** ### **Before** ![image](https://github.com/MetaMask/metamask-extension/assets/1182864/e0b45ed4-0d89-493c-b4ef-de948fa0072e) ![image](https://github.com/MetaMask/metamask-extension/assets/1182864/aca5de71-d8ba-4623-8368-69e0a8c057ae) ### **After** https://www.loom.com/share/08e09a602c06472597cc230ab6133245 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../multichain/account-list-item/account-list-item.js | 5 +++++ ui/components/multichain/account-list-item/index.scss | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index 56a2438cbceb..09e9b0455366 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -58,6 +58,7 @@ import { TEST_NETWORKS } from '../../../../shared/constants/network'; import { ConnectedStatus } from '../connected-status/connected-status'; ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) import { getCustodianIconForAddress } from '../../../selectors/institutional/selectors'; +import { useTheme } from '../../../hooks/useTheme'; ///: END:ONLY_INCLUDE_IF import { normalizeSafeAddress } from '../../../../app/scripts/lib/multichain/address'; import { AccountListItemMenuTypes } from './account-list-item.types'; @@ -108,6 +109,7 @@ export const AccountListItem = ({ const custodianIcon = useSelector((state) => getCustodianIconForAddress(state, account.address), ); + const theme = useTheme(); ///: END:ONLY_INCLUDE_IF // If this is the selected item in the Account menu, @@ -193,6 +195,9 @@ export const AccountListItem = ({ data-testid="custody-logo" className="custody-logo" alt="custody logo" + style={{ + backgroundColor: theme === 'light' ? 'transparent' : 'white', + }} /> ) : ( Date: Fri, 7 Jun 2024 13:25:03 +0200 Subject: [PATCH 006/281] fix: deprecating more networks (#24994) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Deprecates Mumbai and linea goerli test networks. Users should see a deprecation warning when switching to those networks. Linea goerli is removed from the default network list. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23695?quickstart=1) ## **Related issues** ticket: https://consensyssoftware.atlassian.net/browse/MMASSETS-183 patch for controller-utils: https://github.com/MetaMask/metamask-extension/pull/23727/files ## **Manual testing steps** 1. Go to home page 2. Click on network selector, You should not see Linea testnet in the list. 3. Add Mumbai network to metamask 4. You should see deprecation warning ## **Screenshots/Recordings** ### **Before** Linea goerli appears in the list of default networks Screenshot 2024-03-26 at 16 17 41 ### **After** In this video initially the user is on Linea goerli (i am on develop branch), the user makes a few transactions on linea goerli, then i switch to this branch so the migration runs, and notice that the user has switeched to linea-sepolia. Linea goerli is removed from the default networks tab. When the user adds linea-goerli using chainlist, he sees the deprecation warning and his transactions. https://github.com/MetaMask/metamask-extension/assets/10994169/3ffd6a63-6bb0-4ea3-85ab-c31b8317cfd6 This short video shows the deprecation warning when we switch to Mumbai network https://github.com/MetaMask/metamask-extension/assets/10994169/496a9433-0547-4475-8320-39b1c5d01e2e ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/scripts/controllers/preferences.js | 1 - app/scripts/controllers/preferences.test.js | 2 - app/scripts/migrations/121.test.ts | 194 ++++++++++++++++++ app/scripts/migrations/121.ts | 81 ++++++++ app/scripts/migrations/index.js | 1 + shared/constants/network.ts | 7 - ui/helpers/utils/i18n-helper.tsx | 3 - .../templates/add-ethereum-chain.js | 22 +- .../templates/add-ethereum-chain.test.js | 49 ++++- .../privacy-settings/privacy-settings.test.js | 2 + .../networks-list-item/networks-list-item.js | 4 +- .../networks-tab/networks-tab.constants.js | 12 -- .../__snapshots__/security-tab.test.js.snap | 87 -------- ui/selectors/selectors.js | 13 -- ui/selectors/selectors.test.js | 4 +- 15 files changed, 350 insertions(+), 132 deletions(-) create mode 100644 app/scripts/migrations/121.test.ts create mode 100644 app/scripts/migrations/121.ts diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 19d805b26cab..2bcf9d4697f2 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -14,7 +14,6 @@ const mainNetworks = { const testNetworks = { [CHAIN_IDS.GOERLI]: true, [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_GOERLI]: true, [CHAIN_IDS.LINEA_SEPOLIA]: true, }; diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index 53c0386ba123..c2a382725c0b 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -485,7 +485,6 @@ describe('preferences controller', () => { [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1]].chainId]: true, [CHAIN_IDS.GOERLI]: true, [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_GOERLI]: true, [CHAIN_IDS.LINEA_SEPOLIA]: true, }); }); @@ -503,7 +502,6 @@ describe('preferences controller', () => { [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1]].chainId]: true, [CHAIN_IDS.GOERLI]: true, [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_GOERLI]: true, [CHAIN_IDS.LINEA_SEPOLIA]: true, }); }); diff --git a/app/scripts/migrations/121.test.ts b/app/scripts/migrations/121.test.ts new file mode 100644 index 000000000000..06cba77de93e --- /dev/null +++ b/app/scripts/migrations/121.test.ts @@ -0,0 +1,194 @@ +import { NetworkType } from '@metamask/controller-utils'; +import { + CHAIN_IDS, + CHAIN_ID_TO_RPC_URL_MAP, + LINEA_SEPOLIA_DISPLAY_NAME, + NETWORK_TYPES, + TEST_NETWORK_TICKER_MAP, +} from '../../../shared/constants/network'; +import { migrate, version } from './121'; + +const oldVersion = 120; + +const ethereumProviderConfig = { + chainId: '0x1', + rpcPrefs: { + blockExplorerUrl: 'https://etherscan.io', + }, + ticker: 'ETH', + type: 'mainnet', +}; + +const ethereumNetworksMetadata = { + mainnet: { + EIPS: { + '1559': true, + }, + status: 'available', + }, +}; +const ethereumOldState = { + CurrencyController: { + currencyRates: { + ETH: { + conversionDate: 1708532473.416, + conversionRate: 2918.02, + usdConversionRate: 2918.02, + }, + GoerliETH: { + conversionDate: 1708532466.732, + conversionRate: 2918.02, + usdConversionRate: 2918.02, + }, + }, + currentCurrency: 'usd', + }, + NetworkController: { + networkConfigurations: {}, + networksMetadata: ethereumNetworksMetadata, + providerConfig: ethereumProviderConfig, + selectedNetworkClientId: 'mainnet', + }, +}; + +const lineaGoerliState = { + NetworkController: { + networkConfigurations: {}, + networksMetadata: { + 'linea-goerli': { + EIPS: { + '1559': true, + }, + status: 'available', + }, + }, + providerConfig: { + chainId: CHAIN_IDS.LINEA_GOERLI, + rpcPrefs: {}, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_GOERLI], + type: NETWORK_TYPES.LINEA_GOERLI, + }, + selectedNetworkClientId: NETWORK_TYPES.LINEA_GOERLI, + }, +}; + +describe('migration #121', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('does nothing if no preferences state', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('Should return state if chainId is not linea-goerli', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: ethereumOldState, + }); + + expect(transformedState.data).toEqual(ethereumOldState); + }); + + it('Should return state if there is no NetworkController in state', async () => { + const { NetworkController, ...state } = ethereumOldState; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: state, + }); + + expect(transformedState.data).toEqual(state); + }); + + it('Should return state if there is no provider in NetworkController', async () => { + const state = { + ...ethereumOldState, + NetworkController: {}, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: state, + }); + + expect(transformedState.data).toEqual(state); + }); + + it('Should return state if there is no chainId in provider in NetworkController', async () => { + const state = { + ...ethereumOldState, + NetworkController: { + providerConfig: {}, + }, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: state, + }); + + expect(transformedState.data).toEqual(state); + }); + + it('Should return state if chainId is not linea-goerli', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: ethereumOldState, + }); + + expect(transformedState.data).toEqual(ethereumOldState); + }); + + it('Should update NetworkController to Linea Sepolia if chainId is on Linea Goerli', async () => { + const expectedNetworkControllerState = { + networkConfigurations: {}, + networksMetadata: { + 'linea-sepolia': { + EIPS: { + '1559': true, + }, + status: 'available', + }, + 'linea-goerli': { + EIPS: { + '1559': true, + }, + status: 'available', + }, + }, + providerConfig: { + type: NetworkType['linea-sepolia'], + rpcPrefs: {}, + chainId: CHAIN_IDS.LINEA_SEPOLIA, + nickname: LINEA_SEPOLIA_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_SEPOLIA], + providerType: NETWORK_TYPES.LINEA_SEPOLIA, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], + id: NETWORK_TYPES.LINEA_SEPOLIA, + }, + selectedNetworkClientId: 'linea-sepolia', + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: lineaGoerliState, + }); + + expect(transformedState.data).toEqual({ + NetworkController: expectedNetworkControllerState, + }); + }); +}); diff --git a/app/scripts/migrations/121.ts b/app/scripts/migrations/121.ts new file mode 100644 index 000000000000..a034eeaa7c81 --- /dev/null +++ b/app/scripts/migrations/121.ts @@ -0,0 +1,81 @@ +import { cloneDeep, isObject } from 'lodash'; +import { NetworkType } from '@metamask/controller-utils'; +import { hasProperty } from '@metamask/utils'; +import { NetworkStatus } from '@metamask/network-controller'; +import { + CHAIN_IDS, + CHAIN_ID_TO_RPC_URL_MAP, + NETWORK_TYPES, + TEST_NETWORK_TICKER_MAP, + LINEA_SEPOLIA_DISPLAY_NAME, +} from '../../../shared/constants/network'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 121; + +/** + * Migrates the user network to Linea Sepolia if the user is on Linea Goerli network. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + const NetworkController = state?.NetworkController || {}; + const provider = NetworkController?.providerConfig || {}; + + if (provider?.chainId !== CHAIN_IDS.LINEA_GOERLI) { + return state; + } + const networkControllerState = state.NetworkController; + + if ( + hasProperty(state, 'NetworkController') && + isObject(state.NetworkController) && + hasProperty(state.NetworkController, 'providerConfig') && + isObject(state.NetworkController.providerConfig) && + hasProperty(state.NetworkController.providerConfig, 'chainId') && + state.NetworkController.providerConfig.chainId === CHAIN_IDS.LINEA_GOERLI + ) { + networkControllerState.providerConfig = { + type: NetworkType['linea-sepolia'], + rpcPrefs: {}, + chainId: CHAIN_IDS.LINEA_SEPOLIA, + nickname: LINEA_SEPOLIA_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_SEPOLIA], + providerType: NETWORK_TYPES.LINEA_SEPOLIA, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], + id: NETWORK_TYPES.LINEA_SEPOLIA, + }; + networkControllerState.selectedNetworkClientId = + NETWORK_TYPES.LINEA_SEPOLIA; + networkControllerState.networksMetadata = { + ...networkControllerState.networksMetadata, + 'linea-sepolia': { + EIPS: { + '1559': true, + }, + status: NetworkStatus.Available, + }, + }; + } + return { + ...state, + NetworkController: networkControllerState, + }; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index f3503f750344..f3ca59feb158 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -131,6 +131,7 @@ const migrations = [ require('./118'), require('./119'), require('./120'), + require('./121'), ]; export default migrations; diff --git a/shared/constants/network.ts b/shared/constants/network.ts index 5801b4029c4d..62fe072bf0c0 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -448,14 +448,12 @@ export const SEI_IMAGE_URL = './images/sei.svg'; export const INFURA_PROVIDER_TYPES = [ NETWORK_TYPES.MAINNET, NETWORK_TYPES.SEPOLIA, - NETWORK_TYPES.LINEA_GOERLI, NETWORK_TYPES.LINEA_SEPOLIA, NETWORK_TYPES.LINEA_MAINNET, ] as const; export const TEST_CHAINS = [ CHAIN_IDS.SEPOLIA, - NETWORK_TYPES.LINEA_GOERLI, CHAIN_IDS.LINEA_SEPOLIA, CHAIN_IDS.LOCALHOST, ]; @@ -493,11 +491,6 @@ export const BUILT_IN_NETWORKS = { ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.SEPOLIA], blockExplorerUrl: `https://${NETWORK_TYPES.SEPOLIA}.etherscan.io`, }, - [NETWORK_TYPES.LINEA_GOERLI]: { - chainId: CHAIN_IDS.LINEA_GOERLI, - ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_GOERLI], - blockExplorerUrl: 'https://goerli.lineascan.build', - }, [NETWORK_TYPES.LINEA_SEPOLIA]: { chainId: CHAIN_IDS.LINEA_SEPOLIA, ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], diff --git a/ui/helpers/utils/i18n-helper.tsx b/ui/helpers/utils/i18n-helper.tsx index b639a158b312..eb53c9b5afd6 100644 --- a/ui/helpers/utils/i18n-helper.tsx +++ b/ui/helpers/utils/i18n-helper.tsx @@ -47,9 +47,6 @@ export const getMessage = ( }; export function getNetworkLabelKey(network: string): string { - if (network === NETWORK_TYPES.LINEA_GOERLI) { - return 'lineaGoerli'; - } if (network === NETWORK_TYPES.LINEA_SEPOLIA) { return 'lineaSepolia'; } diff --git a/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.js b/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.js index f4ee0f60893b..4b6e3d7a1480 100644 --- a/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.js +++ b/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.js @@ -1,6 +1,9 @@ import { ethErrors } from 'eth-rpc-errors'; import React from 'react'; -import { infuraProjectId } from '../../../../../shared/constants/network'; +import { + infuraProjectId, + DEPRECATED_NETWORKS, +} from '../../../../../shared/constants/network'; import { Severity, TypographyVariant, @@ -74,6 +77,20 @@ const MISMATCHED_CHAIN_RECOMMENDATION = { }, }; +const DEPRECATED_CHAIN_ALERT = { + id: 'DEPRECATED_CHAIN_ALERT', + severity: Severity.Warning, + content: { + element: 'span', + children: { + element: 'MetaMaskTranslation', + props: { + translationKey: 'deprecatedNetwork', + }, + }, + }, +}; + const MISMATCHED_NETWORK_NAME = { id: 'MISMATCHED_NETWORK_NAME', severity: Severity.Warning, @@ -172,6 +189,9 @@ async function getAlerts(pendingApproval, data) { ) { alerts.push(MISMATCHED_NETWORK_RPC); } + if (DEPRECATED_NETWORKS.includes(pendingApproval.requestData.chainId)) { + alerts.push(DEPRECATED_CHAIN_ALERT); + } } if (!data.matchedChain && data.useSafeChainsListValidation) { diff --git a/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.test.js b/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.test.js index 9079b2e80111..f260252387c9 100644 --- a/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.test.js +++ b/ui/pages/confirmations/confirmation/templates/add-ethereum-chain.test.js @@ -1,13 +1,15 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import { waitFor } from '@testing-library/react'; +import { waitFor, act } from '@testing-library/react'; import { NetworkStatus } from '@metamask/network-controller'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; import Confirmation from '../confirmation'; +import { CHAIN_IDS } from '../../../../../shared/constants/network'; +import fetchWithCache from '../../../../../shared/lib/fetch-with-cache'; jest.mock('../../../../../shared/lib/fetch-with-cache'); @@ -80,6 +82,51 @@ describe('add-ethereum-chain confirmation', () => { }); }); + it('should show deprecation alert', async () => { + const testStore = { + metamask: { + ...mockBaseStore.metamask, + useSafeChainsListValidation: true, + pendingApprovals: { + [mockApprovalId]: { + ...mockApproval, + requestData: { + rpcUrl: 'https://rpcurl.test.chain', + rpcPrefs: { + blockExplorerUrl: 'https://blockexplorer.test.chain', + }, + chainName: 'Test chain', + ticker: 'TST', + chainId: CHAIN_IDS.LINEA_GOERLI, // mumbai chainId + nickname: 'Test chain', + }, + type: MESSAGE_TYPE.ADD_ETHEREUM_CHAIN, + }, + }, + }, + }; + + const store = configureMockStore(middleware)(testStore); + fetchWithCache.mockResolvedValue([ + { + name: 'Linea Goerli', + title: 'Linea Goerli Testnet', + shortName: 'linea-goerli', + chainId: 59140, + }, + ]); + + let result; + act(() => { + result = renderWithProvider(, store); + }); + const { getByText } = result; + + await waitFor(() => { + expect(getByText('This network is deprecated')).toBeInTheDocument(); + }); + }); + it('should convert RPC URL to lowercase', async () => { const testStore = { metamask: { diff --git a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js index 28046a4d5375..84461097dc78 100644 --- a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js +++ b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.test.js @@ -120,7 +120,9 @@ describe('Privacy Settings Onboarding View', () => { fireEvent.click(toggles[1]); // setIncomingTransactionsPreferencesStub fireEvent.click(toggles[2]); // setIncomingTransactionsPreferencesStub (2) fireEvent.click(toggles[3]); // setIncomingTransactionsPreferencesStub (3) + fireEvent.click(toggles[4]); // setIncomingTransactionsPreferencesStub (4) fireEvent.click(toggles[5]); // setUsePhishDetectStub + fireEvent.click(toggles[6]); fireEvent.click(toggles[7]); // setUse4ByteResolutionStub fireEvent.click(toggles[8]); // setUseTokenDetectionStub fireEvent.click(toggles[9]); // setUseMultiAccountBalanceCheckerStub diff --git a/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js b/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js index b480730f796c..c23a1c6a4a3b 100644 --- a/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js +++ b/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js @@ -102,9 +102,7 @@ const NetworksListItem = ({ ) )} {network.isATestNetwork && - ![CHAIN_IDS.LINEA_GOERLI, CHAIN_IDS.LINEA_SEPOLIA].includes( - network.chainId, - ) && ( + ![CHAIN_IDS.LINEA_SEPOLIA].includes(network.chainId) && ( -
-
-
- Linea Goerli logo -
-
-

- Linea Goerli -

-

- - Lineascan.build - -

-
-
-
-