@metamask/snaps-rpc-methods
Version:
MetaMask Snaps JSON-RPC method implementations
105 lines • 3.91 kB
JavaScript
import { PermissionType } from "@metamask/permission-controller";
import { rpcErrors } from "@metamask/rpc-errors";
import { HandlerType, SnapCaveatType } from "@metamask/snaps-utils";
export const WALLET_SNAP_PERMISSION_KEY = 'wallet_snap';
/**
* The side-effect method to handle the snap install.
*
* @param params - The side-effect params.
* @param params.requestData - The request data associated to the requested permission.
* @param params.messenger - The messenger to call an action.
* @returns The result of the Snap installation.
*/
export const handleSnapInstall = async ({ requestData, messenger }) => {
const snaps = requestData.permissions[WALLET_SNAP_PERMISSION_KEY].caveats?.[0]
.value;
const permittedSnaps = messenger.call(`SnapController:getPermittedSnaps`, requestData.metadata.origin);
const dedupedSnaps = Object.keys(snaps).reduce((filteredSnaps, snap) => {
if (!permittedSnaps[snap]) {
filteredSnaps[snap] = snaps[snap];
}
return filteredSnaps;
}, {});
return messenger.call(`SnapController:installSnaps`, requestData.metadata.origin, dedupedSnaps);
};
/**
* The specification builder for the `wallet_snap_*` permission.
*
* `wallet_snap_*` attempts to invoke an RPC method of the specified Snap.
*
* Requesting its corresponding permission will attempt to connect to the Snap,
* and install it if it's not available yet.
*
* @param options - The specification builder options.
* @param options.messenger - The messenger.
* @returns The specification for the `wallet_snap_*` permission.
*/
const specificationBuilder = ({ messenger }) => {
return {
permissionType: PermissionType.RestrictedMethod,
targetName: WALLET_SNAP_PERMISSION_KEY,
allowedCaveats: [SnapCaveatType.SnapIds],
methodImplementation: getInvokeSnapImplementation({
messenger,
}),
validator: ({ caveats }) => {
if (caveats?.length !== 1 || caveats[0].type !== SnapCaveatType.SnapIds) {
throw rpcErrors.invalidParams({
message: `Expected a single "${SnapCaveatType.SnapIds}" caveat.`,
});
}
},
sideEffect: {
onPermitted: handleSnapInstall,
},
};
};
/**
* Calls the specified JSON-RPC API method of the specified Snap. The Snap
* must be installed and the dapp must have permission to communicate with the
* Snap, or the request is rejected. The dapp can install the Snap and request
* permission to communicate with it using
* [`wallet_requestSnaps`](http://docs.metamask.io/snaps/reference/snaps-api/wallet_requestsnaps).
*
* @example
* ```ts
* const result = await ethereum.request({
* method: 'wallet_snap',
* params: {
* snapId: 'npm:my-snap',
* request: {
* method: 'hello',
* params: { name: 'world' },
* },
* },
* });
* console.log(result); // "Hello, world!"
* ```
*/
export const invokeSnapBuilder = Object.freeze({
targetName: WALLET_SNAP_PERMISSION_KEY,
specificationBuilder,
actionNames: ['SnapController:handleRequest'],
});
/**
* Builds the method implementation for `wallet_snap_*`.
*
* @param options - The options.
* @param options.messenger - The messenger.
* @returns The method implementation which returns the result of `SnapController:handleRequest`.
* @throws If the params are invalid.
*/
export function getInvokeSnapImplementation({ messenger, }) {
return async function invokeSnap(options) {
const { params = {}, context } = options;
const { snapId, request } = params;
const { origin } = context;
return (await messenger.call('SnapController:handleRequest', {
snapId,
origin,
request,
handler: HandlerType.OnRpcRequest,
}));
};
}
//# sourceMappingURL=invokeSnap.mjs.map