UNPKG

@metamask/snaps-simulation

Version:

A simulation framework for MetaMask Snaps, enabling headless testing of Snaps in a controlled environment

284 lines 10.2 kB
import { HandlerType } from "@metamask/snaps-utils"; import { create } from "@metamask/superstruct"; import { createModuleLogger } from "@metamask/utils"; import { rootLogger } from "./logger.mjs"; import { handleRequest } from "./request.mjs"; import { addJsonRpcMock, removeJsonRpcMock } from "./store/index.mjs"; import { assertIsResponseWithInterface, JsonRpcMockOptionsStruct, NameLookupOptionsStruct, SignatureOptionsStruct, TransactionOptionsStruct } from "./structs.mjs"; const log = createModuleLogger(rootLogger, 'helpers'); /** * Get the helper functions for the Snap. * * @param snap - The installed Snap. * @param snap.snapId - The ID of the Snap. * @param snap.store - The Redux store. * @param snap.executionService - The execution service. * @param snap.runSaga - The `runSaga` function. * @param snap.controllerMessenger - The controller messenger. * @param snap.options - The simulation options. * @returns The Snap helpers. */ export function getHelpers({ snapId, store, executionService, runSaga, controllerMessenger, options, }) { const onTransaction = async (request) => { log('Sending transaction %o.', request); const { origin: transactionOrigin, chainId, ...transaction } = create(request, TransactionOptionsStruct); const response = await handleRequest({ snapId, store, executionService, runSaga, controllerMessenger, simulationOptions: options, handler: HandlerType.OnTransaction, request: { method: '', params: { chainId, transaction, transactionOrigin, }, }, }); assertIsResponseWithInterface(response); return response; }; // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async const onCronjob = (request) => { log('Running cronjob %o.', options); return handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnCronjob, request, }); }; // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async const onKeyringRequest = (request) => { log('Sending keyring request %o.', request); return handleRequest({ snapId, store, executionService, runSaga, controllerMessenger, simulationOptions: options, handler: HandlerType.OnKeyringRequest, request, }); }; return { // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async request: (request) => { log('Sending request %o.', request); return handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnRpcRequest, request, }); }, onTransaction, sendTransaction: onTransaction, onKeyringRequest, // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async onInstall: (request) => { log('Running onInstall handler.'); return handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnInstall, request: { method: '', ...request, }, }); }, // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async onUpdate: (request) => { log('Running onUpdate handler.'); return handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnUpdate, request: { method: '', ...request, }, }); }, // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async onStart: (request) => { log('Running onStart handler.'); return handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnStart, request: { method: '', ...request, }, }); }, onNameLookup: async (nameLookupOptions) => { log('Requesting name lookup %o.', nameLookupOptions); const params = create(nameLookupOptions, NameLookupOptionsStruct); const response = await handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnNameLookup, request: { method: '', params, }, }); return response; }, onSignature: async (request) => { log('Requesting signature %o.', request); const { origin: signatureOrigin, ...signature } = create(request, SignatureOptionsStruct); const response = await handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnSignature, request: { method: '', params: { signature, signatureOrigin, }, }, }); assertIsResponseWithInterface(response); return response; }, onCronjob, runCronjob: onCronjob, onBackgroundEvent: onCronjob, onHomePage: async () => { log('Rendering home page.'); const response = await handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnHomePage, request: { method: '', }, }); assertIsResponseWithInterface(response); return response; }, onSettingsPage: async () => { log('Rendering settings page.'); const response = await handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnSettingsPage, request: { method: '', }, }); assertIsResponseWithInterface(response); return response; }, onProtocolRequest: async (scope, rawRequest) => { log('Sending protocol request.'); const request = { jsonrpc: '2.0', id: rawRequest.id ?? 1, method: rawRequest.method, ...(rawRequest.params ? { params: rawRequest.params } : {}), }; const response = await handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnProtocolRequest, request: { origin: rawRequest.origin, method: '', params: { scope, request, }, }, }); return response; }, // This can't be async because it returns a `SnapRequest`. // eslint-disable-next-line @typescript-eslint/promise-function-async onClientRequest: (request) => { log('Sending client request.'); return handleRequest({ snapId, store, executionService, controllerMessenger, simulationOptions: options, runSaga, handler: HandlerType.OnClientRequest, request, }); }, mockJsonRpc(mock) { log('Mocking JSON-RPC request %o.', mock); const { method, result } = create(mock, JsonRpcMockOptionsStruct); store.dispatch(addJsonRpcMock({ method, result })); return { unmock() { log('Unmocking JSON-RPC request %o.', mock); store.dispatch(removeJsonRpcMock(method)); }, }; }, close: async () => { log('Closing execution service.'); await executionService.terminateAllSnaps(); }, }; } //# sourceMappingURL=helpers.mjs.map