diff --git a/app/scripts/controllers/network/network-controller.test.ts b/app/scripts/controllers/network/network-controller.test.ts index 7ceb32d2a41d..057896e2302d 100644 --- a/app/scripts/controllers/network/network-controller.test.ts +++ b/app/scripts/controllers/network/network-controller.test.ts @@ -5,6 +5,7 @@ import { v4 } from 'uuid'; import nock from 'nock'; import { ControllerMessenger } from '@metamask/base-controller'; import { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider'; +import { toHex } from '@metamask/controller-utils'; import { when, resetAllWhenMocks } from 'jest-when'; import { ethErrors } from 'eth-rpc-errors'; import { NETWORK_TYPES } from '../../../../shared/constants/network'; @@ -6320,55 +6321,62 @@ function lookupNetworkTests({ operation: (controller: NetworkController) => Promise; }) { describe('if the network ID and network details requests resolve successfully', () => { - describe('if the current network is different from the network in state', () => { - it('updates the network in state to match', async () => { - await withController( - { - state: initialState, - }, - async ({ controller }) => { - await setFakeProvider(controller, { - stubs: [ - { - request: { method: 'net_version' }, - response: { result: '12345' }, - }, - ], - stubLookupNetworkWhileSetting: true, - }); + const validNetworkIds = [12345, '12345', toHex(12345)]; + for (const networkId of validNetworkIds) { + describe(`with a network id of '${networkId}'`, () => { + describe('if the current network is different from the network in state', () => { + it('updates the network in state to match', async () => { + await withController( + { + state: initialState, + }, + async ({ controller }) => { + await setFakeProvider(controller, { + stubs: [ + { + request: { method: 'net_version' }, + response: { result: networkId }, + }, + ], + stubLookupNetworkWhileSetting: true, + }); - await operation(controller); + await operation(controller); - expect(controller.store.getState().networkId).toBe('12345'); - }, - ); - }); - }); + expect(controller.store.getState().networkId).toBe('12345'); + }, + ); + }); + }); - describe('if the version of the current network is the same as that in state', () => { - it('does not change network ID in state', async () => { - await withController( - { - state: initialState, - }, - async ({ controller }) => { - await setFakeProvider(controller, { - stubs: [ - { - request: { method: 'net_version' }, - response: { result: '12345' }, - }, - ], - stubLookupNetworkWhileSetting: true, - }); + describe('if the version of the current network is the same as that in state', () => { + it('does not change network ID in state', async () => { + await withController( + { + state: initialState, + }, + async ({ controller }) => { + await setFakeProvider(controller, { + stubs: [ + { + request: { method: 'net_version' }, + response: { result: networkId }, + }, + ], + stubLookupNetworkWhileSetting: true, + }); - await operation(controller); + await operation(controller); - await expect(controller.store.getState().networkId).toBe('12345'); - }, - ); + await expect(controller.store.getState().networkId).toBe( + '12345', + ); + }, + ); + }); + }); }); - }); + } describe('if the network details of the current network are different from the network details in state', () => { it('updates the network in state to match', async () => { diff --git a/app/scripts/controllers/network/network-controller.ts b/app/scripts/controllers/network/network-controller.ts index 4a79eaf1ad67..fdb14b0f1ce6 100644 --- a/app/scripts/controllers/network/network-controller.ts +++ b/app/scripts/controllers/network/network-controller.ts @@ -10,10 +10,11 @@ import { import EthQuery from 'eth-query'; import { RestrictedControllerMessenger } from '@metamask/base-controller'; import { v4 as uuid } from 'uuid'; -import { Hex, isPlainObject } from '@metamask/utils'; +import { Hex, isPlainObject, isStrictHexString } from '@metamask/utils'; import { errorCodes } from 'eth-rpc-errors'; import { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider'; import { PollingBlockTracker } from 'eth-block-tracker'; +import { hexToDecimal } from '../../../../shared/modules/conversion.utils'; import { INFURA_PROVIDER_TYPES, INFURA_BLOCKED_KEY, @@ -301,15 +302,22 @@ function isErrorWithCode(error: unknown): error is { code: string | number } { } /** - * Asserts that the given value is a network ID, i.e., that it is a decimal - * number represented as a string. + * Convert the given value into a valid network ID. The ID is accepted + * as either a number, a decimal string, or a 0x-prefixed hex string. * - * @param value - The value to check. + * @param value - The network ID to convert, in an unknown format. + * @returns A valid network ID (as a decimal string) + * @throws If the given value cannot be safely parsed. */ -function assertNetworkId(value: any): asserts value is NetworkId { - if (!/^\d+$/u.test(value) || Number.isNaN(Number(value))) { - throw new Error('value is not a number'); +function convertNetworkId(value: unknown): NetworkId { + if (typeof value === 'number' && !Number.isNaN(value)) { + return `${value}`; + } else if (isStrictHexString(value)) { + return hexToDecimal(value) as NetworkId; + } else if (typeof value === 'string' && /^\d+$/u.test(value)) { + return value as NetworkId; } + throw new Error(`Cannot parse as a valid network ID: '${value}'`); } /** @@ -618,8 +626,7 @@ export class NetworkController extends EventEmitter { this.#determineEIP1559Compatibility(provider), ]); const possibleNetworkId = results[0]; - assertNetworkId(possibleNetworkId); - networkId = possibleNetworkId; + networkId = convertNetworkId(possibleNetworkId); supportsEIP1559 = results[1]; networkStatus = NetworkStatus.Available; } catch (error) {