UNPKG

@metamask/snaps-rpc-methods

Version:
1 lines 8.21 kB
{"version":3,"file":"invokeSnap.mjs","sourceRoot":"","sources":["../../src/restricted/invokeSnap.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,wCAAwC;AACjE,OAAO,EAAE,SAAS,EAAE,6BAA6B;AAOjD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,8BAA8B;AAKpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,aAAa,CAAC;AAsCxD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAGX,KAAK,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE;IACtD,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;SAC3E,KAA2B,CAAC;IAE/B,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,CACnC,kCAAkC,EAClC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAC5B,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAC5C,CAAC,aAAa,EAAE,IAAI,EAAE,EAAE;QACtB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,aAAa,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC,EACD,EAAE,CACH,CAAC;IAEF,OAAO,SAAS,CAAC,IAAI,CACnB,6BAA6B,EAC7B,WAAW,CAAC,QAAQ,CAAC,MAAM,EAC3B,YAAY,CACb,CAAC;AACJ,CAAC,CAAC;AACF;;;;;;;;;;;GAWG;AACH,MAAM,oBAAoB,GAItB,CAAC,EAAE,SAAS,EAAyC,EAAE,EAAE;IAC3D,OAAO;QACL,cAAc,EAAE,cAAc,CAAC,gBAAgB;QAC/C,UAAU,EAAE,0BAA0B;QACtC,cAAc,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC;QACxC,oBAAoB,EAAE,2BAA2B,CAAC;YAChD,SAAS;SACV,CAAC;QACF,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;YACzB,IAAI,OAAO,EAAE,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO,EAAE,CAAC;gBACxE,MAAM,SAAS,CAAC,aAAa,CAAC;oBAC5B,OAAO,EAAE,sBAAsB,cAAc,CAAC,OAAO,WAAW;iBACjE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,UAAU,EAAE;YACV,WAAW,EAAE,iBAAiB;SAC/B;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,UAAU,EAAE,0BAA0B;IACtC,oBAAoB;IACpB,WAAW,EAAE,CAAC,8BAA8B,CAAC;CACrC,CAAC,CAAC;AAEZ;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,EAC1C,SAAS,GAC6B;IACtC,OAAO,KAAK,UAAU,UAAU,CAC9B,OAAkD;QAElD,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAEzC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAA0B,CAAC;QAEvD,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAE3B,OAAO,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,8BAA8B,EAAE;YAC3D,MAAM;YACN,MAAM;YACN,OAAO;YACP,OAAO,EAAE,WAAW,CAAC,YAAY;SAClC,CAAC,CAAS,CAAC;IACd,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { Messenger } from '@metamask/messenger';\nimport type {\n PermissionSpecificationBuilder,\n RestrictedMethodOptions,\n ValidPermissionSpecification,\n PermissionValidatorConstraint,\n PermissionSideEffect,\n} from '@metamask/permission-controller';\nimport { PermissionType } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type {\n InvokeSnapParams,\n InvokeSnapResult,\n RequestSnapsParams,\n RequestSnapsResult,\n} from '@metamask/snaps-sdk';\nimport { HandlerType, SnapCaveatType } from '@metamask/snaps-utils';\nimport type { Json, NonEmptyArray } from '@metamask/utils';\n\nimport type { SnapControllerHandleRequestAction } from '../types';\n\nexport const WALLET_SNAP_PERMISSION_KEY = 'wallet_snap';\n\n// Redeclare installSnaps action type to avoid circular dependencies\nexport type SnapControllerInstallSnapsAction = {\n type: `SnapController:installSnaps`;\n handler: (\n origin: string,\n requestedSnaps: RequestSnapsParams,\n ) => Promise<RequestSnapsResult>;\n};\n\nexport type SnapControllerGetPermittedSnapsAction = {\n type: `SnapController:getPermittedSnaps`;\n handler: (origin: string) => RequestSnapsResult;\n};\n\ntype AllowedActions =\n | SnapControllerInstallSnapsAction\n | SnapControllerGetPermittedSnapsAction;\n\nexport type InvokeSnapMessengerActions = SnapControllerHandleRequestAction;\n\ntype InvokeSnapSpecificationBuilderOptions = {\n allowedCaveats?: Readonly<NonEmptyArray<string>> | null;\n messenger: Messenger<string, InvokeSnapMessengerActions>;\n};\n\ntype InvokeSnapSpecification = ValidPermissionSpecification<{\n permissionType: PermissionType.RestrictedMethod;\n targetName: typeof WALLET_SNAP_PERMISSION_KEY;\n methodImplementation: ReturnType<typeof getInvokeSnapImplementation>;\n allowedCaveats: Readonly<NonEmptyArray<string>> | null;\n validator: PermissionValidatorConstraint;\n sideEffect: {\n onPermitted: PermissionSideEffect<AllowedActions, never>['onPermitted'];\n };\n}>;\n\n/**\n * The side-effect method to handle the snap install.\n *\n * @param params - The side-effect params.\n * @param params.requestData - The request data associated to the requested permission.\n * @param params.messenger - The messenger to call an action.\n * @returns The result of the Snap installation.\n */\nexport const handleSnapInstall: PermissionSideEffect<\n AllowedActions,\n never\n>['onPermitted'] = async ({ requestData, messenger }) => {\n const snaps = requestData.permissions[WALLET_SNAP_PERMISSION_KEY].caveats?.[0]\n .value as RequestSnapsParams;\n\n const permittedSnaps = messenger.call(\n `SnapController:getPermittedSnaps`,\n requestData.metadata.origin,\n );\n\n const dedupedSnaps = Object.keys(snaps).reduce<RequestSnapsParams>(\n (filteredSnaps, snap) => {\n if (!permittedSnaps[snap]) {\n filteredSnaps[snap] = snaps[snap];\n }\n return filteredSnaps;\n },\n {},\n );\n\n return messenger.call(\n `SnapController:installSnaps`,\n requestData.metadata.origin,\n dedupedSnaps,\n );\n};\n/**\n * The specification builder for the `wallet_snap_*` permission.\n *\n * `wallet_snap_*` attempts to invoke an RPC method of the specified Snap.\n *\n * Requesting its corresponding permission will attempt to connect to the Snap,\n * and install it if it's not available yet.\n *\n * @param options - The specification builder options.\n * @param options.messenger - The messenger.\n * @returns The specification for the `wallet_snap_*` permission.\n */\nconst specificationBuilder: PermissionSpecificationBuilder<\n PermissionType.RestrictedMethod,\n InvokeSnapSpecificationBuilderOptions,\n InvokeSnapSpecification\n> = ({ messenger }: InvokeSnapSpecificationBuilderOptions) => {\n return {\n permissionType: PermissionType.RestrictedMethod,\n targetName: WALLET_SNAP_PERMISSION_KEY,\n allowedCaveats: [SnapCaveatType.SnapIds],\n methodImplementation: getInvokeSnapImplementation({\n messenger,\n }),\n validator: ({ caveats }) => {\n if (caveats?.length !== 1 || caveats[0].type !== SnapCaveatType.SnapIds) {\n throw rpcErrors.invalidParams({\n message: `Expected a single \"${SnapCaveatType.SnapIds}\" caveat.`,\n });\n }\n },\n sideEffect: {\n onPermitted: handleSnapInstall,\n },\n };\n};\n\n/**\n * Calls the specified JSON-RPC API method of the specified Snap. The Snap\n * must be installed and the dapp must have permission to communicate with the\n * Snap, or the request is rejected. The dapp can install the Snap and request\n * permission to communicate with it using\n * [`wallet_requestSnaps`](http://docs.metamask.io/snaps/reference/snaps-api/wallet_requestsnaps).\n *\n * @example\n * ```ts\n * const result = await ethereum.request({\n * method: 'wallet_snap',\n * params: {\n * snapId: 'npm:my-snap',\n * request: {\n * method: 'hello',\n * params: { name: 'world' },\n * },\n * },\n * });\n * console.log(result); // \"Hello, world!\"\n * ```\n */\nexport const invokeSnapBuilder = Object.freeze({\n targetName: WALLET_SNAP_PERMISSION_KEY,\n specificationBuilder,\n actionNames: ['SnapController:handleRequest'],\n} as const);\n\n/**\n * Builds the method implementation for `wallet_snap_*`.\n *\n * @param options - The options.\n * @param options.messenger - The messenger.\n * @returns The method implementation which returns the result of `SnapController:handleRequest`.\n * @throws If the params are invalid.\n */\nexport function getInvokeSnapImplementation({\n messenger,\n}: InvokeSnapSpecificationBuilderOptions) {\n return async function invokeSnap(\n options: RestrictedMethodOptions<InvokeSnapParams>,\n ): Promise<InvokeSnapResult> {\n const { params = {}, context } = options;\n\n const { snapId, request } = params as InvokeSnapParams;\n\n const { origin } = context;\n\n return (await messenger.call('SnapController:handleRequest', {\n snapId,\n origin,\n request,\n handler: HandlerType.OnRpcRequest,\n })) as Json;\n };\n}\n"]}