Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('AssetsContractController with NetworkClientId', () => {
'invalidNetworkClientId',
),
).rejects.toThrow(
`No custom network client was found with the ID "invalidNetworkClientId".`,
`No network client was found with ID "invalidNetworkClientId".`,
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});
Expand All @@ -46,7 +46,7 @@ describe('AssetsContractController with NetworkClientId', () => {
'invalidNetworkClientId',
),
).rejects.toThrow(
`No custom network client was found with the ID "invalidNetworkClientId".`,
`No network client was found with ID "invalidNetworkClientId".`,
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});
Expand Down Expand Up @@ -154,7 +154,9 @@ describe('AssetsContractController with NetworkClientId', () => {
undefined,
'invalidNetworkClientId',
),
).rejects.toThrow('No custom network client was found');
).rejects.toThrow(
'No network client was found with ID "invalidNetworkClientId".',
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});

Expand Down Expand Up @@ -582,7 +584,9 @@ describe('AssetsContractController with NetworkClientId', () => {
ERC721_GODS_ADDRESS,
'invalidNetworkClientId',
),
).rejects.toThrow('No custom network client was found');
).rejects.toThrow(
'No network client was found with ID "invalidNetworkClientId".',
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});

Expand Down Expand Up @@ -698,7 +702,9 @@ describe('AssetsContractController with NetworkClientId', () => {
'148332',
'invalidNetworkClientId',
),
).rejects.toThrow('No custom network client was found');
).rejects.toThrow(
'No network client was found with ID "invalidNetworkClientId".',
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});

Expand Down Expand Up @@ -823,7 +829,9 @@ describe('AssetsContractController with NetworkClientId', () => {
'1',
'invalidNetworkClientId',
),
).rejects.toThrow('No custom network client was found');
).rejects.toThrow(
'No network client was found with ID "invalidNetworkClientId".',
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});

Expand Down Expand Up @@ -873,7 +881,9 @@ describe('AssetsContractController with NetworkClientId', () => {
ERC1155_ID,
'invalidNetworkClientId',
),
).rejects.toThrow('No custom network client was found');
).rejects.toThrow(
'No network client was found with ID "invalidNetworkClientId".',
);
messenger.clearEventSubscriptions('NetworkController:networkDidChange');
});

Expand Down
11 changes: 11 additions & 0 deletions packages/network-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **BREAKING:** `BuiltInNetworkClientId` is now `string` instead of `InfuraNetworkType` ([#9432](https://github.com/MetaMask/core/pull/9432))
- This type was previously constrained to known Infura network names (e.g. `"mainnet"`, `"sepolia"`). It is now `string` to allow dynamically configured Infura networks whose names are not bundled into the package.
- If you have code that narrows on `BuiltInNetworkClientId`, you will need to remove the narrowing or check the network client type via `NetworkClientType` instead.
- **BREAKING:** `InfuraNetworkClientConfiguration.network` is now `string` instead of `InfuraNetworkType` ([#9432](https://github.com/MetaMask/core/pull/9432))
- Previously only known Infura network names were accepted. Any valid Infura subdomain string is now accepted.
- **BREAKING:** `NetworkController.getNetworkClientById` no longer distinguishes between Infura and custom network clients when the provided ID is not found ([#9432](https://github.com/MetaMask/core/pull/9432))
- The method now checks the Infura registry first and falls back to the custom registry, without using `isInfuraNetworkType` to decide which registry to consult.
- The error message when no client is found has changed from `"No Infura network client was found with the ID \"<id>\"."` / `"No custom network client was found with the ID \"<id>\"."` to `"No network client was found with ID \"<id>\"."`.
- Remove validation that prevented a custom RPC endpoint from having a `networkClientId` that matches a known Infura network name ([#9432](https://github.com/MetaMask/core/pull/9432))
- Remove validation that required an Infura RPC endpoint URL's implied chain ID to match the chain ID of the network configuration it belongs to ([#9432](https://github.com/MetaMask/core/pull/9432))
- This allows Infura-backed networks to be added and updated dynamically without being constrained to the known Infura network list bundled in `@metamask/controller-utils`.
- Bump `@metamask/messenger` from `^1.2.0` to `^2.0.0` ([#9392](https://github.com/MetaMask/core/pull/9392))

## [34.0.0]
Expand Down
73 changes: 15 additions & 58 deletions packages/network-controller/src/NetworkController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ function isErrorWithCode(error: unknown): error is { code: string | number } {
/**
* The string that uniquely identifies an Infura network client.
*/
export type BuiltInNetworkClientId = InfuraNetworkType;
export type BuiltInNetworkClientId = string;

/**
* The string that uniquely identifies a custom network client.
Expand Down Expand Up @@ -1074,20 +1074,15 @@ function isValidUrl(url: string): boolean {
*
* @param rpcEndpointUrl - The URL to operate on.
* @returns The Infura network name that the URL references.
* @throws if the URL is not an Infura API URL, or if an Infura network is not
* present in the URL.
* @throws if no Infura network is present in the URL.
*/
function deriveInfuraNetworkNameFromRpcEndpointUrl(
rpcEndpointUrl: string,
): InfuraNetworkType {
): string {
const match = INFURA_URL_REGEX.exec(rpcEndpointUrl);

if (match?.groups) {
if (isInfuraNetworkType(match.groups.networkName)) {
return match.groups.networkName;
}

throw new Error(`Unknown Infura network '${match.groups.networkName}'`);
return match.groups.networkName;
}

throw new Error('Could not derive Infura network from RPC endpoint URL');
Expand Down Expand Up @@ -1409,11 +1404,7 @@ export class NetworkController extends BaseController<
autoManagedNetworkClientRegistry,
)) {
for (const networkClientId of Object.keys(networkClientsById)) {
// Type assertion: We can assume that `networkClientId` is valid here.
const networkClient =
networkClientsById[
networkClientId as keyof typeof networkClientsById
];
const networkClient = networkClientsById[networkClientId];
if (
networkClient.configuration.failoverRpcUrls &&
networkClient.configuration.failoverRpcUrls.length > 0
Expand Down Expand Up @@ -1529,18 +1520,11 @@ export class NetworkController extends BaseController<
const autoManagedNetworkClientRegistry =
this.#ensureAutoManagedNetworkClientRegistryPopulated();

if (isInfuraNetworkType(networkClientId)) {
const infuraNetworkClient =
autoManagedNetworkClientRegistry[NetworkClientType.Infura][
networkClientId
];
// This is impossible to reach
/* istanbul ignore if */
if (!infuraNetworkClient) {
throw new Error(
`No Infura network client was found with the ID "${networkClientId}".`,
);
}
const infuraNetworkClient =
autoManagedNetworkClientRegistry[NetworkClientType.Infura][
networkClientId
];
if (infuraNetworkClient) {
return infuraNetworkClient;
}

Expand All @@ -1550,7 +1534,7 @@ export class NetworkController extends BaseController<
];
if (!customNetworkClient) {
throw new Error(
`No custom network client was found with the ID "${networkClientId}".`,
`No network client was found with ID "${networkClientId}".`,
);
}
return customNetworkClient;
Expand Down Expand Up @@ -1620,10 +1604,7 @@ export class NetworkController extends BaseController<
| NetworkStatus.Blocked;
isEIP1559Compatible: undefined | boolean;
}> {
// Force TypeScript to use one of the two overloads explicitly
const networkClient = isInfuraNetworkType(networkClientId)
? this.getNetworkClientById(networkClientId)
: this.getNetworkClientById(networkClientId);
const networkClient = this.getNetworkClientById(networkClientId);

const isInfura =
networkClient.configuration.type === NetworkClientType.Infura;
Expand Down Expand Up @@ -2603,16 +2584,6 @@ export class NetworkController extends BaseController<
? rpcEndpointFields.networkClientId
: undefined;

if (
rpcEndpointFields.type === RpcEndpointType.Custom &&
networkClientId !== undefined &&
isInfuraNetworkType(networkClientId)
) {
throw new Error(
`${errorMessagePrefix}: Custom RPC endpoint '${rpcEndpointFields.url}' has invalid network client ID '${networkClientId}'`,
);
}

if (
mode === 'update' &&
networkClientId !== undefined &&
Expand Down Expand Up @@ -2700,22 +2671,6 @@ export class NetworkController extends BaseController<
);
}

const soleInfuraRpcEndpoint = infuraRpcEndpoints[0];
if (soleInfuraRpcEndpoint) {
const infuraNetworkName = deriveInfuraNetworkNameFromRpcEndpointUrl(
soleInfuraRpcEndpoint.url,
);
const infuraNetworkNickname = NetworkNickname[infuraNetworkName];
const infuraChainId = ChainId[infuraNetworkName];
if (networkFields.chainId !== infuraChainId) {
throw new Error(
mode === 'add'
? `Could not add network with chain ID ${networkFields.chainId} and Infura RPC endpoint for '${infuraNetworkNickname}' which represents ${infuraChainId}, as the two conflict`
: `Could not update network with chain ID ${networkFields.chainId} and Infura RPC endpoint for '${infuraNetworkNickname}' which represents ${infuraChainId}, as the two conflict`,
);
}
}

if (
networkFields.rpcEndpoints[networkFields.defaultRpcEndpointIndex] ===
undefined
Expand Down Expand Up @@ -3097,14 +3052,16 @@ export class NetworkController extends BaseController<
updateState?: (state: Draft<NetworkState>) => void;
} = {},
): void {
const networkClient = this.getNetworkClientById(networkClientId);

const autoManagedNetworkClientRegistry =
this.#ensureAutoManagedNetworkClientRegistryPopulated();

let autoManagedNetworkClient:
| AutoManagedNetworkClient<CustomNetworkClientConfiguration>
| AutoManagedNetworkClient<InfuraNetworkClientConfiguration>;

if (isInfuraNetworkType(networkClientId)) {
if (networkClient.configuration.type === NetworkClientType.Infura) {
const possibleAutoManagedNetworkClient =
autoManagedNetworkClientRegistry[NetworkClientType.Infura][
networkClientId
Expand Down
24 changes: 10 additions & 14 deletions packages/network-controller/src/create-network-client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller';
import type {
CockatielFailureReason,
InfuraNetworkType,
} from '@metamask/controller-utils';
import type { CockatielFailureReason } from '@metamask/controller-utils';
import {
ChainId,
DEFAULT_MAX_CONSECUTIVE_FAILURES,
DEFAULT_MAX_RETRIES,
} from '@metamask/controller-utils';
Expand Down Expand Up @@ -200,7 +196,7 @@ export function createNetworkClient({
configuration.type === NetworkClientType.Infura
? createInfuraNetworkMiddleware({
blockTracker,
network: configuration.network,
chainId: configuration.chainId,
rpcProvider,
rpcApiMiddleware,
})
Expand Down Expand Up @@ -556,19 +552,19 @@ function createBlockTracker({
*
* @param args - The arguments.
* @param args.blockTracker - The block tracker to use.
* @param args.network - The Infura network to use.
* @param args.chainId - The chain id to use.
* @param args.rpcProvider - The RPC provider to use.
* @param args.rpcApiMiddleware - Additional middleware.
* @returns The collection of middleware that makes up the Infura client.
*/
function createInfuraNetworkMiddleware({
blockTracker,
network,
chainId,
rpcProvider,
rpcApiMiddleware,
}: {
blockTracker: PollingBlockTracker;
network: InfuraNetworkType;
chainId: string;
rpcProvider: InternalProvider;
rpcApiMiddleware: RpcApiMiddleware;
}): JsonRpcMiddleware<
Expand All @@ -578,7 +574,7 @@ function createInfuraNetworkMiddleware({
> {
return JsonRpcEngineV2.create({
middleware: [
createNetworkAndChainIdMiddleware({ network }),
createNetworkAndChainIdMiddleware({ chainId }),
createBlockCacheMiddleware({ blockTracker }),
createInflightCacheMiddleware(),
createBlockRefMiddleware({ blockTracker, provider: rpcProvider }),
Expand All @@ -593,16 +589,16 @@ function createInfuraNetworkMiddleware({
* Creates static method middleware.
*
* @param args - The Arguments.
* @param args.network - The Infura network to use.
* @param args.chainId - The chain id to use.
* @returns The middleware that implements the eth_chainId method.
*/
function createNetworkAndChainIdMiddleware({
network,
chainId,
}: {
network: InfuraNetworkType;
chainId: string;
}): JsonRpcMiddleware<JsonRpcRequest> {
return createScaffoldMiddleware({
eth_chainId: ChainId[network],
eth_chainId: chainId,
});
}

Expand Down
3 changes: 1 addition & 2 deletions packages/network-controller/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { InfuraNetworkType } from '@metamask/controller-utils';
import type { BlockTracker as BaseBlockTracker } from '@metamask/eth-block-tracker';
import type { InternalProvider } from '@metamask/eth-json-rpc-provider';
import type { MiddlewareContext } from '@metamask/json-rpc-engine/v2';
Expand Down Expand Up @@ -47,7 +46,7 @@ export type CustomNetworkClientConfiguration =
*/
export type InfuraNetworkClientConfiguration =
CommonNetworkClientConfiguration & {
network: InfuraNetworkType;
network: string;
infuraProjectId: string;
type: NetworkClientType.Infura;
};
Expand Down
Loading