Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: refactor network picker #30433

Merged
merged 91 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
2a456cc
refactor: refactor network picker
gantunesr Feb 19, 2025
51cd056
fix: data type for networks mock
gantunesr Feb 20, 2025
652c7e8
chore: add modal texts
gantunesr Feb 20, 2025
0a26875
feat: add "Add Account" modal
gantunesr Feb 20, 2025
de379aa
refactor: add "Add Account" modal to network picker
gantunesr Feb 20, 2025
dd52fe4
chore: lint
gantunesr Feb 20, 2025
a6c17ef
chore: lint
gantunesr Feb 20, 2025
4bb8c3e
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 20, 2025
94ba583
refactor: add network nickname
gantunesr Feb 20, 2025
0e8529d
test: fix test for app-header
gantunesr Feb 20, 2025
bdccc79
chore: cast type network ID to CaipChainId
gantunesr Feb 20, 2025
318d372
chore: add texts to en_GB
gantunesr Feb 20, 2025
e1f118d
fix: sortNetworks unit test
gantunesr Feb 20, 2025
caaa905
test: update mocks
gantunesr Feb 20, 2025
93961ab
chore: lint
gantunesr Feb 20, 2025
4c44f90
test: update mocks for storyboard
gantunesr Feb 20, 2025
39f5bc5
fix: onRpcEndpointClick callback
gantunesr Feb 20, 2025
c25c567
fix: SelectRpcUrlModal Component unit test
gantunesr Feb 20, 2025
d1629ea
refactor: use EthScope
gantunesr Feb 20, 2025
c75c0aa
test: update network-list-menu snapshot
gantunesr Feb 20, 2025
7e6ad06
test: update network-list-menu tests
gantunesr Feb 20, 2025
03fcddb
fix: test-data
gantunesr Feb 20, 2025
4e56429
test: update mockMultichainNetworkState to include Solana
gantunesr Feb 20, 2025
7dc4ea8
test: update test data
gantunesr Feb 20, 2025
a7dbde5
chore: lint
gantunesr Feb 20, 2025
4e8c094
chore: lint
gantunesr Feb 20, 2025
f6229d9
chore: remove solana code fences for getIsSolanaSupportEnabled
gantunesr Feb 20, 2025
1fa5e30
chore: revert code fence removal for action
gantunesr Feb 20, 2025
7bdfa0f
test: update accounts mocks to include scopes
gantunesr Feb 20, 2025
a9dbafa
fix: set scopes to optional
gantunesr Feb 20, 2025
95bf9d0
chore: pass chainId to network-list-item
gantunesr Feb 20, 2025
51a5c82
test: update snapshots
gantunesr Feb 20, 2025
c540b8a
chore: update currentChainId selector
gantunesr Feb 21, 2025
144fb33
test: fix network-controller-page
gantunesr Feb 21, 2025
1e14c38
test: update snapshots
gantunesr Feb 21, 2025
d49f3d4
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 21, 2025
56fc426
fix: fix currentlyOnTestNetwork
gantunesr Feb 21, 2025
1c0920f
chore: add migration 145
gantunesr Feb 21, 2025
bf03b15
chore: add migration 145
gantunesr Feb 21, 2025
9ad0e2e
test: update e2e tests and snapshots
gantunesr Feb 21, 2025
7744b28
test: fix multi-rpc e2e test
gantunesr Feb 21, 2025
8364ccc
test: remove skip and log from network-list-menu test
gantunesr Feb 21, 2025
340924b
chore: lint
gantunesr Feb 21, 2025
c0d4e1c
chore: update privacy-snapshot
gantunesr Feb 21, 2025
7b3e1a1
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 21, 2025
a27b3c7
Merge branch 'main' of https://github.com/MetaMask/metamask-extension…
gantunesr Feb 22, 2025
f380cfa
Revert "chore: remove solana code fences for getIsSolanaSupportEnabled"
gantunesr Feb 22, 2025
93cdd0f
test: fix ui.spec.ts tests
gantunesr Feb 22, 2025
0f99e82
test: update snapshots
gantunesr Feb 22, 2025
b426a38
test: fix solana e2e tests
gantunesr Feb 22, 2025
c515e9a
fix: setTokenNetworkFilter
gantunesr Feb 24, 2025
cf8addd
fix: editingChainId data type
gantunesr Feb 24, 2025
166af52
chore: lint
gantunesr Feb 24, 2025
119a7a4
chore: resolve feedback
gantunesr Feb 24, 2025
dedba3c
refactor: enabled logic
gantunesr Feb 24, 2025
24e4d5c
chore: add guard to getImageForChainId
gantunesr Feb 24, 2025
7bf20c2
chroe: revert changes in getImageForChainId
gantunesr Feb 24, 2025
0fba9a9
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 24, 2025
69fdccd
fix: Hex import
gantunesr Feb 24, 2025
9e74447
chore: revert test name
gantunesr Feb 24, 2025
952d8e4
fix: typo
gantunesr Feb 24, 2025
bdeb4ed
chore: update comment to TODO
gantunesr Feb 24, 2025
bceb0f2
Merge branch 'gar/refactor-network-picker' of https://github.com/Meta…
gantunesr Feb 24, 2025
8f67c16
chore: minor changes
gantunesr Feb 24, 2025
50a5ba4
chore: revert change to policies
gantunesr Feb 24, 2025
44dc850
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 24, 2025
6eeb810
refactor: refactor getRpcDataByChainId method use
gantunesr Feb 24, 2025
8ce37b2
refactor: update chain ID values
gantunesr Feb 24, 2025
dc0777d
refactor: refactor convertCaipToHexChainId to use add0x
gantunesr Feb 24, 2025
13233a7
refactor: refactor getNetworkIcon
gantunesr Feb 24, 2025
04bdfbd
chore: remove line
gantunesr Feb 24, 2025
5c3b048
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 24, 2025
198ae2e
chore: apply changes from review
gantunesr Feb 24, 2025
b25feb6
Merge branch 'gar/refactor-network-picker' of https://github.com/Meta…
gantunesr Feb 24, 2025
f91b8d6
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 24, 2025
ff96634
refactor: add guard to getRpcDataByChainId
gantunesr Feb 24, 2025
917a1be
Merge branch 'gar/refactor-network-picker' of https://github.com/Meta…
gantunesr Feb 24, 2025
edf1786
test: add delay to custom rpc test
gantunesr Feb 25, 2025
3bb12c0
refactor: refactor network item callbacks
gantunesr Feb 25, 2025
3eeade1
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 25, 2025
f7f95b0
fix: method generateMultichainNetworkListItem
gantunesr Feb 25, 2025
4670fa9
fix: await setActiveNetwork
gantunesr Feb 25, 2025
654152c
Merge branch 'gar/refactor-network-picker' of https://github.com/Meta…
gantunesr Feb 25, 2025
27c0a3d
chore: update comment
gantunesr Feb 25, 2025
caebee9
Merge branch 'main' into gar/refactor-network-picker
gantunesr Feb 25, 2025
20fc2bf
test: increase delay value
gantunesr Feb 25, 2025
b828633
test: update delays
gantunesr Feb 25, 2025
7d49776
test: use waitForSelector
gantunesr Feb 25, 2025
c19ce48
test: class selector
gantunesr Feb 25, 2025
1bf1044
test: remove only
gantunesr Feb 25, 2025
40cd6de
chore: lint
gantunesr Feb 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .storybook/test-data.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { draftTransactionInitialState } from '../ui/ducks/send';
import { KeyringType } from '../shared/constants/keyring';
import { NetworkStatus } from '@metamask/network-controller';
import { EthAccountType } from '@metamask/keyring-api';
import { EthAccountType, EthScope } from '@metamask/keyring-api';
import {
CHAIN_IDS,
LINEA_MAINNET_DISPLAY_NAME,
Expand All @@ -10,7 +10,7 @@ import { copyable, divider, heading, panel, text } from '@metamask/snaps-sdk';
import { getJsxElementFromComponent } from '@metamask/snaps-utils';
import { FirstTimeFlowType } from '../shared/constants/onboarding';
import { ETH_EOA_METHODS } from '../shared/constants/eth-methods';
import { mockNetworkState } from '../test/stub/networks';
import { mockNetworkState, mockMultichainNetworkState } from '../test/stub/networks';

const state = {
invalidCustomNetwork: {
Expand Down Expand Up @@ -325,6 +325,7 @@ const state = {
options: {},
methods: ETH_EOA_METHODS,
type: EthAccountType.Eoa,
scopes: [EthScope.Eoa],
},
'07c2cfec-36c9-46c4-8115-3836d3ac9047': {
address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
Expand All @@ -338,6 +339,7 @@ const state = {
options: {},
methods: ETH_EOA_METHODS,
type: EthAccountType.Eoa,
scopes: [EthScope.Eoa],
},
'15e69915-2a1a-4019-93b3-916e11fd432f': {
address: '0x9d0ba4ddac06032527b140912ec808ab9451b788',
Expand All @@ -351,6 +353,7 @@ const state = {
options: {},
methods: ETH_EOA_METHODS,
type: EthAccountType.Eoa,
scopes: [EthScope.Eoa],
},
'784225f4-d30b-4e77-a900-c8bbce735b88': {
address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823',
Expand All @@ -364,6 +367,7 @@ const state = {
options: {},
methods: ETH_EOA_METHODS,
type: EthAccountType.Eoa,
scopes: [EthScope.Eoa],
},
'b990b846-b384-4508-93d9-587461f1123e': {
address: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
Expand All @@ -377,6 +381,7 @@ const state = {
options: {},
methods: ETH_EOA_METHODS,
type: EthAccountType.Eoa,
scopes: [EthScope.Eoa],
},
},
selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3',
Expand Down Expand Up @@ -1283,6 +1288,7 @@ const state = {
nickname: 'Localhost 8545',
},
),
...mockMultichainNetworkState(),
accountTokens: {
'0x64a845a5b02460acf8a3d84503b0d68d028b4bb4': {
'0x1': [
Expand Down
8 changes: 8 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions app/_locales/en_GB/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 19 additions & 5 deletions app/scripts/controllers/network-order.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { BtcScope, SolScope } from '@metamask/keyring-api';
import { BaseController, RestrictedMessenger } from '@metamask/base-controller';
import {
NetworkControllerStateChangeEvent,
NetworkState,
} from '@metamask/network-controller';
import { Hex } from '@metamask/utils';
import { toEvmCaipChainId } from '@metamask/multichain-network-controller';
import type { CaipChainId, Hex } from '@metamask/utils';
import type { Patch } from 'immer';
import { TEST_CHAINS } from '../../../shared/constants/network';

Expand All @@ -14,7 +16,7 @@ const controllerName = 'NetworkOrderController';
* Information about an ordered network.
*/
export type NetworksInfo = {
networkId: Hex; // The network's chain id
networkId: CaipChainId; // The network's chain id
};

// State shape for NetworkOrderController
Expand Down Expand Up @@ -112,10 +114,15 @@ export class NetworkOrderController extends BaseController<
}: NetworkState) {
this.update((state) => {
// Filter out testnets, which are in the state but not orderable
const chainIds = Object.keys(networkConfigurationsByChainId).filter(
const hexChainIds = Object.keys(networkConfigurationsByChainId).filter(
(chainId) =>
!TEST_CHAINS.includes(chainId as (typeof TEST_CHAINS)[number]),
) as Hex[];
const chainIds: CaipChainId[] = hexChainIds.map(toEvmCaipChainId);
const nonEvmChainIds: CaipChainId[] = [
BtcScope.Mainnet,
SolScope.Mainnet,
];

const newNetworks = chainIds
.filter(
Expand All @@ -128,7 +135,14 @@ export class NetworkOrderController extends BaseController<

state.orderedNetworkList = state.orderedNetworkList
// Filter out deleted networks
.filter(({ networkId }) => chainIds.includes(networkId))
.filter(
({ networkId }) =>
chainIds.includes(networkId) ||
// Since Bitcoin and Solana are not part of the @metamask/network-controller, we have
// to add a second check to make sure it is not filtered out.
// TODO: Update this logic to @metamask/multichain-network-controller once all networks are migrated.
nonEvmChainIds.includes(networkId),
)
// Append new networks to the end
.concat(newNetworks);
});
Expand All @@ -140,7 +154,7 @@ export class NetworkOrderController extends BaseController<
* @param networkList - The list of networks to update in the state.
*/

updateNetworksList(chainIds: Hex[]) {
updateNetworksList(chainIds: CaipChainId[]) {
this.update((state) => {
state.orderedNetworkList = chainIds.map((chainId) => ({
networkId: chainId,
Expand Down
6 changes: 4 additions & 2 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3324,8 +3324,10 @@ export default class MetamaskController extends EventEmitter {
verifyPassword: this.verifyPassword.bind(this),

// network management
setActiveNetwork: (networkConfigurationId) => {
return this.networkController.setActiveNetwork(networkConfigurationId);
setActiveNetwork: async (id) => {
// The multichain network controller will proxy the call to the network controller
// in the case that the ID is an EVM network client ID.
return await this.multichainNetworkController.setActiveNetwork(id);
},
// Avoids returning the promise so that initial call to switch network
// doesn't block on the network lookup step
Expand Down
77 changes: 77 additions & 0 deletions app/scripts/migrations/145.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { migrate, version } from './145';

const oldVersion = 144;

describe(`migration #${version}`, () => {
it('updates the version metadata', async () => {
const oldStorage = {
meta: { version: oldVersion },
data: {},
};
const newStorage = await migrate(oldStorage);
expect(newStorage.meta).toStrictEqual({ version });
});

describe(`migration #${version}`, () => {
it('does nothing if NetworkOrderController is missing', async () => {
const oldStorage = {
meta: { version: oldVersion },
data: {},
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual({});
});

it('does nothing if NetworkOrderController is not an object', async () => {
const oldStorage = {
meta: { version: oldVersion },
data: {
NetworkOrderController: 'invalidData',
},
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual(oldStorage.data);
});

it('changes network IDs from hex to caip', async () => {
const oldStorage = {
meta: { version: oldVersion },
data: {
NetworkOrderController: {
orderedNetworkList: [
{ networkId: '0x1' },
{ networkId: '0x5' },
{ networkId: '0x38' },
{ networkId: '0x2105' },
],
},
},
};
const expectedData = {
NetworkOrderController: {
orderedNetworkList: [
{ networkId: 'eip155:1' },
{ networkId: 'eip155:5' },
{ networkId: 'eip155:56' },
{ networkId: 'eip155:8453' },
],
},
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual(expectedData);
});

it('does nothing if NetworkOrderController.orderedNetworkList is not an array', async () => {
const oldStorage = {
meta: { version: oldVersion },
data: {
NetworkOrderController: {
orderedNetworkList: 'not an array',
},
},
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual(oldStorage.data);
});
});
});
45 changes: 45 additions & 0 deletions app/scripts/migrations/145.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { toEvmCaipChainId } from '@metamask/multichain-network-controller';
import { type Hex, hasProperty, isObject } from '@metamask/utils';
import { cloneDeep } from 'lodash';

type VersionedData = {
meta: { version: number };
data: Record<string, unknown>;
};

export const version = 145;

/**
* This migration updates the values of the chain IDs in the NetworkOrderController
* from Hex to CaipChainId format (CAIP-19).
*
* @param originalVersionedData - Versioned MetaMask extension state, exactly
* what we persist to disk.
* @returns Updated versioned MetaMask extension state.
*/
export async function migrate(
originalVersionedData: VersionedData,
): Promise<VersionedData> {
const versionedData = cloneDeep(originalVersionedData);
versionedData.meta.version = version;
transformState(versionedData.data);
return versionedData;
}

function transformState(
state: Record<string, unknown>,
): Record<string, unknown> {
// Migrate the user's drag + drop preference order for the network menu
if (
hasProperty(state, 'NetworkOrderController') &&
isObject(state.NetworkOrderController) &&
Array.isArray(state.NetworkOrderController.orderedNetworkList)
) {
state.NetworkOrderController.orderedNetworkList =
state.NetworkOrderController.orderedNetworkList.map(({ networkId }) => ({
networkId: toEvmCaipChainId(networkId as Hex),
}));
}

return state;
}
1 change: 1 addition & 0 deletions app/scripts/migrations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ const migrations = [
require('./142'),
require('./143'),
require('./144'),
require('./145'),
];

export default migrations;
10 changes: 9 additions & 1 deletion shared/constants/multichain/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ export const MULTICHAIN_ACCOUNT_TYPE_TO_MAINNET = {
[SolAccountType.DataAccount]: MultichainNetworks.SOLANA,
} as const;

export const MULTICHAIN_NETWORK_TO_NICKNAME: Record<CaipChainId, string> = {
[MultichainNetworks.BITCOIN]: 'Bitcoin',
[MultichainNetworks.BITCOIN_TESTNET]: 'Bitcoin (testnet)',
[MultichainNetworks.SOLANA]: 'Solana',
[MultichainNetworks.SOLANA_DEVNET]: 'Solana (devnet)',
[MultichainNetworks.SOLANA_TESTNET]: 'Solana (testnet)',
};

export const BITCOIN_TOKEN_IMAGE_URL = './images/bitcoin-logo.svg';
export const SOLANA_TOKEN_IMAGE_URL = './images/solana-logo.svg';

Expand Down Expand Up @@ -81,7 +89,7 @@ export const MULTICHAIN_NETWORK_BLOCK_EXPLORER_FORMAT_URLS_MAP: Record<
},
} as const;

export const MULTICHAIN_TOKEN_IMAGE_MAP = {
export const MULTICHAIN_TOKEN_IMAGE_MAP: Record<CaipChainId, string> = {
[MultichainNetworks.BITCOIN]: BITCOIN_TOKEN_IMAGE_URL,
[MultichainNetworks.SOLANA]: SOLANA_TOKEN_IMAGE_URL,
} as const;
Expand Down
6 changes: 4 additions & 2 deletions shared/constants/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
RpcEndpointType,
} from '@metamask/network-controller';
import { capitalize, pick } from 'lodash';
import { Hex } from '@metamask/utils';

/**
* A type representing built-in network types, used as an identifier.
*/
Expand Down Expand Up @@ -529,7 +531,7 @@ export const INFURA_PROVIDER_TYPES = [
NETWORK_TYPES.LINEA_MAINNET,
] as const;

export const TEST_CHAINS = [
export const TEST_CHAINS: Hex[] = [
CHAIN_IDS.SEPOLIA,
CHAIN_IDS.LINEA_SEPOLIA,
CHAIN_IDS.LOCALHOST,
Expand Down Expand Up @@ -797,7 +799,7 @@ export const CHAIN_ID_TO_RPC_URL_MAP = {
[CHAIN_IDS.LOCALHOST]: LOCALHOST_RPC_URL,
} as const;

export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = {
export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP: Record<Hex, string> = {
[CHAIN_IDS.MAINNET]: ETH_TOKEN_IMAGE_URL,
[CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_TOKEN_IMAGE_URL,
[CHAIN_IDS.LINEA_SEPOLIA]: LINEA_SEPOLIA_TOKEN_IMAGE_URL,
Expand Down
Loading
Loading