diff --git a/privacy-snapshot.json b/privacy-snapshot.json
index 41b04a9b5210..846674b77855 100644
--- a/privacy-snapshot.json
+++ b/privacy-snapshot.json
@@ -8,6 +8,7 @@
"api.web3modal.com",
"app.ens.domains",
"arbitrum-mainnet.infura.io",
+ "avalanche-mainnet.infura.io",
"authentication.api.cx.metamask.io",
"bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link",
"bafybeidxfmwycgzcp4v2togflpqh2gnibuexjy4m4qqwxp7nh3jx5zlh4y.ipfs.dweb.link",
diff --git a/test/e2e/tests/network/multi-rpc.spec.ts b/test/e2e/tests/network/multi-rpc.spec.ts
index 6fc7025f5dbc..2ab43445c484 100644
--- a/test/e2e/tests/network/multi-rpc.spec.ts
+++ b/test/e2e/tests/network/multi-rpc.spec.ts
@@ -27,7 +27,7 @@ describe('MultiRpc:', function (this: Suite) {
json: {
id: '1694444405781',
jsonrpc: '2.0',
- result: '0xa4b1',
+ result: '0xa86a',
},
})),
];
@@ -37,7 +37,7 @@ describe('MultiRpc:', function (this: Suite) {
fixtures: new FixtureBuilder({ onboarding: true })
.withNetworkController({
providerConfig: {
- rpcPrefs: { blockExplorerUrl: 'https://etherscan.io/' },
+ rpcPrefs: { blockExplorerUrl: 'https://snowtrace.io/' },
},
networkConfigurations: {
networkConfigurationId: {
@@ -48,20 +48,20 @@ describe('MultiRpc:', function (this: Suite) {
rpcPrefs: { blockExplorerUrl: 'https://etherscan.io/' },
},
'2ce66016-8aab-47df-b27f-318c80865eb0': {
- chainId: '0xa4b1',
+ chainId: '0xa86a',
id: '2ce66016-8aab-47df-b27f-318c80865eb0',
- nickname: 'Arbitrum mainnet',
+ nickname: 'Avalanche mainnet',
rpcPrefs: {},
- rpcUrl: 'https://arbitrum-mainnet.infura.io',
- ticker: 'ETH',
+ rpcUrl: 'https://avalanche-mainnet.infura.io',
+ ticker: 'AVAX',
},
'2ce66016-8aab-47df-b27f-318c80865eb1': {
- chainId: '0xa4b1',
+ chainId: '0xa86a',
id: '2ce66016-8aab-47df-b27f-318c80865eb1',
- nickname: 'Arbitrum mainnet 2',
+ nickname: 'Avalanche mainnet 2',
rpcPrefs: {},
rpcUrl: 'https://responsive-rpc.test/',
- ticker: 'ETH',
+ ticker: 'AVAX',
},
},
selectedNetworkClientId: 'networkConfigurationId',
@@ -81,7 +81,7 @@ describe('MultiRpc:', function (this: Suite) {
await driver.delay(regularDelayMs);
- // complete
+ // complete onboarding
await driver.clickElement('[data-testid="onboarding-complete-done"]');
// pin extension
@@ -96,7 +96,7 @@ describe('MultiRpc:', function (this: Suite) {
await driver.clickElement('[data-testid="network-display"]');
await driver.clickElement(
- '[data-testid="network-rpc-name-button-0xa4b1"]',
+ '[data-testid="network-rpc-name-button-0xa86a"]',
);
const menuItems = await driver.findElements('.select-rpc-url__item');
@@ -341,7 +341,7 @@ describe('MultiRpc:', function (this: Suite) {
json: {
id: '1694444405781',
jsonrpc: '2.0',
- result: '0xa4b1',
+ result: '0xa86a',
},
})),
];
@@ -351,7 +351,7 @@ describe('MultiRpc:', function (this: Suite) {
fixtures: new FixtureBuilder({ onboarding: true })
.withNetworkController({
providerConfig: {
- rpcPrefs: { blockExplorerUrl: 'https://etherscan.io/' },
+ rpcPrefs: { blockExplorerUrl: 'https://snowtrace.io/' },
},
networkConfigurations: {
networkConfigurationId: {
@@ -362,20 +362,20 @@ describe('MultiRpc:', function (this: Suite) {
rpcPrefs: { blockExplorerUrl: 'https://etherscan.io/' },
},
'2ce66016-8aab-47df-b27f-318c80865eb0': {
- chainId: '0xa4b1',
+ chainId: '0xa86a',
id: '2ce66016-8aab-47df-b27f-318c80865eb0',
- nickname: 'Arbitrum mainnet',
+ nickname: 'Avalanche mainnet',
rpcPrefs: {},
- rpcUrl: 'https://arbitrum-mainnet.infura.io',
- ticker: 'ETH',
+ rpcUrl: 'https://avalanche-mainnet.infura.io',
+ ticker: 'AVAX',
},
'2ce66016-8aab-47df-b27f-318c80865eb1': {
- chainId: '0xa4b1',
+ chainId: '0xa86a',
id: '2ce66016-8aab-47df-b27f-318c80865eb1',
- nickname: 'Arbitrum mainnet 2',
+ nickname: 'Avalanche mainnet 2',
rpcPrefs: {},
rpcUrl: 'https://responsive-rpc.test/',
- ticker: 'ETH',
+ ticker: 'AVAX',
},
},
selectedNetworkClientId: 'networkConfigurationId',
@@ -395,7 +395,7 @@ describe('MultiRpc:', function (this: Suite) {
await driver.delay(regularDelayMs);
- // go to advanced settigns
+ // go to advanced settings
await driver.clickElementAndWaitToDisappear({
text: 'Manage default privacy settings',
});
@@ -406,7 +406,7 @@ describe('MultiRpc:', function (this: Suite) {
// open edit modal
await driver.clickElement({
- text: 'arbitrum-mainnet.infura.io',
+ text: 'avalanche-mainnet.infura.io',
tag: 'p',
});
@@ -414,7 +414,7 @@ describe('MultiRpc:', function (this: Suite) {
await driver.delay(regularDelayMs);
await driver.clickElement({
- text: 'Arbitrum mainnet 2',
+ text: 'Avalanche mainnet 2',
tag: 'button',
});
@@ -446,14 +446,14 @@ describe('MultiRpc:', function (this: Suite) {
// Validate the network was edited
const networkEdited = await driver.isElementPresent({
- text: '“Arbitrum One” was successfully edited!',
+ text: '“Avalanche Network C-Chain” was successfully edited!',
});
assert.equal(
networkEdited,
true,
- '“Arbitrum One” was successfully edited!',
+ '“Avalanche Network C-Chain” was successfully edited!',
);
- // Ensures popover backround doesn't kill test
+ // Ensures popover background doesn't kill test
await driver.assertElementNotPresent('.popover-bg');
// We need to use clickElementSafe + assertElementNotPresent as sometimes the network dialog doesn't appear, as per this issue (#27870)
@@ -467,12 +467,12 @@ describe('MultiRpc:', function (this: Suite) {
await driver.clickElement('[data-testid="network-display"]');
- const arbitrumRpcUsed = await driver.findElement({
- text: 'Arbitrum mainnet 2',
+ const avalancheRpcUsed = await driver.findElement({
+ text: 'Avalanche mainnet 2',
tag: 'button',
});
- const existRpcUsed = arbitrumRpcUsed !== undefined;
+ const existRpcUsed = avalancheRpcUsed !== undefined;
assert.equal(existRpcUsed, true, 'Second Rpc is used');
},
);
diff --git a/ui/pages/onboarding-flow/welcome/welcome.js b/ui/pages/onboarding-flow/welcome/welcome.js
index 52825815be70..b71798f33804 100644
--- a/ui/pages/onboarding-flow/welcome/welcome.js
+++ b/ui/pages/onboarding-flow/welcome/welcome.js
@@ -5,6 +5,7 @@ import { useHistory } from 'react-router-dom';
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
import { Carousel } from 'react-responsive-carousel';
///: END:ONLY_INCLUDE_IF
+import { CHAIN_IDS } from '@metamask/transaction-controller';
import Mascot from '../../../components/ui/mascot';
import Button from '../../../components/ui/button';
import { Text } from '../../../components/component-library';
@@ -25,6 +26,8 @@ import {
import {
setFirstTimeFlowType,
setTermsOfUseLastAgreed,
+ addNetwork,
+ updateNetworksList,
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
setParticipateInMetaMetrics,
///: END:ONLY_INCLUDE_IF
@@ -42,6 +45,8 @@ import {
} from '../../../helpers/constants/routes';
import { getFirstTimeFlowType, getCurrentKeyring } from '../../../selectors';
import { FirstTimeFlowType } from '../../../../shared/constants/onboarding';
+import { FEATURED_RPCS } from '../../../../shared/constants/network';
+import { getCompletedOnboarding } from '../../../ducks/metamask/metamask';
export default function OnboardingWelcome() {
const t = useI18nContext();
@@ -54,6 +59,8 @@ export default function OnboardingWelcome() {
const [newAccountCreationInProgress, setNewAccountCreationInProgress] =
useState(false);
+ const completedOnboarding = useSelector(getCompletedOnboarding);
+
// Don't allow users to come back to this screen after they
// have already imported or created a wallet
useEffect(() => {
@@ -72,7 +79,78 @@ export default function OnboardingWelcome() {
history,
firstTimeFlowType,
newAccountCreationInProgress,
+ dispatch,
]);
+
+ useEffect(() => {
+ const addNetworks = async () => {
+ if (!completedOnboarding) {
+ // List of chainIds to add (as hex strings)
+ const chainIdsToAdd = [
+ CHAIN_IDS.ARBITRUM,
+ CHAIN_IDS.BASE,
+ CHAIN_IDS.BSC,
+ CHAIN_IDS.OPTIMISM,
+ CHAIN_IDS.POLYGON,
+ ];
+
+ // Define the desired order based on `networkId`
+ const networkOrder = [
+ CHAIN_IDS.MAINNET,
+ CHAIN_IDS.ARBITRUM,
+ CHAIN_IDS.BASE,
+ CHAIN_IDS.BSC,
+ CHAIN_IDS.LINEA_MAINNET,
+ CHAIN_IDS.OPTIMISM,
+ CHAIN_IDS.POLYGON,
+ ];
+
+ // Filter the FEATURED_RPCS based on the chainIdsToAdd array
+ const selectedNetworks = FEATURED_RPCS.filter((network) =>
+ chainIdsToAdd.includes(network.chainId),
+ );
+
+ try {
+ await Promise.all(
+ selectedNetworks.map(async (network) => {
+ const {
+ chainId,
+ blockExplorerUrls,
+ defaultRpcEndpointIndex,
+ defaultBlockExplorerUrlIndex,
+ name,
+ nativeCurrency,
+ rpcEndpoints,
+ } = network;
+
+ await dispatch(
+ addNetwork({
+ chainId,
+ blockExplorerUrls,
+ defaultRpcEndpointIndex,
+ defaultBlockExplorerUrlIndex,
+ name,
+ nativeCurrency,
+ rpcEndpoints,
+ }),
+ );
+
+ console.info(`Successfully added network: ${name}`);
+ }),
+ );
+ } catch (error) {
+ console.error('Error adding networks:', error);
+ }
+
+ await dispatch(updateNetworksList(networkOrder));
+ }
+ };
+
+ addNetworks().catch((error) => {
+ console.error('Error adding networks:', error);
+ });
+ }, [dispatch, completedOnboarding]);
+
const trackEvent = useContext(MetaMetricsContext);
const onCreateClick = async () => {
diff --git a/ui/pages/onboarding-flow/welcome/welcome.test.js b/ui/pages/onboarding-flow/welcome/welcome.test.js
index c76f93a21f75..ba79f2e1e579 100644
--- a/ui/pages/onboarding-flow/welcome/welcome.test.js
+++ b/ui/pages/onboarding-flow/welcome/welcome.test.js
@@ -7,6 +7,8 @@ import { renderWithProvider } from '../../../../test/lib/render-helpers';
import {
setFirstTimeFlowType,
setTermsOfUseLastAgreed,
+ addNetwork,
+ updateNetworksList,
} from '../../../store/actions';
import {
ONBOARDING_METAMETRICS,
@@ -35,6 +37,8 @@ jest.mock('../../../store/actions.ts', () => ({
return type;
}),
),
+ addNetwork: jest.fn(),
+ updateNetworksList: jest.fn(),
}));
jest.mock('react-router-dom', () => ({
@@ -122,5 +126,52 @@ describe('Onboarding Welcome Component', () => {
expect(mockHistoryPush).toHaveBeenCalledWith(ONBOARDING_METAMETRICS);
});
});
+
+ describe('useEffect for adding networks', () => {
+ it('should add networks when onboarding is incomplete', async () => {
+ // Render the component
+ renderWithProvider(, mockStore);
+
+ await waitFor(() => {
+ // Verify addNetwork is called with Arbitrum (or other networks)
+ expect(addNetwork).toHaveBeenCalledWith({
+ chainId: '0xa4b1', // Arbitrum's chain ID
+ blockExplorerUrls: ['https://explorer.arbitrum.io'], // Arbitrum block explorer
+ defaultRpcEndpointIndex: 0,
+ defaultBlockExplorerUrlIndex: 0,
+ name: 'Arbitrum One',
+ nativeCurrency: 'ETH',
+ rpcEndpoints: [
+ {
+ url: 'https://arbitrum-mainnet.infura.io/v3/undefined',
+ type: 'custom',
+ },
+ ],
+ });
+ });
+ });
+
+ it('should not add networks when onboarding is completed', async () => {
+ const mockCompletedOnboardingState = {
+ ...mockState,
+ metamask: {
+ ...mockState.metamask,
+ completedOnboarding: true, // Simulate completed onboarding
+ },
+ };
+ const mockStore2 = configureMockStore([thunk])(
+ mockCompletedOnboardingState,
+ );
+
+ renderWithProvider(, mockStore2);
+
+ // Wait to ensure the effect runs (or doesn't in this case)
+ await waitFor(() => {
+ // Expect that neither addNetwork nor updateNetworksList was called
+ expect(addNetwork).not.toHaveBeenCalled();
+ expect(updateNetworksList).not.toHaveBeenCalled();
+ });
+ });
+ });
});
});
diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js
index 7f9327f7a45c..349f305d5d46 100644
--- a/ui/selectors/selectors.js
+++ b/ui/selectors/selectors.js
@@ -1803,6 +1803,10 @@ export function getSortedAnnouncementsToShow(state) {
* @returns {{networkId: string}[]}
*/
export function getOrderedNetworksList(state) {
+ console.log(
+ 'state.metamask.orderedNetworkList ----',
+ state.metamask.orderedNetworkList,
+ );
return state.metamask.orderedNetworkList;
}