@metamask/multichain-api-middleware 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.0]
11
+
12
+ ### Changed
13
+
14
+ - Bump `@metamask/utils` from `^11.8.0` to `^11.8.1` ([#6708](https://github.com/MetaMask/core/pull/6708))
15
+ - `wallet_invokeMethod` no longer fails with unauthorized error if the `isMultichainOrigin` property is false on the requesting origin's CAIP-25 Permission ([#6703](https://github.com/MetaMask/core/pull/6703))
16
+
10
17
  ## [1.1.0]
11
18
 
12
19
  ### Changed
@@ -78,7 +85,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
78
85
 
79
86
  - Initial release
80
87
 
81
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/multichain-api-middleware@1.1.0...HEAD
88
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/multichain-api-middleware@1.2.0...HEAD
89
+ [1.2.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-api-middleware@1.1.0...@metamask/multichain-api-middleware@1.2.0
82
90
  [1.1.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-api-middleware@1.0.0...@metamask/multichain-api-middleware@1.1.0
83
91
  [1.0.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-api-middleware@0.4.0...@metamask/multichain-api-middleware@1.0.0
84
92
  [0.4.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-api-middleware@0.3.0...@metamask/multichain-api-middleware@0.4.0
@@ -31,7 +31,7 @@ async function walletInvokeMethodHandler(request, response, next, end, hooks) {
31
31
  catch {
32
32
  // noop
33
33
  }
34
- if (!caveat?.value?.isMultichainOrigin) {
34
+ if (!caveat) {
35
35
  return end(rpc_errors_1.providerErrors.unauthorized());
36
36
  }
37
37
  const scopeObject = (0, chain_agnostic_permission_1.getSessionScopes)(caveat.value, {
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-invokeMethod.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat?.value?.isMultichainOrigin) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-invokeMethod.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
@@ -28,7 +28,7 @@ async function walletInvokeMethodHandler(request, response, next, end, hooks) {
28
28
  catch {
29
29
  // noop
30
30
  }
31
- if (!caveat?.value?.isMultichainOrigin) {
31
+ if (!caveat) {
32
32
  return end(providerErrors.unauthorized());
33
33
  }
34
34
  const scopeObject = getSessionScopes(caveat.value, {
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-invokeMethod.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat?.value?.isMultichainOrigin) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-invokeMethod.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/multichain-api-middleware",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "JSON-RPC methods and middleware to support the MetaMask Multichain API",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -54,7 +54,7 @@
54
54
  "@metamask/network-controller": "^24.2.0",
55
55
  "@metamask/permission-controller": "^11.0.6",
56
56
  "@metamask/rpc-errors": "^7.0.2",
57
- "@metamask/utils": "^11.8.0",
57
+ "@metamask/utils": "^11.8.1",
58
58
  "@open-rpc/meta-schema": "^1.14.6",
59
59
  "@open-rpc/schema-utils-js": "^2.0.5",
60
60
  "jsonschema": "^1.4.1"