{"version":3,"file":"experimentalProviderRequest.cjs","sourceRoot":"","sources":["../../src/permitted/experimentalProviderRequest.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonRpcEngineEndCallback } from '@metamask/json-rpc-engine';\nimport type { PermittedHandlerExport } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type {\n  JsonRpcRequest,\n  ProviderRequestParams,\n  ProviderRequestResult,\n} from '@metamask/snaps-sdk';\nimport { type InferMatching } from '@metamask/snaps-utils';\nimport {\n  StructError,\n  create,\n  object,\n  optional,\n  string,\n  type,\n} from '@metamask/superstruct';\nimport {\n  bigIntToHex,\n  parseCaipChainId,\n  type PendingJsonRpcResponse,\n  type Json,\n  CaipChainIdStruct,\n  JsonRpcParamsStruct,\n} from '@metamask/utils';\n\nimport { SnapEndowments } from '../endowments';\nimport type { MethodHooksObject } from '../utils';\n\n// Read-only methods that are currently allowed for this RPC method.\nconst METHOD_ALLOWLIST = Object.freeze([\n  'eth_blockNumber',\n  'eth_call',\n  'eth_chainId',\n  'eth_coinbase',\n  'eth_estimateGas',\n  'eth_feeHistory',\n  'eth_gasPrice',\n  'eth_getBalance',\n  'eth_getBlockByHash',\n  'eth_getBlockByNumber',\n  'eth_getBlockTransactionCountByHash',\n  'eth_getBlockTransactionCountByNumber',\n  'eth_getCode',\n  'eth_getFilterChanges',\n  'eth_getFilterLogs',\n  'eth_getLogs',\n  'eth_getProof',\n  'eth_getStorageAt',\n  'eth_getTransactionByBlockHashAndIndex',\n  'eth_getTransactionByBlockNumberAndIndex',\n  'eth_getTransactionByHash',\n  'eth_getTransactionCount',\n  'eth_getTransactionReceipt',\n  'eth_getUncleByBlockHashAndIndex',\n  'eth_getUncleByBlockNumberAndIndex',\n  'eth_getUncleCountByBlockHash',\n  'eth_getUncleCountByBlockNumber',\n  'eth_getWork',\n  'eth_hashrate',\n  'eth_mining',\n  'eth_newBlockFilter',\n  'eth_newFilter',\n  'eth_newPendingTransactionFilter',\n  'eth_protocolVersion',\n  'eth_sendRawTransaction',\n  'eth_submitHashrate',\n  'eth_submitWork',\n  'eth_syncing',\n  'eth_uninstallFilter',\n  'net_listening',\n  'net_peerCount',\n  'net_version',\n  'web3_clientVersion',\n  'web3_sha3',\n]);\n\nconst hookNames: MethodHooksObject<ProviderRequestMethodHooks> = {\n  hasPermission: true,\n  getNetworkConfigurationByChainId: true,\n  getNetworkClientById: true,\n};\n\ntype NetworkConfiguration = {\n  defaultRpcEndpointIndex: number;\n  rpcEndpoints: { networkClientId: string }[];\n};\n\nexport type ProviderRequestMethodHooks = {\n  hasPermission: (permissionName: string) => boolean;\n\n  getNetworkConfigurationByChainId: (\n    chainId: string,\n  ) => NetworkConfiguration | undefined;\n\n  getNetworkClientById: (id: string) => {\n    provider: { request: (request: Json) => Promise<Json> };\n  };\n};\n\nexport const providerRequestHandler: PermittedHandlerExport<\n  ProviderRequestMethodHooks,\n  ProviderRequestParameters,\n  ProviderRequestResult\n> = {\n  methodNames: ['snap_experimentalProviderRequest'],\n  implementation: providerRequestImplementation,\n  hookNames,\n};\n\nconst ProviderRequestParametersStruct = object({\n  chainId: CaipChainIdStruct,\n  request: type({\n    method: string(),\n    params: optional(JsonRpcParamsStruct),\n  }),\n});\n\nexport type ProviderRequestParameters = InferMatching<\n  typeof ProviderRequestParametersStruct,\n  ProviderRequestParams\n>;\n\n/**\n * The `snap_experimentalProviderRequest` method implementation.\n *\n * This RPC method lets Snaps make requests to MetaMask networks that are not currently selected in the UI.\n *\n * The RPC method requires the caller to have the endowment:ethereum-provider permission.\n *\n * NOTE: This implementation is experimental and may be removed or changed without warning.\n *\n * @param req - The JSON-RPC request object.\n * @param res - The JSON-RPC response object.\n * @param _next - The `json-rpc-engine` \"next\" callback. Not used by this\n * function.\n * @param end - The `json-rpc-engine` \"end\" callback.\n * @param hooks - The RPC method hooks.\n * @param hooks.hasPermission - Checks whether a given origin has a given permission.\n * @param hooks.getNetworkConfigurationByChainId - Get a network configuration for a given chain ID.\n * @param hooks.getNetworkClientById - Get a network client for a given ID.\n * @returns Nothing.\n */\nasync function providerRequestImplementation(\n  req: JsonRpcRequest<ProviderRequestParams>,\n  // `ProviderRequestResult` is an alias for `Json` (which is the default type\n  // argument for `PendingJsonRpcResponse`), but that may not be the case in the\n  // future. We use `ProviderRequestResult` here to make it clear that this is\n  // the expected type of the result.\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-arguments\n  res: PendingJsonRpcResponse<ProviderRequestResult>,\n  _next: unknown,\n  end: JsonRpcEngineEndCallback,\n  {\n    hasPermission,\n    getNetworkConfigurationByChainId,\n    getNetworkClientById,\n  }: ProviderRequestMethodHooks,\n): Promise<void> {\n  if (!hasPermission(SnapEndowments.EthereumProvider)) {\n    return end(rpcErrors.methodNotFound());\n  }\n\n  const { params } = req;\n\n  try {\n    const { chainId, request } = getValidatedParams(params);\n\n    if (!METHOD_ALLOWLIST.includes(request.method)) {\n      return end(rpcErrors.methodNotFound());\n    }\n\n    const parsedChainId = parseCaipChainId(chainId);\n\n    if (parsedChainId.namespace !== 'eip155') {\n      return end(\n        rpcErrors.invalidParams({\n          message: 'Only EVM networks are currently supported.',\n        }),\n      );\n    }\n\n    const numericalChainId = BigInt(parsedChainId.reference);\n\n    const networkConfiguration = getNetworkConfigurationByChainId(\n      bigIntToHex(numericalChainId),\n    );\n\n    if (!networkConfiguration) {\n      return end(\n        rpcErrors.invalidParams({\n          message: 'The requested network is not available.',\n        }),\n      );\n    }\n\n    const rpc =\n      networkConfiguration.rpcEndpoints[\n        networkConfiguration.defaultRpcEndpointIndex\n      ];\n\n    const networkClient = getNetworkClientById(rpc.networkClientId);\n\n    const { provider } = networkClient;\n\n    res.result = await provider.request(request);\n  } catch (error) {\n    return end(error);\n  }\n\n  return end();\n}\n\n/**\n * Validate the method `params` and returns them cast to the correct\n * type. Throws if validation fails.\n *\n * @param params - The unvalidated params object from the method request.\n * @returns The validated updateInterface method parameter object.\n */\nfunction getValidatedParams(params: unknown): ProviderRequestParameters {\n  try {\n    return create(params, ProviderRequestParametersStruct);\n  } catch (error) {\n    if (error instanceof StructError) {\n      throw rpcErrors.invalidParams({\n        message: `Invalid params: ${error.message}.`,\n      });\n    }\n    /* istanbul ignore next */\n    throw rpcErrors.internal();\n  }\n}\n"]}