diff --git a/packages/snaps-controllers/coverage.json b/packages/snaps-controllers/coverage.json index 993ff36acf..b8cc8451e6 100644 --- a/packages/snaps-controllers/coverage.json +++ b/packages/snaps-controllers/coverage.json @@ -1,6 +1,6 @@ { - "branches": 93.61, + "branches": 93.64, "functions": 98.16, "lines": 98.5, - "statements": 98.33 + "statements": 98.34 } diff --git a/packages/snaps-controllers/src/snaps/SnapController.test.tsx b/packages/snaps-controllers/src/snaps/SnapController.test.tsx index 2c33a87d89..84a2117975 100644 --- a/packages/snaps-controllers/src/snaps/SnapController.test.tsx +++ b/packages/snaps-controllers/src/snaps/SnapController.test.tsx @@ -77,6 +77,7 @@ import { inc } from 'semver'; import { LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS, + METAMASK_ORIGIN, STATE_DEBOUNCE_TIMEOUT, } from './constants'; import { SnapsRegistryStatus } from './registry'; @@ -2243,7 +2244,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: snap.id, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnUserInput, request: { jsonrpc: '2.0', @@ -2294,7 +2295,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: snap.id, - origin: 'metamask', + origin: METAMASK_ORIGIN, handler: HandlerType.OnRpcRequest, request: { jsonrpc: '2.0', method: 'test' }, }), @@ -2341,7 +2342,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: snap.id, - origin: 'metamask', + origin: METAMASK_ORIGIN, handler: HandlerType.OnKeyringRequest, request: { jsonrpc: '2.0', method: 'test' }, }), @@ -2807,7 +2808,7 @@ describe('SnapController', () => { await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnUserInput, request: { jsonrpc: '2.0', @@ -2827,7 +2828,7 @@ describe('SnapController', () => { 'ExecutionService:handleRpcRequest', MOCK_SNAP_ID, { - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnUserInput, request: { id: expect.any(String), @@ -2896,7 +2897,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnTransaction, request: { jsonrpc: '2.0', @@ -2952,7 +2953,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnTransaction, request: { jsonrpc: '2.0', @@ -3007,7 +3008,7 @@ describe('SnapController', () => { const result = await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnTransaction, request: { jsonrpc: '2.0', @@ -3062,7 +3063,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnTransaction, request: { jsonrpc: '2.0', @@ -3120,7 +3121,7 @@ describe('SnapController', () => { const result = await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnTransaction, request: { jsonrpc: '2.0', @@ -3183,7 +3184,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSignature, request: { jsonrpc: '2.0', @@ -3239,7 +3240,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSignature, request: { jsonrpc: '2.0', @@ -3295,7 +3296,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSignature, request: { jsonrpc: '2.0', @@ -3348,7 +3349,7 @@ describe('SnapController', () => { const result = await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSignature, request: { jsonrpc: '2.0', @@ -3402,7 +3403,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnTransaction, request: { jsonrpc: '2.0', @@ -3454,7 +3455,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSignature, request: { jsonrpc: '2.0', @@ -3516,7 +3517,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnHomePage, request: { jsonrpc: '2.0', @@ -3570,7 +3571,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnHomePage, request: { jsonrpc: '2.0', @@ -3623,7 +3624,7 @@ describe('SnapController', () => { const result = await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnHomePage, request: { jsonrpc: '2.0', @@ -3686,7 +3687,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSettingsPage, request: { jsonrpc: '2.0', @@ -3740,7 +3741,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSettingsPage, request: { jsonrpc: '2.0', @@ -3793,7 +3794,7 @@ describe('SnapController', () => { const result = await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnSettingsPage, request: { jsonrpc: '2.0', @@ -3849,7 +3850,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: 'metamask', + origin: METAMASK_ORIGIN, handler: HandlerType.OnNameLookup, request: { jsonrpc: '2.0', @@ -3912,7 +3913,7 @@ describe('SnapController', () => { const result = await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnNameLookup, request: { jsonrpc: '2.0', @@ -3965,7 +3966,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnNameLookup, request: { jsonrpc: '2.0', @@ -4026,7 +4027,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsLookup, request: { jsonrpc: '2.0', @@ -4102,7 +4103,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsLookup, request: { jsonrpc: '2.0', @@ -4178,7 +4179,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsLookup, request: { jsonrpc: '2.0', @@ -4258,7 +4259,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsConversion, request: { jsonrpc: '2.0', @@ -4327,7 +4328,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsConversion, request: { jsonrpc: '2.0', @@ -4401,7 +4402,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsConversion, request: { jsonrpc: '2.0', @@ -4492,7 +4493,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetsConversion, request: { jsonrpc: '2.0', @@ -4579,7 +4580,7 @@ describe('SnapController', () => { await expect( snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetHistoricalPrice, request: { jsonrpc: '2.0', @@ -4646,7 +4647,7 @@ describe('SnapController', () => { expect( await snapController.handleRequest({ snapId: MOCK_SNAP_ID, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnAssetHistoricalPrice, request: { jsonrpc: '2.0', @@ -4671,6 +4672,93 @@ describe('SnapController', () => { }); }); + describe('onClientRequest', () => { + it('returns the value when `onClientRequest` returns a valid response', async () => { + const rootMessenger = getControllerMessenger(); + const messenger = getSnapControllerMessenger(rootMessenger); + const snapController = getSnapController( + getSnapControllerOptions({ + messenger, + state: { + snaps: getPersistedSnapsState(), + }, + }), + ); + + rootMessenger.registerActionHandler( + 'SubjectMetadataController:getSubjectMetadata', + () => MOCK_SNAP_SUBJECT_METADATA, + ); + + rootMessenger.registerActionHandler( + 'ExecutionService:handleRpcRequest', + async () => ({ + foo: 'bar', + }), + ); + + expect( + await snapController.handleRequest({ + snapId: MOCK_SNAP_ID, + origin: METAMASK_ORIGIN, + handler: HandlerType.OnClientRequest, + request: { + jsonrpc: '2.0', + method: 'foo', + params: {}, + id: 1, + }, + }), + ).toStrictEqual({ + foo: 'bar', + }); + + snapController.destroy(); + }); + + it('throws if the origin is not "metamask"', async () => { + const rootMessenger = getControllerMessenger(); + const messenger = getSnapControllerMessenger(rootMessenger); + const snapController = getSnapController( + getSnapControllerOptions({ + messenger, + state: { + snaps: getPersistedSnapsState(), + }, + }), + ); + + rootMessenger.registerActionHandler( + 'SubjectMetadataController:getSubjectMetadata', + () => MOCK_SNAP_SUBJECT_METADATA, + ); + + rootMessenger.registerActionHandler( + 'ExecutionService:handleRpcRequest', + async () => + Promise.resolve({ + foo: 'bar', + }), + ); + + await expect( + snapController.handleRequest({ + snapId: MOCK_SNAP_ID, + origin: MOCK_ORIGIN, + handler: HandlerType.OnClientRequest, + request: { + jsonrpc: '2.0', + method: 'foo', + params: {}, + id: 1, + }, + }), + ).rejects.toThrow('"onClientRequest" can only be invoked by MetaMask.'); + + snapController.destroy(); + }); + }); + describe('getRpcRequestHandler', () => { it('handlers populate the "jsonrpc" property if missing', async () => { const rootMessenger = getControllerMessenger(); @@ -5661,7 +5749,7 @@ describe('SnapController', () => { expect(rootMessenger.publish).toHaveBeenCalledWith( 'SnapController:snapInstalled', getTruncatedSnap(), - 'metamask', + METAMASK_ORIGIN, true, ); @@ -5900,7 +5988,7 @@ describe('SnapController', () => { }, }), '1.0.0', - 'metamask', + METAMASK_ORIGIN, true, ); @@ -9478,7 +9566,7 @@ describe('SnapController', () => { await snapController.handleRequest({ snapId: snap.id, - origin: MOCK_ORIGIN, + origin: METAMASK_ORIGIN, handler: HandlerType.OnCronjob, request: { jsonrpc: '2.0', @@ -9656,7 +9744,7 @@ describe('SnapController', () => { await messenger.call('SnapController:handleRequest', { snapId: MOCK_SNAP_ID, handler: HandlerType.OnNameLookup, - origin: 'metamask', + origin: METAMASK_ORIGIN, request: {}, }), ).toBe(true); @@ -10923,7 +11011,7 @@ describe('SnapController', () => { MOCK_SNAP_ID, { handler: HandlerType.OnInstall, - origin: 'metamask', + origin: METAMASK_ORIGIN, request: { jsonrpc: '2.0', id: expect.any(String), @@ -11066,7 +11154,7 @@ describe('SnapController', () => { MOCK_SNAP_ID, { handler: HandlerType.OnUpdate, - origin: 'metamask', + origin: METAMASK_ORIGIN, request: { jsonrpc: '2.0', id: expect.any(String), diff --git a/packages/snaps-controllers/src/snaps/SnapController.ts b/packages/snaps-controllers/src/snaps/SnapController.ts index 805a6fd827..c7739fba54 100644 --- a/packages/snaps-controllers/src/snaps/SnapController.ts +++ b/packages/snaps-controllers/src/snaps/SnapController.ts @@ -136,7 +136,9 @@ import { gt } from 'semver'; import { ALLOWED_PERMISSIONS, + CLIENT_ONLY_HANDLERS, LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS, + METAMASK_ORIGIN, STATE_DEBOUNCE_TIMEOUT, } from './constants'; import type { SnapLocation } from './location'; @@ -1311,7 +1313,7 @@ export class SnapController extends BaseController< // Add snap to the SnapController state this.#set({ id: snapId, - origin: 'metamask', + origin: METAMASK_ORIGIN, files: filesObject, removable, hidden, @@ -1350,14 +1352,14 @@ export class SnapController extends BaseController< 'SnapController:snapUpdated', this.getTruncatedExpect(snapId), existingSnap.version, - 'metamask', + METAMASK_ORIGIN, true, ); } else { this.messagingSystem.publish( 'SnapController:snapInstalled', this.getTruncatedExpect(snapId), - 'metamask', + METAMASK_ORIGIN, true, ); } @@ -3415,7 +3417,7 @@ export class SnapController extends BaseController< this.#assertCanUsePlatform(); assert( - origin === 'metamask' || isValidUrl(origin), + origin === METAMASK_ORIGIN || isValidUrl(origin), "'origin' must be a valid URL or 'metamask'.", ); @@ -3485,6 +3487,13 @@ export class SnapController extends BaseController< } } + if ( + origin !== METAMASK_ORIGIN && + CLIENT_ONLY_HANDLERS.includes(handlerType) + ) { + throw new Error(`"${handlerType}" can only be invoked by MetaMask.`); + } + const handler = this.#getRpcRequestHandler(snapId); if (!handler) { throw new Error( diff --git a/packages/snaps-controllers/src/snaps/constants.ts b/packages/snaps-controllers/src/snaps/constants.ts index dfaaa88ad3..0d380ad015 100644 --- a/packages/snaps-controllers/src/snaps/constants.ts +++ b/packages/snaps-controllers/src/snaps/constants.ts @@ -1,4 +1,5 @@ import { SnapEndowments } from '@metamask/snaps-rpc-methods'; +import { HandlerType } from '@metamask/snaps-utils'; // These permissions are allowed without being on the allowlist. export const ALLOWED_PERMISSIONS = Object.freeze([ @@ -25,3 +26,21 @@ export const LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS = { * The timeout for debouncing state updates. */ export const STATE_DEBOUNCE_TIMEOUT = 500; + +// The origin used to indicate requests coming from the client. +export const METAMASK_ORIGIN = 'metamask'; + +// These handlers are only allowed to be invoked by the client. +export const CLIENT_ONLY_HANDLERS = Object.freeze([ + HandlerType.OnClientRequest, + HandlerType.OnSignature, + HandlerType.OnTransaction, + HandlerType.OnCronjob, + HandlerType.OnNameLookup, + HandlerType.OnHomePage, + HandlerType.OnSettingsPage, + HandlerType.OnUserInput, + HandlerType.OnAssetsLookup, + HandlerType.OnAssetsConversion, + HandlerType.OnAssetHistoricalPrice, +]); diff --git a/packages/snaps-execution-environments/coverage.json b/packages/snaps-execution-environments/coverage.json index a805965c70..47984c18cf 100644 --- a/packages/snaps-execution-environments/coverage.json +++ b/packages/snaps-execution-environments/coverage.json @@ -1,6 +1,6 @@ { - "branches": 90, + "branches": 90.04, "functions": 94.57, - "lines": 90.15, - "statements": 89.52 + "lines": 90.16, + "statements": 89.53 } diff --git a/packages/snaps-execution-environments/src/common/BaseSnapExecutor.test.browser.ts b/packages/snaps-execution-environments/src/common/BaseSnapExecutor.test.browser.ts index a1f673c48e..c39bcfed8a 100644 --- a/packages/snaps-execution-environments/src/common/BaseSnapExecutor.test.browser.ts +++ b/packages/snaps-execution-environments/src/common/BaseSnapExecutor.test.browser.ts @@ -1821,6 +1821,39 @@ describe('BaseSnapExecutor', () => { }); }); + it('supports onClientRequest export', async () => { + const CODE = ` + module.exports.onClientRequest = ({ request }) => ({ request }); + `; + + const executor = new TestSnapExecutor(); + await executor.executeSnap(1, MOCK_SNAP_ID, CODE, []); + + expect(await executor.readCommand()).toStrictEqual({ + jsonrpc: '2.0', + id: 1, + result: 'OK', + }); + + await executor.writeCommand({ + jsonrpc: '2.0', + id: 2, + method: 'snapRpc', + params: [ + MOCK_SNAP_ID, + HandlerType.OnClientRequest, + MOCK_ORIGIN, + { jsonrpc: '2.0', method: 'foo', params: [] }, + ], + }); + + expect(await executor.readCommand()).toStrictEqual({ + id: 2, + jsonrpc: '2.0', + result: { request: { jsonrpc: '2.0', method: 'foo', params: [] } }, + }); + }); + describe('lifecycle hooks', () => { const LIFECYCLE_HOOKS = [HandlerType.OnInstall, HandlerType.OnUpdate]; diff --git a/packages/snaps-execution-environments/src/common/commands.ts b/packages/snaps-execution-environments/src/common/commands.ts index 333ab29897..6d42a8cb9c 100644 --- a/packages/snaps-execution-environments/src/common/commands.ts +++ b/packages/snaps-execution-environments/src/common/commands.ts @@ -107,6 +107,7 @@ export function getHandlerArguments( case HandlerType.OnKeyringRequest: return { origin, request }; + case HandlerType.OnClientRequest: case HandlerType.OnCronjob: return { request }; diff --git a/packages/snaps-rpc-methods/src/endowments/index.ts b/packages/snaps-rpc-methods/src/endowments/index.ts index 60c68b1c01..7e460241fd 100644 --- a/packages/snaps-rpc-methods/src/endowments/index.ts +++ b/packages/snaps-rpc-methods/src/endowments/index.ts @@ -130,6 +130,7 @@ export const handlerEndowments: Record = { [HandlerType.OnAssetsLookup]: assetsEndowmentBuilder.targetName, [HandlerType.OnAssetsConversion]: assetsEndowmentBuilder.targetName, [HandlerType.OnProtocolRequest]: protocolEndowmentBuilder.targetName, + [HandlerType.OnClientRequest]: null, }; export * from './enum'; diff --git a/packages/snaps-sdk/src/types/handlers/client-request.ts b/packages/snaps-sdk/src/types/handlers/client-request.ts new file mode 100644 index 0000000000..50e216aa28 --- /dev/null +++ b/packages/snaps-sdk/src/types/handlers/client-request.ts @@ -0,0 +1,16 @@ +import type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils'; + +/** + * The `onClientRequest` handler, which is called when a Snap receives a JSON-RPC + * request from the client exclusively. + * + * @param args - The request arguments. + * @param args.request - The JSON-RPC request sent to the snap. This includes + * the method name and parameters. + * @returns The response to the JSON-RPC request. This must be a + * JSON-serializable value. In order to return an error, throw a `SnapError` + * instead. + */ +export type OnClientRequestHandler< + Params extends JsonRpcParams = JsonRpcParams, +> = (args: { request: JsonRpcRequest }) => Promise; diff --git a/packages/snaps-sdk/src/types/handlers/index.ts b/packages/snaps-sdk/src/types/handlers/index.ts index 470fa182e2..d8049efac4 100644 --- a/packages/snaps-sdk/src/types/handlers/index.ts +++ b/packages/snaps-sdk/src/types/handlers/index.ts @@ -1,6 +1,7 @@ export type * from './asset-historical-price'; export type * from './assets-conversion'; export * from './assets-lookup'; +export type * from './client-request'; export type * from './cronjob'; export type * from './home-page'; export type * from './keyring'; diff --git a/packages/snaps-utils/coverage.json b/packages/snaps-utils/coverage.json index 3a08980160..0141f93a65 100644 --- a/packages/snaps-utils/coverage.json +++ b/packages/snaps-utils/coverage.json @@ -2,5 +2,5 @@ "branches": 99.75, "functions": 98.95, "lines": 98.57, - "statements": 97.07 + "statements": 97.08 } diff --git a/packages/snaps-utils/src/handlers/exports.test.ts b/packages/snaps-utils/src/handlers/exports.test.ts index 3f1d445147..ad927a2198 100644 --- a/packages/snaps-utils/src/handlers/exports.test.ts +++ b/packages/snaps-utils/src/handlers/exports.test.ts @@ -30,6 +30,7 @@ describe('SNAP_EXPORT_NAMES', () => { 'onAssetsConversion', 'onAssetHistoricalPrice', 'onProtocolRequest', + 'onClientRequest', ]); }); }); diff --git a/packages/snaps-utils/src/handlers/exports.ts b/packages/snaps-utils/src/handlers/exports.ts index e9e491b68d..6e47244992 100644 --- a/packages/snaps-utils/src/handlers/exports.ts +++ b/packages/snaps-utils/src/handlers/exports.ts @@ -2,6 +2,7 @@ import type { OnAssetHistoricalPriceHandler, OnAssetsConversionHandler, OnAssetsLookupHandler, + OnClientRequestHandler, OnCronjobHandler, OnHomePageHandler, OnInstallHandler, @@ -130,6 +131,13 @@ export const SNAP_EXPORTS = { return typeof snapExport === 'function'; }, }, + [HandlerType.OnClientRequest]: { + type: HandlerType.OnClientRequest, + required: true, + validator: (snapExport: unknown): snapExport is OnClientRequestHandler => { + return typeof snapExport === 'function'; + }, + }, } as const; export const SNAP_EXPORT_NAMES = Object.values(HandlerType); diff --git a/packages/snaps-utils/src/handlers/types.ts b/packages/snaps-utils/src/handlers/types.ts index 882893e303..d6ddb7fd57 100644 --- a/packages/snaps-utils/src/handlers/types.ts +++ b/packages/snaps-utils/src/handlers/types.ts @@ -44,6 +44,7 @@ export enum HandlerType { OnAssetsConversion = 'onAssetsConversion', OnAssetHistoricalPrice = 'onAssetHistoricalPrice', OnProtocolRequest = 'onProtocolRequest', + OnClientRequest = 'onClientRequest', } export type SnapHandler = {