Skip to content

Commit

Permalink
Support hex and number net_version responses
Browse files Browse the repository at this point in the history
Hex and number responses from the `net_version` request are now
accepted. While most chains return decimal strings for this request,
some chains were returning hex responses instead and failing our
validation for this request (which was added in v10.30.0). This
resolves that problem.

Support for number responses was added because it likely worked in
older versions as well, so support is maintained to avoid similar
problems.

Fixes #19151
  • Loading branch information
Gudahtt committed May 15, 2023
1 parent 5135b80 commit 5616f6b
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 52 deletions.
94 changes: 51 additions & 43 deletions app/scripts/controllers/network/network-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -6320,55 +6321,62 @@ function lookupNetworkTests({
operation: (controller: NetworkController) => Promise<void>;
}) {
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 () => {
Expand Down
25 changes: 16 additions & 9 deletions app/scripts/controllers/network/network-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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}'`);
}

/**
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 5616f6b

Please sign in to comment.