UNPKG

@metamask/network-controller

Version:

Provides an interface to the currently selected network via a MetaMask-compatible provider object

1 lines 15.5 kB
{"version":3,"file":"create-network-client.mjs","sourceRoot":"","sources":["../src/create-network-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InfuraNetworkType } from '@metamask/controller-utils';\nimport { ChainId } from '@metamask/controller-utils';\nimport type { PollingBlockTrackerOptions } from '@metamask/eth-block-tracker';\nimport { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport { createInfuraMiddleware } from '@metamask/eth-json-rpc-infura';\nimport {\n createBlockCacheMiddleware,\n createBlockRefMiddleware,\n createBlockRefRewriteMiddleware,\n createBlockTrackerInspectorMiddleware,\n createInflightCacheMiddleware,\n createFetchMiddleware,\n createRetryOnEmptyMiddleware,\n} from '@metamask/eth-json-rpc-middleware';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport {\n providerFromEngine,\n providerFromMiddleware,\n} from '@metamask/eth-json-rpc-provider';\nimport {\n createAsyncMiddleware,\n createScaffoldMiddleware,\n JsonRpcEngine,\n mergeMiddleware,\n} from '@metamask/json-rpc-engine';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport type { Hex, Json, JsonRpcParams } from '@metamask/utils';\n\nimport type { NetworkControllerMessenger } from './NetworkController';\nimport type { RpcServiceOptions } from './rpc-service/rpc-service';\nimport { RpcServiceChain } from './rpc-service/rpc-service-chain';\nimport type {\n BlockTracker,\n NetworkClientConfiguration,\n Provider,\n} from './types';\nimport { NetworkClientType } from './types';\n\nconst SECOND = 1000;\n\n/**\n * The pair of provider / block tracker that can be used to interface with the\n * network and respond to new activity.\n */\nexport type NetworkClient = {\n configuration: NetworkClientConfiguration;\n provider: Provider;\n blockTracker: BlockTracker;\n destroy: () => void;\n};\n\n/**\n * Create a JSON RPC network client for a specific network.\n *\n * @param args - The arguments.\n * @param args.configuration - The network configuration.\n * @param args.getRpcServiceOptions - Factory for constructing RPC service\n * options. See {@link NetworkControllerOptions.getRpcServiceOptions}.\n * @param args.getBlockTrackerOptions - Factory for constructing block tracker\n * options. See {@link NetworkControllerOptions.getBlockTrackerOptions}.\n * @param args.messenger - The network controller messenger.\n * @param args.isRpcFailoverEnabled - Whether or not requests sent to the\n * primary RPC endpoint for this network should be automatically diverted to\n * provided failover endpoints if the primary is unavailable. This effectively\n * causes the `failoverRpcUrls` property of the network client configuration\n * to be honored or ignored.\n * @returns The network client.\n */\nexport function createNetworkClient({\n configuration,\n getRpcServiceOptions,\n getBlockTrackerOptions,\n messenger,\n isRpcFailoverEnabled,\n}: {\n configuration: NetworkClientConfiguration;\n getRpcServiceOptions: (\n rpcEndpointUrl: string,\n ) => Omit<RpcServiceOptions, 'failoverService' | 'endpointUrl'>;\n getBlockTrackerOptions: (\n rpcEndpointUrl: string,\n ) => Omit<PollingBlockTrackerOptions, 'provider'>;\n messenger: NetworkControllerMessenger;\n isRpcFailoverEnabled: boolean;\n}): NetworkClient {\n const primaryEndpointUrl =\n configuration.type === NetworkClientType.Infura\n ? `https://${configuration.network}.infura.io/v3/${configuration.infuraProjectId}`\n : configuration.rpcUrl;\n const availableEndpointUrls = isRpcFailoverEnabled\n ? [primaryEndpointUrl, ...(configuration.failoverRpcUrls ?? [])]\n : [primaryEndpointUrl];\n const rpcServiceChain = new RpcServiceChain(\n availableEndpointUrls.map((endpointUrl) => ({\n ...getRpcServiceOptions(endpointUrl),\n endpointUrl,\n })),\n );\n rpcServiceChain.onBreak(({ endpointUrl, failoverEndpointUrl, ...rest }) => {\n let error: unknown;\n if ('error' in rest) {\n error = rest.error;\n } else if ('value' in rest) {\n error = rest.value;\n }\n\n messenger.publish('NetworkController:rpcEndpointUnavailable', {\n chainId: configuration.chainId,\n endpointUrl,\n failoverEndpointUrl,\n error,\n });\n });\n rpcServiceChain.onDegraded(({ endpointUrl, ...rest }) => {\n let error: unknown;\n if ('error' in rest) {\n error = rest.error;\n } else if ('value' in rest) {\n error = rest.value;\n }\n\n messenger.publish('NetworkController:rpcEndpointDegraded', {\n chainId: configuration.chainId,\n endpointUrl,\n error,\n });\n });\n rpcServiceChain.onRetry(({ endpointUrl, attempt }) => {\n messenger.publish('NetworkController:rpcEndpointRequestRetried', {\n endpointUrl,\n attempt,\n });\n });\n\n const rpcApiMiddleware =\n configuration.type === NetworkClientType.Infura\n ? createInfuraMiddleware({\n rpcService: rpcServiceChain,\n options: {\n source: 'metamask',\n },\n })\n : createFetchMiddleware({ rpcService: rpcServiceChain });\n\n const rpcProvider = providerFromMiddleware(rpcApiMiddleware);\n\n const blockTracker = createBlockTracker({\n networkClientType: configuration.type,\n endpointUrl: primaryEndpointUrl,\n getOptions: getBlockTrackerOptions,\n provider: rpcProvider,\n });\n\n const networkMiddleware =\n configuration.type === NetworkClientType.Infura\n ? createInfuraNetworkMiddleware({\n blockTracker,\n network: configuration.network,\n rpcProvider,\n rpcApiMiddleware,\n })\n : createCustomNetworkMiddleware({\n blockTracker,\n chainId: configuration.chainId,\n rpcApiMiddleware,\n });\n\n const engine = new JsonRpcEngine();\n\n engine.push(networkMiddleware);\n\n const provider = providerFromEngine(engine);\n\n const destroy = () => {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n blockTracker.destroy();\n };\n\n return { configuration, provider, blockTracker, destroy };\n}\n\n/**\n * Create the block tracker for the network.\n *\n * @param args - The arguments.\n * @param args.networkClientType - The type of the network client (\"infura\" or\n * \"custom\").\n * @param args.endpointUrl - The URL of the endpoint.\n * @param args.getOptions - Factory for the block tracker options.\n * @param args.provider - The EIP-1193 provider for the network's JSON-RPC\n * middleware stack.\n * @returns The created block tracker.\n */\nfunction createBlockTracker({\n networkClientType,\n endpointUrl,\n getOptions,\n provider,\n}: {\n networkClientType: NetworkClientType;\n endpointUrl: string;\n getOptions: (\n rpcEndpointUrl: string,\n ) => Omit<PollingBlockTrackerOptions, 'provider'>;\n provider: SafeEventEmitterProvider;\n}) {\n const testOptions =\n process.env.IN_TEST && networkClientType === NetworkClientType.Custom\n ? { pollingInterval: SECOND }\n : {};\n\n return new PollingBlockTracker({\n ...testOptions,\n ...getOptions(endpointUrl),\n provider,\n });\n}\n\n/**\n * Create middleware for infura.\n *\n * @param args - The arguments.\n * @param args.blockTracker - The block tracker to use.\n * @param args.network - The Infura network to use.\n * @param args.rpcProvider - The RPC provider to use.\n * @param args.rpcApiMiddleware - Additional middleware.\n * @returns The collection of middleware that makes up the Infura client.\n */\nfunction createInfuraNetworkMiddleware({\n blockTracker,\n network,\n rpcProvider,\n rpcApiMiddleware,\n}: {\n blockTracker: PollingBlockTracker;\n network: InfuraNetworkType;\n rpcProvider: SafeEventEmitterProvider;\n rpcApiMiddleware: JsonRpcMiddleware<JsonRpcParams, Json>;\n}) {\n return mergeMiddleware([\n createNetworkAndChainIdMiddleware({ network }),\n createBlockCacheMiddleware({ blockTracker }),\n createInflightCacheMiddleware(),\n createBlockRefMiddleware({ blockTracker, provider: rpcProvider }),\n createRetryOnEmptyMiddleware({ blockTracker, provider: rpcProvider }),\n createBlockTrackerInspectorMiddleware({ blockTracker }),\n rpcApiMiddleware,\n ]);\n}\n\n/**\n * Creates static method middleware.\n *\n * @param args - The Arguments.\n * @param args.network - The Infura network to use.\n * @returns The middleware that implements the eth_chainId method.\n */\nfunction createNetworkAndChainIdMiddleware({\n network,\n}: {\n network: InfuraNetworkType;\n}) {\n return createScaffoldMiddleware({\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n eth_chainId: ChainId[network],\n });\n}\n\nconst createChainIdMiddleware = (\n chainId: Hex,\n): JsonRpcMiddleware<JsonRpcParams, Json> => {\n return (req, res, next, end) => {\n if (req.method === 'eth_chainId') {\n res.result = chainId;\n return end();\n }\n return next();\n };\n};\n\n/**\n * Creates custom middleware.\n *\n * @param args - The arguments.\n * @param args.blockTracker - The block tracker to use.\n * @param args.chainId - The chain id to use.\n * @param args.rpcApiMiddleware - Additional middleware.\n * @returns The collection of middleware that makes up the Infura client.\n */\nfunction createCustomNetworkMiddleware({\n blockTracker,\n chainId,\n rpcApiMiddleware,\n}: {\n blockTracker: PollingBlockTracker;\n chainId: Hex;\n rpcApiMiddleware: JsonRpcMiddleware<JsonRpcParams, Json>;\n}): JsonRpcMiddleware<JsonRpcParams, Json> {\n const testMiddlewares = process.env.IN_TEST\n ? [createEstimateGasDelayTestMiddleware()]\n : [];\n\n return mergeMiddleware([\n ...testMiddlewares,\n createChainIdMiddleware(chainId),\n createBlockRefRewriteMiddleware({ blockTracker }),\n createBlockCacheMiddleware({ blockTracker }),\n createInflightCacheMiddleware(),\n createBlockTrackerInspectorMiddleware({ blockTracker }),\n rpcApiMiddleware,\n ]);\n}\n\n/**\n * For use in tests only.\n * Adds a delay to `eth_estimateGas` calls.\n *\n * @returns The middleware for delaying gas estimation calls by 2 seconds when in test.\n */\nfunction createEstimateGasDelayTestMiddleware() {\n return createAsyncMiddleware(async (req, _, next) => {\n if (req.method === 'eth_estimateGas') {\n await new Promise((resolve) => setTimeout(resolve, SECOND * 2));\n }\n return next();\n });\n}\n"]}