@metamask/providers
Version:
A JavaScript Ethereum provider that connects to the wallet over a stream
1 lines • 21.3 kB
Source Map (JSON)
{"version":3,"file":"BaseProvider.cjs","sourceRoot":"","sources":["../src/BaseProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { JsonRpcEngine } from '@metamask/json-rpc-engine';\nimport { rpcErrors, JsonRpcError } from '@metamask/rpc-errors';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport type {\n JsonRpcRequest,\n JsonRpcId,\n JsonRpcVersion2,\n JsonRpcSuccess,\n JsonRpcParams,\n Json,\n} from '@metamask/utils';\nimport dequal from 'fast-deep-equal';\n\nimport messages from './messages';\nimport type { ConsoleLike, Maybe } from './utils';\nimport { getRpcPromiseCallback, isValidChainId } from './utils';\n\nexport type UnvalidatedJsonRpcRequest = {\n id?: JsonRpcId;\n jsonrpc?: JsonRpcVersion2;\n method: string;\n params?: unknown;\n};\n\nexport type BaseProviderOptions = {\n /**\n * The logging API to use.\n */\n logger?: ConsoleLike;\n\n /**\n * The maximum number of event listeners.\n */\n maxEventListeners?: number;\n\n /**\n * `@metamask/json-rpc-engine` middleware. The middleware will be inserted in the given\n * order immediately after engine initialization.\n */\n rpcMiddleware?: JsonRpcMiddleware<JsonRpcParams, Json>[];\n};\n\nexport type RequestArguments = {\n /** The RPC method to request. */\n method: string;\n\n /** The params of the RPC method, if any. */\n params?: unknown[] | Record<string, unknown>;\n};\n\nexport type BaseProviderState = {\n accounts: null | string[];\n isConnected: boolean;\n initialized: boolean;\n isPermanentlyDisconnected: boolean;\n};\n\n/**\n * An abstract class implementing the EIP-1193 interface. Implementers must:\n *\n * 1. At initialization, push a middleware to the internal `_rpcEngine` that\n * hands off requests to the server and receives responses in return.\n * 2. At initialization, retrieve initial state and call\n * {@link BaseProvider._initializeState} **once**.\n * 3. Ensure that the provider's state is synchronized with the wallet.\n * 4. Ensure that notifications are received and emitted as appropriate.\n */\nexport abstract class BaseProvider extends SafeEventEmitter {\n protected readonly _log: ConsoleLike;\n\n protected _state: BaseProviderState;\n\n protected _rpcEngine: JsonRpcEngine;\n\n protected static _defaultState: BaseProviderState = {\n accounts: null,\n isConnected: false,\n initialized: false,\n isPermanentlyDisconnected: false,\n };\n\n /**\n * The chain ID of the currently connected Ethereum chain.\n * See [chainId.network]{@link https://chainid.network} for more information.\n */\n #chainId: string | null;\n\n /**\n * The user's currently selected Ethereum address.\n * If null, MetaMask is either locked or the user has not permitted any\n * addresses to be viewed.\n */\n #selectedAddress: string | null;\n\n /**\n * Create a new instance of the provider.\n *\n * @param options - An options bag.\n * @param options.logger - The logging API to use. Default: `console`.\n * @param options.maxEventListeners - The maximum number of event\n * listeners. Default: 100.\n * @param options.rpcMiddleware - The RPC middleware stack. Default: [].\n */\n constructor({\n logger = console,\n maxEventListeners = 100,\n rpcMiddleware = [],\n }: BaseProviderOptions = {}) {\n super();\n\n this._log = logger;\n\n this.setMaxListeners(maxEventListeners);\n\n // Private state\n this._state = {\n ...BaseProvider._defaultState,\n };\n\n // Public state\n this.#selectedAddress = null;\n this.#chainId = null;\n\n // Bind functions to prevent consumers from making unbound calls\n this._handleAccountsChanged = this._handleAccountsChanged.bind(this);\n this._handleConnect = this._handleConnect.bind(this);\n this._handleChainChanged = this._handleChainChanged.bind(this);\n this._handleDisconnect = this._handleDisconnect.bind(this);\n this._rpcRequest = this._rpcRequest.bind(this);\n this.request = this.request.bind(this);\n\n // Handle RPC requests via dapp-side RPC engine.\n //\n // ATTN: Implementers must push a middleware that hands off requests to\n // the server.\n const rpcEngine = new JsonRpcEngine();\n rpcMiddleware.forEach((middleware) => rpcEngine.push(middleware));\n this._rpcEngine = rpcEngine;\n }\n\n //====================\n // Public Properties\n //====================\n\n get chainId(): string | null {\n return this.#chainId;\n }\n\n get selectedAddress(): string | null {\n return this.#selectedAddress;\n }\n\n //====================\n // Public Methods\n //====================\n\n /**\n * Returns whether the provider can process RPC requests.\n *\n * @returns Whether the provider can process RPC requests.\n */\n isConnected(): boolean {\n return this._state.isConnected;\n }\n\n /**\n * Submits an RPC request for the given method, with the given params.\n * Resolves with the result of the method call, or rejects on error.\n *\n * @param args - The RPC request arguments.\n * @param args.method - The RPC method name.\n * @param args.params - The parameters for the RPC method.\n * @returns A Promise that resolves with the result of the RPC method,\n * or rejects if an error is encountered.\n */\n async request<Type>(args: RequestArguments): Promise<Maybe<Type>> {\n if (!args || typeof args !== 'object' || Array.isArray(args)) {\n throw rpcErrors.invalidRequest({\n message: messages.errors.invalidRequestArgs(),\n data: args,\n });\n }\n\n const { method, params } = args;\n\n if (typeof method !== 'string' || method.length === 0) {\n throw rpcErrors.invalidRequest({\n message: messages.errors.invalidRequestMethod(),\n data: args,\n });\n }\n\n if (\n params !== undefined &&\n !Array.isArray(params) &&\n (typeof params !== 'object' || params === null)\n ) {\n throw rpcErrors.invalidRequest({\n message: messages.errors.invalidRequestParams(),\n data: args,\n });\n }\n\n const payload =\n params === undefined || params === null\n ? {\n method,\n }\n : {\n method,\n params,\n };\n\n return new Promise<Type>((resolve, reject) => {\n this._rpcRequest(payload, getRpcPromiseCallback(resolve, reject));\n });\n }\n\n //====================\n // Private Methods\n //====================\n\n /**\n * MUST be called by child classes.\n *\n * Sets initial state if provided and marks this provider as initialized.\n * Throws if called more than once.\n *\n * Permits the `networkVersion` field in the parameter object for\n * compatibility with child classes that use this value.\n *\n * @param initialState - The provider's initial state.\n * @param initialState.accounts - The user's accounts.\n * @param initialState.chainId - The chain ID.\n * @param initialState.networkVersion - The network version.\n * @param initialState.isConnected - Whether the network is available.\n * @fires BaseProvider#_initialized - If `initialState` is defined.\n * @fires BaseProvider#connect - If `initialState` is defined.\n */\n protected _initializeState(initialState?: {\n accounts: string[];\n chainId: string;\n networkVersion?: string;\n isConnected?: boolean;\n }) {\n if (this._state.initialized) {\n throw new Error('Provider already initialized.');\n }\n\n if (initialState) {\n const { accounts, chainId, networkVersion, isConnected } = initialState;\n\n // EIP-1193 connect\n this._handleConnect({ chainId, isConnected });\n this._handleChainChanged({ chainId, networkVersion, isConnected });\n this._handleAccountsChanged(accounts);\n }\n\n // Mark provider as initialized regardless of whether initial state was\n // retrieved.\n this._state.initialized = true;\n this.emit('_initialized');\n }\n\n /**\n * Internal RPC method. Forwards requests to background via the RPC engine.\n * Also remap ids inbound and outbound.\n *\n * @param payload - The RPC request object.\n * @param callback - The consumer's callback.\n * @returns The result of the RPC request.\n */\n protected _rpcRequest(\n payload: UnvalidatedJsonRpcRequest | UnvalidatedJsonRpcRequest[],\n callback: (...args: any[]) => void,\n ) {\n let callbackWrapper = callback;\n\n if (!Array.isArray(payload)) {\n if (!payload.jsonrpc) {\n payload.jsonrpc = '2.0';\n }\n\n if (\n payload.method === 'eth_accounts' ||\n payload.method === 'eth_requestAccounts'\n ) {\n // handle accounts changing\n callbackWrapper = (\n error: Error,\n response: JsonRpcSuccess<string[]>,\n ) => {\n this._handleAccountsChanged(\n response.result ?? [],\n payload.method === 'eth_accounts',\n );\n callback(error, response);\n };\n }\n return this._rpcEngine.handle(payload as JsonRpcRequest, callbackWrapper);\n }\n return this._rpcEngine.handle(payload as JsonRpcRequest[], callbackWrapper);\n }\n\n /**\n * When the provider becomes connected, updates internal state and emits\n * required events. Idempotent.\n *\n * @param networkInfo - The options object.\n * @param networkInfo.chainId - The ID of the newly connected chain.\n * @param networkInfo.isConnected - Whether the network is available.\n * @fires MetaMaskInpageProvider#connect\n */\n protected _handleConnect({\n chainId,\n isConnected,\n }: {\n chainId: string;\n isConnected?: boolean | undefined;\n }) {\n if (!this._state.isConnected && isConnected) {\n this._state.isConnected = true;\n this.emit('connect', { chainId });\n this._log.debug(messages.info.connected(chainId));\n }\n }\n\n /**\n * When the provider becomes disconnected, updates internal state and emits\n * required events. Idempotent with respect to the isRecoverable parameter.\n *\n * Error codes per the CloseEvent status codes as required by EIP-1193:\n * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes.\n *\n * @param isRecoverable - Whether the disconnection is recoverable.\n * @param errorMessage - A custom error message.\n * @fires BaseProvider#disconnect - If the disconnection is not recoverable.\n */\n protected _handleDisconnect(isRecoverable: boolean, errorMessage?: string) {\n if (\n this._state.isConnected ||\n (!this._state.isPermanentlyDisconnected && !isRecoverable)\n ) {\n this._state.isConnected = false;\n\n let error;\n if (isRecoverable) {\n error = new JsonRpcError(\n 1013, // Try again later\n errorMessage ?? messages.errors.disconnected(),\n );\n this._log.debug(error);\n } else {\n error = new JsonRpcError(\n 1011, // Internal error\n errorMessage ?? messages.errors.permanentlyDisconnected(),\n );\n this._log.error(error);\n this.#chainId = null;\n this._state.accounts = null;\n this.#selectedAddress = null;\n this._state.isPermanentlyDisconnected = true;\n }\n\n this.emit('disconnect', error);\n }\n }\n\n /**\n * Upon receipt of a new `chainId`, emits the corresponding event and sets\n * and sets relevant public state. Does nothing if the given `chainId` is\n * equivalent to the existing value.\n *\n * Permits the `networkVersion` field in the parameter object for\n * compatibility with child classes that use this value.\n *\n * @fires BaseProvider#chainChanged\n * @param networkInfo - An object with network info.\n * @param networkInfo.chainId - The latest chain ID.\n * @param networkInfo.isConnected - Whether the network is available.\n */\n protected _handleChainChanged({\n chainId,\n isConnected,\n }:\n | {\n chainId?: string;\n networkVersion?: string | undefined;\n isConnected?: boolean | undefined;\n }\n | undefined = {}) {\n if (!isValidChainId(chainId)) {\n this._log.error(messages.errors.invalidNetworkParams(), { chainId });\n return;\n }\n\n this._handleConnect({ chainId, isConnected });\n\n if (chainId !== this.#chainId) {\n this.#chainId = chainId;\n if (this._state.initialized) {\n this.emit('chainChanged', this.#chainId);\n }\n }\n }\n\n /**\n * Called when accounts may have changed. Diffs the new accounts value with\n * the current one, updates all state as necessary, and emits the\n * accountsChanged event.\n *\n * @param accounts - The new accounts value.\n * @param isEthAccounts - Whether the accounts value was returned by\n * a call to eth_accounts.\n */\n protected _handleAccountsChanged(\n accounts: unknown[],\n isEthAccounts = false,\n ): void {\n let _accounts = accounts;\n\n if (!Array.isArray(accounts)) {\n this._log.error(\n 'MetaMask: Received invalid accounts parameter. Please report this bug.',\n accounts,\n );\n _accounts = [];\n }\n\n for (const account of accounts) {\n if (typeof account !== 'string') {\n this._log.error(\n 'MetaMask: Received non-string account. Please report this bug.',\n accounts,\n );\n _accounts = [];\n break;\n }\n }\n\n // emit accountsChanged if anything about the accounts array has changed\n if (!dequal(this._state.accounts, _accounts)) {\n // we should always have the correct accounts even before eth_accounts\n // returns\n if (isEthAccounts && this._state.accounts !== null) {\n this._log.error(\n `MetaMask: 'eth_accounts' unexpectedly updated accounts. Please report this bug.`,\n _accounts,\n );\n }\n\n this._state.accounts = _accounts as string[];\n\n // handle selectedAddress\n if (this.#selectedAddress !== _accounts[0]) {\n this.#selectedAddress = (_accounts[0] as string) || null;\n }\n\n // finally, after all state has been updated, emit the event\n if (this._state.initialized) {\n const _nextAccounts = [..._accounts];\n this.emit('accountsChanged', _nextAccounts);\n }\n }\n }\n}\n"]}