Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ linkStyle default opacity:0.5
network_connection_banner_controller --> network_enablement_controller;
network_controller --> analytics_controller;
network_controller --> base_controller;
network_controller --> config_registry_controller;
network_controller --> connectivity_controller;
network_controller --> controller_utils;
network_controller --> eth_block_tracker;
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@
"eslint-plugin-import-x>unrs-resolver": false,
"simple-git-hooks": false,
"tsx>esbuild": false,
"jest>@jest/core>jest-resolve>unrs-resolver": false
"jest>@jest/core>jest-resolve>unrs-resolver": false,
"@metamask/network-controller>@metamask/config-registry-controller>@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography>keccak": false,
"@metamask/network-controller>@metamask/config-registry-controller>@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography>secp256k1": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ async function setupAssetContractControllers({
}),
);

messenger.registerActionHandler('ConfigRegistryController:getState', () => ({
configs: {
networks: {},
},
lastFetched: 0,
etag: '',
version: '1',
}));

const networkControllerMessenger: NetworkControllerMessenger = new Messenger({
namespace: 'NetworkController',
parent: messenger,
Expand All @@ -119,6 +128,8 @@ async function setupAssetContractControllers({
messenger.delegate({
messenger: networkControllerMessenger,
actions: [
'ConfigRegistryController:getNetworkConfigByCaip2ChainId',
'ConfigRegistryController:getState',
'ConnectivityController:getState',
'RemoteFeatureFlagController:getState',
],
Expand Down
4 changes: 4 additions & 0 deletions packages/config-registry-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add optional `isAutoEnabled?: boolean` property to `RegistryNetworkConfig.config` ([#9879](https://github.com/MetaMask/core/pull/9879))

## [3.0.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const ChainConfigSchema = type({
isFeatured: boolean(),
isDeprecated: boolean(),
isDeletable: boolean(),
isAutoEnabled: optional(boolean()),
priority: number(),
});

Expand Down
1 change: 1 addition & 0 deletions packages/config-registry-controller/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export type {
ConfigRegistryControllerOptions,
ConfigRegistryControllerActions,
ConfigRegistryControllerGetStateAction,
ConfigRegistryControllerStateChangedEvent,
ConfigRegistryControllerEvents,
ConfigRegistryControllerMessenger,
} from './ConfigRegistryController.js';
Expand Down
11 changes: 11 additions & 0 deletions packages/gas-fee-controller/src/GasFeeController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ const getRootMessenger = (): RootMessenger => {
}),
);

rootMessenger.registerActionHandler(
'ConfigRegistryController:getState',
() => ({
configs: { networks: {} },
lastFetched: 0,
etag: '',
version: '1',
}),
);

return rootMessenger;
};

Expand All @@ -105,6 +115,7 @@ const setupNetworkController = async ({
rootMessenger.delegate({
messenger: networkControllerMessenger,
actions: [
'ConfigRegistryController:getState',
'ConnectivityController:getState',
'RemoteFeatureFlagController:getState',
],
Expand Down
5 changes: 5 additions & 0 deletions packages/network-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **BREAKING:** `NetworkControllerMessenger` now requires the `ConfigRegistryController:stateChanged` event and `ConfigRegistryController:getNetworkConfigByCaip2ChainId` action to be delegated from the root messenger ([#9879](https://github.com/MetaMask/core/pull/9879))
- `NetworkController` now depends on the `ConfigRegistryController` to auto-enable default networks from the registry.

## [35.0.1]

### Changed
Expand Down
8 changes: 4 additions & 4 deletions packages/network-controller/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ module.exports = merge(baseConfig, {
// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 93.42,
functions: 98,
lines: 97.67,
statements: 97.56,
branches: 94.04,
functions: 98.17,
lines: 97.94,
statements: 97.83,
},
},

Expand Down
1 change: 1 addition & 0 deletions packages/network-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"dependencies": {
"@metamask/analytics-controller": "^2.0.0",
"@metamask/base-controller": "^9.1.0",
"@metamask/config-registry-controller": "^3.0.0",
"@metamask/connectivity-controller": "^0.3.0",
"@metamask/controller-utils": "^12.3.0",
"@metamask/eth-block-tracker": "^15.0.1",
Expand Down
95 changes: 88 additions & 7 deletions packages/network-controller/src/NetworkController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import type {
ControllerStateChangeEvent,
} from '@metamask/base-controller';
import { BaseController } from '@metamask/base-controller';
import type {
ConfigRegistryControllerStateChangedEvent,
ConfigRegistryControllerGetNetworkConfigByCaip2ChainIdAction,
ConfigRegistryControllerGetStateAction,
} from '@metamask/config-registry-controller';
import type { ConnectivityControllerGetStateAction } from '@metamask/connectivity-controller';
import type { Partialize } from '@metamask/controller-utils';
import {
Expand Down Expand Up @@ -35,8 +40,14 @@ import {
createSwappableProxy,
} from '@metamask/swappable-obj-proxy';
import type { SwappableProxy } from '@metamask/swappable-obj-proxy';
import type { Hex } from '@metamask/utils';
import { hasProperty, isPlainObject, isStrictHexString } from '@metamask/utils';
import type { CaipChainId, Hex } from '@metamask/utils';
import {
hasProperty,
isPlainObject,
isStrictHexString,
numberToHex,
parseCaipChainId,
} from '@metamask/utils';
import deepEqual from 'fast-deep-equal';
import type { Draft } from 'immer';
import { produce } from 'immer';
Expand Down Expand Up @@ -71,7 +82,10 @@ import type {
ResolvedNetworkControllerAnalyticsOptions,
} from './rpc-service-analytics.js';
import type { RpcServiceOptionsWithDefaults } from './rpc-service/rpc-service.js';
import { getRpcFailoverMode } from './selectors.js';
import {
getConfigRegistryEvmAutoEnabledChains,
getRpcFailoverMode,
} from './selectors.js';
import type { RpcFailoverMode } from './selectors.js';
import { NetworkClientType } from './types.js';
import type {
Expand Down Expand Up @@ -680,7 +694,9 @@ export type NetworkControllerEvents =
/**
* All events that {@link NetworkController} calls internally.
*/
type AllowedEvents = RemoteFeatureFlagControllerStateChangeEvent;
type AllowedEvents =
| RemoteFeatureFlagControllerStateChangeEvent
| ConfigRegistryControllerStateChangedEvent;

const MESSENGER_EXPOSED_METHODS = [
'addNetwork',
Expand Down Expand Up @@ -723,6 +739,8 @@ export type NetworkControllerActions =
* All actions that {@link NetworkController} calls internally.
*/
type AllowedActions =
| ConfigRegistryControllerGetNetworkConfigByCaip2ChainIdAction
| ConfigRegistryControllerGetStateAction
| ConnectivityControllerGetStateAction
| RemoteFeatureFlagControllerGetStateAction
| AnalyticsControllerGetStateAction
Expand Down Expand Up @@ -1418,6 +1436,12 @@ export class NetworkController extends BaseController<
},
getRpcFailoverMode,
);

this.messenger.subscribe(
'ConfigRegistryController:stateChanged',
(autoEnabledChains) => this.#autoEnableChains(autoEnabledChains),
getConfigRegistryEvmAutoEnabledChains,
);
}

/**
Expand Down Expand Up @@ -1617,15 +1641,22 @@ export class NetworkController extends BaseController<
}

/**
* Initialize the NetworkController, applying the RPC failover mode from the
* `corePlatformRpcFailoverMode` remote feature flag and applying the network
* selection.
* Initialize the NetworkController:
* - Apply the RPC failover mode from the `corePlatformRpcFailoverMode` remote feature flag;
* - Apply the network selection.
* - Auto-enable any chains that are configured to be auto-enabled in ConfigRegistryController.
*/
init(): void {
const state = this.messenger.call('RemoteFeatureFlagController:getState');
this.#updateRpcFailover(getRpcFailoverMode(state));

this.#applyNetworkSelection(this.state.selectedNetworkClientId);

this.#autoEnableChains(
getConfigRegistryEvmAutoEnabledChains(
this.messenger.call('ConfigRegistryController:getState'),
),
);
}

/**
Expand Down Expand Up @@ -3133,4 +3164,54 @@ export class NetworkController extends BaseController<

this.#ethQuery = new EthQuery(this.#providerProxy);
}

/**
* Enables networks for the given CAIP-2 chain IDs by adding
* them to state if they are not already present. Configurations for
* these networks are retrieved from ConfigRegistryController.
*
* @param chainIds - The CAIP-2 chain IDs of the networks to enable.
*/
#autoEnableChains(chainIds: CaipChainId[]): void {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that a continue will cover case like missing config but will not process remaining chains in case of exceptions. A try/catch might secure the loading of next chains.

for (const chainId of chainIds) {
const networkConfiguration = this.messenger.call(
'ConfigRegistryController:getNetworkConfigByCaip2ChainId',
chainId,
);
const hexChainId = numberToHex(
Number(parseCaipChainId(chainId).reference),
);

if (
!networkConfiguration ||
this.state.networkConfigurationsByChainId[hexChainId]
) {
continue;
}
Comment thread
cursor[bot] marked this conversation as resolved.

const rpcEndpoint: InfuraRpcEndpoint | AddNetworkCustomRpcEndpointFields =
networkConfiguration.rpcProviders.default.type === 'infura'
? {
type: RpcEndpointType.Infura,
networkClientId:
networkConfiguration.rpcProviders.default.networkClientId,
url: networkConfiguration.rpcProviders.default
.url as InfuraRpcEndpoint['url'],
}
: {
type: RpcEndpointType.Custom,
url: networkConfiguration.rpcProviders.default.url,
};

this.addNetwork({
chainId: hexChainId,
name: networkConfiguration.name,
nativeCurrency: networkConfiguration.assets.native.symbol,
rpcEndpoints: [rpcEndpoint],
defaultRpcEndpointIndex: 0,
blockExplorerUrls: [networkConfiguration.blockExplorerUrls.default],
defaultBlockExplorerUrlIndex: 0,
});
}
}
}
63 changes: 62 additions & 1 deletion packages/network-controller/src/selectors.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { getRpcFailoverMode } from './selectors.js';
import {
getConfigRegistryEvmAutoEnabledChains,
getRpcFailoverMode,
} from './selectors.js';

/**
* Builds a remote feature flag controller state with the given failover mode.
Expand Down Expand Up @@ -40,3 +43,61 @@ describe('getRpcFailoverMode', () => {
expect(getRpcFailoverMode(buildState('yes') as never)).toBe('disabled');
});
});

describe('getConfigRegistryEvmAutoEnabledChains', () => {
it('returns the list of CAIP-2 chain IDs for auto-enabled EVM networks', () => {
const state = {
configs: {
networks: {
'eip155:1': {
chainId: 'eip155:1',
config: {
isAutoEnabled: true,
isActive: true,
isDeprecated: false,
},
},
'eip155:3': {
chainId: 'eip155:3',
config: {
isAutoEnabled: false,
isActive: true,
isDeprecated: false,
},
},
'eip155:4': {
chainId: 'eip155:4',
config: {
isAutoEnabled: true,
isActive: false,
isDeprecated: false,
},
},
'eip155:5': {
chainId: 'eip155:5',
config: { isAutoEnabled: true, isActive: true, isDeprecated: true },
},
'eip155:6': {
chainId: 'eip155:6',
config: {
isAutoEnabled: true,
isActive: true,
isDeprecated: false,
},
},
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': {
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
config: {
isAutoEnabled: true,
isActive: true,
isDeprecated: false,
},
},
},
},
};

const result = getConfigRegistryEvmAutoEnabledChains(state);
expect(result).toStrictEqual(['eip155:1', 'eip155:6']);
});
});
23 changes: 23 additions & 0 deletions packages/network-controller/src/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ConfigRegistryControllerState } from '@metamask/config-registry-controller';
import { RemoteFeatureFlagControllerState } from '@metamask/remote-feature-flag-controller';
import { CaipChainId, KnownCaipNamespace } from '@metamask/utils';

/**
* The RPC failover behavior for Infura networks, controlled by the
Expand Down Expand Up @@ -26,3 +28,24 @@ export function getRpcFailoverMode(
const mode = state.remoteFeatureFlags.corePlatformRpcFailoverMode;
return mode === 'enabled' || mode === 'forced' ? mode : 'disabled';
}

/**
* Returns the list of CAIP-2 chain IDs for networks that are auto-enabled in the
* config registry.
*
* @param state - The config registry controller state.
* @returns The list of CAIP-2 chain IDs for auto-enabled networks.
*/
export function getConfigRegistryEvmAutoEnabledChains(
state: ConfigRegistryControllerState,
): CaipChainId[] {
return Object.values(state.configs.networks)
.filter(
({ chainId, config }) =>
chainId.startsWith(KnownCaipNamespace.Eip155) &&
config.isAutoEnabled &&
config.isActive &&
!config.isDeprecated,
)
.map((config) => config.chainId);
}
Loading