diff --git a/packages/snaps-controllers/CHANGELOG.md b/packages/snaps-controllers/CHANGELOG.md index dd6302c997..28ea6c8921 100644 --- a/packages/snaps-controllers/CHANGELOG.md +++ b/packages/snaps-controllers/CHANGELOG.md @@ -64,6 +64,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `SnapTerminated` is now `SnapControllerSnapTerminatedEvent`. - `SnapEnabled` is now `SnapControllerSnapEnabledEvent`. - `SnapDisabled` is now `SnapControllerSnapDisabledEvent`. +- **BREAKING:**: Rename `MultichainRouter` to `MultichainRoutingService` and update action types accordingly ([#3913](https://github.com/MetaMask/snaps/pull/3913)) + - This is consistent with the naming of other services. +- **BREAKING:** `MultichainRoutingService` now requires `SnapController:getRunnableSnaps` instead of `SnapController:getAllSnaps` ([#3913](https://github.com/MetaMask/snaps/pull/3913)) ### Removed diff --git a/packages/snaps-controllers/src/multichain/MultichainRoutingService-method-action-types.ts b/packages/snaps-controllers/src/multichain/MultichainRoutingService-method-action-types.ts new file mode 100644 index 0000000000..e851e9c737 --- /dev/null +++ b/packages/snaps-controllers/src/multichain/MultichainRoutingService-method-action-types.ts @@ -0,0 +1,70 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { MultichainRoutingService } from './MultichainRoutingService'; + +/** + * Handle an incoming JSON-RPC request tied to a specific scope by routing + * to either a protocol Snap or an account Snap. + * + * Note: Addresses are considered case-sensitive by the MultichainRoutingService as + * not all non-EVM chains are case-insensitive. + * + * @param options - An options bag. + * @param options.connectedAddresses - Addresses currently connected to the + * origin for the requested scope. + * @param options.origin - The origin of the RPC request. + * @param options.request - The JSON-RPC request. + * @param options.scope - The CAIP-2 scope for the request. + * @returns The response from the chosen Snap. + * @throws If no handler was found. + */ +export type MultichainRoutingServiceHandleRequestAction = { + type: `MultichainRoutingService:handleRequest`; + handler: MultichainRoutingService['handleRequest']; +}; + +/** + * Get a list of supported methods for a given scope. + * This combines both protocol and account Snaps supported methods. + * + * @param scope - The CAIP-2 scope. + * @returns A list of supported methods. + */ +export type MultichainRoutingServiceGetSupportedMethodsAction = { + type: `MultichainRoutingService:getSupportedMethods`; + handler: MultichainRoutingService['getSupportedMethods']; +}; + +/** + * Get a list of supported accounts for a given scope. + * + * @param scope - The CAIP-2 scope. + * @returns A list of CAIP-10 addresses. + */ +export type MultichainRoutingServiceGetSupportedAccountsAction = { + type: `MultichainRoutingService:getSupportedAccounts`; + handler: MultichainRoutingService['getSupportedAccounts']; +}; + +/** + * Determine whether a given CAIP-2 scope is supported by the router. + * + * @param scope - The CAIP-2 scope. + * @returns True if the router can service the scope, otherwise false. + */ +export type MultichainRoutingServiceIsSupportedScopeAction = { + type: `MultichainRoutingService:isSupportedScope`; + handler: MultichainRoutingService['isSupportedScope']; +}; + +/** + * Union of all MultichainRoutingService action types. + */ +export type MultichainRoutingServiceMethodActions = + | MultichainRoutingServiceHandleRequestAction + | MultichainRoutingServiceGetSupportedMethodsAction + | MultichainRoutingServiceGetSupportedAccountsAction + | MultichainRoutingServiceIsSupportedScopeAction; diff --git a/packages/snaps-controllers/src/multichain/MultichainRouter.test.ts b/packages/snaps-controllers/src/multichain/MultichainRoutingService.test.ts similarity index 66% rename from packages/snaps-controllers/src/multichain/MultichainRouter.test.ts rename to packages/snaps-controllers/src/multichain/MultichainRoutingService.test.ts index b0a0895edd..bbdb8d374f 100644 --- a/packages/snaps-controllers/src/multichain/MultichainRouter.test.ts +++ b/packages/snaps-controllers/src/multichain/MultichainRoutingService.test.ts @@ -4,11 +4,11 @@ import { MOCK_SNAP_ID, } from '@metamask/snaps-utils/test-utils'; -import { MultichainRouter } from './MultichainRouter'; +import { MultichainRoutingService } from './MultichainRoutingService'; import { METAMASK_ORIGIN } from '../snaps/constants'; import { - getMultichainRouterRootMessenger, - getRestrictedMultichainRouterMessenger, + getMultichainRoutingServiceRootMessenger, + getRestrictedMultichainRoutingServiceMessenger, BTC_CAIP2, BTC_CONNECTED_ACCOUNTS, MOCK_SOLANA_SNAP_PERMISSIONS, @@ -19,11 +19,12 @@ import { getMockWithSnapKeyring, } from '../test-utils'; -describe('MultichainRouter', () => { +describe('MultichainRoutingService', () => { describe('handleRequest', () => { it('can route signing requests to account Snaps without address resolution', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring({ submitRequest: jest.fn().mockResolvedValue({ txid: '53de51e2fa75c3cfa51132865f7d430138b1cd92a8f5267ec836ec565b422969', @@ -31,7 +32,7 @@ describe('MultichainRouter', () => { }); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -51,19 +52,22 @@ describe('MultichainRouter', () => { }, ); - const result = await messenger.call('MultichainRouter:handleRequest', { - origin: METAMASK_ORIGIN, - connectedAddresses: BTC_CONNECTED_ACCOUNTS, - scope: BTC_CAIP2, - request: { - jsonrpc: '2.0', - id: 1, - method: 'sendBitcoin', - params: { - message: 'foo', + const result = await messenger.call( + 'MultichainRoutingService:handleRequest', + { + origin: METAMASK_ORIGIN, + connectedAddresses: BTC_CONNECTED_ACCOUNTS, + scope: BTC_CAIP2, + request: { + jsonrpc: '2.0', + id: 1, + method: 'sendBitcoin', + params: { + message: 'foo', + }, }, }, - }); + ); expect(result).toStrictEqual({ txid: '53de51e2fa75c3cfa51132865f7d430138b1cd92a8f5267ec836ec565b422969', @@ -71,8 +75,9 @@ describe('MultichainRouter', () => { }); it('can route signing requests to account Snaps using address resolution', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring({ submitRequest: jest.fn().mockResolvedValue({ signature: '0x', @@ -80,7 +85,7 @@ describe('MultichainRouter', () => { }); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -105,30 +110,34 @@ describe('MultichainRouter', () => { }, ); - const result = await messenger.call('MultichainRouter:handleRequest', { - origin: METAMASK_ORIGIN, - connectedAddresses: SOLANA_CONNECTED_ACCOUNTS, - scope: SOLANA_CAIP2, - request: { - jsonrpc: '2.0', - id: 1, - method: 'signAndSendTransaction', - params: { - message: 'foo', + const result = await messenger.call( + 'MultichainRoutingService:handleRequest', + { + origin: METAMASK_ORIGIN, + connectedAddresses: SOLANA_CONNECTED_ACCOUNTS, + scope: SOLANA_CAIP2, + request: { + jsonrpc: '2.0', + id: 1, + method: 'signAndSendTransaction', + params: { + message: 'foo', + }, }, }, - }); + ); expect(result).toStrictEqual({ signature: '0x' }); }); it('disallows routing to unconnected accounts', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -149,7 +158,7 @@ describe('MultichainRouter', () => { ); await expect( - messenger.call('MultichainRouter:handleRequest', { + messenger.call('MultichainRoutingService:handleRequest', { origin: METAMASK_ORIGIN, connectedAddresses: [], scope: SOLANA_CAIP2, @@ -166,12 +175,13 @@ describe('MultichainRouter', () => { }); it('can route protocol requests to protocol Snaps', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -181,9 +191,12 @@ describe('MultichainRouter', () => { () => [], ); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return [getTruncatedSnap()]; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return [getTruncatedSnap()]; + }, + ); rootMessenger.registerActionHandler( 'PermissionController:getPermissions', @@ -198,16 +211,19 @@ describe('MultichainRouter', () => { }), ); - const result = await messenger.call('MultichainRouter:handleRequest', { - origin: METAMASK_ORIGIN, - connectedAddresses: [], - scope: SOLANA_CAIP2, - request: { - jsonrpc: '2.0', - id: 1, - method: 'getVersion', + const result = await messenger.call( + 'MultichainRoutingService:handleRequest', + { + origin: METAMASK_ORIGIN, + connectedAddresses: [], + scope: SOLANA_CAIP2, + request: { + jsonrpc: '2.0', + id: 1, + method: 'getVersion', + }, }, - }); + ); expect(result).toStrictEqual({ 'feature-set': 2891131721, @@ -237,12 +253,13 @@ describe('MultichainRouter', () => { }); it('throws if no suitable Snaps are found', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -252,12 +269,15 @@ describe('MultichainRouter', () => { () => [], ); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return []; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return []; + }, + ); await expect( - messenger.call('MultichainRouter:handleRequest', { + messenger.call('MultichainRoutingService:handleRequest', { origin: METAMASK_ORIGIN, connectedAddresses: [], scope: SOLANA_CAIP2, @@ -271,12 +291,13 @@ describe('MultichainRouter', () => { }); it('throws if address resolution fails', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -303,7 +324,7 @@ describe('MultichainRouter', () => { ); await expect( - messenger.call('MultichainRouter:handleRequest', { + messenger.call('MultichainRoutingService:handleRequest', { origin: METAMASK_ORIGIN, connectedAddresses: SOLANA_CONNECTED_ACCOUNTS, scope: SOLANA_CAIP2, @@ -320,12 +341,13 @@ describe('MultichainRouter', () => { }); it('throws if address resolution returns an address that isnt available', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -355,7 +377,7 @@ describe('MultichainRouter', () => { ); await expect( - messenger.call('MultichainRouter:handleRequest', { + messenger.call('MultichainRoutingService:handleRequest', { origin: METAMASK_ORIGIN, connectedAddresses: SOLANA_CONNECTED_ACCOUNTS, scope: SOLANA_CAIP2, @@ -372,12 +394,13 @@ describe('MultichainRouter', () => { }); it(`throws if address resolution returns a lower case address that isn't available`, async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -406,7 +429,7 @@ describe('MultichainRouter', () => { ); await expect( - messenger.call('MultichainRouter:handleRequest', { + messenger.call('MultichainRoutingService:handleRequest', { origin: METAMASK_ORIGIN, connectedAddresses: SOLANA_CONNECTED_ACCOUNTS, scope: SOLANA_CAIP2, @@ -425,19 +448,23 @@ describe('MultichainRouter', () => { describe('getSupportedMethods', () => { it('returns a set of both protocol and account Snap methods', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return [getTruncatedSnap()]; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return [getTruncatedSnap()]; + }, + ); rootMessenger.registerActionHandler( 'AccountsController:listMultichainAccounts', @@ -450,24 +477,31 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:getSupportedMethods', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:getSupportedMethods', + SOLANA_CAIP2, + ), ).toStrictEqual(['signAndSendTransaction', 'getVersion']); }); it('handles lack of protocol Snaps', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return [getTruncatedSnap()]; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return [getTruncatedSnap()]; + }, + ); rootMessenger.registerActionHandler( 'AccountsController:listMultichainAccounts', @@ -480,24 +514,31 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:getSupportedMethods', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:getSupportedMethods', + SOLANA_CAIP2, + ), ).toStrictEqual(['signAndSendTransaction']); }); it('handles lack of account Snaps', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return [getTruncatedSnap()]; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return [getTruncatedSnap()]; + }, + ); rootMessenger.registerActionHandler( 'AccountsController:listMultichainAccounts', @@ -510,19 +551,23 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:getSupportedMethods', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:getSupportedMethods', + SOLANA_CAIP2, + ), ).toStrictEqual(['getVersion']); }); }); describe('getSupportedAccounts', () => { it('returns a set of accounts for the requested scope', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); @@ -533,7 +578,10 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:getSupportedAccounts', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:getSupportedAccounts', + SOLANA_CAIP2, + ), ).toStrictEqual([ 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv', ]); @@ -542,19 +590,23 @@ describe('MultichainRouter', () => { describe('isSupportedScope', () => { it('returns true if an account Snap exists', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return [getTruncatedSnap()]; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return [getTruncatedSnap()]; + }, + ); rootMessenger.registerActionHandler( 'PermissionController:getPermissions', @@ -567,24 +619,31 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:isSupportedScope', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:isSupportedScope', + SOLANA_CAIP2, + ), ).toBe(true); }); it('returns true if a protocol Snap exists', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return [getTruncatedSnap()]; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return [getTruncatedSnap()]; + }, + ); rootMessenger.registerActionHandler( 'PermissionController:getPermissions', @@ -597,24 +656,31 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:isSupportedScope', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:isSupportedScope', + SOLANA_CAIP2, + ), ).toBe(true); }); it('returns false if no Snap is found', async () => { - const rootMessenger = getMultichainRouterRootMessenger(); - const messenger = getRestrictedMultichainRouterMessenger(rootMessenger); + const rootMessenger = getMultichainRoutingServiceRootMessenger(); + const messenger = + getRestrictedMultichainRoutingServiceMessenger(rootMessenger); const withSnapKeyring = getMockWithSnapKeyring(); /* eslint-disable-next-line no-new */ - new MultichainRouter({ + new MultichainRoutingService({ messenger, withSnapKeyring, }); - rootMessenger.registerActionHandler('SnapController:getAllSnaps', () => { - return []; - }); + rootMessenger.registerActionHandler( + 'SnapController:getRunnableSnaps', + () => { + return []; + }, + ); rootMessenger.registerActionHandler( 'AccountsController:listMultichainAccounts', @@ -622,7 +688,10 @@ describe('MultichainRouter', () => { ); expect( - messenger.call('MultichainRouter:isSupportedScope', SOLANA_CAIP2), + messenger.call( + 'MultichainRoutingService:isSupportedScope', + SOLANA_CAIP2, + ), ).toBe(false); }); }); diff --git a/packages/snaps-controllers/src/multichain/MultichainRouter.ts b/packages/snaps-controllers/src/multichain/MultichainRoutingService.ts similarity index 84% rename from packages/snaps-controllers/src/multichain/MultichainRouter.ts rename to packages/snaps-controllers/src/multichain/MultichainRoutingService.ts index fefa0aa408..1f5fc7a983 100644 --- a/packages/snaps-controllers/src/multichain/MultichainRouter.ts +++ b/packages/snaps-controllers/src/multichain/MultichainRoutingService.ts @@ -22,31 +22,11 @@ import { } from '@metamask/utils'; import { nanoid } from 'nanoid'; +import type { MultichainRoutingServiceMethodActions } from './MultichainRoutingService-method-action-types'; import type { - SnapControllerGetAllSnapsAction, + SnapControllerGetRunnableSnapsAction, SnapControllerHandleRequestAction, } from '../snaps'; -import { getRunnableSnaps } from '../snaps'; - -export type MultichainRouterHandleRequestAction = { - type: `${typeof name}:handleRequest`; - handler: MultichainRouter['handleRequest']; -}; - -export type MultichainRouterGetSupportedMethodsAction = { - type: `${typeof name}:getSupportedMethods`; - handler: MultichainRouter['getSupportedMethods']; -}; - -export type MultichainRouterGetSupportedAccountsAction = { - type: `${typeof name}:getSupportedAccounts`; - handler: MultichainRouter['getSupportedAccounts']; -}; - -export type MultichainRouterIsSupportedScopeAction = { - type: `${typeof name}:isSupportedScope`; - handler: MultichainRouter['isSupportedScope']; -}; type SnapKeyring = { submitRequest: (request: { @@ -68,27 +48,24 @@ export type AccountsControllerListMultichainAccountsAction = { handler: (chainId?: CaipChainId) => InternalAccount[]; }; -export type MultichainRouterActions = - | MultichainRouterHandleRequestAction - | MultichainRouterGetSupportedMethodsAction - | MultichainRouterGetSupportedAccountsAction - | MultichainRouterIsSupportedScopeAction; +export type MultichainRoutingServiceActions = + MultichainRoutingServiceMethodActions; -export type MultichainRouterAllowedActions = - | SnapControllerGetAllSnapsAction +export type MultichainRoutingServiceAllowedActions = + | SnapControllerGetRunnableSnapsAction | SnapControllerHandleRequestAction | GetPermissions | AccountsControllerListMultichainAccountsAction; -export type MultichainRouterEvents = never; +export type MultichainRoutingServiceEvents = never; -export type MultichainRouterMessenger = Messenger< +export type MultichainRoutingServiceMessenger = Messenger< typeof name, - MultichainRouterActions | MultichainRouterAllowedActions + MultichainRoutingServiceActions | MultichainRoutingServiceAllowedActions >; -export type MultichainRouterArgs = { - messenger: MultichainRouterMessenger; +export type MultichainRoutingServiceArgs = { + messenger: MultichainRoutingServiceMessenger; withSnapKeyring: WithSnapKeyringFunction; }; @@ -97,39 +74,31 @@ type ProtocolSnap = { methods: string[]; }; -const name = 'MultichainRouter'; +const name = 'MultichainRoutingService'; -export class MultichainRouter { +const MESSENGER_EXPOSED_METHODS = [ + 'handleRequest', + 'getSupportedMethods', + 'getSupportedAccounts', + 'isSupportedScope', +] as const; + +export class MultichainRoutingService { name: typeof name = name; state = null; - readonly #messenger: MultichainRouterMessenger; + readonly #messenger: MultichainRoutingServiceMessenger; readonly #withSnapKeyring: WithSnapKeyringFunction; - constructor({ messenger, withSnapKeyring }: MultichainRouterArgs) { + constructor({ messenger, withSnapKeyring }: MultichainRoutingServiceArgs) { this.#messenger = messenger; this.#withSnapKeyring = withSnapKeyring; - this.#messenger.registerActionHandler( - `${name}:handleRequest`, - async (...args) => this.handleRequest(...args), - ); - - this.#messenger.registerActionHandler( - `${name}:getSupportedMethods`, - (...args) => this.getSupportedMethods(...args), - ); - - this.#messenger.registerActionHandler( - `${name}:getSupportedAccounts`, - (...args) => this.getSupportedAccounts(...args), - ); - - this.#messenger.registerActionHandler( - `${name}:isSupportedScope`, - (...args) => this.isSupportedScope(...args), + this.#messenger.registerMethodActionHandlers( + this, + MESSENGER_EXPOSED_METHODS, ); } @@ -263,8 +232,9 @@ export class MultichainRouter { * @returns A list of all the protocol Snaps available and their RPC methods. */ #getProtocolSnaps(scope: CaipChainId) { - const allSnaps = this.#messenger.call('SnapController:getAllSnaps'); - const filteredSnaps = getRunnableSnaps(allSnaps); + const filteredSnaps = this.#messenger.call( + 'SnapController:getRunnableSnaps', + ); return filteredSnaps.reduce((accumulator, snap) => { const permissions = this.#messenger.call( @@ -291,7 +261,7 @@ export class MultichainRouter { * Handle an incoming JSON-RPC request tied to a specific scope by routing * to either a protocol Snap or an account Snap. * - * Note: Addresses are considered case-sensitive by the MultichainRouter as + * Note: Addresses are considered case-sensitive by the MultichainRoutingService as * not all non-EVM chains are case-insensitive. * * @param options - An options bag. diff --git a/packages/snaps-controllers/src/multichain/index.ts b/packages/snaps-controllers/src/multichain/index.ts index 8c696c379e..7a1ce9328d 100644 --- a/packages/snaps-controllers/src/multichain/index.ts +++ b/packages/snaps-controllers/src/multichain/index.ts @@ -1 +1,7 @@ -export * from './MultichainRouter'; +export { MultichainRoutingService } from './MultichainRoutingService'; +export type { + MultichainRoutingServiceGetSupportedAccountsAction, + MultichainRoutingServiceGetSupportedMethodsAction, + MultichainRoutingServiceHandleRequestAction, + MultichainRoutingServiceIsSupportedScopeAction, +} from './MultichainRoutingService-method-action-types'; diff --git a/packages/snaps-controllers/src/test-utils/controller.tsx b/packages/snaps-controllers/src/test-utils/controller.tsx index ef26f2925d..42c735cf56 100644 --- a/packages/snaps-controllers/src/test-utils/controller.tsx +++ b/packages/snaps-controllers/src/test-utils/controller.tsx @@ -54,13 +54,13 @@ import type { Json } from '@metamask/utils'; import { MOCK_CRONJOB_PERMISSION } from './cronjob'; import { getNodeEES, getNodeEESMessenger } from './execution-environment'; import { MockSnapsRegistry } from './registry'; -import type { CronjobControllerMessenger } from '../cronjob'; +import type { CronjobControllerMessenger } from '../cronjob/CronjobController'; import type { SnapInsightsControllerMessenger } from '../insights'; import type { SnapInterfaceControllerMessenger, StoredInterface, } from '../interface/SnapInterfaceController'; -import type { MultichainRouterMessenger } from '../multichain'; +import type { MultichainRoutingServiceMessenger } from '../multichain/MultichainRoutingService'; import type { AbstractExecutionService, ExecutionServiceMessenger, @@ -986,14 +986,14 @@ export async function waitForStateChange( }); } -type MultichainRouterRootMessenger = Messenger< +type MultichainRoutingServiceRootMessenger = Messenger< MockAnyNamespace, - MessengerActions + MessengerActions >; // Mock controller messenger for Multichain Router -export const getMultichainRouterRootMessenger = () => { - const messenger: MultichainRouterRootMessenger = +export const getMultichainRoutingServiceRootMessenger = () => { + const messenger: MultichainRoutingServiceRootMessenger = new MockControllerMessenger(); jest.spyOn(messenger, 'call'); @@ -1001,18 +1001,18 @@ export const getMultichainRouterRootMessenger = () => { return messenger; }; -export const getRestrictedMultichainRouterMessenger = ( - messenger: MultichainRouterRootMessenger = getMultichainRouterRootMessenger(), +export const getRestrictedMultichainRoutingServiceMessenger = ( + messenger: MultichainRoutingServiceRootMessenger = getMultichainRoutingServiceRootMessenger(), ) => { - const controllerMessenger: MultichainRouterMessenger = new Messenger({ - namespace: 'MultichainRouter', + const controllerMessenger: MultichainRoutingServiceMessenger = new Messenger({ + namespace: 'MultichainRoutingService', parent: messenger, }); messenger.delegate({ actions: [ 'PermissionController:getPermissions', - 'SnapController:getAllSnaps', + 'SnapController:getRunnableSnaps', 'SnapController:handleRequest', 'AccountsController:listMultichainAccounts', ],