diff --git a/README.md b/README.md index c671ed0bca5..b401eb6d425 100644 --- a/README.md +++ b/README.md @@ -147,16 +147,22 @@ linkStyle default opacity:0.5 account_tree_controller --> multichain_account_service; account_tree_controller --> profile_sync_controller; accounts_controller --> base_controller; + accounts_controller --> messenger; accounts_controller --> controller_utils; accounts_controller --> keyring_controller; accounts_controller --> network_controller; address_book_controller --> base_controller; address_book_controller --> controller_utils; + address_book_controller --> messenger; announcement_controller --> base_controller; + announcement_controller --> messenger; app_metadata_controller --> base_controller; + app_metadata_controller --> messenger; approval_controller --> base_controller; + approval_controller --> messenger; assets_controllers --> base_controller; assets_controllers --> controller_utils; + assets_controllers --> messenger; assets_controllers --> polling_controller; assets_controllers --> account_tree_controller; assets_controllers --> accounts_controller; @@ -174,6 +180,7 @@ linkStyle default opacity:0.5 bridge_controller --> base_controller; bridge_controller --> controller_utils; bridge_controller --> gas_fee_controller; + bridge_controller --> messenger; bridge_controller --> multichain_network_controller; bridge_controller --> polling_controller; bridge_controller --> accounts_controller; @@ -201,10 +208,12 @@ linkStyle default opacity:0.5 core_backend --> accounts_controller; core_backend --> keyring_controller; delegation_controller --> base_controller; + delegation_controller --> messenger; delegation_controller --> accounts_controller; delegation_controller --> keyring_controller; earn_controller --> base_controller; earn_controller --> controller_utils; + earn_controller --> messenger; earn_controller --> account_tree_controller; earn_controller --> network_controller; earn_controller --> transaction_controller; @@ -216,6 +225,7 @@ linkStyle default opacity:0.5 eip1193_permission_middleware --> permission_controller; ens_controller --> base_controller; ens_controller --> controller_utils; + ens_controller --> messenger; ens_controller --> network_controller; error_reporting_service --> base_controller; eth_json_rpc_provider --> json_rpc_engine; @@ -224,8 +234,10 @@ linkStyle default opacity:0.5 gas_fee_controller --> polling_controller; gas_fee_controller --> network_controller; gator_permissions_controller --> base_controller; + gator_permissions_controller --> messenger; json_rpc_middleware_stream --> json_rpc_engine; keyring_controller --> base_controller; + keyring_controller --> messenger; logging_controller --> base_controller; logging_controller --> controller_utils; message_manager --> base_controller; @@ -254,6 +266,7 @@ linkStyle default opacity:0.5 network_controller --> controller_utils; network_controller --> eth_json_rpc_provider; network_controller --> json_rpc_engine; + network_controller --> messenger; network_controller --> error_reporting_service; network_enablement_controller --> base_controller; network_enablement_controller --> controller_utils; @@ -301,6 +314,7 @@ linkStyle default opacity:0.5 signature_controller --> controller_utils; signature_controller --> accounts_controller; signature_controller --> approval_controller; + signature_controller --> gator_permissions_controller; signature_controller --> keyring_controller; signature_controller --> logging_controller; signature_controller --> network_controller; @@ -310,6 +324,7 @@ linkStyle default opacity:0.5 token_search_discovery_controller --> base_controller; transaction_controller --> base_controller; transaction_controller --> controller_utils; + transaction_controller --> messenger; transaction_controller --> accounts_controller; transaction_controller --> approval_controller; transaction_controller --> eth_json_rpc_provider; diff --git a/eslint-warning-thresholds.json b/eslint-warning-thresholds.json index 254e13963dd..72532d38b10 100644 --- a/eslint-warning-thresholds.json +++ b/eslint-warning-thresholds.json @@ -34,8 +34,8 @@ "jsdoc/tag-lines": 1 }, "packages/assets-controllers/src/RatesController/RatesController.test.ts": { - "import-x/order": 2, - "jsdoc/tag-lines": 4 + "import-x/order": 1, + "jsdoc/tag-lines": 2 }, "packages/assets-controllers/src/RatesController/RatesController.ts": { "@typescript-eslint/prefer-readonly": 1, @@ -56,7 +56,7 @@ }, "packages/assets-controllers/src/TokenListController.test.ts": { "import-x/namespace": 7, - "import-x/order": 3, + "import-x/order": 2, "jest/no-conditional-in-test": 2 }, "packages/assets-controllers/src/TokenRatesController.test.ts": { @@ -68,7 +68,7 @@ }, "packages/assets-controllers/src/TokensController.test.ts": { "import-x/namespace": 1, - "import-x/order": 4, + "import-x/order": 3, "jest/no-conditional-in-test": 2 }, "packages/assets-controllers/src/TokensController.ts": { diff --git a/packages/account-tree-controller/CHANGELOG.md b/packages/account-tree-controller/CHANGELOG.md index 8bc0b13f409..aab4d44274d 100644 --- a/packages/account-tree-controller/CHANGELOG.md +++ b/packages/account-tree-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6380](https://github.com/MetaMask/core/pull/6380)) + - Previously, `AccountTreeController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ### Fixed - Fix wallet metadata cleanup when wallets are completely removed ([#6813](https://github.com/MetaMask/core/pull/6813)) diff --git a/packages/account-tree-controller/package.json b/packages/account-tree-controller/package.json index 18644d5af15..8672ecc83a1 100644 --- a/packages/account-tree-controller/package.json +++ b/packages/account-tree-controller/package.json @@ -48,6 +48,7 @@ }, "dependencies": { "@metamask/base-controller": "^8.4.1", + "@metamask/messenger": "^0.3.0", "@metamask/snaps-sdk": "^9.0.0", "@metamask/snaps-utils": "^11.0.0", "@metamask/superstruct": "^3.1.0", diff --git a/packages/account-tree-controller/src/AccountTreeController.test.ts b/packages/account-tree-controller/src/AccountTreeController.test.ts index 4e992378152..7e8c404b26f 100644 --- a/packages/account-tree-controller/src/AccountTreeController.test.ts +++ b/packages/account-tree-controller/src/AccountTreeController.test.ts @@ -8,7 +8,7 @@ import { toMultichainAccountWalletId, type AccountGroupId, } from '@metamask/account-api'; -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { EthAccountType, EthMethod, @@ -34,14 +34,11 @@ import type { BackupAndSyncAnalyticsEventPayload } from './backup-and-sync/analy import { BackupAndSyncService } from './backup-and-sync/service'; import { isAccountGroupNameUnique } from './group'; import { getAccountWalletNameFromKeyringType } from './rules/keyring'; +import { type AccountTreeControllerState } from './types'; import { - type AccountTreeControllerMessenger, - type AccountTreeControllerActions, - type AccountTreeControllerEvents, - type AccountTreeControllerState, - type AllowedActions, - type AllowedEvents, -} from './types'; + getAccountTreeControllerMessenger, + getRootMessenger, +} from '../tests/mockMessenger'; // Local mock of EMPTY_ACCOUNT to avoid circular dependency const EMPTY_ACCOUNT_MOCK: InternalAccount = { @@ -231,53 +228,7 @@ const MOCK_HARDWARE_ACCOUNT_1: InternalAccount = { }, }; -/** - * Creates a new root messenger instance for testing. - * - * @returns A new Messenger instance. - */ -function getRootMessenger() { - return new Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents - >(); -} - -/** - * Retrieves a restricted messenger for the AccountTreeController. - * - * @param messenger - The root messenger instance. Defaults to a new Messenger created by getRootMessenger(). - * @returns The restricted messenger for the AccountTreeController. - */ -function getAccountTreeControllerMessenger( - messenger = getRootMessenger(), -): AccountTreeControllerMessenger { - return messenger.getRestricted({ - name: 'AccountTreeController', - allowedEvents: [ - 'AccountsController:accountAdded', - 'AccountsController:accountRemoved', - 'AccountsController:selectedAccountChange', - 'UserStorageController:stateChange', - 'MultichainAccountService:walletStatusChange', - ], - allowedActions: [ - 'AccountsController:listMultichainAccounts', - 'AccountsController:getAccount', - 'AccountsController:getSelectedMultichainAccount', - 'AccountsController:setSelectedAccount', - 'UserStorageController:getState', - 'UserStorageController:performGetStorage', - 'UserStorageController:performGetStorageAllFeatureEntries', - 'UserStorageController:performSetStorage', - 'UserStorageController:performBatchSetStorage', - 'AuthenticationController:getSessionProfile', - 'MultichainAccountService:createMultichainAccountGroup', - 'KeyringController:getState', - 'SnapController:get', - ], - }); -} +const mockGetSelectedMultichainAccountActionHandler = jest.fn(); /** * Sets up the AccountTreeController for testing. @@ -308,10 +259,7 @@ function setup({ }, }: { state?: Partial; - messenger?: Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents - >; + messenger?: ReturnType; accounts?: InternalAccount[]; keyrings?: KeyringObject[]; config?: { @@ -325,9 +273,9 @@ function setup({ }; } = {}): { controller: AccountTreeController; - messenger: Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents + messenger: ReturnType; + accountTreeControllerMessenger: ReturnType< + typeof getAccountTreeControllerMessenger >; spies: { consoleWarn: jest.SpyInstance; @@ -388,6 +336,7 @@ function setup({ mocks.AccountsController.listMultichainAccounts.mockImplementation( () => mocks.AccountsController.accounts, ); + messenger.registerActionHandler( 'AccountsController:listMultichainAccounts', mocks.AccountsController.listMultichainAccounts, @@ -461,8 +410,10 @@ function setup({ ); } + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); const controller = new AccountTreeController({ - messenger: getAccountTreeControllerMessenger(messenger), + messenger: accountTreeControllerMessenger, state, ...(config && { config }), }); @@ -474,6 +425,7 @@ function setup({ return { controller, messenger, + accountTreeControllerMessenger, spies: { consoleWarn: consoleWarnSpy }, mocks, }; @@ -1709,12 +1661,15 @@ describe('AccountTreeController', () => { }); it('updates AccountsController selected account (with EVM account) when selectedAccountGroup changes', () => { - const { controller, messenger } = setup({ + const { controller, accountTreeControllerMessenger } = setup({ accounts: [MOCK_HD_ACCOUNT_1, MOCK_HD_ACCOUNT_2], keyrings: [MOCK_HD_KEYRING_1, MOCK_HD_KEYRING_2], }); - const setSelectedAccountSpy = jest.spyOn(messenger, 'call'); + const setSelectedAccountSpy = jest.spyOn( + accountTreeControllerMessenger, + 'call', + ); controller.init(); @@ -1746,7 +1701,7 @@ describe('AccountTreeController', () => { }, }, } as const; - const { controller, messenger } = setup({ + const { controller, accountTreeControllerMessenger } = setup({ accounts: [ MOCK_HD_ACCOUNT_1, nonEvmAccount2, // Wallet 2 > Account 1. @@ -1754,7 +1709,10 @@ describe('AccountTreeController', () => { keyrings: [MOCK_HD_KEYRING_1, MOCK_HD_KEYRING_2], }); - const setSelectedAccountSpy = jest.spyOn(messenger, 'call'); + const setSelectedAccountSpy = jest.spyOn( + accountTreeControllerMessenger, + 'call', + ); controller.init(); @@ -1876,18 +1834,14 @@ describe('AccountTreeController', () => { }); it('falls back to first wallet first group when AccountsController returns EMPTY_ACCOUNT', () => { - const { controller, messenger } = setup({ + const { controller } = setup({ accounts: [MOCK_HD_ACCOUNT_1, MOCK_HD_ACCOUNT_2], keyrings: [MOCK_HD_KEYRING_1, MOCK_HD_KEYRING_2], }); - // Unregister existing handler and register new one BEFORE init - messenger.unregisterActionHandler( - 'AccountsController:getSelectedMultichainAccount', - ); - messenger.registerActionHandler( - 'AccountsController:getSelectedMultichainAccount', - () => EMPTY_ACCOUNT_MOCK, + // Mock action handler BEFORE init + mockGetSelectedMultichainAccountActionHandler.mockReturnValue( + EMPTY_ACCOUNT_MOCK, ); controller.init(); @@ -1905,7 +1859,7 @@ describe('AccountTreeController', () => { }); it('falls back to first wallet first group when selected account is not in tree', () => { - const { controller, messenger } = setup({ + const { controller } = setup({ accounts: [MOCK_HD_ACCOUNT_1, MOCK_HD_ACCOUNT_2], keyrings: [MOCK_HD_KEYRING_1, MOCK_HD_KEYRING_2], }); @@ -1916,12 +1870,8 @@ describe('AccountTreeController', () => { id: 'unknown-account-id', }; - messenger.unregisterActionHandler( - 'AccountsController:getSelectedMultichainAccount', - ); - messenger.registerActionHandler( - 'AccountsController:getSelectedMultichainAccount', - () => unknownAccount, + mockGetSelectedMultichainAccountActionHandler.mockReturnValue( + unknownAccount, ); controller.init(); @@ -1939,18 +1889,14 @@ describe('AccountTreeController', () => { }); it('returns empty string when no wallets exist and getSelectedMultichainAccount returns EMPTY_ACCOUNT', () => { - const { controller, messenger } = setup({ + const { controller } = setup({ accounts: [], keyrings: [], }); - // Mock getSelectedMultichainAccount to return EMPTY_ACCOUNT_MOCK (id is '') BEFORE init - messenger.unregisterActionHandler( - 'AccountsController:getSelectedMultichainAccount', - ); - messenger.registerActionHandler( - 'AccountsController:getSelectedMultichainAccount', - () => EMPTY_ACCOUNT_MOCK, + // Mock getSelectedAccount to return EMPTY_ACCOUNT_MOCK (id is '') BEFORE init + mockGetSelectedMultichainAccountActionHandler.mockReturnValue( + EMPTY_ACCOUNT_MOCK, ); controller.init(); @@ -4154,7 +4100,7 @@ describe('AccountTreeController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/account-tree-controller/src/AccountTreeController.ts b/packages/account-tree-controller/src/AccountTreeController.ts index 3ae88120a0c..f43f44b75a4 100644 --- a/packages/account-tree-controller/src/AccountTreeController.ts +++ b/packages/account-tree-controller/src/AccountTreeController.ts @@ -8,8 +8,8 @@ import type { } from '@metamask/account-api'; import type { MultichainAccountWalletStatus } from '@metamask/account-api'; import { type AccountId } from '@metamask/accounts-controller'; -import type { StateMetadata } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +import type { StateMetadata } from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import type { TraceCallback } from '@metamask/controller-utils'; import { isEvmAccountType } from '@metamask/keyring-api'; import type { InternalAccount } from '@metamask/keyring-internal-api'; @@ -49,31 +49,31 @@ const accountTreeControllerMetadata: StateMetadata = accountTree: { includeInStateLogs: true, persist: false, // We do re-recompute this state everytime. - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, isAccountTreeSyncingInProgress: { includeInStateLogs: false, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, hasAccountTreeSyncingSyncedAtLeastOnce: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, accountGroupsMetadata: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, accountWalletsMetadata: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -178,11 +178,11 @@ export class AccountTreeController extends BaseController< // Rules to apply to construct the wallets tree. this.#rules = [ // 1. We group by entropy-source - new EntropyRule(this.messagingSystem), + new EntropyRule(this.messenger), // 2. We group by Snap ID - new SnapRule(this.messagingSystem), + new SnapRule(this.messenger), // 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts) - new KeyringRule(this.messagingSystem), + new KeyringRule(this.messenger), ]; // Initialize trace function @@ -203,28 +203,25 @@ export class AccountTreeController extends BaseController< this.#createBackupAndSyncContext(), ); - this.messagingSystem.subscribe( - 'AccountsController:accountAdded', - (account) => { - this.#handleAccountAdded(account); - }, - ); + this.messenger.subscribe('AccountsController:accountAdded', (account) => { + this.#handleAccountAdded(account); + }); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountRemoved', (accountId) => { this.#handleAccountRemoved(accountId); }, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:selectedAccountChange', (account) => { this.#handleSelectedAccountChange(account); }, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'UserStorageController:stateChange', (userStorageControllerState) => { this.#backupAndSyncService.handleUserStorageStateChange( @@ -233,7 +230,7 @@ export class AccountTreeController extends BaseController< }, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'MultichainAccountService:walletStatusChange', (walletId, status) => { this.#handleMultichainAccountWalletStatusChange(walletId, status); @@ -348,7 +345,7 @@ export class AccountTreeController extends BaseController< log( `Selected (initial) group is: [${this.state.accountTree.selectedAccountGroup}]`, ); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:selectedAccountGroupChange`, this.state.accountTree.selectedAccountGroup, previousSelectedAccountGroup, @@ -478,10 +475,7 @@ export class AccountTreeController extends BaseController< let proposedName = ''; // Empty means there's no computed name for this group. for (const id of group.accounts) { - const account = this.messagingSystem.call( - 'AccountsController:getAccount', - id, - ); + const account = this.messenger.call('AccountsController:getAccount', id); if (!account) { continue; } @@ -723,10 +717,7 @@ export class AccountTreeController extends BaseController< const accounts: InternalAccount[] = []; for (const id of group.accounts) { - const account = this.messagingSystem.call( - 'AccountsController:getAccount', - id, - ); + const account = this.messenger.call('AccountsController:getAccount', id); // For now, we're filtering undefined account, but I believe // throwing would be more appropriate here. @@ -787,7 +778,7 @@ export class AccountTreeController extends BaseController< } }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:accountTreeChange`, this.state.accountTree, ); @@ -845,14 +836,14 @@ export class AccountTreeController extends BaseController< } } }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:accountTreeChange`, this.state.accountTree, ); // Emit selectedAccountGroupChange event if the selected group changed if (selectedAccountGroupChanged) { - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:selectedAccountGroupChange`, this.state.accountTree.selectedAccountGroup, previousSelectedAccountGroup, @@ -1009,9 +1000,7 @@ export class AccountTreeController extends BaseController< * @returns The list of all internal accounts. */ #listAccounts(): InternalAccount[] { - return this.messagingSystem.call( - 'AccountsController:listMultichainAccounts', - ); + return this.messenger.call('AccountsController:listMultichainAccounts'); } /** @@ -1091,7 +1080,7 @@ export class AccountTreeController extends BaseController< `Selected group is now: [${this.state.accountTree.selectedAccountGroup}]`, ); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:selectedAccountGroupChange`, groupId, previousSelectedAccountGroup, @@ -1099,7 +1088,7 @@ export class AccountTreeController extends BaseController< // Update AccountsController - this will trigger selectedAccountChange event, // but our handler is idempotent so it won't cause infinite loop - this.messagingSystem.call( + this.messenger.call( 'AccountsController:setSelectedAccount', accountToSelect, ); @@ -1114,7 +1103,7 @@ export class AccountTreeController extends BaseController< #getDefaultSelectedAccountGroup(wallets: { [walletId: AccountWalletId]: AccountWalletObject; }): AccountGroupId | '' { - const selectedAccount = this.messagingSystem.call( + const selectedAccount = this.messenger.call( 'AccountsController:getSelectedMultichainAccount', ); if (selectedAccount && selectedAccount.id) { @@ -1156,7 +1145,7 @@ export class AccountTreeController extends BaseController< this.update((state) => { state.accountTree.selectedAccountGroup = groupId; }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:selectedAccountGroupChange`, groupId, previousSelectedAccountGroup, @@ -1211,7 +1200,7 @@ export class AccountTreeController extends BaseController< if (group) { let candidate; for (const id of group.accounts) { - const account = this.messagingSystem.call( + const account = this.messenger.call( 'AccountsController:getAccount', id, ); @@ -1254,7 +1243,7 @@ export class AccountTreeController extends BaseController< } for (const id of group.accounts) { - const account = this.messagingSystem.call( + const account = this.messenger.call( 'AccountsController:getAccount', id, ); @@ -1497,37 +1486,37 @@ export class AccountTreeController extends BaseController< * Registers message handlers for the AccountTreeController. */ #registerMessageHandlers(): void { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getSelectedAccountGroup`, this.getSelectedAccountGroup.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setSelectedAccountGroup`, this.setSelectedAccountGroup.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getAccountsFromSelectedAccountGroup`, this.getAccountsFromSelectedAccountGroup.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setAccountWalletName`, this.setAccountWalletName.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setAccountGroupName`, this.setAccountGroupName.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setAccountGroupPinned`, this.setAccountGroupPinned.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setAccountGroupHidden`, this.setAccountGroupHidden.bind(this), ); @@ -1574,7 +1563,7 @@ export class AccountTreeController extends BaseController< return { ...this.#backupAndSyncConfig, controller: this, - messenger: this.messagingSystem, + messenger: this.messenger, controllerStateUpdateFn: this.update.bind(this), traceFn: this.#trace.bind(this), groupIdToWalletId: this.#groupIdToWalletId, diff --git a/packages/account-tree-controller/src/rule.test.ts b/packages/account-tree-controller/src/rule.test.ts index f370fbfdf5b..20318183277 100644 --- a/packages/account-tree-controller/src/rule.test.ts +++ b/packages/account-tree-controller/src/rule.test.ts @@ -4,7 +4,6 @@ import { toMultichainAccountGroupId, toMultichainAccountWalletId, } from '@metamask/account-api'; -import { Messenger } from '@metamask/base-controller'; import { EthAccountType, EthMethod, @@ -16,14 +15,11 @@ import type { InternalAccount } from '@metamask/keyring-internal-api'; import type { AccountGroupObject } from './group'; import { BaseRule } from './rule'; -import type { - AccountTreeControllerMessenger, - AccountTreeControllerActions, - AccountTreeControllerEvents, - AllowedActions, - AllowedEvents, -} from './types'; import type { AccountWalletObject } from './wallet'; +import { + getAccountTreeControllerMessenger, + getRootMessenger, +} from '../tests/mockMessenger'; const ETH_EOA_METHODS = [ EthMethod.PersonalSign, @@ -57,53 +53,15 @@ const MOCK_HD_ACCOUNT_1: Bip44Account = { }, }; -/** - * Creates a new root messenger instance for testing. - * - * @returns A new Messenger instance. - */ -function getRootMessenger() { - return new Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents - >(); -} - -/** - * Retrieves a restricted messenger for the AccountTreeController. - * - * @param messenger - The root messenger instance. Defaults to a new Messenger created by getRootMessenger(). - * @returns The restricted messenger for the AccountTreeController. - */ -function getAccountTreeControllerMessenger( - messenger = getRootMessenger(), -): AccountTreeControllerMessenger { - return messenger.getRestricted({ - name: 'AccountTreeController', - allowedEvents: [ - 'AccountsController:accountAdded', - 'AccountsController:accountRemoved', - 'AccountsController:selectedAccountChange', - ], - allowedActions: [ - 'AccountsController:listMultichainAccounts', - 'AccountsController:getAccount', - 'AccountsController:getSelectedMultichainAccount', - 'AccountsController:setSelectedAccount', - 'KeyringController:getState', - 'SnapController:get', - ], - }); -} - describe('BaseRule', () => { describe('getComputedAccountGroupName', () => { it('returns empty string when account is not found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new BaseRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new BaseRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => undefined, ); @@ -129,11 +87,12 @@ describe('BaseRule', () => { }); it('returns account name when account is found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new BaseRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new BaseRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => MOCK_HD_ACCOUNT_1, ); diff --git a/packages/account-tree-controller/src/rules/entropy.test.ts b/packages/account-tree-controller/src/rules/entropy.test.ts index 6874ddc7abf..9023d344de4 100644 --- a/packages/account-tree-controller/src/rules/entropy.test.ts +++ b/packages/account-tree-controller/src/rules/entropy.test.ts @@ -4,7 +4,6 @@ import { toMultichainAccountGroupId, toMultichainAccountWalletId, } from '@metamask/account-api'; -import { Messenger } from '@metamask/base-controller'; import { EthAccountType, EthMethod, @@ -17,14 +16,11 @@ import type { InternalAccount } from '@metamask/keyring-internal-api'; import type { AccountWalletEntropyObject } from 'src/wallet'; import { EntropyRule } from './entropy'; +import { + getAccountTreeControllerMessenger, + getRootMessenger, +} from '../../tests/mockMessenger'; import type { AccountGroupObjectOf } from '../group'; -import type { - AccountTreeControllerMessenger, - AccountTreeControllerActions, - AccountTreeControllerEvents, - AllowedActions, - AllowedEvents, -} from '../types'; const ETH_EOA_METHODS = [ EthMethod.PersonalSign, @@ -64,53 +60,15 @@ const MOCK_HD_ACCOUNT_1: Bip44Account = { }, }; -/** - * Creates a new root messenger instance for testing. - * - * @returns A new Messenger instance. - */ -function getRootMessenger() { - return new Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents - >(); -} - -/** - * Retrieves a restricted messenger for the AccountTreeController. - * - * @param messenger - The root messenger instance. Defaults to a new Messenger created by getRootMessenger(). - * @returns The restricted messenger for the AccountTreeController. - */ -function getAccountTreeControllerMessenger( - messenger = getRootMessenger(), -): AccountTreeControllerMessenger { - return messenger.getRestricted({ - name: 'AccountTreeController', - allowedEvents: [ - 'AccountsController:accountAdded', - 'AccountsController:accountRemoved', - 'AccountsController:selectedAccountChange', - ], - allowedActions: [ - 'AccountsController:listMultichainAccounts', - 'AccountsController:getAccount', - 'AccountsController:getSelectedMultichainAccount', - 'AccountsController:setSelectedAccount', - 'KeyringController:getState', - 'SnapController:get', - ], - }); -} - describe('EntropyRule', () => { describe('getComputedAccountGroupName', () => { it('uses BaseRule implementation', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new EntropyRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new EntropyRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => MOCK_HD_ACCOUNT_1, ); @@ -138,11 +96,12 @@ describe('EntropyRule', () => { }); it('returns empty string when account is not found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new EntropyRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new EntropyRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => undefined, ); @@ -180,9 +139,10 @@ describe('EntropyRule', () => { }); it('getComputedAccountGroupName returns account name with EVM priority', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new EntropyRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new EntropyRule(accountTreeControllerMessenger); const mockEvmAccount: InternalAccount = { ...MOCK_HD_ACCOUNT_1, @@ -194,7 +154,7 @@ describe('EntropyRule', () => { }, }; - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => mockEvmAccount, ); @@ -220,11 +180,12 @@ describe('EntropyRule', () => { }); it('getComputedAccountGroupName returns empty string when no accounts found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new EntropyRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new EntropyRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => undefined, ); @@ -250,9 +211,10 @@ describe('EntropyRule', () => { }); it('getComputedAccountGroupName returns empty string for non-EVM accounts to prevent chain-specific names', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new EntropyRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new EntropyRule(accountTreeControllerMessenger); const mockSolanaAccount: InternalAccount = { ...MOCK_HD_ACCOUNT_1, @@ -264,7 +226,7 @@ describe('EntropyRule', () => { }, }; - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', (accountId: string) => { const accounts: Record = { diff --git a/packages/account-tree-controller/src/rules/keyring.test.ts b/packages/account-tree-controller/src/rules/keyring.test.ts index 033b2c4239a..441c4652b14 100644 --- a/packages/account-tree-controller/src/rules/keyring.test.ts +++ b/packages/account-tree-controller/src/rules/keyring.test.ts @@ -4,20 +4,16 @@ import { toAccountWalletId, AccountWalletType, } from '@metamask/account-api'; -import { Messenger } from '@metamask/base-controller'; import { EthAccountType, EthMethod, EthScope } from '@metamask/keyring-api'; import { KeyringTypes } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; import { KeyringRule, getAccountWalletNameFromKeyringType } from './keyring'; +import { + getAccountTreeControllerMessenger, + getRootMessenger, +} from '../../tests/mockMessenger'; import type { AccountGroupObjectOf } from '../group'; -import type { - AccountTreeControllerMessenger, - AccountTreeControllerActions, - AccountTreeControllerEvents, - AllowedActions, - AllowedEvents, -} from '../types'; import type { AccountWalletKeyringObject, AccountWalletObjectOf, @@ -70,52 +66,14 @@ describe('keyring', () => { }, }; - /** - * Creates a new root messenger instance for testing. - * - * @returns A new Messenger instance. - */ - function getRootMessenger() { - return new Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents - >(); - } - - /** - * Retrieves a restricted messenger for the AccountTreeController. - * - * @param messenger - The root messenger instance. Defaults to a new Messenger created by getRootMessenger(). - * @returns The restricted messenger for the AccountTreeController. - */ - function getAccountTreeControllerMessenger( - messenger = getRootMessenger(), - ): AccountTreeControllerMessenger { - return messenger.getRestricted({ - name: 'AccountTreeController', - allowedEvents: [ - 'AccountsController:accountAdded', - 'AccountsController:accountRemoved', - 'AccountsController:selectedAccountChange', - ], - allowedActions: [ - 'AccountsController:listMultichainAccounts', - 'AccountsController:getAccount', - 'AccountsController:getSelectedMultichainAccount', - 'AccountsController:setSelectedAccount', - 'KeyringController:getState', - 'SnapController:get', - ], - }); - } - describe('getComputedAccountGroupName', () => { it('uses BaseRule implementation', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new KeyringRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new KeyringRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => MOCK_HARDWARE_ACCOUNT_1, ); @@ -140,11 +98,12 @@ describe('keyring', () => { }); it('returns empty string when account is not found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new KeyringRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new KeyringRule(accountTreeControllerMessenger); - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => undefined, ); @@ -198,12 +157,13 @@ describe('keyring', () => { ); it('getComputedAccountGroupName returns computed name from base class', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new KeyringRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new KeyringRule(accountTreeControllerMessenger); // Mock the AccountsController to always return the account - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => MOCK_HARDWARE_ACCOUNT_1, ); @@ -231,12 +191,13 @@ describe('keyring', () => { }); it('getComputedAccountGroupName returns empty string when account not found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new KeyringRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new KeyringRule(accountTreeControllerMessenger); // Mock the AccountsController to return undefined (account not found) - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => undefined, ); @@ -263,9 +224,10 @@ describe('keyring', () => { }); it('getDefaultAccountWalletName returns wallet name based on keyring type', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new KeyringRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new KeyringRule(accountTreeControllerMessenger); const hdWallet: AccountWalletObjectOf = { id: toAccountWalletId(AccountWalletType.Keyring, KeyringTypes.hd), diff --git a/packages/account-tree-controller/src/rules/snap.test.ts b/packages/account-tree-controller/src/rules/snap.test.ts index 839d859856d..672f074db72 100644 --- a/packages/account-tree-controller/src/rules/snap.test.ts +++ b/packages/account-tree-controller/src/rules/snap.test.ts @@ -4,7 +4,6 @@ import { toAccountWalletId, AccountWalletType, } from '@metamask/account-api'; -import { Messenger } from '@metamask/base-controller'; import { EthAccountType, EthMethod, EthScope } from '@metamask/keyring-api'; import { KeyringTypes } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; @@ -12,14 +11,11 @@ import type { SnapId } from '@metamask/snaps-sdk'; import type { Snap } from '@metamask/snaps-utils'; import { SnapRule } from './snap'; +import { + getAccountTreeControllerMessenger, + getRootMessenger, +} from '../../tests/mockMessenger'; import type { AccountGroupObjectOf } from '../group'; -import type { - AccountTreeControllerMessenger, - AccountTreeControllerActions, - AccountTreeControllerEvents, - AllowedActions, - AllowedEvents, -} from '../types'; import type { AccountWalletObjectOf, AccountWalletSnapObject } from '../wallet'; const ETH_EOA_METHODS = [ @@ -58,55 +54,16 @@ const MOCK_SNAP_ACCOUNT_1: InternalAccount = { }, }; -/** - * Creates a new root messenger instance for testing. - * - * @returns A new Messenger instance. - */ -function getRootMessenger() { - return new Messenger< - AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents - >(); -} - -/** - * Retrieves a restricted messenger for the AccountTreeController. - * - * @param messenger - The root messenger instance. Defaults to a new Messenger created by getRootMessenger(). - * @returns The restricted messenger for the AccountTreeController. - */ -function getAccountTreeControllerMessenger( - messenger = getRootMessenger(), -): AccountTreeControllerMessenger { - return messenger.getRestricted({ - name: 'AccountTreeController', - allowedEvents: [ - 'AccountsController:accountAdded', - 'AccountsController:accountRemoved', - 'AccountsController:selectedAccountChange', - 'MultichainAccountService:walletStatusChange', - ], - allowedActions: [ - 'AccountsController:listMultichainAccounts', - 'AccountsController:getAccount', - 'AccountsController:getSelectedMultichainAccount', - 'AccountsController:setSelectedAccount', - 'KeyringController:getState', - 'SnapController:get', - ], - }); -} - describe('SnapRule', () => { describe('getComputedAccountGroupName', () => { it('returns computed name from base class', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new SnapRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new SnapRule(accountTreeControllerMessenger); // Mock the AccountsController to return an account - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => MOCK_SNAP_ACCOUNT_1, ); @@ -131,12 +88,13 @@ describe('SnapRule', () => { }); it('returns empty string when account not found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new SnapRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new SnapRule(accountTreeControllerMessenger); // Mock the AccountsController to return undefined (account not found) - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'AccountsController:getAccount', () => undefined, ); @@ -174,12 +132,13 @@ describe('SnapRule', () => { describe('getDefaultAccountWalletName', () => { it('returns snap proposed name when available', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new SnapRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new SnapRule(accountTreeControllerMessenger); // Mock SnapController to return snap with proposed name - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'SnapController:get', () => MOCK_SNAP_1 as unknown as Snap, ); @@ -199,9 +158,10 @@ describe('SnapRule', () => { }); it('returns cleaned snap ID when no proposed name available', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new SnapRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new SnapRule(accountTreeControllerMessenger); const snapWithoutProposedName = { id: 'npm:@metamask/example-snap' as unknown as SnapId, @@ -215,7 +175,7 @@ describe('SnapRule', () => { }; // Mock SnapController to return snap without proposed name - rootMessenger.registerActionHandler( + messenger.registerActionHandler( 'SnapController:get', () => snapWithoutProposedName as unknown as Snap, ); @@ -239,15 +199,13 @@ describe('SnapRule', () => { }); it('returns cleaned snap ID when snap not found', () => { - const rootMessenger = getRootMessenger(); - const messenger = getAccountTreeControllerMessenger(rootMessenger); - const rule = new SnapRule(messenger); + const messenger = getRootMessenger(); + const accountTreeControllerMessenger = + getAccountTreeControllerMessenger(messenger); + const rule = new SnapRule(accountTreeControllerMessenger); // Mock SnapController to return undefined (snap not found) - rootMessenger.registerActionHandler( - 'SnapController:get', - () => undefined, - ); + messenger.registerActionHandler('SnapController:get', () => undefined); const snapId = 'npm:@metamask/missing-snap'; const wallet: AccountWalletObjectOf = { diff --git a/packages/account-tree-controller/src/types.ts b/packages/account-tree-controller/src/types.ts index 231a3de226d..10e22680ac7 100644 --- a/packages/account-tree-controller/src/types.ts +++ b/packages/account-tree-controller/src/types.ts @@ -11,10 +11,10 @@ import type { import { type ControllerGetStateAction, type ControllerStateChangeEvent, - type RestrictedMessenger, } from '@metamask/base-controller'; import type { TraceCallback } from '@metamask/controller-utils'; import type { KeyringControllerGetStateAction } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import type { MultichainAccountServiceCreateMultichainAccountGroupAction } from '@metamask/multichain-account-service'; import type { AuthenticationController, @@ -173,12 +173,10 @@ export type AccountTreeControllerEvents = | AccountTreeControllerAccountTreeChangeEvent | AccountTreeControllerSelectedAccountGroupChangeEvent; -export type AccountTreeControllerMessenger = RestrictedMessenger< +export type AccountTreeControllerMessenger = Messenger< typeof controllerName, AccountTreeControllerActions | AllowedActions, - AccountTreeControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + AccountTreeControllerEvents | AllowedEvents >; export type AccountTreeControllerConfig = { diff --git a/packages/account-tree-controller/tests/mockMessenger.ts b/packages/account-tree-controller/tests/mockMessenger.ts new file mode 100644 index 00000000000..10fa770a675 --- /dev/null +++ b/packages/account-tree-controller/tests/mockMessenger.ts @@ -0,0 +1,71 @@ +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, +} from '@metamask/messenger'; + +import type { AccountTreeControllerMessenger } from '../src/types'; + +type AllAccountTreeControllerActions = + MessengerActions; + +type AllAccountTreeControllerEvents = + MessengerEvents; + +/** + * Creates a new root messenger instance for testing. + * + * @returns A new Messenger instance. + */ +export function getRootMessenger() { + return new Messenger< + MockAnyNamespace, + AllAccountTreeControllerActions, + AllAccountTreeControllerEvents + >({ namespace: MOCK_ANY_NAMESPACE }); +} + +/** + * Retrieves a messenger for the AccountTreeController. + * + * @param rootMessenger - The root messenger instance. + * @returns The messenger for the AccountTreeController. + */ +export function getAccountTreeControllerMessenger( + rootMessenger: ReturnType, +): AccountTreeControllerMessenger { + const accountTreeControllerMessenger = new Messenger< + 'AccountTreeController', + AllAccountTreeControllerActions, + AllAccountTreeControllerEvents, + typeof rootMessenger + >({ namespace: 'AccountTreeController', parent: rootMessenger }); + rootMessenger.delegate({ + messenger: accountTreeControllerMessenger, + events: [ + 'AccountsController:accountAdded', + 'AccountsController:accountRemoved', + 'AccountsController:selectedAccountChange', + 'UserStorageController:stateChange', + 'MultichainAccountService:walletStatusChange', + ], + actions: [ + 'AccountsController:listMultichainAccounts', + 'AccountsController:getAccount', + 'AccountsController:getSelectedMultichainAccount', + 'AccountsController:setSelectedAccount', + 'UserStorageController:getState', + 'UserStorageController:performGetStorage', + 'UserStorageController:performGetStorageAllFeatureEntries', + 'UserStorageController:performSetStorage', + 'UserStorageController:performBatchSetStorage', + 'AuthenticationController:getSessionProfile', + 'MultichainAccountService:createMultichainAccountGroup', + 'KeyringController:getState', + 'SnapController:get', + ], + }); + return accountTreeControllerMessenger; +} diff --git a/packages/account-tree-controller/tsconfig.build.json b/packages/account-tree-controller/tsconfig.build.json index 707a559080c..d52110b5b4f 100644 --- a/packages/account-tree-controller/tsconfig.build.json +++ b/packages/account-tree-controller/tsconfig.build.json @@ -9,6 +9,7 @@ { "path": "../accounts-controller/tsconfig.build.json" }, { "path": "../base-controller/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" }, { "path": "../multichain-account-service/tsconfig.build.json" }, { "path": "../profile-sync-controller/tsconfig.build.json" } ], diff --git a/packages/account-tree-controller/tsconfig.json b/packages/account-tree-controller/tsconfig.json index ca31cc28bbc..80394fb0531 100644 --- a/packages/account-tree-controller/tsconfig.json +++ b/packages/account-tree-controller/tsconfig.json @@ -13,6 +13,9 @@ { "path": "../accounts-controller" }, + { + "path": "../messenger" + }, { "path": "../multichain-account-service" }, @@ -20,5 +23,5 @@ "path": "../profile-sync-controller" } ], - "include": ["../../types", "./src"] + "include": ["../../types", "./src", "./tests"] } diff --git a/packages/accounts-controller/CHANGELOG.md b/packages/accounts-controller/CHANGELOG.md index 720231ce347..e72f2dbfb34 100644 --- a/packages/accounts-controller/CHANGELOG.md +++ b/packages/accounts-controller/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6426](https://github.com/MetaMask/core/pull/6426)) + - Previously, `AccountsController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/utils` from `^11.4.2` to `^11.8.1` ([#6588](https://github.com/MetaMask/core/pull/6588), [#6708](https://github.com/MetaMask/core/pull/6708)) - Bump `@metamask/base-controller` from `^8.3.0` to `^8.4.1` ([#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) diff --git a/packages/accounts-controller/package.json b/packages/accounts-controller/package.json index 4525f6640b1..972e7264f3f 100644 --- a/packages/accounts-controller/package.json +++ b/packages/accounts-controller/package.json @@ -53,6 +53,7 @@ "@metamask/keyring-api": "^21.0.0", "@metamask/keyring-internal-api": "^9.0.0", "@metamask/keyring-utils": "^3.1.0", + "@metamask/messenger": "^0.3.0", "@metamask/snaps-sdk": "^9.0.0", "@metamask/snaps-utils": "^11.0.0", "@metamask/superstruct": "^3.1.0", diff --git a/packages/accounts-controller/src/AccountsController.test.ts b/packages/accounts-controller/src/AccountsController.test.ts index eb95dcb199a..ecb620c4f76 100644 --- a/packages/accounts-controller/src/AccountsController.test.ts +++ b/packages/accounts-controller/src/AccountsController.test.ts @@ -1,4 +1,4 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { InfuraNetworkType } from '@metamask/controller-utils'; import type { AccountAssetListUpdatedEventPayload, @@ -15,6 +15,13 @@ import { } from '@metamask/keyring-api'; import { KeyringTypes } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { NetworkClientId } from '@metamask/network-controller'; import type { SnapControllerState } from '@metamask/snaps-controllers'; import { SnapStatus } from '@metamask/snaps-utils'; @@ -23,11 +30,8 @@ import type { V4Options } from 'uuid'; import * as uuid from 'uuid'; import type { - AccountsControllerActions, - AccountsControllerEvents, + AccountsControllerMessenger, AccountsControllerState, - AllowedActions, - AllowedEvents, } from './AccountsController'; import { AccountsController, EMPTY_ACCOUNT } from './AccountsController'; import { @@ -41,6 +45,17 @@ import { keyringTypeToName, } from './utils'; +type AllAccountsControllerActions = + MessengerActions; + +type AllAccountsControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllAccountsControllerActions, + AllAccountsControllerEvents +>; + jest.mock('uuid'); const mockUUID = jest.spyOn(uuid, 'v4'); const actualUUID = jest.requireActual('uuid').v4; // We also use uuid.v4 in our mocks @@ -217,27 +232,37 @@ function setExpectedLastSelectedAsAny( } /** - * Builds a new instance of the Messenger class for the AccountsController. + * Builds a new instance of the root messenger. * - * @returns A new instance of the Messenger class for the AccountsController. + * @returns A new instance of the root messenger. */ -function buildMessenger() { - return new Messenger< - AccountsControllerActions | AllowedActions, - AccountsControllerEvents | AllowedEvents - >(); +function buildMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** - * Builds a restricted messenger for the AccountsController. + * Builds a messenger for the AccountsController. * - * @param messenger - The messenger to restrict. - * @returns The restricted messenger. + * @param rootMessenger - The root messenger. + * @returns The messenger for AccountsController. */ -function buildAccountsControllerMessenger(messenger = buildMessenger()) { - return messenger.getRestricted({ - name: 'AccountsController', - allowedEvents: [ +function buildAccountsControllerMessenger(rootMessenger = buildMessenger()) { + const accountsControllerMessenger = new Messenger< + 'AccountsController', + AllAccountsControllerActions, + AllAccountsControllerEvents, + typeof rootMessenger + >({ + namespace: 'AccountsController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: accountsControllerMessenger, + actions: [ + 'KeyringController:getState', + 'KeyringController:getKeyringsByType', + ], + events: [ 'SnapController:stateChange', 'KeyringController:stateChange', 'SnapKeyring:accountAssetListUpdated', @@ -245,11 +270,8 @@ function buildAccountsControllerMessenger(messenger = buildMessenger()) { 'SnapKeyring:accountTransactionsUpdated', 'MultichainNetworkController:networkDidChange', ], - allowedActions: [ - 'KeyringController:getState', - 'KeyringController:getKeyringsByType', - ], }); + return accountsControllerMessenger; } /** @@ -257,7 +279,7 @@ function buildAccountsControllerMessenger(messenger = buildMessenger()) { * * @param options - The options object. * @param [options.initialState] - The initial state to use for the AccountsController. - * @param [options.messenger] - Messenger to use for the AccountsController. + * @param [options.messenger] - The root messenger to use for creating the AccountsController messenger. * @returns An instance of the AccountsController class. */ function setupAccountsController({ @@ -265,16 +287,11 @@ function setupAccountsController({ messenger = buildMessenger(), }: { initialState?: Partial; - messenger?: Messenger< - AccountsControllerActions | AllowedActions, - AccountsControllerEvents | AllowedEvents - >; -} = {}): { + messenger?: RootMessenger; +}): { accountsController: AccountsController; - messenger: Messenger< - AccountsControllerActions | AllowedActions, - AccountsControllerEvents | AllowedEvents - >; + messenger: RootMessenger; + accountsControllerMessenger: AccountsControllerMessenger; triggerMultichainNetworkChange: (id: NetworkClientId | CaipChainId) => void; } { const accountsControllerMessenger = @@ -288,7 +305,12 @@ function setupAccountsController({ const triggerMultichainNetworkChange = (id: NetworkClientId | CaipChainId) => messenger.publish('MultichainNetworkController:networkDidChange', id); - return { accountsController, messenger, triggerMultichainNetworkChange }; + return { + accountsController, + messenger, + accountsControllerMessenger, + triggerMultichainNetworkChange, + }; } describe('AccountsController', () => { @@ -1136,11 +1158,10 @@ describe('AccountsController', () => { it('publishes accountAdded event', async () => { const messenger = buildMessenger(); - const messengerSpy = jest.spyOn(messenger, 'publish'); mockUUIDWithNormalAccounts([mockAccount, mockAccount2]); - setupAccountsController({ + const { accountsControllerMessenger } = setupAccountsController({ initialState: { internalAccounts: { accounts: { @@ -1152,6 +1173,8 @@ describe('AccountsController', () => { messenger, }); + const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); + const mockNewKeyringState = { isUnlocked: true, keyrings: [ @@ -1172,11 +1195,10 @@ describe('AccountsController', () => { [], ); - // First call is 'KeyringController:stateChange' + // First call is 'AccountsController:stateChange' expect(messengerSpy).toHaveBeenNthCalledWith( - // 1. KeyringController:stateChange - // 2. AccountsController:stateChange - 3, + // 1. AccountsController:stateChange + 2, 'AccountsController:accountAdded', MockExpectedInternalAccountBuilder.from(mockAccount2) .setExpectedLastSelectedAsAny() @@ -1437,11 +1459,10 @@ describe('AccountsController', () => { it('publishes accountRemoved event', async () => { const messenger = buildMessenger(); - const messengerSpy = jest.spyOn(messenger, 'publish'); mockUUIDWithNormalAccounts([mockAccount, mockAccount2]); - setupAccountsController({ + const { accountsControllerMessenger } = setupAccountsController({ initialState: { internalAccounts: { accounts: { @@ -1454,6 +1475,8 @@ describe('AccountsController', () => { messenger, }); + const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); + const mockNewKeyringState = { isUnlocked: true, keyrings: [ @@ -1473,11 +1496,10 @@ describe('AccountsController', () => { [], ); - // First call is 'KeyringController:stateChange' + // First call is 'AccountsController:stateChange' expect(messengerSpy).toHaveBeenNthCalledWith( - // 1. KeyringController:stateChange - // 2. AccountsController:stateChange - 3, + // 1. AccountsController:stateChange + 2, 'AccountsController:accountRemoved', mockAccount3.id, ); @@ -3141,19 +3163,20 @@ describe('AccountsController', () => { }, type: BtcAccountType.P2wpkh, }); - const { accountsController, messenger } = setupAccountsController({ - initialState: { - internalAccounts: { - accounts: { - [mockAccount.id]: mockAccount, - [mockNonEvmAccount.id]: mockNonEvmAccount, + const { accountsController, accountsControllerMessenger } = + setupAccountsController({ + initialState: { + internalAccounts: { + accounts: { + [mockAccount.id]: mockAccount, + [mockNonEvmAccount.id]: mockNonEvmAccount, + }, + selectedAccount: mockAccount.id, }, - selectedAccount: mockAccount.id, }, - }, - }); + }); - const messengerSpy = jest.spyOn(messenger, 'publish'); + const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); accountsController.setSelectedAccount(mockNonEvmAccount.id); @@ -3247,10 +3270,10 @@ describe('AccountsController', () => { }); it('publishes the accountRenamed event', () => { - const { accountsController, messenger } = + const { accountsController, accountsControllerMessenger } = setupAccountsController(mockState); - const messengerSpy = jest.spyOn(messenger, 'publish'); + const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); accountsController.setAccountNameAndSelectAccount( mockAccount.id, @@ -3325,16 +3348,17 @@ describe('AccountsController', () => { }); it('publishes the accountRenamed event', () => { - const { accountsController, messenger } = setupAccountsController({ - initialState: { - internalAccounts: { - accounts: { [mockAccount.id]: mockAccount }, - selectedAccount: mockAccount.id, + const { accountsController, accountsControllerMessenger } = + setupAccountsController({ + initialState: { + internalAccounts: { + accounts: { [mockAccount.id]: mockAccount }, + selectedAccount: mockAccount.id, + }, }, - }, - }); + }); - const messengerSpy = jest.spyOn(messenger, 'publish'); + const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); accountsController.setAccountName(mockAccount.id, 'new name'); @@ -3898,19 +3922,19 @@ describe('AccountsController', () => { describe('metadata', () => { it('includes expected state in debug snapshots', () => { - const { accountsController: controller } = setupAccountsController(); + const { accountsController: controller } = setupAccountsController({}); expect( deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); it('includes expected state in state logs', () => { - const { accountsController: controller } = setupAccountsController(); + const { accountsController: controller } = setupAccountsController({}); expect( deriveStateFromMetadata( @@ -3929,7 +3953,7 @@ describe('AccountsController', () => { }); it('persists expected state', () => { - const { accountsController: controller } = setupAccountsController(); + const { accountsController: controller } = setupAccountsController({}); expect( deriveStateFromMetadata( @@ -3948,7 +3972,7 @@ describe('AccountsController', () => { }); it('exposes expected state to UI', () => { - const { accountsController: controller } = setupAccountsController(); + const { accountsController: controller } = setupAccountsController({}); expect( deriveStateFromMetadata( diff --git a/packages/accounts-controller/src/AccountsController.ts b/packages/accounts-controller/src/AccountsController.ts index 3ca7bee9817..b5206c47626 100644 --- a/packages/accounts-controller/src/AccountsController.ts +++ b/packages/accounts-controller/src/AccountsController.ts @@ -1,10 +1,8 @@ import { type ControllerGetStateAction, type ControllerStateChangeEvent, - type ExtractEventPayload, - type RestrictedMessenger, BaseController, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; import { type SnapKeyringAccountAssetListUpdatedEvent, type SnapKeyringAccountBalancesUpdatedEvent, @@ -29,6 +27,7 @@ import { } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; import { isScopeEqualToAny } from '@metamask/keyring-utils'; +import type { Messenger, ExtractEventPayload } from '@metamask/messenger'; import type { NetworkClientId } from '@metamask/network-controller'; import type { SnapControllerState, @@ -212,19 +211,17 @@ export type AccountsControllerEvents = | AccountsControllerAccountTransactionsUpdatedEvent | AccountsControllerAccountAssetListUpdatedEvent; -export type AccountsControllerMessenger = RestrictedMessenger< +export type AccountsControllerMessenger = Messenger< typeof controllerName, AccountsControllerActions | AllowedActions, - AccountsControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + AccountsControllerEvents | AllowedEvents >; const accountsControllerMetadata = { internalAccounts: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -486,7 +483,7 @@ export class AccountsController extends BaseController< state.internalAccounts.selectedAccount = account.id; }); - this.messagingSystem.publish( + this.messenger.publish( 'AccountsController:accountRenamed', internalAccount, ); @@ -530,7 +527,7 @@ export class AccountsController extends BaseController< }); if (metadata.name) { - this.messagingSystem.publish( + this.messenger.publish( 'AccountsController:accountRenamed', internalAccount, ); @@ -550,9 +547,7 @@ export class AccountsController extends BaseController< const internalAccounts: AccountsControllerState['internalAccounts']['accounts'] = {}; - const { keyrings } = this.messagingSystem.call( - 'KeyringController:getState', - ); + const { keyrings } = this.messenger.call('KeyringController:getState'); for (const keyring of keyrings) { const keyringTypeName = keyringTypeToName(keyring.type); @@ -709,7 +704,7 @@ export class AccountsController extends BaseController< * @returns The Snap keyring if available. */ #getSnapKeyring(): SnapKeyring | undefined { - const [snapKeyring] = this.messagingSystem.call( + const [snapKeyring] = this.messenger.call( 'KeyringController:getKeyringsByType', SnapKeyring.type, ); @@ -733,7 +728,7 @@ export class AccountsController extends BaseController< event: EventType, ...payload: ExtractEventPayload ): void { - this.messagingSystem.publish(event, ...payload); + this.messenger.publish(event, ...payload); } /** @@ -887,14 +882,11 @@ export class AccountsController extends BaseController< () => { // Now publish events for (const id of diff.removed) { - this.messagingSystem.publish('AccountsController:accountRemoved', id); + this.messenger.publish('AccountsController:accountRemoved', id); } for (const account of diff.added) { - this.messagingSystem.publish( - 'AccountsController:accountAdded', - account, - ); + this.messenger.publish('AccountsController:accountAdded', account); } }, ); @@ -955,12 +947,12 @@ export class AccountsController extends BaseController< // `selectedAccount` to be non-empty. if (account) { if (isEvmAccountType(account.type)) { - this.messagingSystem.publish( + this.messenger.publish( 'AccountsController:selectedEvmAccountChange', account, ); } - this.messagingSystem.publish( + this.messenger.publish( 'AccountsController:selectedAccountChange', account, ); @@ -1202,17 +1194,15 @@ export class AccountsController extends BaseController< * Subscribes to message events. */ #subscribeToMessageEvents() { - this.messagingSystem.subscribe( - 'SnapController:stateChange', - (snapStateState) => this.#handleOnSnapStateChange(snapStateState), + this.messenger.subscribe('SnapController:stateChange', (snapStateState) => + this.#handleOnSnapStateChange(snapStateState), ); - this.messagingSystem.subscribe( - 'KeyringController:stateChange', - (keyringState) => this.#handleOnKeyringStateChange(keyringState), + this.messenger.subscribe('KeyringController:stateChange', (keyringState) => + this.#handleOnKeyringStateChange(keyringState), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'SnapKeyring:accountAssetListUpdated', (snapAccountEvent) => this.#handleOnSnapKeyringAccountEvent( @@ -1221,7 +1211,7 @@ export class AccountsController extends BaseController< ), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'SnapKeyring:accountBalancesUpdated', (snapAccountEvent) => this.#handleOnSnapKeyringAccountEvent( @@ -1230,7 +1220,7 @@ export class AccountsController extends BaseController< ), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'SnapKeyring:accountTransactionsUpdated', (snapAccountEvent) => this.#handleOnSnapKeyringAccountEvent( @@ -1240,7 +1230,7 @@ export class AccountsController extends BaseController< ); // Handle account change when multichain network is changed - this.messagingSystem.subscribe( + this.messenger.subscribe( 'MultichainNetworkController:networkDidChange', (id) => this.#handleOnMultichainNetworkDidChange(id), ); @@ -1250,62 +1240,62 @@ export class AccountsController extends BaseController< * Registers message handlers for the AccountsController. */ #registerMessageHandlers() { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setSelectedAccount`, this.setSelectedAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:listAccounts`, this.listAccounts.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:listMultichainAccounts`, this.listMultichainAccounts.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setAccountName`, this.setAccountName.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setAccountNameAndSelectAccount`, this.setAccountNameAndSelectAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:updateAccounts`, this.updateAccounts.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getSelectedAccount`, this.getSelectedAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getSelectedMultichainAccount`, this.getSelectedMultichainAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getAccountByAddress`, this.getAccountByAddress.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getNextAvailableAccountName`, this.getNextAvailableAccountName.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `AccountsController:getAccount`, this.getAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `AccountsController:updateAccountMetadata`, this.updateAccountMetadata.bind(this), ); diff --git a/packages/accounts-controller/tsconfig.build.json b/packages/accounts-controller/tsconfig.build.json index 2ccd968d36d..d95a2cae72e 100644 --- a/packages/accounts-controller/tsconfig.build.json +++ b/packages/accounts-controller/tsconfig.build.json @@ -11,7 +11,8 @@ "path": "../base-controller/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, - { "path": "../network-controller/tsconfig.build.json" } + { "path": "../network-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] } diff --git a/packages/accounts-controller/tsconfig.json b/packages/accounts-controller/tsconfig.json index 12cd20ecb5c..d568399237d 100644 --- a/packages/accounts-controller/tsconfig.json +++ b/packages/accounts-controller/tsconfig.json @@ -10,7 +10,8 @@ { "path": "../keyring-controller" }, - { "path": "../network-controller" } + { "path": "../network-controller" }, + { "path": "../messenger" } ], "include": ["../../types", "./src", "src/tests"] } diff --git a/packages/address-book-controller/CHANGELOG.md b/packages/address-book-controller/CHANGELOG.md index b679865219a..87a929dc1af 100644 --- a/packages/address-book-controller/CHANGELOG.md +++ b/packages/address-book-controller/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6383](https://github.com/MetaMask/core/pull/6383)) + - Previously, `AddressBookController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/base-controller` from `^8.0.1` to `^8.4.1` ([#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) - Bump `@metamask/controller-utils` from `^11.11.0` to `^11.14.1` ([#6303](https://github.com/MetaMask/core/pull/6303), [#6620](https://github.com/MetaMask/core/pull/6620), [#6629](https://github.com/MetaMask/core/pull/6629), [#6807](https://github.com/MetaMask/core/pull/6807)) - Bump `@metamask/utils` from `^11.4.2` to `^11.8.1` ([#6588](https://github.com/MetaMask/core/pull/6588), [#6708](https://github.com/MetaMask/core/pull/6708)) diff --git a/packages/address-book-controller/package.json b/packages/address-book-controller/package.json index 707c466ad65..e38bf256582 100644 --- a/packages/address-book-controller/package.json +++ b/packages/address-book-controller/package.json @@ -49,6 +49,7 @@ "dependencies": { "@metamask/base-controller": "^8.4.1", "@metamask/controller-utils": "^11.14.1", + "@metamask/messenger": "^0.3.0", "@metamask/utils": "^11.8.1" }, "devDependencies": { diff --git a/packages/address-book-controller/src/AddressBookController.test.ts b/packages/address-book-controller/src/AddressBookController.test.ts index 0a918ce8716..1b8e4ed5fb3 100644 --- a/packages/address-book-controller/src/AddressBookController.test.ts +++ b/packages/address-book-controller/src/AddressBookController.test.ts @@ -1,12 +1,17 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { toHex } from '@metamask/controller-utils'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; import type { - AddressBookControllerActions, - AddressBookControllerEvents, - AddressBookControllerContactUpdatedEvent, AddressBookControllerContactDeletedEvent, + AddressBookControllerMessenger, } from './AddressBookController'; import { AddressBookController, @@ -14,23 +19,39 @@ import { controllerName, } from './AddressBookController'; +type AllActions = MessengerActions; + +type AllEvents = MessengerEvents; + +type RootMessenger = Messenger; + +/** + * Creates a new root messenger instance for testing. + * + * @returns A new Messenger instance. + */ +function getRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); +} + /** * Helper function to create test fixtures * * @returns Test fixtures including messenger, controller, and event listeners */ function arrangeMocks() { - const messenger = new Messenger< - AddressBookControllerActions, - AddressBookControllerEvents - >(); - const restrictedMessenger = messenger.getRestricted({ - name: controllerName, - allowedActions: [], - allowedEvents: [], + const rootMessenger = getRootMessenger(); + const addressBookControllerMessenger = new Messenger< + typeof controllerName, + AllActions, + AllEvents, + typeof rootMessenger + >({ + namespace: controllerName, + parent: rootMessenger, }); const controller = new AddressBookController({ - messenger: restrictedMessenger, + messenger: addressBookControllerMessenger, }); // Set up mock event listeners @@ -38,11 +59,11 @@ function arrangeMocks() { const contactDeletedListener = jest.fn(); // Subscribe to events - messenger.subscribe( - 'AddressBookController:contactUpdated' as AddressBookControllerContactUpdatedEvent['type'], + rootMessenger.subscribe( + 'AddressBookController:contactUpdated', contactUpdatedListener, ); - messenger.subscribe( + rootMessenger.subscribe( 'AddressBookController:contactDeleted' as AddressBookControllerContactDeletedEvent['type'], contactDeletedListener, ); @@ -627,7 +648,7 @@ describe('AddressBookController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/address-book-controller/src/AddressBookController.ts b/packages/address-book-controller/src/AddressBookController.ts index e02200b0710..13d00a1561b 100644 --- a/packages/address-book-controller/src/AddressBookController.ts +++ b/packages/address-book-controller/src/AddressBookController.ts @@ -1,9 +1,8 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import { normalizeEnsName, isValidHexAddress, @@ -11,6 +10,7 @@ import { toChecksumHexAddress, toHex, } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; /** @@ -150,7 +150,7 @@ const addressBookControllerMetadata = { addressBook: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -170,12 +170,10 @@ export const getDefaultAddressBookControllerState = /** * The messenger of the {@link AddressBookController} for communication. */ -export type AddressBookControllerMessenger = RestrictedMessenger< +export type AddressBookControllerMessenger = Messenger< typeof controllerName, AddressBookControllerActions, - AddressBookControllerEvents, - never, - never + AddressBookControllerEvents >; /** @@ -275,7 +273,7 @@ export class AddressBookController extends BaseController< // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts), // not user-created contacts. They don't need to trigger sync events. if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) { - this.messagingSystem.publish( + this.messenger.publish( 'AddressBookController:contactDeleted', deletedEntry, ); @@ -335,10 +333,7 @@ export class AddressBookController extends BaseController< // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts), // not user-created contacts. They don't need to trigger sync events. if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) { - this.messagingSystem.publish( - 'AddressBookController:contactUpdated', - entry, - ); + this.messenger.publish('AddressBookController:contactUpdated', entry); } return true; @@ -348,15 +343,15 @@ export class AddressBookController extends BaseController< * Registers message handlers for the AddressBookController. */ #registerMessageHandlers() { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:list`, this.list.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:set`, this.set.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:delete`, this.delete.bind(this), ); diff --git a/packages/address-book-controller/tsconfig.build.json b/packages/address-book-controller/tsconfig.build.json index bbfe057a207..5a5c9e2326a 100644 --- a/packages/address-book-controller/tsconfig.build.json +++ b/packages/address-book-controller/tsconfig.build.json @@ -7,7 +7,8 @@ }, "references": [ { "path": "../base-controller/tsconfig.build.json" }, - { "path": "../controller-utils/tsconfig.build.json" } + { "path": "../controller-utils/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] } diff --git a/packages/address-book-controller/tsconfig.json b/packages/address-book-controller/tsconfig.json index 7ee9852347a..dfd15011442 100644 --- a/packages/address-book-controller/tsconfig.json +++ b/packages/address-book-controller/tsconfig.json @@ -5,7 +5,8 @@ }, "references": [ { "path": "../base-controller" }, - { "path": "../controller-utils" } + { "path": "../controller-utils" }, + { "path": "../messenger" } ], "include": ["../../types", "./src"] } diff --git a/packages/announcement-controller/CHANGELOG.md b/packages/announcement-controller/CHANGELOG.md index 26ed9693a8e..64f3a3aebb7 100644 --- a/packages/announcement-controller/CHANGELOG.md +++ b/packages/announcement-controller/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6384](https://github.com/MetaMask/core/pull/6384)) + - Previously, `AnnouncementController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/base-controller` from `^8.0.0` to `^8.4.1` ([#5722](https://github.com/MetaMask/core/pull/5722), [#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) ## [7.0.3] diff --git a/packages/announcement-controller/package.json b/packages/announcement-controller/package.json index fcff194cd0b..32c61ccc1e5 100644 --- a/packages/announcement-controller/package.json +++ b/packages/announcement-controller/package.json @@ -47,7 +47,8 @@ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" }, "dependencies": { - "@metamask/base-controller": "^8.4.1" + "@metamask/base-controller": "^8.4.1", + "@metamask/messenger": "^0.3.0" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", diff --git a/packages/announcement-controller/src/AnnouncementController.test.ts b/packages/announcement-controller/src/AnnouncementController.test.ts index 32fed68792e..ee36b0ce4e5 100644 --- a/packages/announcement-controller/src/AnnouncementController.test.ts +++ b/packages/announcement-controller/src/AnnouncementController.test.ts @@ -1,4 +1,9 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { AnnouncementControllerState, @@ -16,15 +21,20 @@ const name = 'AnnouncementController'; * * @returns A restricted controller messenger. */ -function getRestrictedMessenger() { +function getMessenger() { const messenger = new Messenger< + MockAnyNamespace, AnnouncementControllerActions, AnnouncementControllerEvents - >(); - return messenger.getRestricted({ - name, - allowedActions: [], - allowedEvents: [], + >({ namespace: MOCK_ANY_NAMESPACE }); + return new Messenger< + typeof name, + AnnouncementControllerActions, + AnnouncementControllerEvents, + typeof messenger + >({ + namespace: name, + parent: messenger, }); } const allAnnouncements: AnnouncementMap = { @@ -89,7 +99,7 @@ const state2: AnnouncementControllerState = { describe('announcement controller', () => { it('should add announcement to state', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), allAnnouncements, }); expect(Object.keys(controller.state.announcements)).toHaveLength(2); @@ -110,7 +120,7 @@ describe('announcement controller', () => { it('should add new announcement to state and a new announcement should be created with isShown as false', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), state: state1, allAnnouncements: allAnnouncements2, }); @@ -123,7 +133,7 @@ describe('announcement controller', () => { describe('resetViewed', () => { it('resets all announcement isShown states to false', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), state: state2, allAnnouncements: allAnnouncements2, }); @@ -142,7 +152,7 @@ describe('announcement controller', () => { describe('update viewed announcements', () => { it('should update isShown status', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), state: state2, allAnnouncements: allAnnouncements2, }); @@ -154,7 +164,7 @@ describe('announcement controller', () => { it('should update isShown of more than one announcement', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), state: state2, allAnnouncements: allAnnouncements2, }); @@ -168,7 +178,7 @@ describe('announcement controller', () => { describe('metadata', () => { it('includes expected state in debug snapshots', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), allAnnouncements, }); @@ -176,7 +186,7 @@ describe('announcement controller', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { @@ -198,7 +208,7 @@ describe('announcement controller', () => { it('includes expected state in state logs', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), allAnnouncements, }); @@ -228,7 +238,7 @@ describe('announcement controller', () => { it('persists expected state', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), allAnnouncements, }); @@ -258,7 +268,7 @@ describe('announcement controller', () => { it('exposes expected state to UI', () => { const controller = new AnnouncementController({ - messenger: getRestrictedMessenger(), + messenger: getMessenger(), allAnnouncements, }); diff --git a/packages/announcement-controller/src/AnnouncementController.ts b/packages/announcement-controller/src/AnnouncementController.ts index 66f9858031a..f98cca82034 100644 --- a/packages/announcement-controller/src/AnnouncementController.ts +++ b/packages/announcement-controller/src/AnnouncementController.ts @@ -1,10 +1,10 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, StateMetadata, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; +import type { Messenger } from '@metamask/messenger'; type ViewedAnnouncement = { [id: number]: boolean; @@ -64,17 +64,15 @@ const metadata: StateMetadata = { announcements: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, }; -export type AnnouncementControllerMessenger = RestrictedMessenger< +export type AnnouncementControllerMessenger = Messenger< typeof controllerName, AnnouncementControllerActions, - AnnouncementControllerEvents, - never, - never + AnnouncementControllerEvents >; /** diff --git a/packages/announcement-controller/tsconfig.build.json b/packages/announcement-controller/tsconfig.build.json index e5fd7422b9a..931c4d6594b 100644 --- a/packages/announcement-controller/tsconfig.build.json +++ b/packages/announcement-controller/tsconfig.build.json @@ -5,6 +5,9 @@ "outDir": "./dist", "rootDir": "./src" }, - "references": [{ "path": "../base-controller/tsconfig.build.json" }], + "references": [ + { "path": "../base-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } + ], "include": ["../../types", "./src"] } diff --git a/packages/announcement-controller/tsconfig.json b/packages/announcement-controller/tsconfig.json index 34354c4b09d..8af2380112d 100644 --- a/packages/announcement-controller/tsconfig.json +++ b/packages/announcement-controller/tsconfig.json @@ -3,6 +3,9 @@ "compilerOptions": { "baseUrl": "./" }, - "references": [{ "path": "../base-controller" }], + "references": [ + { "path": "../base-controller" }, + { "path": "../messenger" } + ], "include": ["../../types", "./src"] } diff --git a/packages/app-metadata-controller/CHANGELOG.md b/packages/app-metadata-controller/CHANGELOG.md index 9d81f5c6ce6..832426e44a6 100644 --- a/packages/app-metadata-controller/CHANGELOG.md +++ b/packages/app-metadata-controller/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6385](https://github.com/MetaMask/core/pull/6385)) + - Previously, `AppMetadataController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/base-controller` from `^8.0.0` to `^8.4.1` ([#5722](https://github.com/MetaMask/core/pull/5722), [#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) ## [1.0.0] diff --git a/packages/app-metadata-controller/package.json b/packages/app-metadata-controller/package.json index 83ca18c71d8..a4a08029618 100644 --- a/packages/app-metadata-controller/package.json +++ b/packages/app-metadata-controller/package.json @@ -47,7 +47,8 @@ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" }, "dependencies": { - "@metamask/base-controller": "^8.4.1" + "@metamask/base-controller": "^8.4.1", + "@metamask/messenger": "^0.3.0" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", diff --git a/packages/app-metadata-controller/src/AppMetadataController.test.ts b/packages/app-metadata-controller/src/AppMetadataController.test.ts index 16c379b1a51..25722e514fd 100644 --- a/packages/app-metadata-controller/src/AppMetadataController.test.ts +++ b/packages/app-metadata-controller/src/AppMetadataController.test.ts @@ -1,9 +1,16 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MockAnyNamespace, +} from '@metamask/messenger'; import { AppMetadataController, getDefaultAppMetadataControllerState, type AppMetadataControllerOptions, + type AppMetadataControllerActions, + type AppMetadataControllerEvents, } from './AppMetadataController'; describe('AppMetadataController', () => { @@ -128,7 +135,7 @@ describe('AppMetadataController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { @@ -219,12 +226,20 @@ function withController( ): ReturnValue { const [options = {}, fn] = args.length === 2 ? args : [{}, args[0]]; - const messenger = new Messenger(); - - const appMetadataControllerMessenger = messenger.getRestricted({ - name: 'AppMetadataController', - allowedActions: [], - allowedEvents: [], + const rootMessenger = new Messenger< + MockAnyNamespace, + AppMetadataControllerActions, + AppMetadataControllerEvents + >({ namespace: MOCK_ANY_NAMESPACE }); + + const appMetadataControllerMessenger = new Messenger< + 'AppMetadataController', + AppMetadataControllerActions, + AppMetadataControllerEvents, + typeof rootMessenger + >({ + namespace: 'AppMetadataController', + parent: rootMessenger, }); return fn({ diff --git a/packages/app-metadata-controller/src/AppMetadataController.ts b/packages/app-metadata-controller/src/AppMetadataController.ts index b71818b7fd6..ffd346aea48 100644 --- a/packages/app-metadata-controller/src/AppMetadataController.ts +++ b/packages/app-metadata-controller/src/AppMetadataController.ts @@ -1,10 +1,10 @@ -import { BaseController } from '@metamask/base-controller'; import type { StateMetadata, ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; +import type { Messenger } from '@metamask/messenger'; // Unique name for the controller const controllerName = 'AppMetadataController'; @@ -88,12 +88,10 @@ type AllowedEvents = never; * @returns A restricted messenger type that defines the allowed actions and events * for the AppMetadataController */ -export type AppMetadataControllerMessenger = RestrictedMessenger< +export type AppMetadataControllerMessenger = Messenger< typeof controllerName, AppMetadataControllerActions | AllowedActions, - AppMetadataControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + AppMetadataControllerEvents | AllowedEvents >; /** @@ -105,25 +103,25 @@ const controllerMetadata = { currentAppVersion: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, previousAppVersion: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, previousMigrationVersion: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, currentMigrationVersion: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, } satisfies StateMetadata; diff --git a/packages/app-metadata-controller/tsconfig.build.json b/packages/app-metadata-controller/tsconfig.build.json index e5fd7422b9a..931c4d6594b 100644 --- a/packages/app-metadata-controller/tsconfig.build.json +++ b/packages/app-metadata-controller/tsconfig.build.json @@ -5,6 +5,9 @@ "outDir": "./dist", "rootDir": "./src" }, - "references": [{ "path": "../base-controller/tsconfig.build.json" }], + "references": [ + { "path": "../base-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } + ], "include": ["../../types", "./src"] } diff --git a/packages/app-metadata-controller/tsconfig.json b/packages/app-metadata-controller/tsconfig.json index 34354c4b09d..68c3ddfc2cd 100644 --- a/packages/app-metadata-controller/tsconfig.json +++ b/packages/app-metadata-controller/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "baseUrl": "./" }, - "references": [{ "path": "../base-controller" }], + "references": [{ "path": "../base-controller" }, { "path": "../messenger" }], "include": ["../../types", "./src"] } diff --git a/packages/approval-controller/CHANGELOG.md b/packages/approval-controller/CHANGELOG.md index fb156a1d799..3139a314369 100644 --- a/packages/approval-controller/CHANGELOG.md +++ b/packages/approval-controller/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6386](https://github.com/MetaMask/core/pull/6386)) + - Previously, `ApprovalController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/utils` from `^11.2.0` to `^11.8.1` ([#6054](https://github.com/MetaMask/core/pull/6054), [#6588](https://github.com/MetaMask/core/pull/6588), [#6708](https://github.com/MetaMask/core/pull/6708)) - Bump `@metamask/base-controller` from `^8.0.0` to `^8.4.1` ([#5722](https://github.com/MetaMask/core/pull/5722), [#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) diff --git a/packages/approval-controller/package.json b/packages/approval-controller/package.json index 958b55a3ae9..1165788f233 100644 --- a/packages/approval-controller/package.json +++ b/packages/approval-controller/package.json @@ -48,6 +48,7 @@ }, "dependencies": { "@metamask/base-controller": "^8.4.1", + "@metamask/messenger": "^0.3.0", "@metamask/rpc-errors": "^7.0.2", "@metamask/utils": "^11.8.1", "nanoid": "^3.3.8" diff --git a/packages/approval-controller/src/ApprovalController.test.ts b/packages/approval-controller/src/ApprovalController.test.ts index e817a38ed56..652a87ba4f3 100644 --- a/packages/approval-controller/src/ApprovalController.test.ts +++ b/packages/approval-controller/src/ApprovalController.test.ts @@ -1,6 +1,13 @@ /* eslint-disable jest/expect-expect */ -import { deriveStateFromMetadata, Messenger } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { errorCodes, JsonRpcError } from '@metamask/rpc-errors'; import { nanoid } from 'nanoid'; @@ -9,6 +16,7 @@ import type { AddApprovalOptions, ApprovalControllerActions, ApprovalControllerEvents, + ApprovalControllerMessenger, ErrorOptions, StartFlowOptions, SuccessOptions, @@ -28,6 +36,12 @@ import { jest.mock('nanoid'); +type AllActions = MessengerActions; + +type AllEvents = MessengerEvents; + +type RootMessenger = Messenger; + const nanoidMock = jest.mocked(nanoid); const PENDING_APPROVALS_STORE_KEY = 'pendingApprovals'; @@ -223,20 +237,26 @@ function getError(message: string, code?: number) { } /** - * Constructs a restricted messenger. + * Constructs a controller messenger. * - * @returns A restricted messenger. + * @returns A controller messenger. */ -function getRestrictedMessenger() { - const messenger = new Messenger< - ApprovalControllerActions, - ApprovalControllerEvents - >(); - return messenger.getRestricted({ - name: 'ApprovalController', - allowedActions: [], - allowedEvents: [], +function getMessengers() { + const rootMessenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, }); + return { + rootMessenger, + approvalControllerMessenger: new Messenger< + typeof controllerName, + ApprovalControllerActions, + ApprovalControllerEvents, + typeof rootMessenger + >({ + namespace: controllerName, + parent: rootMessenger, + }), + }; } describe('approval controller', () => { @@ -250,7 +270,7 @@ describe('approval controller', () => { showApprovalRequest = jest.fn(); approvalController = new ApprovalController({ - messenger: getRestrictedMessenger(), + messenger: getMessengers().approvalControllerMessenger, showApprovalRequest, }); }); @@ -445,7 +465,7 @@ describe('approval controller', () => { it('does not throw on origin and type collision if type excluded', () => { approvalController = new ApprovalController({ - messenger: getRestrictedMessenger(), + messenger: getMessengers().approvalControllerMessenger, showApprovalRequest, typesExcludedFromRateLimiting: ['myType'], }); @@ -638,7 +658,7 @@ describe('approval controller', () => { it('gets the count when specifying origin and type with type excluded from rate limiting', () => { approvalController = new ApprovalController({ - messenger: getRestrictedMessenger(), + messenger: getMessengers().approvalControllerMessenger, showApprovalRequest, typesExcludedFromRateLimiting: [TYPE], }); @@ -678,7 +698,7 @@ describe('approval controller', () => { it('gets the total approval count with type excluded from rate limiting', () => { approvalController = new ApprovalController({ - messenger: getRestrictedMessenger(), + messenger: getMessengers().approvalControllerMessenger, showApprovalRequest, typesExcludedFromRateLimiting: ['type0'], }); @@ -1269,23 +1289,16 @@ describe('approval controller', () => { describe('actions', () => { it('addApprovalRequest: shouldShowRequest = true', async () => { - const messenger = new Messenger< - ApprovalControllerActions, - ApprovalControllerEvents - >(); + const { rootMessenger, approvalControllerMessenger } = getMessengers(); approvalController = new ApprovalController({ - messenger: messenger.getRestricted({ - name: controllerName, - allowedActions: [], - allowedEvents: [], - }), + messenger: approvalControllerMessenger, showApprovalRequest, }); // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/no-floating-promises - messenger.call( + rootMessenger.call( 'ApprovalController:addRequest', { id: 'foo', origin: 'bar.baz', type: TYPE }, true, @@ -1295,23 +1308,16 @@ describe('approval controller', () => { }); it('addApprovalRequest: shouldShowRequest = false', async () => { - const messenger = new Messenger< - ApprovalControllerActions, - ApprovalControllerEvents - >(); + const { rootMessenger, approvalControllerMessenger } = getMessengers(); approvalController = new ApprovalController({ - messenger: messenger.getRestricted({ - name: controllerName, - allowedActions: [], - allowedEvents: [], - }), + messenger: approvalControllerMessenger, showApprovalRequest, }); // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/no-floating-promises - messenger.call( + rootMessenger.call( 'ApprovalController:addRequest', { id: 'foo', origin: 'bar.baz', type: TYPE }, false, @@ -1321,17 +1327,10 @@ describe('approval controller', () => { }); it('updateRequestState', () => { - const messenger = new Messenger< - ApprovalControllerActions, - ApprovalControllerEvents - >(); + const { approvalControllerMessenger } = getMessengers(); approvalController = new ApprovalController({ - messenger: messenger.getRestricted({ - name: controllerName, - allowedActions: [], - allowedEvents: [], - }), + messenger: approvalControllerMessenger, showApprovalRequest, }); @@ -1344,10 +1343,13 @@ describe('approval controller', () => { requestState: { foo: 'bar' }, }); - messenger.call('ApprovalController:updateRequestState', { - id: 'foo', - requestState: { foo: 'foobar' }, - }); + approvalControllerMessenger.call( + 'ApprovalController:updateRequestState', + { + id: 'foo', + requestState: { foo: 'foobar' }, + }, + ); expect(approvalController.get('foo')?.requestState).toStrictEqual({ foo: 'foobar', @@ -1719,7 +1721,7 @@ describe('approval controller', () => { deriveStateFromMetadata( approvalController.state, approvalController.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { diff --git a/packages/approval-controller/src/ApprovalController.ts b/packages/approval-controller/src/ApprovalController.ts index 9f577677cf5..f2e7efe13c3 100644 --- a/packages/approval-controller/src/ApprovalController.ts +++ b/packages/approval-controller/src/ApprovalController.ts @@ -1,9 +1,12 @@ -import type { ControllerGetStateAction } from '@metamask/base-controller'; +import type { + ControllerGetStateAction, + StateMetadata, +} from '@metamask/base-controller/next'; import { BaseController, type ControllerStateChangeEvent, - type RestrictedMessenger, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import type { Messenger } from '@metamask/messenger'; import type { JsonRpcError, DataWithOptionalCause } from '@metamask/rpc-errors'; import { rpcErrors } from '@metamask/rpc-errors'; import type { Json, OptionalField } from '@metamask/utils'; @@ -26,23 +29,23 @@ export const APPROVAL_TYPE_RESULT_SUCCESS = 'result_success'; const controllerName = 'ApprovalController'; -const stateMetadata = { +const stateMetadata: StateMetadata = { pendingApprovals: { includeInStateLogs: true, persist: false, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, pendingApprovalCount: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, approvalFlows: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -134,12 +137,10 @@ export type ApprovalControllerState = { approvalFlows: ApprovalFlowState[]; }; -export type ApprovalControllerMessenger = RestrictedMessenger< +export type ApprovalControllerMessenger = Messenger< typeof controllerName, ApprovalControllerActions, - ApprovalControllerEvents, - never, - never + ApprovalControllerEvents >; // Option Types @@ -413,12 +414,12 @@ export class ApprovalController extends BaseController< * actions. */ private registerMessageHandlers(): void { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:clearRequests` as const, this.clear.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:addRequest` as const, (opts: AddApprovalOptions, shouldShowRequest: boolean) => { if (shouldShowRequest) { @@ -428,47 +429,47 @@ export class ApprovalController extends BaseController< }, ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:hasRequest` as const, this.has.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:acceptRequest` as const, this.accept.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:rejectRequest` as const, this.reject.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:updateRequestState` as const, this.updateRequestState.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:startFlow` as const, this.startFlow.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:endFlow` as const, this.endFlow.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:setFlowLoadingText` as const, this.setFlowLoadingText.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:showSuccess` as const, this.success.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:showError` as const, this.error.bind(this), ); diff --git a/packages/approval-controller/tsconfig.build.json b/packages/approval-controller/tsconfig.build.json index 779d385a6ab..249f327913d 100644 --- a/packages/approval-controller/tsconfig.build.json +++ b/packages/approval-controller/tsconfig.build.json @@ -8,6 +8,9 @@ "references": [ { "path": "../base-controller/tsconfig.build.json" + }, + { + "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] diff --git a/packages/approval-controller/tsconfig.json b/packages/approval-controller/tsconfig.json index f2d7b67ff66..cb296895b28 100644 --- a/packages/approval-controller/tsconfig.json +++ b/packages/approval-controller/tsconfig.json @@ -6,6 +6,9 @@ "references": [ { "path": "../base-controller" + }, + { + "path": "../messenger" } ], "include": ["../../types", "./src"] diff --git a/packages/assets-controllers/CHANGELOG.md b/packages/assets-controllers/CHANGELOG.md index 3657d41ca7b..bae98c18814 100644 --- a/packages/assets-controllers/CHANGELOG.md +++ b/packages/assets-controllers/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add export for `CurrencyRateMessenger` ([#6444](https://github.com/MetaMask/core/pull/6444)) + +### Changed + +- **BREAKING:** Migrate controllers to new `Messenger` from `@metamask/messenger` ([#6444](https://github.com/MetaMask/core/pull/6444), [#6386](https://github.com/MetaMask/core/pull/6386), [#6745](https://github.com/MetaMask/core/pull/6745)) + - Previously, the controllers accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [81.0.0] ### Changed diff --git a/packages/assets-controllers/package.json b/packages/assets-controllers/package.json index eb6374e00ef..07cd9a012c9 100644 --- a/packages/assets-controllers/package.json +++ b/packages/assets-controllers/package.json @@ -59,6 +59,7 @@ "@metamask/controller-utils": "^11.14.1", "@metamask/eth-query": "^4.0.0", "@metamask/keyring-api": "^21.0.0", + "@metamask/messenger": "^0.3.0", "@metamask/metamask-eth-abis": "^3.1.1", "@metamask/polling-controller": "^14.0.1", "@metamask/rpc-errors": "^7.0.2", diff --git a/packages/assets-controllers/src/AccountTrackerController.test.ts b/packages/assets-controllers/src/AccountTrackerController.test.ts index d0e14203c6a..3628a1a7367 100644 --- a/packages/assets-controllers/src/AccountTrackerController.test.ts +++ b/packages/assets-controllers/src/AccountTrackerController.test.ts @@ -1,6 +1,13 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { query, toChecksumHexAddress } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { type NetworkClientId, type NetworkClientConfiguration, @@ -10,26 +17,30 @@ import { getDefaultPreferencesState } from '@metamask/preferences-controller'; import BN from 'bn.js'; import { useFakeTimers, type SinonFakeTimers } from 'sinon'; -import type { - AccountTrackerControllerMessenger, - AllowedActions, - AllowedEvents, -} from './AccountTrackerController'; +import type { AccountTrackerControllerMessenger } from './AccountTrackerController'; import { AccountTrackerController } from './AccountTrackerController'; import { AccountsApiBalanceFetcher } from './multi-chain-accounts-service/api-balance-fetcher'; import { getTokenBalancesForMultipleAddresses } from './multicall'; import { FakeProvider } from '../../../tests/fake-provider'; import { advanceTime } from '../../../tests/helpers'; import { createMockInternalAccount } from '../../accounts-controller/src/tests/mocks'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../base-controller/tests/helpers'; import { buildCustomNetworkClientConfiguration, buildMockGetNetworkClientById, } from '../../network-controller/tests/helpers'; +type AllAccountTrackerControllerActions = + MessengerActions; + +type AllAccountTrackerControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllAccountTrackerControllerActions, + AllAccountTrackerControllerEvents +>; + jest.mock('@metamask/controller-utils', () => { return { ...jest.requireActual('@metamask/controller-utils'), @@ -1282,7 +1293,7 @@ describe('AccountTrackerController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); @@ -1385,10 +1396,9 @@ async function withController( testFunction, ] = args.length === 2 ? args : [{}, args[0]]; - const messenger = new Messenger< - ExtractAvailableAction | AllowedActions, - ExtractAvailableEvent | AllowedEvents - >(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const mockGetSelectedAccount = jest.fn().mockReturnValue(selectedAccount); messenger.registerActionHandler( @@ -1494,16 +1504,25 @@ async function withController( mockNetworkState, ); - const accountTrackerMessenger = messenger.getRestricted({ - name: 'AccountTrackerController', - allowedActions: [ + const accountTrackerMessenger = new Messenger< + 'AccountTrackerController', + AllAccountTrackerControllerActions, + AllAccountTrackerControllerEvents, + RootMessenger + >({ + namespace: 'AccountTrackerController', + parent: messenger, + }); + messenger.delegate({ + messenger: accountTrackerMessenger, + actions: [ 'NetworkController:getNetworkClientById', 'NetworkController:getState', 'PreferencesController:getState', 'AccountsController:getSelectedAccount', 'AccountsController:listAccounts', ], - allowedEvents: ['AccountsController:selectedEvmAccountChange'], + events: ['AccountsController:selectedEvmAccountChange'], }); const triggerSelectedAccountChange = (account: InternalAccount) => { diff --git a/packages/assets-controllers/src/AccountTrackerController.ts b/packages/assets-controllers/src/AccountTrackerController.ts index cd704374660..6832f784b7d 100644 --- a/packages/assets-controllers/src/AccountTrackerController.ts +++ b/packages/assets-controllers/src/AccountTrackerController.ts @@ -8,14 +8,15 @@ import type { import type { ControllerStateChangeEvent, ControllerGetStateAction, - RestrictedMessenger, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { query, safelyExecuteWithTimeout, toChecksumHexAddress, } from '@metamask/controller-utils'; import EthQuery from '@metamask/eth-query'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkClient, NetworkClientId, @@ -120,11 +121,11 @@ export type AccountTrackerControllerState = { accountsByChainId: Record; }; -const accountTrackerMetadata = { +const accountTrackerMetadata: StateMetadata = { accountsByChainId: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -196,12 +197,10 @@ export type AllowedEvents = /** * The messenger of the {@link AccountTrackerController}. */ -export type AccountTrackerControllerMessenger = RestrictedMessenger< +export type AccountTrackerControllerMessenger = Messenger< typeof controllerName, AccountTrackerControllerActions | AllowedActions, - AccountTrackerControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + AccountTrackerControllerEvents | AllowedEvents >; /** The input to start polling for the {@link AccountTrackerController} */ @@ -234,7 +233,7 @@ export class AccountTrackerController extends StaticIntervalPollingController { if (newAddress !== prevAddress) { @@ -313,12 +312,12 @@ export class AccountTrackerController extends StaticIntervalPollingController toChecksumHexAddress(internalAccount.address), @@ -372,12 +371,12 @@ export class AccountTrackerController extends StaticIntervalPollingController { - const { networkConfigurationsByChainId } = this.messagingSystem.call( + const { networkConfigurationsByChainId } = this.messenger.call( 'NetworkController:getState', ); const cfg = networkConfigurationsByChainId[chainId]; const { networkClientId } = cfg.rpcEndpoints[cfg.defaultRpcEndpointIndex]; - const client = this.messagingSystem.call( + const client = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -385,12 +384,12 @@ export class AccountTrackerController extends StaticIntervalPollingController { - const { networkConfigurationsByChainId } = this.messagingSystem.call( + const { networkConfigurationsByChainId } = this.messenger.call( 'NetworkController:getState', ); const cfg = networkConfigurationsByChainId[chainId]; const { networkClientId } = cfg.rpcEndpoints[cfg.defaultRpcEndpointIndex]; - return this.messagingSystem.call( + return this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -431,13 +430,12 @@ export class AccountTrackerController extends StaticIntervalPollingController; + +type AllAssetsContractControllerEvents = + MessengerEvents; + +type AllNetworkControllerActions = MessengerActions; + +type AllNetworkControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllAssetsContractControllerActions | AllNetworkControllerActions, + AllAssetsContractControllerEvents | AllNetworkControllerEvents +>; + const ERC20_UNI_ADDRESS = '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984'; const ERC20_SAI_ADDRESS = '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359'; const ERC20_DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f'; @@ -80,18 +97,19 @@ async function setupAssetContractControllers({ }; let provider: Provider; - const messenger = new Messenger< - | ExtractAvailableAction - | NetworkControllerActions, - | ExtractAvailableEvent - | NetworkControllerEvents - >(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const networkController = new NetworkController({ infuraProjectId, - messenger: messenger.getRestricted({ - name: 'NetworkController', - allowedActions: [], - allowedEvents: [], + messenger: new Messenger< + 'NetworkController', + MessengerActions, + MessengerEvents, + RootMessenger + >({ + namespace: 'NetworkController', + parent: messenger, }), getRpcServiceOptions: () => ({ fetch, @@ -121,15 +139,24 @@ async function setupAssetContractControllers({ }), ); - const assetsContractMessenger = messenger.getRestricted({ - name: 'AssetsContractController', - allowedActions: [ + const assetsContractMessenger = new Messenger< + 'AssetsContractController', + MessengerActions, + MessengerEvents, + RootMessenger + >({ + namespace: 'AssetsContractController', + parent: messenger, + }); + messenger.delegate({ + messenger: assetsContractMessenger, + actions: [ 'NetworkController:getNetworkClientById', 'NetworkController:getNetworkConfigurationByNetworkClientId', 'NetworkController:getSelectedNetworkClient', 'NetworkController:getState', ], - allowedEvents: [ + events: [ 'PreferencesController:stateChange', 'NetworkController:networkDidChange', ], diff --git a/packages/assets-controllers/src/AssetsContractController.ts b/packages/assets-controllers/src/AssetsContractController.ts index 64cf7a77536..0cd4c42ab57 100644 --- a/packages/assets-controllers/src/AssetsContractController.ts +++ b/packages/assets-controllers/src/AssetsContractController.ts @@ -2,11 +2,8 @@ import type { BigNumber } from '@ethersproject/bignumber'; import { Contract } from '@ethersproject/contracts'; import { Web3Provider } from '@ethersproject/providers'; -import type { - ActionConstraint, - RestrictedMessenger, -} from '@metamask/base-controller'; import { IPFS_DEFAULT_GATEWAY_URL } from '@metamask/controller-utils'; +import type { Messenger, ActionConstraint } from '@metamask/messenger'; import type { NetworkClientId, NetworkControllerGetNetworkClientByIdAction, @@ -207,12 +204,10 @@ export type AllowedEvents = /** * The messenger of the {@link AssetsContractController}. */ -export type AssetsContractControllerMessenger = RestrictedMessenger< +export type AssetsContractControllerMessenger = Messenger< typeof name, AssetsContractControllerActions | AllowedActions, - AssetsContractControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + AssetsContractControllerEvents | AllowedEvents >; export type StakedBalance = string | undefined; diff --git a/packages/assets-controllers/src/CurrencyRateController.test.ts b/packages/assets-controllers/src/CurrencyRateController.test.ts index ce7e559b7a5..e11d7683785 100644 --- a/packages/assets-controllers/src/CurrencyRateController.test.ts +++ b/packages/assets-controllers/src/CurrencyRateController.test.ts @@ -1,32 +1,44 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { ChainId, NetworkType, NetworksTicker, } from '@metamask/controller-utils'; -import type { NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import nock from 'nock'; import { useFakeTimers } from 'sinon'; import { advanceTime } from '../../../tests/helpers'; -import type { - CurrencyRateStateChange, - GetCurrencyRateState, -} from './CurrencyRateController'; +import type { CurrencyRateMessenger } from './CurrencyRateController'; import { CurrencyRateController } from './CurrencyRateController'; -const name = 'CurrencyRateController' as const; +const namespace = 'CurrencyRateController' as const; + +type AllCurrencyRateControllerActions = MessengerActions; + +type AllCurrencyRateControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllCurrencyRateControllerActions, + AllCurrencyRateControllerEvents +>; /** - * Constructs a restricted messenger. + * Constructs a messenger for CurrencyRateController. * - * @returns A restricted messenger. + * @returns A controller messenger. */ -function getRestrictedMessenger() { - const messenger = new Messenger< - GetCurrencyRateState | NetworkControllerGetNetworkClientByIdAction, - CurrencyRateStateChange - >(); +function getCurrencyRateControllerMessenger(): CurrencyRateMessenger { + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); messenger.registerActionHandler( 'NetworkController:getNetworkClientById', jest.fn().mockImplementation((networkClientId) => { @@ -52,14 +64,19 @@ function getRestrictedMessenger() { } }), ); - return messenger.getRestricted< - typeof name, - NetworkControllerGetNetworkClientByIdAction['type'] + const currencyRateControllerMessenger = new Messenger< + typeof namespace, + AllCurrencyRateControllerActions, + AllCurrencyRateControllerEvents, + RootMessenger >({ - name, - allowedActions: ['NetworkController:getNetworkClientById'], - allowedEvents: [], + namespace, + }); + messenger.delegate({ + messenger: currencyRateControllerMessenger, + actions: ['NetworkController:getNetworkClientById'], }); + return currencyRateControllerMessenger; } const getStubbedDate = () => { @@ -77,7 +94,7 @@ describe('CurrencyRateController', () => { }); it('should set default state', () => { - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ messenger }); expect(controller.state).toStrictEqual({ @@ -95,7 +112,7 @@ describe('CurrencyRateController', () => { }); it('should initialize with initial state', () => { - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const existingState = { currentCurrency: 'rep' }; const controller = new CurrencyRateController({ messenger, @@ -118,7 +135,7 @@ describe('CurrencyRateController', () => { it('should not poll before being started', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ interval: 100, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -150,7 +167,7 @@ describe('CurrencyRateController', () => { usd: 22, }, }); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ interval: 100, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -188,7 +205,7 @@ describe('CurrencyRateController', () => { it('should not poll after being stopped', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ interval: 100, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -214,7 +231,7 @@ describe('CurrencyRateController', () => { it('should poll correctly after being started, stopped, and started again', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ interval: 100, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -245,7 +262,7 @@ describe('CurrencyRateController', () => { const fetchMultiExchangeRateStub = jest .fn() .mockResolvedValue({ eth: { [currentCurrency]: 10, usd: 111 } }); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ interval: 10, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -297,7 +314,7 @@ describe('CurrencyRateController', () => { }, }; }); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ fetchMultiExchangeRate: fetchMultiExchangeRateStub, messenger, @@ -337,7 +354,7 @@ describe('CurrencyRateController', () => { eth: { [currentCurrency]: 10, usd: 11 }, btc: { [currentCurrency]: 10, usd: 11 }, }); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ interval: 10, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -394,7 +411,7 @@ describe('CurrencyRateController', () => { it('should add usd rate to state when includeUsdRate is configured true', async () => { const fetchMultiExchangeRateStub = jest.fn().mockResolvedValue({}); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ includeUsdRate: true, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -418,7 +435,7 @@ describe('CurrencyRateController', () => { .get('/data/pricemulti?fsyms=ETH&tsyms=xyz') .reply(200, { ETH: { XYZ: 2000.42 } }) .persist(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ messenger, state: { currentCurrency: 'xyz' }, @@ -450,7 +467,7 @@ describe('CurrencyRateController', () => { }) .persist(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ messenger, state: { currentCurrency: 'xyz' }, @@ -480,7 +497,7 @@ describe('CurrencyRateController', () => { }, }, }; - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ messenger, state }); // Error should still be thrown @@ -505,7 +522,7 @@ describe('CurrencyRateController', () => { POL: { XYZ: 0.3 }, }) .persist(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ messenger, state: { currentCurrency: 'xyz' }, @@ -548,7 +565,7 @@ describe('CurrencyRateController', () => { }) .persist(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ messenger, state: { currentCurrency: 'xyz' }, @@ -576,7 +593,7 @@ describe('CurrencyRateController', () => { describe('useExternalServices', () => { it('should not fetch exchange rates when useExternalServices is false', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => false, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -600,7 +617,7 @@ describe('CurrencyRateController', () => { it('should not poll when useExternalServices is false', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => false, interval: 100, @@ -623,7 +640,7 @@ describe('CurrencyRateController', () => { it('should not fetch exchange rates when useExternalServices is false even with multiple currencies', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => false, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -647,7 +664,7 @@ describe('CurrencyRateController', () => { it('should not fetch exchange rates when useExternalServices is false even with testnet currencies', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => false, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -671,7 +688,7 @@ describe('CurrencyRateController', () => { it('should not fetch exchange rates when useExternalServices is false even with includeUsdRate true', async () => { const fetchMultiExchangeRateStub = jest.fn(); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => false, includeUsdRate: true, @@ -699,7 +716,7 @@ describe('CurrencyRateController', () => { const fetchMultiExchangeRateStub = jest .fn() .mockResolvedValue({ eth: { usd: 2000, eur: 1800 } }); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => true, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -731,7 +748,7 @@ describe('CurrencyRateController', () => { const fetchMultiExchangeRateStub = jest .fn() .mockResolvedValue({ eth: { usd: 2000, gbp: 1600 } }); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ fetchMultiExchangeRate: fetchMultiExchangeRateStub, messenger, @@ -761,7 +778,7 @@ describe('CurrencyRateController', () => { const fetchMultiExchangeRateStub = jest .fn() .mockRejectedValue(new Error('API Error')); - const messenger = getRestrictedMessenger(); + const messenger = getCurrencyRateControllerMessenger(); const controller = new CurrencyRateController({ useExternalServices: () => false, fetchMultiExchangeRate: fetchMultiExchangeRateStub, @@ -781,14 +798,14 @@ describe('CurrencyRateController', () => { describe('metadata', () => { it('includes expected state in debug snapshots', () => { const controller = new CurrencyRateController({ - messenger: getRestrictedMessenger(), + messenger: getCurrencyRateControllerMessenger(), }); expect( deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { @@ -806,7 +823,7 @@ describe('CurrencyRateController', () => { it('includes expected state in state logs', () => { const controller = new CurrencyRateController({ - messenger: getRestrictedMessenger(), + messenger: getCurrencyRateControllerMessenger(), }); expect( @@ -831,7 +848,7 @@ describe('CurrencyRateController', () => { it('persists expected state', () => { const controller = new CurrencyRateController({ - messenger: getRestrictedMessenger(), + messenger: getCurrencyRateControllerMessenger(), }); expect( @@ -856,7 +873,7 @@ describe('CurrencyRateController', () => { it('exposes expected state to UI', () => { const controller = new CurrencyRateController({ - messenger: getRestrictedMessenger(), + messenger: getCurrencyRateControllerMessenger(), }); expect( diff --git a/packages/assets-controllers/src/CurrencyRateController.ts b/packages/assets-controllers/src/CurrencyRateController.ts index 9827eb2ea67..a116e8ac337 100644 --- a/packages/assets-controllers/src/CurrencyRateController.ts +++ b/packages/assets-controllers/src/CurrencyRateController.ts @@ -1,12 +1,13 @@ import type { - RestrictedMessenger, ControllerGetStateAction, ControllerStateChangeEvent, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { TESTNET_TICKER_SYMBOLS, FALL_BACK_VS_CURRENCY, } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller'; import { StaticIntervalPollingController } from '@metamask/polling-controller'; import { Mutex } from 'async-mutex'; @@ -51,25 +52,23 @@ export type CurrencyRateControllerActions = GetCurrencyRateState; type AllowedActions = NetworkControllerGetNetworkClientByIdAction; -type CurrencyRateMessenger = RestrictedMessenger< +export type CurrencyRateMessenger = Messenger< typeof name, CurrencyRateControllerActions | AllowedActions, - CurrencyRateControllerEvents, - AllowedActions['type'], - never + CurrencyRateControllerEvents >; -const metadata = { +const metadata: StateMetadata = { currentCurrency: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, currencyRates: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, }; @@ -113,7 +112,7 @@ export class CurrencyRateController extends StaticIntervalPollingController, - ExtractAvailableEvent +type AllDefiPositionsControllerActions = + MessengerActions; + +type AllDefiPositionsControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllDefiPositionsControllerActions, + AllDefiPositionsControllerEvents >; /** @@ -65,7 +74,9 @@ function setupController({ mockCalculateDefiMetrics?: jest.Mock; mockTrackEvent?: jest.Mock; } = {}) { - const messenger: MainMessenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const mockListAccounts = jest.fn().mockReturnValue(OWNER_ACCOUNTS); messenger.registerActionHandler( @@ -73,10 +84,19 @@ function setupController({ mockListAccounts, ); - const restrictedMessenger = messenger.getRestricted({ - name: 'DeFiPositionsController', - allowedActions: ['AccountsController:listAccounts'], - allowedEvents: [ + const defiPositionControllerMessenger = new Messenger< + 'DeFiPositionsController', + AllDefiPositionsControllerActions, + AllDefiPositionsControllerEvents, + RootMessenger + >({ + namespace: 'DeFiPositionsController', + parent: messenger, + }); + messenger.delegate({ + messenger: defiPositionControllerMessenger, + actions: ['AccountsController:listAccounts'], + events: [ 'KeyringController:unlock', 'KeyringController:lock', 'TransactionController:transactionConfirmed', @@ -105,7 +125,7 @@ function setupController({ groupDeFiPositionsSpy.mockImplementation(mockGroupDeFiPositions); const controller = new DeFiPositionsController({ - messenger: restrictedMessenger, + messenger: defiPositionControllerMessenger, isEnabled, trackEvent: mockTrackEvent, }); @@ -512,7 +532,7 @@ describe('DeFiPositionsController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/assets-controllers/src/DeFiPositionsController/DeFiPositionsController.ts b/packages/assets-controllers/src/DeFiPositionsController/DeFiPositionsController.ts index 53a61974e25..9b53e15443c 100644 --- a/packages/assets-controllers/src/DeFiPositionsController/DeFiPositionsController.ts +++ b/packages/assets-controllers/src/DeFiPositionsController/DeFiPositionsController.ts @@ -5,11 +5,11 @@ import type { import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, StateMetadata, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; import type { KeyringControllerUnlockEvent } from '@metamask/keyring-controller'; import type { KeyringControllerLockEvent } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import { StaticIntervalPollingController } from '@metamask/polling-controller'; import type { TransactionControllerTransactionConfirmedEvent } from '@metamask/transaction-controller'; import type { Hex } from '@metamask/utils'; @@ -70,13 +70,13 @@ const controllerMetadata: StateMetadata = { allDeFiPositions: { includeInStateLogs: false, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, allDeFiPositionsCount: { includeInStateLogs: false, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, }; @@ -123,12 +123,10 @@ export type AllowedEvents = /** * The messenger of the {@link DeFiPositionsController}. */ -export type DeFiPositionsControllerMessenger = RestrictedMessenger< +export type DeFiPositionsControllerMessenger = Messenger< typeof controllerName, DeFiPositionsControllerActions | AllowedActions, - DeFiPositionsControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + DeFiPositionsControllerEvents | AllowedEvents >; /** @@ -176,15 +174,15 @@ export class DeFiPositionsController extends StaticIntervalPollingController()< this.#fetchPositions = buildPositionFetcher(); this.#isEnabled = isEnabled; - this.messagingSystem.subscribe('KeyringController:unlock', () => { + this.messenger.subscribe('KeyringController:unlock', () => { this.startPolling(null); }); - this.messagingSystem.subscribe('KeyringController:lock', () => { + this.messenger.subscribe('KeyringController:lock', () => { this.stopAllPolling(); }); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TransactionController:transactionConfirmed', async (transactionMeta) => { if (!this.#isEnabled()) { @@ -195,7 +193,7 @@ export class DeFiPositionsController extends StaticIntervalPollingController()< }, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountAdded', async (account) => { if (!this.#isEnabled() || !account.type.startsWith('eip155:')) { @@ -214,9 +212,7 @@ export class DeFiPositionsController extends StaticIntervalPollingController()< return; } - const accounts = this.messagingSystem.call( - 'AccountsController:listAccounts', - ); + const accounts = this.messenger.call('AccountsController:listAccounts'); const initialResult: { accountAddress: string; diff --git a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.test.ts b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.test.ts index 9f07e38a6ab..1bc95642ae5 100644 --- a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.test.ts +++ b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.test.ts @@ -1,4 +1,4 @@ -import { deriveStateFromMetadata, Messenger } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import type { AccountAssetListUpdatedEventPayload, CaipAssetTypeOrId, @@ -11,6 +11,13 @@ import { } from '@metamask/keyring-api'; import { KeyringTypes } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { PermissionConstraint } from '@metamask/permission-controller'; import type { SubjectPermissions } from '@metamask/permission-controller'; import type { Snap } from '@metamask/snaps-utils'; @@ -27,10 +34,6 @@ import type { MultichainAssetsControllerState, } from './MultichainAssetsController'; import { advanceTime } from '../../../../tests/helpers'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../../base-controller/tests/helpers'; const mockSolanaAccount: InternalAccount = { type: 'solana:data-account', @@ -216,21 +219,26 @@ const mockGetMetadataReturnValue: AssetMetadataResponse | undefined = { /** * The union of actions that the root messenger allows. */ -type RootAction = ExtractAvailableAction; +type RootAction = MessengerActions; /** * The union of events that the root messenger allows. */ -type RootEvent = ExtractAvailableEvent; +type RootEvent = MessengerEvents; + +/** + * The root messenger type. + */ +type RootMessenger = Messenger; /** - * Constructs the unrestricted messenger. This can be used to call actions and + * Constructs the root messenger. This can be used to call actions and * publish events within the tests for this controller. * - * @returns The unrestricted messenger suited for MultichainAssetsController. + * @returns The root messenger suited for MultichainAssetsController. */ -function getRootMessenger(): Messenger { - return new Messenger(); +function getRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } const setupController = ({ @@ -248,20 +256,24 @@ const setupController = ({ const messenger = getRootMessenger(); const multichainAssetsControllerMessenger: MultichainAssetsControllerMessenger = - messenger.getRestricted({ - name: 'MultichainAssetsController', - allowedActions: [ - 'AccountsController:listMultichainAccounts', - 'SnapController:handleRequest', - 'SnapController:getAll', - 'PermissionController:getPermissions', - ], - allowedEvents: [ - 'AccountsController:accountAdded', - 'AccountsController:accountRemoved', - 'AccountsController:accountAssetListUpdated', - ], + new Messenger({ + namespace: 'MultichainAssetsController', + parent: messenger, }); + messenger.delegate({ + messenger: multichainAssetsControllerMessenger, + actions: [ + 'AccountsController:listMultichainAccounts', + 'SnapController:handleRequest', + 'SnapController:getAll', + 'PermissionController:getPermissions', + ], + events: [ + 'AccountsController:accountAdded', + 'AccountsController:accountRemoved', + 'AccountsController:accountAssetListUpdated', + ], + }); const mockSnapHandleRequest = jest.fn(); messenger.registerActionHandler( @@ -827,7 +839,7 @@ describe('MultichainAssetsController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts index 5b477a83c70..81358d1378a 100644 --- a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts +++ b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts @@ -8,8 +8,8 @@ import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, - type RestrictedMessenger, -} from '@metamask/base-controller'; + type StateMetadata, +} from '@metamask/base-controller/next'; import { isEvmAccountType } from '@metamask/keyring-api'; import type { AccountAssetListUpdatedEventPayload, @@ -18,6 +18,7 @@ import type { } from '@metamask/keyring-api'; import type { InternalAccount } from '@metamask/keyring-internal-api'; import { KeyringClient } from '@metamask/keyring-snap-client'; +import type { Messenger } from '@metamask/messenger'; import type { GetPermissions, PermissionConstraint, @@ -141,12 +142,10 @@ type AllowedEvents = /** * Messenger type for the MultichainAssetsController. */ -export type MultichainAssetsControllerMessenger = RestrictedMessenger< +export type MultichainAssetsControllerMessenger = Messenger< typeof controllerName, MultichainAssetsControllerActions | AllowedActions, - MultichainAssetsControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + MultichainAssetsControllerEvents | AllowedEvents >; /** @@ -156,20 +155,21 @@ export type MultichainAssetsControllerMessenger = RestrictedMessenger< * using the `persist` flag; and if they can be sent to Sentry or not, using * the `anonymous` flag. */ -const assetsControllerMetadata = { - assetsMetadata: { - includeInStateLogs: false, - persist: true, - anonymous: false, - usedInUi: true, - }, - accountsAssets: { - includeInStateLogs: false, - persist: true, - anonymous: false, - usedInUi: true, - }, -}; +const assetsControllerMetadata: StateMetadata = + { + assetsMetadata: { + includeInStateLogs: false, + persist: true, + includeInDebugSnapshot: false, + usedInUi: true, + }, + accountsAssets: { + includeInStateLogs: false, + persist: true, + includeInDebugSnapshot: false, + usedInUi: true, + }, + }; // TODO: make this controller extends StaticIntervalPollingController and update all assetsMetadata once a day. @@ -202,15 +202,15 @@ export class MultichainAssetsController extends BaseController< this.#snaps = {}; - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountAdded', async (account) => await this.#handleOnAccountAddedEvent(account), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountRemoved', async (account) => await this.#handleOnAccountRemovedEvent(account), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountAssetListUpdated', async (event) => await this.#handleAccountAssetListUpdatedEvent(event), ); @@ -237,7 +237,7 @@ export class MultichainAssetsController extends BaseController< * actions. */ #registerMessageHandlers() { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( 'MultichainAssetsController:getAssetMetadata', this.getAssetMetadata.bind(this), ); @@ -323,7 +323,7 @@ export class MultichainAssetsController extends BaseController< // Trigger fetching metadata for new assets await this.#refreshAssetsMetadata(Array.from(assetsForMetadataRefresh)); - this.messagingSystem.publish(`${controllerName}:accountAssetListUpdated`, { + this.messenger.publish(`${controllerName}:accountAssetListUpdated`, { assets: accountsAndAssetsToUpdate, }); } @@ -364,17 +364,14 @@ export class MultichainAssetsController extends BaseController< this.update((state) => { state.accountsAssets[account.id] = assets; }); - this.messagingSystem.publish( - `${controllerName}:accountAssetListUpdated`, - { - assets: { - [account.id]: { - added: assets, - removed: [], - }, + this.messenger.publish(`${controllerName}:accountAssetListUpdated`, { + assets: { + [account.id]: { + added: assets, + removed: [], }, }, - ); + }); } } @@ -510,7 +507,7 @@ export class MultichainAssetsController extends BaseController< */ #getAllSnaps(): Snap[] { // TODO: Use dedicated SnapController's action once available for this: - return this.messagingSystem + return this.messenger .call('SnapController:getAll') .filter((snap) => snap.enabled && !snap.blocked); } @@ -524,7 +521,7 @@ export class MultichainAssetsController extends BaseController< #getSnapsPermissions( origin: string, ): SubjectPermissions { - return this.messagingSystem.call( + return this.messenger.call( 'PermissionController:getPermissions', origin, ) as SubjectPermissions; @@ -542,7 +539,7 @@ export class MultichainAssetsController extends BaseController< snapId: string, ): Promise { try { - return (await this.messagingSystem.call('SnapController:handleRequest', { + return (await this.messenger.call('SnapController:handleRequest', { snapId: snapId as SnapId, origin: 'metamask', handler: HandlerType.OnAssetsLookup, @@ -584,7 +581,7 @@ export class MultichainAssetsController extends BaseController< #getClient(snapId: string): KeyringClient { return new KeyringClient({ send: async (request: JsonRpcRequest) => - (await this.messagingSystem.call('SnapController:handleRequest', { + (await this.messenger.call('SnapController:handleRequest', { snapId: snapId as SnapId, origin: 'metamask', handler: HandlerType.OnKeyringRequest, diff --git a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.test.ts b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.test.ts index d2d013dd557..7ce1cdc7b9c 100644 --- a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.test.ts +++ b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.test.ts @@ -1,21 +1,37 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { SolScope } from '@metamask/keyring-api'; import { SolMethod } from '@metamask/keyring-api'; import { SolAccountType } from '@metamask/keyring-api'; import { KeyringTypes } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; import { KeyringClient } from '@metamask/keyring-snap-client'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { OnAssetHistoricalPriceResponse } from '@metamask/snaps-sdk'; import { useFakeTimers } from 'sinon'; import { v4 as uuidv4 } from 'uuid'; import { MultichainAssetsRatesController } from '.'; -import { - type AllowedActions, - type AllowedEvents, -} from './MultichainAssetsRatesController'; +import { type MultichainAssetsRatesControllerMessenger } from './MultichainAssetsRatesController'; import { advanceTime } from '../../../../tests/helpers'; +type AllMultichainAssetsRateControllerActions = + MessengerActions; + +type AllMultichainAssetsRateControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllMultichainAssetsRateControllerActions, + AllMultichainAssetsRateControllerEvents +>; + // A fake non‑EVM account (with Snap metadata) that meets the controller’s criteria. const fakeNonEvmAccount: InternalAccount = { id: 'account1', @@ -118,7 +134,9 @@ const setupController = ({ >; accountsAssets?: InternalAccount[]; } = {}) => { - const messenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); messenger.registerActionHandler( 'MultichainAssetsController:getState', @@ -155,16 +173,25 @@ const setupController = ({ currentCurrency: 'USD', })); - const multichainAssetsRatesControllerMessenger = messenger.getRestricted({ - name: 'MultichainAssetsRatesController', - allowedActions: [ + const multichainAssetsRatesControllerMessenger: Messenger< + 'MultichainAssetsRatesController', + AllMultichainAssetsRateControllerActions, + AllMultichainAssetsRateControllerEvents, + RootMessenger + > = new Messenger({ + namespace: 'MultichainAssetsRatesController', + parent: messenger, + }); + messenger.delegate({ + messenger: multichainAssetsRatesControllerMessenger, + actions: [ 'AccountsController:listMultichainAccounts', 'SnapController:handleRequest', 'CurrencyRateController:getState', 'MultichainAssetsController:getState', 'AccountsController:getSelectedMultichainAccount', ], - allowedEvents: [ + events: [ 'AccountsController:accountAdded', 'KeyringController:lock', 'KeyringController:unlock', @@ -913,7 +940,9 @@ describe('MultichainAssetsRatesController', () => { }; // Set up controller with custom accounts and assets configuration - const messenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); // Mock MultichainAssetsController state with one account having no assets messenger.registerActionHandler( @@ -970,24 +999,35 @@ describe('MultichainAssetsRatesController', () => { snapHandler, ); + const multichainAssetsRatesControllerMessenger = new Messenger< + 'MultichainAssetsRatesController', + AllMultichainAssetsRateControllerActions, + AllMultichainAssetsRateControllerEvents, + RootMessenger + >({ + namespace: 'MultichainAssetsRatesController', + parent: messenger, + }); + messenger.delegate({ + messenger: multichainAssetsRatesControllerMessenger, + actions: [ + 'MultichainAssetsController:getState', + 'AccountsController:listMultichainAccounts', + 'AccountsController:getSelectedMultichainAccount', + 'CurrencyRateController:getState', + 'SnapController:handleRequest', + ], + events: [ + 'KeyringController:lock', + 'KeyringController:unlock', + 'AccountsController:accountAdded', + 'CurrencyRateController:stateChange', + 'MultichainAssetsController:accountAssetListUpdated', + ], + }); + const controller = new MultichainAssetsRatesController({ - messenger: messenger.getRestricted({ - name: 'MultichainAssetsRatesController', - allowedActions: [ - 'MultichainAssetsController:getState', - 'AccountsController:listMultichainAccounts', - 'AccountsController:getSelectedMultichainAccount', - 'CurrencyRateController:getState', - 'SnapController:handleRequest', - ], - allowedEvents: [ - 'KeyringController:lock', - 'KeyringController:unlock', - 'AccountsController:accountAdded', - 'CurrencyRateController:stateChange', - 'MultichainAssetsController:accountAssetListUpdated', - ], - }), + messenger: multichainAssetsRatesControllerMessenger, }); await controller.updateAssetsRates(); @@ -1040,7 +1080,7 @@ describe('MultichainAssetsRatesController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { diff --git a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts index c25a861087e..4aa863496d0 100644 --- a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts +++ b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts @@ -4,16 +4,17 @@ import type { AccountsControllerGetSelectedMultichainAccountAction, } from '@metamask/accounts-controller'; import type { - RestrictedMessenger, ControllerStateChangeEvent, ControllerGetStateAction, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { type CaipAssetType, isEvmAccountType } from '@metamask/keyring-api'; import type { KeyringControllerLockEvent, KeyringControllerUnlockEvent, } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import type { Messenger } from '@metamask/messenger'; import { StaticIntervalPollingController } from '@metamask/polling-controller'; import type { HandleSnapRequest } from '@metamask/snaps-controllers'; import type { @@ -144,12 +145,10 @@ export type AllowedEvents = /** * Messenger type for the MultichainAssetsRatesController. */ -export type MultichainAssetsRatesControllerMessenger = RestrictedMessenger< +export type MultichainAssetsRatesControllerMessenger = Messenger< typeof controllerName, MultichainAssetsRatesControllerActions | AllowedActions, - MultichainAssetsRatesControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + MultichainAssetsRatesControllerEvents | AllowedEvents >; /** @@ -159,17 +158,17 @@ export type MultichainAssetsRatesPollingInput = { accountId: string; }; -const metadata = { +const metadata: StateMetadata = { conversionRates: { includeInStateLogs: false, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, historicalPrices: { includeInStateLogs: false, persist: false, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, }; @@ -205,7 +204,7 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro * @param options - Constructor options. * @param options.interval - The polling interval in milliseconds. * @param options.state - The initial state. - * @param options.messenger - A reference to the messaging system. + * @param options.messenger - A reference to the messenger. */ constructor({ interval = 18000, @@ -229,22 +228,22 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro this.setIntervalLength(interval); // Subscribe to keyring lock/unlock events. - this.messagingSystem.subscribe('KeyringController:lock', () => { + this.messenger.subscribe('KeyringController:lock', () => { this.#isUnlocked = false; }); - this.messagingSystem.subscribe('KeyringController:unlock', () => { + this.messenger.subscribe('KeyringController:unlock', () => { this.#isUnlocked = true; }); - ({ accountsAssets: this.#accountsAssets } = this.messagingSystem.call( + ({ accountsAssets: this.#accountsAssets } = this.messenger.call( 'MultichainAssetsController:getState', )); - ({ currentCurrency: this.#currentCurrency } = this.messagingSystem.call( + ({ currentCurrency: this.#currentCurrency } = this.messenger.call( 'CurrencyRateController:getState', )); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'CurrencyRateController:stateChange', async (currentCurrency: string) => { this.#currentCurrency = currentCurrency; @@ -254,7 +253,7 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro currencyRateControllerState.currentCurrency, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'MultichainAssetsController:accountAssetListUpdated', async ({ assets }) => { const newAccountAssets = Object.entries(assets).map( @@ -305,9 +304,7 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro * @returns An array of internal accounts. */ #listMultichainAccounts(): InternalAccount[] { - return this.messagingSystem.call( - 'AccountsController:listMultichainAccounts', - ); + return this.messenger.call('AccountsController:listMultichainAccounts'); } /** @@ -435,11 +432,9 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro const selectedAccount = account ?? - this.messagingSystem.call( - 'AccountsController:getSelectedMultichainAccount', - ); + this.messenger.call('AccountsController:getSelectedMultichainAccount'); try { - const historicalPricesResponse = await this.messagingSystem.call( + const historicalPricesResponse = await this.messenger.call( 'SnapController:handleRequest', { snapId: selectedAccount?.metadata.snap?.id as SnapId, @@ -670,7 +665,7 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro | undefined > { try { - return (await this.messagingSystem.call('SnapController:handleRequest', { + return (await this.messenger.call('SnapController:handleRequest', { snapId, origin: 'metamask', handler, diff --git a/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.test.ts b/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.test.ts index 7d28fc95176..53f17015c27 100644 --- a/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.test.ts +++ b/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.test.ts @@ -1,4 +1,4 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import type { Balance, CaipAssetType } from '@metamask/keyring-api'; import { BtcAccountType, @@ -13,6 +13,13 @@ import { } from '@metamask/keyring-api'; import { KeyringTypes } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { v4 as uuidv4 } from 'uuid'; import { MultichainBalancesController } from '.'; @@ -21,10 +28,6 @@ import type { MultichainBalancesControllerState, } from '.'; import { getDefaultMultichainBalancesControllerState } from './MultichainBalancesController'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../../base-controller/tests/helpers'; const mockBtcAccount = { address: 'bc1qssdcp5kvwh6nghzg9tuk99xsflwkdv4hgvq58q', @@ -103,21 +106,26 @@ const mockBalanceResult = { /** * The union of actions that the root messenger allows. */ -type RootAction = ExtractAvailableAction; +type RootAction = MessengerActions; /** * The union of events that the root messenger allows. */ -type RootEvent = ExtractAvailableEvent; +type RootEvent = MessengerEvents; /** - * Constructs the unrestricted messenger. This can be used to call actions and + * The root messenger type + */ +type RootMessenger = Messenger; + +/** + * Constructs the root messenger. This can be used to call actions and * publish events within the tests for this controller. * - * @returns The unrestricted messenger suited for MultichainBalancesController. + * @returns The root messenger suited for MultichainBalancesController. */ -function getRootMessenger(): Messenger { - return new Messenger(); +function getRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** @@ -127,23 +135,33 @@ function getRootMessenger(): Messenger { * @returns The unrestricted messenger suited for MultichainBalancesController. */ function getRestrictedMessenger( - messenger: Messenger, + messenger: RootMessenger, ): MultichainBalancesControllerMessenger { - return messenger.getRestricted({ - name: 'MultichainBalancesController', - allowedActions: [ + const multichainBalancesControllerMessenger = new Messenger< + 'MultichainBalancesController', + RootAction, + RootEvent, + RootMessenger + >({ + namespace: 'MultichainBalancesController', + parent: messenger, + }); + messenger.delegate({ + messenger: multichainBalancesControllerMessenger, + actions: [ 'SnapController:handleRequest', 'AccountsController:listMultichainAccounts', 'MultichainAssetsController:getState', 'KeyringController:getState', ], - allowedEvents: [ + events: [ 'AccountsController:accountAdded', 'AccountsController:accountRemoved', 'AccountsController:accountBalancesUpdated', 'MultichainAssetsController:accountAssetListUpdated', ], }); + return multichainBalancesControllerMessenger; } const setupController = ({ @@ -651,7 +669,7 @@ describe('MultichainBalancesController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.ts b/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.ts index 1545e547b79..d547f5bc237 100644 --- a/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.ts +++ b/packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.ts @@ -6,10 +6,10 @@ import type { } from '@metamask/accounts-controller'; import { BaseController, + type StateMetadata, type ControllerGetStateAction, type ControllerStateChangeEvent, - type RestrictedMessenger, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; import { isEvmAccountType } from '@metamask/keyring-api'; import type { Balance, @@ -19,6 +19,7 @@ import type { import type { KeyringControllerGetStateAction } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; import { KeyringClient } from '@metamask/keyring-snap-client'; +import type { Messenger } from '@metamask/messenger'; import type { HandleSnapRequest } from '@metamask/snaps-controllers'; import type { SnapId } from '@metamask/snaps-sdk'; import { HandlerType } from '@metamask/snaps-utils'; @@ -108,12 +109,10 @@ type AllowedEvents = /** * Messenger type for the MultichainBalancesController. */ -export type MultichainBalancesControllerMessenger = RestrictedMessenger< +export type MultichainBalancesControllerMessenger = Messenger< typeof controllerName, MultichainBalancesControllerActions | AllowedActions, - MultichainBalancesControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + MultichainBalancesControllerEvents | AllowedEvents >; /** @@ -123,14 +122,15 @@ export type MultichainBalancesControllerMessenger = RestrictedMessenger< * using the `persist` flag; and if they can be sent to Sentry or not, using * the `anonymous` flag. */ -const balancesControllerMetadata = { - balances: { - includeInStateLogs: false, - persist: true, - anonymous: false, - usedInUi: true, - }, -}; +const balancesControllerMetadata: StateMetadata = + { + balances: { + includeInStateLogs: false, + persist: true, + includeInDebugSnapshot: false, + usedInUi: true, + }, + }; /** * The MultichainBalancesController is responsible for fetching and caching account @@ -165,17 +165,17 @@ export class MultichainBalancesController extends BaseController< void this.updateBalance(account.id); } - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountRemoved', (account: string) => this.#handleOnAccountRemoved(account), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:accountBalancesUpdated', (balanceUpdate: AccountBalancesUpdatedEventPayload) => this.#handleOnAccountBalancesUpdated(balanceUpdate), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'MultichainAssetsController:accountAssetListUpdated', async ({ assets }) => { const newAccountAssets = Object.entries(assets).map( @@ -200,9 +200,7 @@ export class MultichainBalancesController extends BaseController< assets: CaipAssetType[]; }[], ): Promise { - const { isUnlocked } = this.messagingSystem.call( - 'KeyringController:getState', - ); + const { isUnlocked } = this.messenger.call('KeyringController:getState'); if (!isUnlocked) { return; @@ -256,9 +254,7 @@ export class MultichainBalancesController extends BaseController< accountId: string, assets: CaipAssetType[], ): Promise { - const { isUnlocked } = this.messagingSystem.call( - 'KeyringController:getState', - ); + const { isUnlocked } = this.messenger.call('KeyringController:getState'); if (!isUnlocked) { return; @@ -305,9 +301,7 @@ export class MultichainBalancesController extends BaseController< * @returns A list of multichain accounts. */ #listMultichainAccounts(): InternalAccount[] { - return this.messagingSystem.call( - 'AccountsController:listMultichainAccounts', - ); + return this.messenger.call('AccountsController:listMultichainAccounts'); } /** @@ -328,7 +322,7 @@ export class MultichainBalancesController extends BaseController< */ #listAccountAssets(accountId: string): CaipAssetType[] { // TODO: Add an action `MultichainAssetsController:getAccountAssets` maybe? - const assetsState = this.messagingSystem.call( + const assetsState = this.messenger.call( 'MultichainAssetsController:getState', ); @@ -427,7 +421,7 @@ export class MultichainBalancesController extends BaseController< #getClient(snapId: string): KeyringClient { return new KeyringClient({ send: async (request: JsonRpcRequest) => - (await this.messagingSystem.call('SnapController:handleRequest', { + (await this.messenger.call('SnapController:handleRequest', { snapId: snapId as SnapId, origin: 'metamask', handler: HandlerType.OnKeyringRequest, diff --git a/packages/assets-controllers/src/NftController.test.ts b/packages/assets-controllers/src/NftController.test.ts index 1f8a75e2f6e..6a8eecb93ba 100644 --- a/packages/assets-controllers/src/NftController.test.ts +++ b/packages/assets-controllers/src/NftController.test.ts @@ -6,7 +6,7 @@ import type { } from '@metamask/accounts-controller'; import type { ApprovalControllerMessenger } from '@metamask/approval-controller'; import { ApprovalController } from '@metamask/approval-controller'; -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { IPFS_DEFAULT_GATEWAY_URL, ERC1155, @@ -22,14 +22,18 @@ import { convertHexToDecimal, } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; -import type { - NetworkClientConfiguration, - NetworkClientId, +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; +import { + type NetworkClientConfiguration, + type NetworkClientId, } from '@metamask/network-controller'; -import type { - BulkPhishingDetectionScanResponse, - PhishingControllerBulkScanUrlsAction, -} from '@metamask/phishing-controller'; +import type { BulkPhishingDetectionScanResponse } from '@metamask/phishing-controller'; import { RecommendedAction } from '@metamask/phishing-controller'; import { getDefaultPreferencesState, @@ -55,24 +59,29 @@ import type { Nft, NftControllerState, NftControllerMessenger, - AllowedActions as NftControllerAllowedActions, - AllowedEvents as NftControllerAllowedEvents, NFTStandardType, NftMetadata, } from './NftController'; import { NftController } from './NftController'; import type { Collection } from './NftDetectionController'; import { createMockInternalAccount } from '../../accounts-controller/src/tests/mocks'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../base-controller/tests/helpers'; import { buildCustomNetworkClientConfiguration, buildMockFindNetworkClientIdByChainId, buildMockGetNetworkClientById, } from '../../network-controller/tests/helpers'; +type AllActions = + | MessengerActions + | MessengerActions; + +type AllEvents = + | MessengerEvents + | MessengerEvents + | AccountsControllerSelectedAccountChangeEvent; + +type RootMessenger = Messenger; + const CRYPTOPUNK_ADDRESS = '0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB'; const ERC721_KUDOSADDRESS = '0x2aEa4Add166EBf38b63d09a75dE1a7b94Aa24163'; const ERC721_KUDOS_TOKEN_ID = '1203'; @@ -226,15 +235,9 @@ function setupController({ mockGetNetworkClientIdByChainId?: Record; displayNftMedia?: boolean; } = {}) { - const messenger = new Messenger< - | ExtractAvailableAction - | NftControllerAllowedActions - | ExtractAvailableAction, - | ExtractAvailableEvent - | NftControllerAllowedEvents - | ExtractAvailableEvent - | AccountsControllerSelectedAccountChangeEvent - >(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const getNetworkClientById = buildMockGetNetworkClientById( mockNetworkClientConfigurationsByNetworkClientId, @@ -331,10 +334,14 @@ function setupController({ mockGetERC1155TokenURI, ); - const approvalControllerMessenger = messenger.getRestricted({ - name: 'ApprovalController', - allowedActions: [], - allowedEvents: [], + const approvalControllerMessenger = new Messenger< + 'ApprovalController', + MessengerActions, + MessengerEvents, + RootMessenger + >({ + namespace: 'ApprovalController', + parent: messenger, }); const approvalController = new ApprovalController({ @@ -350,14 +357,18 @@ function setupController({ ); } - const nftControllerMessenger = messenger.getRestricted< + const nftControllerMessenger = new Messenger< typeof controllerName, - | PhishingControllerBulkScanUrlsAction['type'] - | NftControllerAllowedActions['type'], - NftControllerAllowedEvents['type'] + MessengerActions, + MessengerEvents, + RootMessenger >({ - name: controllerName, - allowedActions: [ + namespace: controllerName, + parent: messenger, + }); + messenger.delegate({ + messenger: nftControllerMessenger, + actions: [ 'ApprovalController:addRequest', 'AccountsController:getSelectedAccount', 'AccountsController:getAccount', @@ -371,7 +382,7 @@ function setupController({ 'NetworkController:findNetworkClientIdByChainId', 'PhishingController:bulkScanUrls', ], - allowedEvents: [ + events: [ 'AccountsController:selectedEvmAccountChange', 'PreferencesController:stateChange', ], @@ -379,7 +390,7 @@ function setupController({ const nftController = new NftController({ onNftAdded: jest.fn(), - messenger: nftControllerMessenger as NftControllerMessenger, + messenger: nftControllerMessenger, ...options, }); @@ -408,6 +419,7 @@ function setupController({ return { nftController, messenger, + nftControllerMessenger, approvalController, triggerPreferencesStateChange, triggerSelectedAccountChange, @@ -645,11 +657,11 @@ describe('NftController', () => { }); it('should error if the user does not own the suggested ERC721 NFT', async function () { - const { nftController, messenger } = setupController({ + const { nftController, nftControllerMessenger } = setupController({ getERC721OwnerOf: jest.fn().mockImplementation(() => '0x12345abcefg'), }); - const callActionSpy = jest.spyOn(messenger, 'call'); + const callActionSpy = jest.spyOn(nftControllerMessenger, 'call'); await expect(() => nftController.watchNft( @@ -684,11 +696,11 @@ describe('NftController', () => { }); it('should error if the user does not own the suggested ERC1155 NFT', async function () { - const { nftController, messenger } = setupController({ + const { nftController, nftControllerMessenger } = setupController({ getERC1155BalanceOf: jest.fn().mockImplementation(() => new BN(0)), }); - const callActionSpy = jest.spyOn(messenger, 'call'); + const callActionSpy = jest.spyOn(nftControllerMessenger, 'call'); await expect(() => nftController.watchNft( @@ -719,7 +731,7 @@ describe('NftController', () => { ); const { nftController, - messenger, + nftControllerMessenger, triggerPreferencesStateChange, triggerSelectedAccountChange, } = setupController({ @@ -746,7 +758,7 @@ describe('NftController', () => { (v4 as jest.Mock).mockImplementationOnce(() => requestId); const callActionSpy = jest - .spyOn(messenger, 'call') + .spyOn(nftControllerMessenger, 'call') // 1. `AccountsController:getAccount` .mockReturnValueOnce(OWNER_ACCOUNT) // 2. `AssetsContractController:getERC721OwnerOf` @@ -846,7 +858,7 @@ describe('NftController', () => { ); const { nftController, - messenger, + nftControllerMessenger, triggerPreferencesStateChange, triggerSelectedAccountChange, } = setupController({ @@ -872,7 +884,7 @@ describe('NftController', () => { (v4 as jest.Mock).mockImplementationOnce(() => requestId); const callActionSpy = jest - .spyOn(messenger, 'call') + .spyOn(nftControllerMessenger, 'call') // 1. `AccountsController:getAccount` .mockReturnValueOnce(OWNER_ACCOUNT) // 2. `AssetsContractController:getERC721OwnerOf` @@ -972,7 +984,7 @@ describe('NftController', () => { ); const { nftController, - messenger, + nftControllerMessenger, triggerPreferencesStateChange, triggerSelectedAccountChange, } = setupController({ @@ -998,7 +1010,7 @@ describe('NftController', () => { (v4 as jest.Mock).mockImplementationOnce(() => requestId); const callActionSpy = jest - .spyOn(messenger, 'call') + .spyOn(nftControllerMessenger, 'call') // 1. `AccountsController:getAccount` .mockReturnValueOnce(OWNER_ACCOUNT) // 2. `AssetsContractController:getERC721OwnerOf` @@ -1098,7 +1110,7 @@ describe('NftController', () => { ); const { nftController, - messenger, + nftControllerMessenger, triggerPreferencesStateChange, triggerSelectedAccountChange, } = setupController({ @@ -1125,7 +1137,7 @@ describe('NftController', () => { (v4 as jest.Mock).mockImplementationOnce(() => requestId); const callActionSpy = jest - .spyOn(messenger, 'call') + .spyOn(nftControllerMessenger, 'call') // 1. `AccountsController:getAccount` .mockReturnValueOnce(OWNER_ACCOUNT) // 2. `AssetsContractController:getERC721OwnerOf` @@ -1226,7 +1238,7 @@ describe('NftController', () => { const { nftController, - messenger, + nftControllerMessenger, triggerPreferencesStateChange, triggerSelectedAccountChange, } = setupController({ @@ -1256,7 +1268,7 @@ describe('NftController', () => { (v4 as jest.Mock).mockImplementationOnce(() => requestId); const callActionSpy = jest - .spyOn(messenger, 'call') + .spyOn(nftControllerMessenger, 'call') // 1. `AccountsController:getAccount` .mockReturnValueOnce(OWNER_ACCOUNT) // 2. `AssetsContractController:getERC721OwnerOf` @@ -1359,20 +1371,23 @@ describe('NftController', () => { }), ); - const { nftController, messenger, triggerPreferencesStateChange } = - setupController({ - getAccount: jest.fn().mockReturnValue(OWNER_ACCOUNT), - getERC721OwnerOf: jest - .fn() - .mockRejectedValue(new Error('Not an ERC721 contract')), - getERC1155BalanceOf: jest.fn().mockResolvedValue(new BN(1)), - getERC721TokenURI: jest - .fn() - .mockRejectedValue(new Error('Not an ERC721 contract')), - getERC1155TokenURI: jest - .fn() - .mockResolvedValue('https://testtokenuri.com'), - }); + const { + nftController, + nftControllerMessenger, + triggerPreferencesStateChange, + } = setupController({ + getAccount: jest.fn().mockReturnValue(OWNER_ACCOUNT), + getERC721OwnerOf: jest + .fn() + .mockRejectedValue(new Error('Not an ERC721 contract')), + getERC1155BalanceOf: jest.fn().mockResolvedValue(new BN(1)), + getERC721TokenURI: jest + .fn() + .mockRejectedValue(new Error('Not an ERC721 contract')), + getERC1155TokenURI: jest + .fn() + .mockResolvedValue('https://testtokenuri.com'), + }); triggerPreferencesStateChange({ ...getDefaultPreferencesState(), isIpfsGatewayEnabled: true, @@ -1385,7 +1400,7 @@ describe('NftController', () => { (v4 as jest.Mock).mockImplementationOnce(() => requestId); const callActionSpy = jest - .spyOn(messenger, 'call') + .spyOn(nftControllerMessenger, 'call') // 1. `AccountsController:getAccount` .mockReturnValueOnce(OWNER_ACCOUNT) // 2. `AssetsContractController:getERC721OwnerOf` @@ -5951,7 +5966,7 @@ describe('NftController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/assets-controllers/src/NftController.ts b/packages/assets-controllers/src/NftController.ts index adbe53087c4..1027997d7f1 100644 --- a/packages/assets-controllers/src/NftController.ts +++ b/packages/assets-controllers/src/NftController.ts @@ -5,14 +5,12 @@ import type { AccountsControllerGetSelectedAccountAction, } from '@metamask/accounts-controller'; import type { AddApprovalRequest } from '@metamask/approval-controller'; -import type { - RestrictedMessenger, - ControllerStateChangeEvent, -} from '@metamask/base-controller'; import { BaseController, + type ControllerStateChangeEvent, type ControllerGetStateAction, -} from '@metamask/base-controller'; + type StateMetadata, +} from '@metamask/base-controller/next'; import { safelyExecute, handleFetch, @@ -29,6 +27,7 @@ import { toHex, } from '@metamask/controller-utils'; import { type InternalAccount } from '@metamask/keyring-internal-api'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkClientId, NetworkControllerGetNetworkClientByIdAction, @@ -238,23 +237,23 @@ export type NftControllerState = { ignoredNfts: Nft[]; }; -const nftControllerMetadata = { +const nftControllerMetadata: StateMetadata = { allNftContracts: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, allNfts: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, ignoredNfts: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, }; @@ -309,12 +308,10 @@ export type NftControllerEvents = NftControllerStateChangeEvent; /** * The messenger of the {@link NftController}. */ -export type NftControllerMessenger = RestrictedMessenger< +export type NftControllerMessenger = Messenger< typeof controllerName, NftControllerActions | AllowedActions, - NftControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + NftControllerEvents | AllowedEvents >; export const getDefaultNftControllerState = (): NftControllerState => ({ @@ -399,7 +396,7 @@ export class NftController extends BaseController< }, }); - this.#selectedAccountId = this.messagingSystem.call( + this.#selectedAccountId = this.messenger.call( 'AccountsController:getSelectedAccount', ).id; this.#ipfsGateway = ipfsGateway; @@ -408,12 +405,12 @@ export class NftController extends BaseController< this.#isIpfsGatewayEnabled = isIpfsGatewayEnabled; this.#onNftAdded = onNftAdded; - this.messagingSystem.subscribe( + this.messenger.subscribe( 'PreferencesController:stateChange', this.#onPreferencesControllerStateChange.bind(this), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:selectedEvmAccountChange', this.#onSelectedAccountChange.bind(this), ); @@ -441,7 +438,7 @@ export class NftController extends BaseController< displayNftMedia?: boolean; openSeaEnabled?: boolean; }) { - const selectedAccount = this.messagingSystem.call( + const selectedAccount = this.messenger.call( 'AccountsController:getSelectedAccount', ); this.#selectedAccountId = selectedAccount.id; @@ -748,7 +745,7 @@ export class NftController extends BaseController< ): Promise<[string, string]> { // try ERC721 uri try { - const uri = await this.messagingSystem.call( + const uri = await this.messenger.call( 'AssetsContractController:getERC721TokenURI', contractAddress, tokenId, @@ -761,7 +758,7 @@ export class NftController extends BaseController< // try ERC1155 uri try { - const tokenURI = await this.messagingSystem.call( + const tokenURI = await this.messenger.call( 'AssetsContractController:getERC1155TokenURI', contractAddress, tokenId, @@ -804,7 +801,7 @@ export class NftController extends BaseController< ): Promise { const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -853,12 +850,12 @@ export class NftController extends BaseController< Pick > { const [name, symbol] = await Promise.all([ - this.messagingSystem.call( + this.messenger.call( 'AssetsContractController:getERC721AssetName', contractAddress, networkClientId, ), - this.messagingSystem.call( + this.messenger.call( 'AssetsContractController:getERC721AssetSymbol', contractAddress, networkClientId, @@ -1055,7 +1052,7 @@ export class NftController extends BaseController< const { allNftContracts } = this.state; const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId as NetworkClientId, ); @@ -1388,7 +1385,7 @@ export class NftController extends BaseController< ): Promise { // Checks the ownership for ERC-721. try { - const owner = await this.messagingSystem.call( + const owner = await this.messenger.call( 'AssetsContractController:getERC721OwnerOf', nftAddress, tokenId, @@ -1401,7 +1398,7 @@ export class NftController extends BaseController< // Checks the ownership for ERC-1155. try { - const balance = await this.messagingSystem.call( + const balance = await this.messenger.call( 'AssetsContractController:getERC1155BalanceOf', ownerAddress, nftAddress, @@ -1520,7 +1517,7 @@ export class NftController extends BaseController< ); const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -1574,7 +1571,7 @@ export class NftController extends BaseController< const unsanitizedResults = await Promise.all( nftsWithChecksumAdr.map(async (nft) => { // Each NFT should have a chainId; convert nft.chainId to networkClientId - const networkClientId = this.messagingSystem.call( + const networkClientId = this.messenger.call( 'NetworkController:findNetworkClientIdByChainId', toHex(nft.chainId as number), ); @@ -1679,7 +1676,7 @@ export class NftController extends BaseController< const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId as NetworkClientId, ); @@ -1721,7 +1718,7 @@ export class NftController extends BaseController< const addressToSearch = this.#getAddressOrSelectedAddress(userAddress); const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId as NetworkClientId, ); @@ -1772,7 +1769,7 @@ export class NftController extends BaseController< const addressToSearch = this.#getAddressOrSelectedAddress(userAddress); const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId as NetworkClientId, ); @@ -1848,7 +1845,7 @@ export class NftController extends BaseController< const addressToSearch = this.#getAddressOrSelectedAddress(userAddress); const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId as NetworkClientId, ); @@ -1899,7 +1896,7 @@ export class NftController extends BaseController< const addressToSearch = this.#getAddressOrSelectedAddress(userAddress); const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId as NetworkClientId, ); @@ -2070,7 +2067,7 @@ export class NftController extends BaseController< } async _requestApproval(suggestedNftMeta: SuggestedNftMeta) { - return this.messagingSystem.call( + return this.messenger.call( 'ApprovalController:addRequest', { id: suggestedNftMeta.id, @@ -2099,7 +2096,7 @@ export class NftController extends BaseController< } // If the address is not defined (or empty), we fallback to the currently selected account's address - const selectedAccount = this.messagingSystem.call( + const selectedAccount = this.messenger.call( 'AccountsController:getAccount', this.#selectedAccountId, ); @@ -2212,7 +2209,7 @@ export class NftController extends BaseController< try { // Use bulkScanUrls to check all URLs at once - const bulkScanResponse = await this.messagingSystem.call( + const bulkScanResponse = await this.messenger.call( 'PhishingController:bulkScanUrls', urlsToCheck, ); diff --git a/packages/assets-controllers/src/NftDetectionController.test.ts b/packages/assets-controllers/src/NftDetectionController.test.ts index 98d4e9b58b7..5cb89d7549e 100644 --- a/packages/assets-controllers/src/NftDetectionController.test.ts +++ b/packages/assets-controllers/src/NftDetectionController.test.ts @@ -1,10 +1,16 @@ import type { AccountsController } from '@metamask/accounts-controller'; -import { Messenger } from '@metamask/base-controller'; import { NFT_API_BASE_URL, ChainId, InfuraNetworkType, } from '@metamask/controller-utils'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { getDefaultNetworkControllerState, NetworkClientType, @@ -36,10 +42,15 @@ import { getDefaultNftControllerState } from './NftController'; import { NftDetectionController, BlockaidResultType, - type AllowedActions, - type AllowedEvents, + type NftDetectionControllerMessenger, } from './NftDetectionController'; +type AllActions = MessengerActions; + +type AllEvents = MessengerEvents; + +type RootMessenger = Messenger; + const controllerName = 'NftDetectionController' as const; const defaultSelectedAccount = createMockInternalAccount(); @@ -1069,7 +1080,9 @@ async function withController( testFunction, ] = args.length === 2 ? args : [{}, args[0]]; - const messenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); messenger.registerActionHandler( 'NetworkController:getState', @@ -1109,21 +1122,32 @@ async function withController( }), ); + const nftDetectionControllerMessenger = new Messenger< + typeof controllerName, + AllActions, + AllEvents, + RootMessenger + >({ + namespace: controllerName, + parent: messenger, + }); + messenger.delegate({ + messenger: nftDetectionControllerMessenger, + actions: [ + 'NetworkController:getState', + 'NetworkController:getNetworkClientById', + 'PreferencesController:getState', + 'AccountsController:getSelectedAccount', + 'NetworkController:findNetworkClientIdByChainId', + ], + events: [ + 'NetworkController:stateChange', + 'PreferencesController:stateChange', + ], + }); + const controller = new NftDetectionController({ - messenger: messenger.getRestricted({ - name: controllerName, - allowedActions: [ - 'NetworkController:getState', - 'NetworkController:getNetworkClientById', - 'PreferencesController:getState', - 'AccountsController:getSelectedAccount', - 'NetworkController:findNetworkClientIdByChainId', - ], - allowedEvents: [ - 'NetworkController:stateChange', - 'PreferencesController:stateChange', - ], - }), + messenger: nftDetectionControllerMessenger, disabled: true, addNft: jest.fn(), getNftState: getDefaultNftControllerState, diff --git a/packages/assets-controllers/src/NftDetectionController.ts b/packages/assets-controllers/src/NftDetectionController.ts index 219ca024f92..3f6845a7a30 100644 --- a/packages/assets-controllers/src/NftDetectionController.ts +++ b/packages/assets-controllers/src/NftDetectionController.ts @@ -1,7 +1,10 @@ import type { AccountsControllerGetSelectedAccountAction } from '@metamask/accounts-controller'; import type { AddApprovalRequest } from '@metamask/approval-controller'; -import type { RestrictedMessenger } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +import { + BaseController, + type ControllerGetStateAction, + type ControllerStateChangeEvent, +} from '@metamask/base-controller/next'; import { toChecksumHexAddress, ChainId, @@ -11,6 +14,7 @@ import { handleFetch, toHex, } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkClient, NetworkControllerGetNetworkClientByIdAction, @@ -37,6 +41,7 @@ const controllerName = 'NftDetectionController'; export type NFTDetectionControllerState = Record; export type AllowedActions = + | ControllerGetStateAction | AddApprovalRequest | NetworkControllerGetStateAction | NetworkControllerGetNetworkClientByIdAction @@ -45,15 +50,17 @@ export type AllowedActions = | NetworkControllerFindNetworkClientIdByChainIdAction; export type AllowedEvents = + | ControllerStateChangeEvent< + typeof controllerName, + NFTDetectionControllerState + > | PreferencesControllerStateChangeEvent | NetworkControllerStateChangeEvent; -export type NftDetectionControllerMessenger = RestrictedMessenger< +export type NftDetectionControllerMessenger = Messenger< typeof controllerName, AllowedActions, - AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + AllowedEvents >; /** @@ -498,7 +505,7 @@ export class NftDetectionController extends BaseController< this.#getNftState = getNftState; this.#addNft = addNft; - this.messagingSystem.subscribe( + this.messenger.subscribe( 'PreferencesController:stateChange', this.#onPreferencesControllerStateChange.bind(this), ); @@ -510,12 +517,12 @@ export class NftDetectionController extends BaseController< * @returns Whether current network is mainnet. */ isMainnet(): boolean { - const { selectedNetworkClientId } = this.messagingSystem.call( + const { selectedNetworkClientId } = this.messenger.call( 'NetworkController:getState', ); const { configuration: { chainId }, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', selectedNetworkClientId, ); @@ -586,8 +593,7 @@ export class NftDetectionController extends BaseController< async detectNfts(chainIds: Hex[], options?: { userAddress?: string }) { const userAddress = options?.userAddress ?? - this.messagingSystem.call('AccountsController:getSelectedAccount') - .address; + this.messenger.call('AccountsController:getSelectedAccount').address; // filter out unsupported chainIds const supportedChainIds = chainIds.filter((chainId) => @@ -693,7 +699,7 @@ export class NftDetectionController extends BaseController< collection && { collection }, chainId && { chainId }, ); - const networkClientId = this.messagingSystem.call( + const networkClientId = this.messenger.call( 'NetworkController:findNetworkClientIdByChainId', toHex(chainId), ); diff --git a/packages/assets-controllers/src/RatesController/RatesController.test.ts b/packages/assets-controllers/src/RatesController/RatesController.test.ts index e2b125ea4db..8ba6ccbe2b5 100644 --- a/packages/assets-controllers/src/RatesController/RatesController.test.ts +++ b/packages/assets-controllers/src/RatesController/RatesController.test.ts @@ -1,6 +1,14 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { useFakeTimers } from 'sinon'; +import type { RatesControllerMessenger, RatesControllerState } from './types'; import { advanceTime } from '../../../../tests/helpers'; import type { fetchMultiExchangeRate as defaultFetchExchangeRate } from '../crypto-compare-service'; import { @@ -8,12 +16,12 @@ import { RatesController, name as ratesControllerName, } from './RatesController'; -import type { - RatesControllerActions, - RatesControllerEvents, - RatesControllerMessenger, - RatesControllerState, -} from './types'; + +type AllActions = MessengerActions; + +type AllEvents = MessengerEvents; + +type RootMessenger = Messenger; const MOCK_TIMESTAMP = 1709983353; @@ -26,28 +34,26 @@ function getStubbedDate(): number { } /** - * Builds a new Messenger instance for RatesController. - * @returns A new Messenger instance. + * Builds a new root messenger instance. + * + * @returns A new root messenger instance. */ -function buildMessenger(): Messenger< - RatesControllerActions, - RatesControllerEvents -> { - return new Messenger(); +function buildRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** * Builds a restricted messenger for the RatesController. + * * @param messenger - The base messenger instance. * @returns A restricted messenger for the RatesController. */ function buildRatesControllerMessenger( - messenger: Messenger, + messenger: RootMessenger, ): RatesControllerMessenger { - return messenger.getRestricted({ - name: ratesControllerName, - allowedEvents: [], - allowedActions: [], + return new Messenger({ + namespace: ratesControllerName, + parent: messenger, }); } @@ -70,7 +76,7 @@ function setupRatesController({ }: { interval?: number; initialState?: Partial; - messenger: Messenger; + messenger: RootMessenger; includeUsdRate: boolean; fetchMultiExchangeRate?: typeof defaultFetchExchangeRate; }) { @@ -91,7 +97,7 @@ describe('RatesController', () => { it('constructs the RatesController with default values', () => { const ratesController = setupRatesController({ initialState: {}, - messenger: buildMessenger(), + messenger: buildRootMessenger(), includeUsdRate: false, }); const { fiatCurrency, rates, cryptocurrencies } = ratesController.state; @@ -118,7 +124,7 @@ describe('RatesController', () => { }); it('starts the polling process with default values', async () => { - const messenger = buildMessenger(); + const messenger = buildRootMessenger(); const publishActionSpy = jest.spyOn(messenger, 'publish'); jest.spyOn(global.Date, 'now').mockImplementation(() => getStubbedDate()); @@ -222,7 +228,7 @@ describe('RatesController', () => { cryptocurrencies: [Cryptocurrency.Btc], fiatCurrency: 'eur', }, - messenger: buildMessenger(), + messenger: buildRootMessenger(), includeUsdRate: true, fetchMultiExchangeRate: fetchExchangeRateStub, }); @@ -263,7 +269,7 @@ describe('RatesController', () => { }); it('stops the polling process', async () => { - const messenger = buildMessenger(); + const messenger = buildRootMessenger(); const publishActionSpy = jest.spyOn(messenger, 'publish'); const fetchExchangeRateStub = jest.fn().mockResolvedValue({}); const ratesController = setupRatesController({ @@ -318,7 +324,7 @@ describe('RatesController', () => { initialState: { cryptocurrencies: mockCryptocurrencyList, }, - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -335,7 +341,7 @@ describe('RatesController', () => { const ratesController = setupRatesController({ interval: 150, initialState: {}, - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -366,7 +372,7 @@ describe('RatesController', () => { const ratesController = setupRatesController({ interval: 150, initialState: {}, - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -385,7 +391,7 @@ describe('RatesController', () => { const ratesController = setupRatesController({ interval: 150, initialState: {}, - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -400,7 +406,7 @@ describe('RatesController', () => { it('includes expected state in debug snapshots', () => { const fetchExchangeRateStub = jest.fn().mockResolvedValue({}); const controller = setupRatesController({ - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -409,7 +415,7 @@ describe('RatesController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { @@ -435,7 +441,7 @@ describe('RatesController', () => { it('includes expected state in state logs', () => { const fetchExchangeRateStub = jest.fn().mockResolvedValue({}); const controller = setupRatesController({ - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -460,7 +466,7 @@ describe('RatesController', () => { it('persists expected state', () => { const fetchExchangeRateStub = jest.fn().mockResolvedValue({}); const controller = setupRatesController({ - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); @@ -495,7 +501,7 @@ describe('RatesController', () => { it('exposes expected state to UI', () => { const fetchExchangeRateStub = jest.fn().mockResolvedValue({}); const controller = setupRatesController({ - messenger: buildMessenger(), + messenger: buildRootMessenger(), fetchMultiExchangeRate: fetchExchangeRateStub, includeUsdRate: false, }); diff --git a/packages/assets-controllers/src/RatesController/RatesController.ts b/packages/assets-controllers/src/RatesController/RatesController.ts index 5c916a7c92a..f2d4430a89f 100644 --- a/packages/assets-controllers/src/RatesController/RatesController.ts +++ b/packages/assets-controllers/src/RatesController/RatesController.ts @@ -1,4 +1,7 @@ -import { BaseController } from '@metamask/base-controller'; +import { + BaseController, + type StateMetadata, +} from '@metamask/base-controller/next'; import { Mutex } from 'async-mutex'; import type { Draft } from 'immer'; @@ -25,23 +28,23 @@ export enum Cryptocurrency { const DEFAULT_INTERVAL = 180000; -const metadata = { +const metadata: StateMetadata = { fiatCurrency: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, rates: { includeInStateLogs: false, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, cryptocurrencies: { includeInStateLogs: true, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, }; @@ -180,7 +183,7 @@ export class RatesController extends BaseController< return; } - this.messagingSystem.publish(`${name}:pollingStarted`); + this.messenger.publish(`${name}:pollingStarted`); await this.#updateRates(); @@ -199,7 +202,7 @@ export class RatesController extends BaseController< clearInterval(this.#intervalId); this.#intervalId = undefined; - this.messagingSystem.publish(`${name}:pollingStopped`); + this.messenger.publish(`${name}:pollingStopped`); } /** diff --git a/packages/assets-controllers/src/RatesController/types.ts b/packages/assets-controllers/src/RatesController/types.ts index c26ae070075..49c5515391b 100644 --- a/packages/assets-controllers/src/RatesController/types.ts +++ b/packages/assets-controllers/src/RatesController/types.ts @@ -1,8 +1,8 @@ import type { - RestrictedMessenger, ControllerGetStateAction, ControllerStateChangeEvent, } from '@metamask/base-controller'; +import type { Messenger } from '@metamask/messenger'; import type { fetchMultiExchangeRate as defaultFetchExchangeRate } from '../crypto-compare-service'; import type { @@ -97,12 +97,10 @@ export type RatesControllerActions = RatesControllerGetStateAction; /** * Defines the actions that the RatesController can perform. */ -export type RatesControllerMessenger = RestrictedMessenger< +export type RatesControllerMessenger = Messenger< typeof ratesControllerName, RatesControllerActions, - RatesControllerEvents, - never, - never + RatesControllerEvents >; /** diff --git a/packages/assets-controllers/src/TokenBalancesController.test.ts b/packages/assets-controllers/src/TokenBalancesController.test.ts index 024173d7d1b..6b6707eff23 100644 --- a/packages/assets-controllers/src/TokenBalancesController.test.ts +++ b/packages/assets-controllers/src/TokenBalancesController.test.ts @@ -1,6 +1,13 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { toHex } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { NetworkState } from '@metamask/network-controller'; import type { PreferencesState } from '@metamask/preferences-controller'; import { CHAIN_IDS } from '@metamask/transaction-controller'; @@ -10,12 +17,9 @@ import { useFakeTimers } from 'sinon'; import * as multicall from './multicall'; import { RpcBalanceFetcher } from './rpc-service/rpc-balance-fetcher'; import type { - AllowedActions, - AllowedEvents, ChainIdHex, + TokenBalancesControllerMessenger, ChecksumAddress, - TokenBalancesControllerActions, - TokenBalancesControllerEvents, TokenBalancesControllerState, } from './TokenBalancesController'; import { @@ -28,6 +32,18 @@ import { advanceTime, flushPromises } from '../../../tests/helpers'; import { createMockInternalAccount } from '../../accounts-controller/src/tests/mocks'; import type { RpcEndpoint } from '../../network-controller/src/NetworkController'; +type AllTokenBalancesControllerActions = + MessengerActions; + +type AllTokenBalancesControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllTokenBalancesControllerActions, + AllTokenBalancesControllerEvents +>; + // Mock safelyExecuteWithTimeout jest.mock('@metamask/controller-utils', () => ({ ...jest.requireActual('@metamask/controller-utils'), @@ -53,14 +69,22 @@ const setupController = ({ tokens?: Partial; listAccounts?: InternalAccount[]; } = {}) => { - const messenger = new Messenger< - TokenBalancesControllerActions | AllowedActions, - TokenBalancesControllerEvents | AllowedEvents - >(); - - const tokenBalancesMessenger = messenger.getRestricted({ - name: 'TokenBalancesController', - allowedActions: [ + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); + + const tokenBalancesControllerMessenger = new Messenger< + 'TokenBalancesController', + AllTokenBalancesControllerActions, + AllTokenBalancesControllerEvents, + RootMessenger + >({ + namespace: 'TokenBalancesController', + parent: messenger, + }); + messenger.delegate({ + messenger: tokenBalancesControllerMessenger, + actions: [ 'NetworkController:getState', 'NetworkController:getNetworkClientById', 'PreferencesController:getState', @@ -72,7 +96,7 @@ const setupController = ({ 'AccountTrackerController:updateNativeBalances', 'AccountTrackerController:updateStakedBalances', ], - allowedEvents: [ + events: [ 'NetworkController:stateChange', 'PreferencesController:stateChange', 'TokensController:stateChange', @@ -169,7 +193,7 @@ const setupController = ({ }), ); const controller = new TokenBalancesController({ - messenger: tokenBalancesMessenger, + messenger: tokenBalancesControllerMessenger, ...config, }); const updateSpy = jest.spyOn(controller, 'update' as never); @@ -178,6 +202,7 @@ const setupController = ({ controller, updateSpy, messenger, + tokenBalancesControllerMessenger, }; }; @@ -1544,7 +1569,7 @@ describe('TokenBalancesController', () => { const accountAddress = '0x1111111111111111111111111111111111111111'; const chainId = '0x1'; - const { controller, messenger } = setupController({ + const { controller, tokenBalancesControllerMessenger } = setupController({ config: { accountsApiChainIds: () => [], allowExternalServices: () => true, @@ -1563,7 +1588,10 @@ describe('TokenBalancesController', () => { }); // Set up spy for event publishing - const publishSpy = jest.spyOn(messenger, 'publish'); + const publishSpy = jest.spyOn( + tokenBalancesControllerMessenger, + 'publish', + ); jest .spyOn(multicall, 'getTokenBalancesForMultipleAddresses') @@ -5194,7 +5222,7 @@ describe('TokenBalancesController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/assets-controllers/src/TokenBalancesController.ts b/packages/assets-controllers/src/TokenBalancesController.ts index 2363246f258..fe775c5f453 100644 --- a/packages/assets-controllers/src/TokenBalancesController.ts +++ b/packages/assets-controllers/src/TokenBalancesController.ts @@ -6,8 +6,8 @@ import type { import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { BNToHex, isValidHexAddress, @@ -20,6 +20,7 @@ import type { AccountActivityServiceStatusChangedEvent, } from '@metamask/core-backend'; import type { KeyringControllerAccountRemovedEvent } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction, @@ -68,11 +69,11 @@ const CONTROLLER = 'TokenBalancesController' as const; const DEFAULT_INTERVAL_MS = 30_000; // 30 seconds const DEFAULT_WEBSOCKET_ACTIVE_POLLING_INTERVAL_MS = 300_000; // 5 minutes -const metadata = { +const metadata: StateMetadata = { tokenBalances: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -139,12 +140,10 @@ export type AllowedEvents = | AccountActivityServiceBalanceUpdatedEvent | AccountActivityServiceStatusChangedEvent; -export type TokenBalancesControllerMessenger = RestrictedMessenger< +export type TokenBalancesControllerMessenger = Messenger< typeof CONTROLLER, TokenBalancesControllerActions | AllowedActions, - TokenBalancesControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TokenBalancesControllerEvents | AllowedEvents >; export type ChainPollingConfig = { @@ -326,12 +325,12 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ // initial token state & subscriptions const { allTokens, allDetectedTokens, allIgnoredTokens } = - this.messagingSystem.call('TokensController:getState'); + this.messenger.call('TokensController:getState'); this.#allTokens = allTokens; this.#detectedTokens = allDetectedTokens; this.#allIgnoredTokens = allIgnoredTokens; - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TokensController:stateChange', (tokensState: TokensControllerState) => { this.#onTokensChanged(tokensState).catch((error) => { @@ -339,34 +338,34 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ }); }, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'NetworkController:stateChange', this.#onNetworkChanged, ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'KeyringController:accountRemoved', this.#onAccountRemoved, ); // Register action handlers for polling interval control - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `TokenBalancesController:updateChainPollingConfigs`, this.updateChainPollingConfigs.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `TokenBalancesController:getChainPollingConfig`, this.getChainPollingConfig.bind(this), ); // Subscribe to AccountActivityService balance updates for real-time updates - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountActivityService:balanceUpdated', this.#onAccountActivityBalanceUpdate.bind(this), ); // Subscribe to AccountActivityService status changes for dynamic polling management - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountActivityService:statusChanged', this.#onAccountActivityStatusChanged.bind(this), ); @@ -382,12 +381,12 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ } readonly #getProvider = (chainId: ChainIdHex): Web3Provider => { - const { networkConfigurationsByChainId } = this.messagingSystem.call( + const { networkConfigurationsByChainId } = this.messenger.call( 'NetworkController:getState', ); const cfg = networkConfigurationsByChainId[chainId]; const { networkClientId } = cfg.rpcEndpoints[cfg.defaultRpcEndpointIndex]; - const client = this.messagingSystem.call( + const client = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -395,12 +394,12 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ }; readonly #getNetworkClient = (chainId: ChainIdHex) => { - const { networkConfigurationsByChainId } = this.messagingSystem.call( + const { networkConfigurationsByChainId } = this.messenger.call( 'NetworkController:getState', ); const cfg = networkConfigurationsByChainId[chainId]; const { networkClientId } = cfg.rpcEndpoints[cfg.defaultRpcEndpointIndex]; - return this.messagingSystem.call( + return this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -636,12 +635,10 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ return; } - const { address: selected } = this.messagingSystem.call( + const { address: selected } = this.messenger.call( 'AccountsController:getSelectedAccount', ); - const allAccounts = this.messagingSystem.call( - 'AccountsController:listAccounts', - ); + const allAccounts = this.messenger.call('AccountsController:listAccounts'); const aggregated: ProcessedBalance[] = []; let remainingChains = [...targetChains]; @@ -755,7 +752,7 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ ); // Get current AccountTracker state to compare existing balances - const accountTrackerState = this.messagingSystem.call( + const accountTrackerState = this.messenger.call( 'AccountTrackerController:getState', ); @@ -777,7 +774,7 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ }); if (balanceUpdates.length > 0) { - this.messagingSystem.call( + this.messenger.call( 'AccountTrackerController:updateNativeBalances', balanceUpdates, ); @@ -818,7 +815,7 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ }); if (stakedBalanceUpdates.length > 0) { - this.messagingSystem.call( + this.messenger.call( 'AccountTrackerController:updateStakedBalances', stakedBalanceUpdates, ); @@ -1265,10 +1262,10 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ } // Unregister action handlers - this.messagingSystem.unregisterActionHandler( + this.messenger.unregisterActionHandler( `TokenBalancesController:updateChainPollingConfigs`, ); - this.messagingSystem.unregisterActionHandler( + this.messenger.unregisterActionHandler( `TokenBalancesController:getChainPollingConfig`, ); diff --git a/packages/assets-controllers/src/TokenDetectionController.test.ts b/packages/assets-controllers/src/TokenDetectionController.test.ts index 6e9c16ecd27..b94d1da4ffa 100644 --- a/packages/assets-controllers/src/TokenDetectionController.test.ts +++ b/packages/assets-controllers/src/TokenDetectionController.test.ts @@ -1,4 +1,3 @@ -import { Messenger } from '@metamask/base-controller'; import { ChainId, NetworkType, @@ -7,6 +6,13 @@ import { } from '@metamask/controller-utils'; import type { KeyringControllerState } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { getDefaultNetworkControllerState, RpcEndpointType, @@ -36,11 +42,7 @@ import { } from './multi-chain-accounts-service/mocks/mock-get-balances'; import { MOCK_GET_SUPPORTED_NETWORKS_RESPONSE } from './multi-chain-accounts-service/mocks/mock-get-supported-networks'; import { TOKEN_END_POINT_API } from './token-service'; -import type { - AllowedActions, - AllowedEvents, - TokenDetectionControllerMessenger, -} from './TokenDetectionController'; +import type { TokenDetectionControllerMessenger } from './TokenDetectionController'; import { STATIC_MAINNET_TOKEN_LIST, TokenDetectionController, @@ -148,20 +150,48 @@ const mockNetworkConfigurations: Record = { }, }; -type MainMessenger = Messenger; +type AllTokenDetectionControllerActions = + MessengerActions; + +type AllTokenDetectionControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllTokenDetectionControllerActions, + AllTokenDetectionControllerEvents +>; + +/** + * Builds a root messenger for testing. + * + * @returns The root messenger. + */ +function buildRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); +} /** * Builds a messenger that `TokenDetectionController` can use to communicate with other controllers. * - * @param messenger - The main messenger. - * @returns The restricted messenger. + * @param messenger - The root messenger. + * @returns The controller messenger. */ function buildTokenDetectionControllerMessenger( - messenger: MainMessenger = new Messenger(), + messenger = buildRootMessenger(), ): TokenDetectionControllerMessenger { - return messenger.getRestricted({ - name: controllerName, - allowedActions: [ + const tokenDetectionControllerMessenger = new Messenger< + 'TokenDetectionController', + AllTokenDetectionControllerActions, + AllTokenDetectionControllerEvents, + RootMessenger + >({ + namespace: controllerName, + parent: messenger, + }); + messenger.delegate({ + messenger: tokenDetectionControllerMessenger, + actions: [ 'AccountsController:getAccount', 'AccountsController:getSelectedAccount', 'KeyringController:getState', @@ -175,7 +205,7 @@ function buildTokenDetectionControllerMessenger( 'TokensController:addTokens', 'NetworkController:findNetworkClientIdByChainId', ], - allowedEvents: [ + events: [ 'AccountsController:selectedEvmAccountChange', 'KeyringController:lock', 'KeyringController:unlock', @@ -185,6 +215,7 @@ function buildTokenDetectionControllerMessenger( 'TransactionController:transactionConfirmed', ], }); + return tokenDetectionControllerMessenger; } const mockMultiChainAccountsService = () => { @@ -3918,7 +3949,7 @@ type WithControllerCallback = ({ triggerTransactionConfirmed, }: { controller: TokenDetectionController; - messenger: MainMessenger; + messenger: RootMessenger; mockGetAccount: (internalAccount: InternalAccount) => void; mockGetSelectedAccount: (address: string) => void; mockKeyringGetState: (state: KeyringControllerState) => void; @@ -3974,7 +4005,7 @@ async function withController( ): Promise { const [{ ...rest }, fn] = args.length === 2 ? args : [{}, args[0]]; const { options, isKeyringUnlocked, mocks } = rest; - const messenger = new Messenger(); + const messenger = buildRootMessenger(); const mockGetAccount = jest.fn(); messenger.registerActionHandler( @@ -4075,12 +4106,15 @@ async function withController( .mockResolvedValue(undefined), ); - const callActionSpy = jest.spyOn(messenger, 'call'); + const tokenDetectionControllerMessenger = + buildTokenDetectionControllerMessenger(messenger); + + const callActionSpy = jest.spyOn(tokenDetectionControllerMessenger, 'call'); const controller = new TokenDetectionController({ getBalancesInSingleCall: jest.fn(), trackMetaMetricsEvent: jest.fn(), - messenger: buildTokenDetectionControllerMessenger(messenger), + messenger: tokenDetectionControllerMessenger, useAccountsAPI: false, platform: 'extension', ...options, diff --git a/packages/assets-controllers/src/TokenDetectionController.ts b/packages/assets-controllers/src/TokenDetectionController.ts index 5b93deaf696..af1a39ef05b 100644 --- a/packages/assets-controllers/src/TokenDetectionController.ts +++ b/packages/assets-controllers/src/TokenDetectionController.ts @@ -4,10 +4,9 @@ import type { AccountsControllerSelectedEvmAccountChangeEvent, } from '@metamask/accounts-controller'; import type { - RestrictedMessenger, ControllerGetStateAction, ControllerStateChangeEvent, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; import contractMap from '@metamask/contract-metadata'; import { ASSET_TYPES, @@ -22,6 +21,7 @@ import type { KeyringControllerLockEvent, KeyringControllerUnlockEvent, } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkClientId, NetworkControllerFindNetworkClientIdByChainIdAction, @@ -158,12 +158,10 @@ export type AllowedEvents = | PreferencesControllerStateChangeEvent | TransactionControllerTransactionConfirmedEvent; -export type TokenDetectionControllerMessenger = RestrictedMessenger< +export type TokenDetectionControllerMessenger = Messenger< typeof controllerName, TokenDetectionControllerActions | AllowedActions, - TokenDetectionControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TokenDetectionControllerEvents | AllowedEvents >; /** The input to start polling for the {@link TokenDetectionController} */ @@ -275,7 +273,7 @@ export class TokenDetectionController extends StaticIntervalPollingController { + this.messenger.subscribe('KeyringController:unlock', async () => { this.#isUnlocked = true; await this.#restartTokenDetection(); }); - this.messagingSystem.subscribe('KeyringController:lock', () => { + this.messenger.subscribe('KeyringController:lock', () => { this.#isUnlocked = false; this.#stopPolling(); }); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TokenListController:stateChange', async ({ tokensChainsCache }) => { const isEqualValues = this.#compareTokensChainsCache( @@ -385,7 +382,7 @@ export class TokenDetectionController extends StaticIntervalPollingController { const selectedAccount = this.#getSelectedAccount(); @@ -402,10 +399,10 @@ export class TokenDetectionController extends StaticIntervalPollingController { - const { networkConfigurationsByChainId } = this.messagingSystem.call( + const { networkConfigurationsByChainId } = this.messenger.call( 'NetworkController:getState', ); @@ -422,7 +419,7 @@ export class TokenDetectionController extends StaticIntervalPollingController { await this.detectTokens({ @@ -521,10 +518,10 @@ export class TokenDetectionController extends StaticIntervalPollingController, - ExtractAvailableEvent +type AllTokenListControllerActions = + MessengerActions; + +type AllTokenListControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllTokenListControllerActions, + AllTokenListControllerEvents >; -const getMessenger = (): MainMessenger => { - return new Messenger(); +const getMessenger = (): RootMessenger => { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); }; -const getRestrictedMessenger = (messenger: MainMessenger) => { - return messenger.getRestricted({ - name, - allowedActions: ['NetworkController:getNetworkClientById'], - allowedEvents: ['NetworkController:stateChange'], +const getRestrictedMessenger = ( + messenger: RootMessenger, +): TokenListControllerMessenger => { + const tokenListControllerMessenger = new Messenger< + typeof namespace, + AllTokenListControllerActions, + AllTokenListControllerEvents, + RootMessenger + >({ + namespace, + parent: messenger, + }); + messenger.delegate({ + messenger: tokenListControllerMessenger, + actions: ['NetworkController:getNetworkClientById'], + events: ['NetworkController:stateChange'], }); + return tokenListControllerMessenger; }; describe('TokenListController', () => { @@ -1276,7 +1298,7 @@ describe('TokenListController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { diff --git a/packages/assets-controllers/src/TokenListController.ts b/packages/assets-controllers/src/TokenListController.ts index c11e4d1692c..3b40ae7b6df 100644 --- a/packages/assets-controllers/src/TokenListController.ts +++ b/packages/assets-controllers/src/TokenListController.ts @@ -1,9 +1,10 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { safelyExecute } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkControllerStateChangeEvent, NetworkState, @@ -68,25 +69,23 @@ type AllowedActions = NetworkControllerGetNetworkClientByIdAction; type AllowedEvents = NetworkControllerStateChangeEvent; -export type TokenListControllerMessenger = RestrictedMessenger< +export type TokenListControllerMessenger = Messenger< typeof name, TokenListControllerActions | AllowedActions, - TokenListControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TokenListControllerEvents | AllowedEvents >; -const metadata = { +const metadata: StateMetadata = { tokensChainsCache: { includeInStateLogs: false, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, preventPollingOnNetworkRestart: { includeInStateLogs: false, persist: true, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, }; @@ -173,7 +172,7 @@ export class TokenListController extends StaticIntervalPollingController; + +type AllTokenRatesControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllTokenRatesControllerActions, + AllTokenRatesControllerEvents >; /** * Builds a messenger that `TokenRatesController` can use to communicate with other controllers. * - * @param messenger - The main messenger. - * @returns The restricted messenger. + * @param messenger - The root messenger. + * @returns The controller messenger. */ function buildTokenRatesControllerMessenger( - messenger: MainMessenger = new Messenger(), + messenger: RootMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }), ): TokenRatesControllerMessenger { - return messenger.getRestricted({ - name: controllerName, - allowedActions: [ + const tokenRatesControllerMessenger = new Messenger< + 'TokenRatesController', + AllTokenRatesControllerActions, + AllTokenRatesControllerEvents, + RootMessenger + >({ + namespace: controllerName, + parent: messenger, + }); + messenger.delegate({ + messenger: tokenRatesControllerMessenger, + actions: [ 'TokensController:getState', 'NetworkController:getNetworkClientById', 'NetworkController:getState', 'AccountsController:getAccount', 'AccountsController:getSelectedAccount', ], - allowedEvents: [ + events: [ 'TokensController:stateChange', 'NetworkController:stateChange', 'AccountsController:selectedEvmAccountChange', ], }); + return tokenRatesControllerMessenger; } describe('TokenRatesController', () => { @@ -2689,7 +2710,7 @@ describe('TokenRatesController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); @@ -2793,7 +2814,9 @@ async function withController( mockTokensControllerState, mockNetworkState, } = rest; - const messenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const mockTokensState = jest.fn(); messenger.registerActionHandler( diff --git a/packages/assets-controllers/src/TokenRatesController.ts b/packages/assets-controllers/src/TokenRatesController.ts index 37ae246919f..f5d1d382d4f 100644 --- a/packages/assets-controllers/src/TokenRatesController.ts +++ b/packages/assets-controllers/src/TokenRatesController.ts @@ -6,13 +6,14 @@ import type { import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { safelyExecute, toChecksumHexAddress, FALL_BACK_VS_CURRENCY, } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction, @@ -157,12 +158,10 @@ export type TokenRatesControllerEvents = TokenRatesControllerStateChangeEvent; /** * The messenger of the {@link TokenRatesController} for communication. */ -export type TokenRatesControllerMessenger = RestrictedMessenger< +export type TokenRatesControllerMessenger = Messenger< typeof controllerName, TokenRatesControllerActions | AllowedActions, - TokenRatesControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TokenRatesControllerEvents | AllowedEvents >; /** @@ -202,11 +201,11 @@ async function getCurrencyConversionRate({ } } -const tokenRatesControllerMetadata = { +const tokenRatesControllerMetadata: StateMetadata = { marketData: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -298,7 +297,7 @@ export class TokenRatesController extends StaticIntervalPollingController { - const { networkConfigurationsByChainId } = this.messagingSystem.call( + const { networkConfigurationsByChainId } = this.messenger.call( 'NetworkController:getState', ); diff --git a/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.test.ts b/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.test.ts index 2148acd60c2..86d1b7e01e2 100644 --- a/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.test.ts +++ b/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.test.ts @@ -1,5 +1,12 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { ChainId } from '@metamask/controller-utils'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; import assert from 'assert'; import { useFakeTimers } from 'sinon'; @@ -9,8 +16,6 @@ import { TokenSearchDiscoveryDataController, controllerName, MAX_TOKEN_DISPLAY_DATA_LENGTH, - type AllowedActions, - type AllowedEvents, type TokenSearchDiscoveryDataControllerMessenger, type TokenSearchDiscoveryDataControllerState, } from './TokenSearchDiscoveryDataController'; @@ -32,7 +37,11 @@ jest.mock('../token-service', () => { }; }); -type MainMessenger = Messenger; +type AllActions = MessengerActions; + +type AllEvents = MessengerEvents; + +type RootMessenger = Messenger; /** * Builds a not found token display data object. @@ -111,13 +120,21 @@ function buildFoundTokenDisplayData( * @returns The restricted messenger. */ function buildTokenSearchDiscoveryDataControllerMessenger( - messenger: MainMessenger = new Messenger(), + messenger: RootMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }), ): TokenSearchDiscoveryDataControllerMessenger { - return messenger.getRestricted({ - name: controllerName, - allowedActions: ['CurrencyRateController:getState'], - allowedEvents: [], + const tokenSearchDiscoveryDataControllerMessenger = new Messenger< + typeof controllerName, + AllActions, + AllEvents, + RootMessenger + >({ + namespace: controllerName, }); + messenger.delegate({ + messenger: tokenSearchDiscoveryDataControllerMessenger, + actions: ['CurrencyRateController:getState'], + }); + return tokenSearchDiscoveryDataControllerMessenger; } /** @@ -206,7 +223,9 @@ async function withController( callback = maybeCallback; } - const messenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); messenger.registerActionHandler('CurrencyRateController:getState', () => ({ currentCurrency: 'USD', @@ -899,7 +918,7 @@ describe('TokenSearchDiscoveryDataController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts b/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts index dc508d7e3f7..7af8e66d20b 100644 --- a/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts +++ b/packages/assets-controllers/src/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.ts @@ -1,9 +1,10 @@ import { BaseController, + type StateMetadata, type ControllerGetStateAction, type ControllerStateChangeEvent, - type RestrictedMessenger, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import type { Messenger } from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; import type { TokenDisplayData } from './types'; @@ -33,20 +34,21 @@ export type TokenSearchDiscoveryDataControllerState = { >; }; -const tokenSearchDiscoveryDataControllerMetadata = { - tokenDisplayData: { - includeInStateLogs: false, - persist: true, - anonymous: false, - usedInUi: true, - }, - swapsTokenAddressesByChainId: { - includeInStateLogs: false, - persist: true, - anonymous: false, - usedInUi: true, - }, -} as const; +const tokenSearchDiscoveryDataControllerMetadata: StateMetadata = + { + tokenDisplayData: { + includeInStateLogs: false, + persist: true, + includeInDebugSnapshot: false, + usedInUi: true, + }, + swapsTokenAddressesByChainId: { + includeInStateLogs: false, + persist: true, + includeInDebugSnapshot: false, + usedInUi: true, + }, + } as const; // === MESSENGER === @@ -98,12 +100,10 @@ export type AllowedEvents = never; * The messenger which is restricted to actions and events accessed by * {@link TokenSearchDiscoveryDataController}. */ -export type TokenSearchDiscoveryDataControllerMessenger = RestrictedMessenger< +export type TokenSearchDiscoveryDataControllerMessenger = Messenger< typeof controllerName, TokenSearchDiscoveryDataControllerActions | AllowedActions, - TokenSearchDiscoveryDataControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TokenSearchDiscoveryDataControllerEvents | AllowedEvents >; /** @@ -176,7 +176,7 @@ export class TokenSearchDiscoveryDataController extends BaseController< chainId: Hex, address: string, ): Promise | null> { - const { currentCurrency } = this.messagingSystem.call( + const { currentCurrency } = this.messenger.call( 'CurrencyRateController:getState', ); @@ -251,7 +251,7 @@ export class TokenSearchDiscoveryDataController extends BaseController< } } - const { currentCurrency } = this.messagingSystem.call( + const { currentCurrency } = this.messenger.call( 'CurrencyRateController:getState', ); diff --git a/packages/assets-controllers/src/TokensController.test.ts b/packages/assets-controllers/src/TokensController.test.ts index 5bfd1fedd6a..b84f5a901b5 100644 --- a/packages/assets-controllers/src/TokensController.test.ts +++ b/packages/assets-controllers/src/TokensController.test.ts @@ -1,10 +1,10 @@ import { Contract } from '@ethersproject/contracts'; -import type { ApprovalStateChange } from '@metamask/approval-controller'; +import type { ApprovalControllerMessenger } from '@metamask/approval-controller'; import { ApprovalController, type ApprovalControllerState, } from '@metamask/approval-controller'; -import { deriveStateFromMetadata, Messenger } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import contractMaps from '@metamask/contract-metadata'; import { ApprovalType, @@ -14,6 +14,13 @@ import { InfuraNetworkType, } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, +} from '@metamask/messenger'; import type { NetworkClientConfiguration, NetworkClientId, @@ -27,10 +34,6 @@ import { v1 as uuidV1 } from 'uuid'; import { FakeProvider } from '../../../tests/fake-provider'; import { createMockInternalAccount } from '../../accounts-controller/src/tests/mocks'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../base-controller/tests/helpers'; import { buildCustomNetworkClientConfiguration, buildMockGetNetworkClientById, @@ -41,8 +44,6 @@ import { TOKEN_END_POINT_API } from './token-service'; import type { Token } from './TokenRatesController'; import { TokensController } from './TokensController'; import type { - AllowedActions, - AllowedEvents, TokensControllerMessenger, TokensControllerState, } from './TokensController'; @@ -55,10 +56,15 @@ jest.mock('uuid', () => ({ jest.mock('./Standards/ERC20Standard'); jest.mock('./Standards/NftStandards/ERC1155/ERC1155Standard'); -type UnrestrictedMessenger = Messenger< - ExtractAvailableAction, - ExtractAvailableEvent | ApprovalStateChange ->; +type AllActions = + | MessengerActions + | MessengerActions; + +type AllEvents = + | MessengerEvents + | MessengerEvents; + +type RootMessenger = Messenger; const ContractMock = jest.mocked(Contract); const uuidV1Mock = jest.mocked(uuidV1); @@ -3477,7 +3483,7 @@ describe('TokensController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); @@ -3545,7 +3551,7 @@ type WithControllerCallback = ({ changeNetwork: (networkControllerState: { selectedNetworkClientId: NetworkClientId; }) => void; - messenger: UnrestrictedMessenger; + messenger: RootMessenger; approvalController: ApprovalController; triggerSelectedAccountChange: (internalAccount: InternalAccount) => void; triggerAccountRemoved: (accountAddress: string) => void; @@ -3603,12 +3609,18 @@ async function withController( fn, ] = args.length === 2 ? args : [{}, args[0]]; - const messenger = new Messenger(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); - const approvalControllerMessenger = messenger.getRestricted({ - name: 'ApprovalController', - allowedActions: [], - allowedEvents: [], + const approvalControllerMessenger = new Messenger< + 'ApprovalController', + MessengerActions, + MessengerEvents, + RootMessenger + >({ + namespace: 'ApprovalController', + parent: messenger, }); const approvalController = new ApprovalController({ messenger: approvalControllerMessenger, @@ -3616,16 +3628,25 @@ async function withController( typesExcludedFromRateLimiting: [ApprovalType.WatchAsset], }); - const restrictedMessenger = messenger.getRestricted({ - name: 'TokensController', - allowedActions: [ + const tokensControllerMessenger = new Messenger< + 'TokensController', + MessengerActions, + MessengerEvents, + RootMessenger + >({ + namespace: 'TokensController', + parent: messenger, + }); + messenger.delegate({ + messenger: tokensControllerMessenger, + actions: [ 'ApprovalController:addRequest', 'NetworkController:getNetworkClientById', 'AccountsController:getAccount', 'AccountsController:getSelectedAccount', 'AccountsController:listAccounts', ], - allowedEvents: [ + events: [ 'NetworkController:networkDidChange', 'NetworkController:stateChange', 'AccountsController:selectedEvmAccountChange', @@ -3663,7 +3684,7 @@ async function withController( // where the provider can possibly be `undefined` if `networkClientId` is // not specified. provider: new FakeProvider(), - messenger: restrictedMessenger, + messenger: tokensControllerMessenger, ...options, }); diff --git a/packages/assets-controllers/src/TokensController.ts b/packages/assets-controllers/src/TokensController.ts index 571e28188de..8a45509a468 100644 --- a/packages/assets-controllers/src/TokensController.ts +++ b/packages/assets-controllers/src/TokensController.ts @@ -8,11 +8,11 @@ import type { } from '@metamask/accounts-controller'; import type { AddApprovalRequest } from '@metamask/approval-controller'; import type { - RestrictedMessenger, ControllerGetStateAction, ControllerStateChangeEvent, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import contractsMap from '@metamask/contract-metadata'; import { toChecksumHexAddress, @@ -27,6 +27,7 @@ import { } from '@metamask/controller-utils'; import type { KeyringControllerAccountRemovedEvent } from '@metamask/keyring-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import type { Messenger } from '@metamask/messenger'; import { abiERC721 } from '@metamask/metamask-eth-abis'; import type { NetworkClientId, @@ -88,23 +89,23 @@ export type TokensControllerState = { allDetectedTokens: { [chainId: Hex]: { [key: string]: Token[] } }; }; -const metadata = { +const metadata: StateMetadata = { allTokens: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, allIgnoredTokens: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, allDetectedTokens: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -158,12 +159,10 @@ export type AllowedEvents = /** * The messenger of the {@link TokensController}. */ -export type TokensControllerMessenger = RestrictedMessenger< +export type TokensControllerMessenger = Messenger< typeof controllerName, TokensControllerActions | AllowedActions, - TokensControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TokensControllerEvents | AllowedEvents >; export const getDefaultTokensState = (): TokensControllerState => { @@ -224,32 +223,32 @@ export class TokensController extends BaseController< this.#abortController = new AbortController(); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:addDetectedTokens` as const, this.addDetectedTokens.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:addTokens` as const, this.addTokens.bind(this), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountsController:selectedEvmAccountChange', this.#onSelectedAccountChange.bind(this), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'NetworkController:stateChange', this.#onNetworkStateChange.bind(this), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'KeyringController:accountRemoved', (accountAddress: string) => this.#handleOnAccountRemoved(accountAddress), ); - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TokenListController:stateChange', ({ tokensChainsCache }) => { const { allTokens } = this.state; @@ -419,7 +418,7 @@ export class TokensController extends BaseController< const releaseLock = await this.#mutex.acquire(); const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state; - const chainIdToUse = this.messagingSystem.call( + const chainIdToUse = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ).configuration.chainId; @@ -505,7 +504,7 @@ export class TokensController extends BaseController< const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state; const importedTokensMap: { [key: string]: true } = {}; - const interactingChainId = this.messagingSystem.call( + const interactingChainId = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ).configuration.chainId; @@ -581,7 +580,7 @@ export class TokensController extends BaseController< tokenAddressesToIgnore: string[], networkClientId: NetworkClientId, ) { - const interactingChainId = this.messagingSystem.call( + const interactingChainId = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ).configuration.chainId; @@ -739,7 +738,7 @@ export class TokensController extends BaseController< tokenAddress: string, networkClientId: NetworkClientId, ) { - const chainIdToUse = this.messagingSystem.call( + const chainIdToUse = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ).configuration.chainId; @@ -798,7 +797,7 @@ export class TokensController extends BaseController< #getProvider(networkClientId?: NetworkClientId): Web3Provider { return new Web3Provider( networkClientId - ? this.messagingSystem.call( + ? this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ).provider @@ -1082,7 +1081,7 @@ export class TokensController extends BaseController< } async #requestApproval(suggestedAssetMeta: SuggestedAssetMeta) { - return this.messagingSystem.call( + return this.messenger.call( 'ApprovalController:addRequest', { id: suggestedAssetMeta.id, @@ -1104,12 +1103,12 @@ export class TokensController extends BaseController< } #getSelectedAccount() { - return this.messagingSystem.call('AccountsController:getSelectedAccount'); + return this.messenger.call('AccountsController:getSelectedAccount'); } #getSelectedAddress() { // If the address is not defined (or empty), we fallback to the currently selected account's address - const account = this.messagingSystem.call( + const account = this.messenger.call( 'AccountsController:getAccount', this.#selectedAccountId, ); diff --git a/packages/assets-controllers/tsconfig.build.json b/packages/assets-controllers/tsconfig.build.json index 629b833e22a..5ef0e52c3b8 100644 --- a/packages/assets-controllers/tsconfig.build.json +++ b/packages/assets-controllers/tsconfig.build.json @@ -14,6 +14,7 @@ { "path": "../controller-utils/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, { "path": "../network-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" }, { "path": "../preferences-controller/tsconfig.build.json" }, { "path": "../polling-controller/tsconfig.build.json" }, { "path": "../permission-controller/tsconfig.build.json" }, diff --git a/packages/assets-controllers/tsconfig.json b/packages/assets-controllers/tsconfig.json index ae60fdfc0d7..a537b98ca39 100644 --- a/packages/assets-controllers/tsconfig.json +++ b/packages/assets-controllers/tsconfig.json @@ -13,6 +13,7 @@ { "path": "../controller-utils" }, { "path": "../keyring-controller" }, { "path": "../network-controller" }, + { "path": "../messenger" }, { "path": "../preferences-controller" }, { "path": "../phishing-controller" }, { "path": "../polling-controller" }, diff --git a/packages/base-controller/src/next/BaseController.test.ts b/packages/base-controller/src/next/BaseController.test.ts index 7bd2339a50a..954d3277030 100644 --- a/packages/base-controller/src/next/BaseController.test.ts +++ b/packages/base-controller/src/next/BaseController.test.ts @@ -1,5 +1,9 @@ /* eslint-disable jest/no-export */ -import { Messenger } from '@metamask/messenger'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { Json } from '@metamask/utils'; import type { Draft, Patch } from 'immer'; import * as sinon from 'sinon'; @@ -728,10 +732,10 @@ describe('BaseController', () => { it('should allow messaging between controllers', () => { // Construct root messenger const rootMessenger = new Messenger< - 'Root', + MockAnyNamespace, VisitorControllerActions | VisitorOverflowControllerActions, VisitorControllerEvents | VisitorOverflowControllerEvents - >({ namespace: 'Root' }); + >({ namespace: MOCK_ANY_NAMESPACE }); // Construct controller messengers, delegating to parent const visitorControllerMessenger = new Messenger< typeof visitorName, diff --git a/packages/bridge-controller/CHANGELOG.md b/packages/bridge-controller/CHANGELOG.md index a4e56ce0940..a4e2bb778a9 100644 --- a/packages/bridge-controller/CHANGELOG.md +++ b/packages/bridge-controller/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `BridgeControllerGetStateAction` and `BridgeControllerStateChangeEvent` types ([#6444](https://github.com/MetaMask/core/pull/6444)) + +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6444](https://github.com/MetaMask/core/pull/6444)) + - Previously, `BridgeController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [52.0.0] ### Changed diff --git a/packages/bridge-controller/package.json b/packages/bridge-controller/package.json index e8791e92762..3ad8d54ee87 100644 --- a/packages/bridge-controller/package.json +++ b/packages/bridge-controller/package.json @@ -56,6 +56,7 @@ "@metamask/controller-utils": "^11.14.1", "@metamask/gas-fee-controller": "^24.1.0", "@metamask/keyring-api": "^21.0.0", + "@metamask/messenger": "^0.3.0", "@metamask/metamask-eth-abis": "^3.1.1", "@metamask/multichain-network-controller": "^1.0.1", "@metamask/polling-controller": "^14.0.1", diff --git a/packages/bridge-controller/src/bridge-controller.test.ts b/packages/bridge-controller/src/bridge-controller.test.ts index 3ead2e8f47d..a3e8d2d2fff 100644 --- a/packages/bridge-controller/src/bridge-controller.test.ts +++ b/packages/bridge-controller/src/bridge-controller.test.ts @@ -1,7 +1,7 @@ /* eslint-disable jest/no-restricted-matchers */ /* eslint-disable jest/no-conditional-in-test */ import { Contract } from '@ethersproject/contracts'; -import { deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { BtcScope, EthAccountType, @@ -2735,7 +2735,7 @@ describe('BridgeController', function () { deriveStateFromMetadata( bridgeController.state, bridgeController.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/bridge-controller/src/bridge-controller.ts b/packages/bridge-controller/src/bridge-controller.ts index d4be29a8716..763a9553280 100644 --- a/packages/bridge-controller/src/bridge-controller.ts +++ b/packages/bridge-controller/src/bridge-controller.ts @@ -1,7 +1,7 @@ import type { BigNumber } from '@ethersproject/bignumber'; import { Contract } from '@ethersproject/contracts'; import { Web3Provider } from '@ethersproject/providers'; -import type { StateMetadata } from '@metamask/base-controller'; +import type { StateMetadata } from '@metamask/base-controller/next'; import type { TraceCallback } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; import { abiERC20 } from '@metamask/metamask-eth-abis'; @@ -80,55 +80,55 @@ const metadata: StateMetadata = { quoteRequest: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, quotes: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, quotesInitialLoadTime: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, quotesLastFetched: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, quotesLoadingStatus: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, quoteFetchError: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, quotesRefreshCount: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, assetExchangeRates: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, minimumBalanceForRentExemptionInLamports: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -236,31 +236,31 @@ export class BridgeController extends StaticIntervalPollingController fn?.()) as TraceCallback); // Register action handlers - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:setChainIntervalLength`, this.setChainIntervalLength.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:updateBridgeQuoteRequestParams`, this.updateBridgeQuoteRequestParams.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:resetState`, this.resetState.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:getBridgeERC20Allowance`, this.getBridgeERC20Allowance.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:trackUnifiedSwapBridgeEvent`, this.trackUnifiedSwapBridgeEvent.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:stopPollingForQuotes`, this.stopPollingForQuotes.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_CONTROLLER_NAME}:fetchQuotes`, this.fetchQuotes.bind(this), ); @@ -342,7 +342,7 @@ export class BridgeController extends StaticIntervalPollingController => { - const bridgeFeatureFlags = getBridgeFeatureFlags(this.messagingSystem); + const bridgeFeatureFlags = getBridgeFeatureFlags(this.messenger); // If featureId is specified, retrieve the quoteRequestOverrides for that featureId const quoteRequestOverrides = featureId ? bridgeFeatureFlags.quoteRequestOverrides?.[featureId] @@ -365,7 +365,7 @@ export class BridgeController extends StaticIntervalPollingController { return { - ...this.messagingSystem.call('MultichainAssetsRatesController:getState'), - ...this.messagingSystem.call('CurrencyRateController:getState'), - ...this.messagingSystem.call('TokenRatesController:getState'), + ...this.messenger.call('MultichainAssetsRatesController:getState'), + ...this.messenger.call('CurrencyRateController:getState'), + ...this.messenger.call('TokenRatesController:getState'), ...this.state, }; }; @@ -441,7 +441,7 @@ export class BridgeController extends StaticIntervalPollingController { const { state } = this; const { srcChainId } = state.quoteRequest; - const bridgeFeatureFlags = getBridgeFeatureFlags(this.messagingSystem); + const bridgeFeatureFlags = getBridgeFeatureFlags(this.messenger); const refreshRateOverride = srcChainId ? bridgeFeatureFlags.chains[formatChainIdToCaip(srcChainId)]?.refreshRate @@ -546,7 +546,7 @@ export class BridgeController extends StaticIntervalPollingController { const quotesWithFees = await appendFeesToQuotes( [quote], - this.messagingSystem, + this.messenger, this.#getLayer1GasFee, selectedAccount, ); @@ -736,10 +736,7 @@ export class BridgeController extends StaticIntervalPollingController { state.minimumBalanceForRentExemptionInLamports = minimumBalanceForRentExemptionInLamports; @@ -753,7 +750,7 @@ export class BridgeController extends StaticIntervalPollingController; + +export type BridgeControllerStateChangeEvent = ControllerStateChangeEvent< + typeof BRIDGE_CONTROLLER_NAME, + BridgeControllerState +>; + // Maps to BridgeController function names export type BridgeControllerActions = + | BridgeControllerGetStateAction | BridgeControllerAction | BridgeControllerAction | BridgeControllerAction @@ -348,10 +360,7 @@ export type BridgeControllerActions = | BridgeControllerAction | BridgeControllerAction; -export type BridgeControllerEvents = ControllerStateChangeEvent< - typeof BRIDGE_CONTROLLER_NAME, - BridgeControllerState ->; +export type BridgeControllerEvents = BridgeControllerStateChangeEvent; export type AllowedActions = | AccountsControllerGetAccountByAddressAction @@ -368,10 +377,8 @@ export type AllowedEvents = never; /** * The messenger for the BridgeController. */ -export type BridgeControllerMessenger = RestrictedMessenger< +export type BridgeControllerMessenger = Messenger< typeof BRIDGE_CONTROLLER_NAME, BridgeControllerActions | AllowedActions, - BridgeControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + BridgeControllerEvents | AllowedEvents >; diff --git a/packages/bridge-status-controller/CHANGELOG.md b/packages/bridge-status-controller/CHANGELOG.md index 813fe208400..bc59736636a 100644 --- a/packages/bridge-status-controller/CHANGELOG.md +++ b/packages/bridge-status-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6444](https://github.com/MetaMask/core/pull/6444)) + - Previously, `BridgeStatusController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [51.0.0] ### Changed diff --git a/packages/bridge-status-controller/src/bridge-status-controller.test.ts b/packages/bridge-status-controller/src/bridge-status-controller.test.ts index 8b0adb571be..f2838f67100 100644 --- a/packages/bridge-status-controller/src/bridge-status-controller.test.ts +++ b/packages/bridge-status-controller/src/bridge-status-controller.test.ts @@ -1,10 +1,8 @@ /* eslint-disable jest/no-conditional-in-test */ /* eslint-disable jest/no-restricted-matchers */ -import type { AccountsControllerActions } from '@metamask/accounts-controller'; -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import type { - BridgeControllerActions, - BridgeControllerEvents, + BridgeControllerMessenger, TxData, } from '@metamask/bridge-controller'; import { @@ -17,13 +15,18 @@ import { } from '@metamask/bridge-controller'; import { ChainId } from '@metamask/bridge-controller'; import { ActionTypes, FeeType } from '@metamask/bridge-controller'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { TransactionType, TransactionStatus, } from '@metamask/transaction-controller'; import type { - TransactionControllerActions, - TransactionControllerEvents, TransactionMeta, TransactionParams, } from '@metamask/transaction-controller'; @@ -36,11 +39,7 @@ import { DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE, MAX_ATTEMPTS, } from './constants'; -import type { - BridgeStatusControllerActions, - BridgeStatusControllerEvents, - StatusResponse, -} from './types'; +import type { StatusResponse } from './types'; import { type BridgeId, type StartPollingForBridgeTxStatusArgsSerialized, @@ -54,6 +53,22 @@ import * as transactionUtils from './utils/transaction'; import { flushPromises } from '../../../tests/helpers'; import { CHAIN_IDS } from '../../bridge-controller/src/constants/chains'; +type AllBridgeStatusControllerActions = + MessengerActions; + +type AllBridgeStatusControllerEvents = + MessengerEvents; + +type AllBridgeControllerActions = MessengerActions; + +type AllBridgeControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllBridgeStatusControllerActions | AllBridgeControllerActions, + AllBridgeStatusControllerEvents | AllBridgeControllerEvents +>; + jest.mock('uuid', () => ({ v4: () => 'test-uuid-1234', })); @@ -3448,19 +3463,16 @@ describe('BridgeStatusController', () => { }); describe('subscription handlers', () => { - let mockBridgeStatusMessenger: jest.Mocked; + let mockMessenger: RootMessenger; + let mockBridgeStatusMessenger: Messenger< + 'BridgeStatusController', + MessengerActions, + MessengerEvents, + RootMessenger + >; let mockTrackEventFn: jest.Mock; let bridgeStatusController: BridgeStatusController; - let mockMessenger: Messenger< - | BridgeStatusControllerActions - | TransactionControllerActions - | BridgeControllerActions - | AccountsControllerActions, - | BridgeStatusControllerEvents - | TransactionControllerEvents - | BridgeControllerEvents - >; let mockFetchFn: jest.Mock; const consoleFn = console.warn; let consoleFnSpy: jest.SpyInstance; @@ -3470,37 +3482,38 @@ describe('BridgeStatusController', () => { jest.clearAllMocks(); // eslint-disable-next-line no-empty-function consoleFnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - mockMessenger = new Messenger< - | BridgeStatusControllerActions - | TransactionControllerActions - | BridgeControllerActions - | AccountsControllerActions, - | BridgeStatusControllerEvents - | TransactionControllerEvents - | BridgeControllerEvents - >(); - - jest.spyOn(mockMessenger, 'call').mockImplementation((..._args) => { - return Promise.resolve(); - }); - - mockBridgeStatusMessenger = mockMessenger.getRestricted({ - name: BRIDGE_STATUS_CONTROLLER_NAME, - allowedActions: [ + mockMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); + mockBridgeStatusMessenger = new Messenger({ + namespace: BRIDGE_STATUS_CONTROLLER_NAME, + parent: mockMessenger, + }); + mockMessenger.delegate({ + messenger: mockBridgeStatusMessenger, + actions: [ 'TransactionController:getState', 'BridgeController:trackUnifiedSwapBridgeEvent', 'AccountsController:getAccountByAddress', ], - allowedEvents: [ + events: [ 'TransactionController:transactionFailed', 'TransactionController:transactionConfirmed', ], - }) as never; + }); + + jest + .spyOn(mockBridgeStatusMessenger, 'call') + .mockImplementation((..._args) => { + return Promise.resolve(); + }); - const mockBridgeMessenger = mockMessenger.getRestricted({ - name: 'BridgeController', - allowedActions: [], - allowedEvents: [], + const mockBridgeMessenger = new Messenger< + 'BridgeController', + MessengerActions, + MessengerEvents, + RootMessenger + >({ + namespace: 'BridgeController', + parent: mockMessenger, }); mockTrackEventFn = jest.fn(); new BridgeController({ @@ -3932,7 +3945,7 @@ describe('BridgeStatusController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/bridge-status-controller/src/bridge-status-controller.ts b/packages/bridge-status-controller/src/bridge-status-controller.ts index 74bf85878bb..d9828b90f7a 100644 --- a/packages/bridge-status-controller/src/bridge-status-controller.ts +++ b/packages/bridge-status-controller/src/bridge-status-controller.ts @@ -1,5 +1,5 @@ import type { AccountsControllerState } from '@metamask/accounts-controller'; -import type { StateMetadata } from '@metamask/base-controller'; +import type { StateMetadata } from '@metamask/base-controller/next'; import type { QuoteMetadata, RequiredEventContextFromClient, @@ -81,7 +81,7 @@ const metadata: StateMetadata = { txHistory: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -167,27 +167,27 @@ export class BridgeStatusController extends StaticIntervalPollingController fn?.()) as TraceCallback); // Register action handlers - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`, this.startPollingForBridgeTxStatus.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_STATUS_CONTROLLER_NAME}:restartPollingForFailedAttempts`, this.restartPollingForFailedAttempts.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${BRIDGE_STATUS_CONTROLLER_NAME}:getBridgeHistoryItemByTxMetaId`, this.getBridgeHistoryItemByTxMetaId.bind(this), ); @@ -195,7 +195,7 @@ export class BridgeStatusController extends StaticIntervalPollingController { const { type, status, id } = transactionMeta; @@ -227,7 +227,7 @@ export class BridgeStatusController extends StaticIntervalPollingController { const { type, id, chainId } = transactionMeta; @@ -283,10 +283,10 @@ export class BridgeStatusController extends StaticIntervalPollingController['result'], ): Promise => { const transactionHash = await hashPromise; - const finalTransactionMeta: TransactionMeta | undefined = - this.messagingSystem - .call('TransactionController:getState') - .transactions.find( - (tx: TransactionMeta) => tx.hash === transactionHash, - ); + const finalTransactionMeta: TransactionMeta | undefined = this.messenger + .call('TransactionController:getState') + .transactions.find((tx: TransactionMeta) => tx.hash === transactionHash); if (!finalTransactionMeta) { throw new Error( 'Failed to submit cross-chain swap tx: txMeta for txHash was not found', @@ -866,7 +863,7 @@ export class BridgeStatusController extends StaticIntervalPollingController => { const actionId = generateActionId().toString(); - const selectedAccount = this.messagingSystem.call( + const selectedAccount = this.messenger.call( 'AccountsController:getAccountByAddress', trade.from, ); @@ -876,7 +873,7 @@ export class BridgeStatusController extends StaticIntervalPollingController & Partial, ) => { const resetApproval = await getUSDTAllowanceResetTx( - this.messagingSystem, + this.messenger, quoteResponse, ); if (resetApproval) { @@ -933,7 +930,7 @@ export class BridgeStatusController extends StaticIntervalPollingController { - const { gasFeeEstimates } = this.messagingSystem.call( + const { gasFeeEstimates } = this.messenger.call( 'GasFeeController:getState', ); const { estimates: txGasFeeEstimates } = await this.#estimateGasFeeFn({ @@ -969,11 +966,11 @@ export class BridgeStatusController extends StaticIntervalPollingController[0], - 'messagingSystem' | 'estimateGasFeeFn' + 'messenger' | 'estimateGasFeeFn' >, ) => { const transactionParams = await getAddTransactionBatchParams({ - messagingSystem: this.messagingSystem, + messenger: this.messenger, estimateGasFeeFn: this.#estimateGasFeeFn, ...args, }); @@ -995,7 +992,7 @@ export class BridgeStatusController extends StaticIntervalPollingController & Partial, isStxEnabledOnClient: boolean, ): Promise> => { - this.messagingSystem.call('BridgeController:stopPollingForQuotes'); + this.messenger.call('BridgeController:stopPollingForQuotes'); const selectedAccount = this.#getMultichainSelectedAccount(accountAddress); if (!selectedAccount) { @@ -1121,7 +1118,7 @@ export class BridgeStatusController extends StaticIntervalPollingController id === txMetaId); @@ -1284,7 +1281,7 @@ export class BridgeStatusController extends StaticIntervalPollingController; diff --git a/packages/bridge-status-controller/src/utils/transaction.test.ts b/packages/bridge-status-controller/src/utils/transaction.test.ts index b3237bc9d43..44473eeb275 100644 --- a/packages/bridge-status-controller/src/utils/transaction.test.ts +++ b/packages/bridge-status-controller/src/utils/transaction.test.ts @@ -1651,7 +1651,7 @@ describe('Bridge Status Controller Transaction Utils', () => { const result = await getAddTransactionBatchParams({ quoteResponse: mockQuoteResponse, - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, isBridgeTx: true, trade: mockQuoteResponse.trade, approval: mockQuoteResponse.approval, @@ -1674,7 +1674,7 @@ describe('Bridge Status Controller Transaction Utils', () => { const result = await getAddTransactionBatchParams({ quoteResponse: mockQuoteResponse, - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, isBridgeTx: false, trade: mockQuoteResponse.trade, estimateGasFeeFn: jest.fn().mockResolvedValue({}), @@ -1697,7 +1697,7 @@ describe('Bridge Status Controller Transaction Utils', () => { const result = await getAddTransactionBatchParams({ quoteResponse: mockQuoteResponse, - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, isBridgeTx: true, trade: mockQuoteResponse.trade, resetApproval: mockQuoteResponse.resetApproval, @@ -1720,7 +1720,7 @@ describe('Bridge Status Controller Transaction Utils', () => { const result = await getAddTransactionBatchParams({ quoteResponse: mockQuoteResponse, - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, isBridgeTx: false, trade: mockQuoteResponse.trade, estimateGasFeeFn: jest.fn().mockResolvedValue({}), @@ -1737,7 +1737,7 @@ describe('Bridge Status Controller Transaction Utils', () => { const result = await getAddTransactionBatchParams({ quoteResponse: mockQuoteResponse, - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, isBridgeTx: false, trade: mockQuoteResponse.trade, estimateGasFeeFn: jest.fn().mockResolvedValue({}), @@ -1754,7 +1754,7 @@ describe('Bridge Status Controller Transaction Utils', () => { const result = await getAddTransactionBatchParams({ quoteResponse: mockQuoteResponse, - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, isBridgeTx: false, trade: mockQuoteResponse.trade, estimateGasFeeFn: jest.fn().mockResolvedValue({}), @@ -1827,7 +1827,7 @@ describe('Bridge Status Controller Transaction Utils', () => { }; findAndUpdateTransactionsInBatch({ - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, batchId, txDataByType, updateTransactionFn: mockUpdateTransactionFn, @@ -1871,7 +1871,7 @@ describe('Bridge Status Controller Transaction Utils', () => { }; findAndUpdateTransactionsInBatch({ - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, batchId, txDataByType, updateTransactionFn: mockUpdateTransactionFn, @@ -1905,7 +1905,7 @@ describe('Bridge Status Controller Transaction Utils', () => { }; findAndUpdateTransactionsInBatch({ - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, batchId, txDataByType, updateTransactionFn: mockUpdateTransactionFn, @@ -1943,7 +1943,7 @@ describe('Bridge Status Controller Transaction Utils', () => { }; findAndUpdateTransactionsInBatch({ - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, batchId, txDataByType, updateTransactionFn: mockUpdateTransactionFn, @@ -1985,7 +1985,7 @@ describe('Bridge Status Controller Transaction Utils', () => { }; findAndUpdateTransactionsInBatch({ - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, batchId, txDataByType, updateTransactionFn: mockUpdateTransactionFn, @@ -2015,7 +2015,7 @@ describe('Bridge Status Controller Transaction Utils', () => { // Test with bridge transaction (not swap) findAndUpdateTransactionsInBatch({ - messagingSystem: mockMessagingSystem, + messenger: mockMessagingSystem, batchId, txDataByType, updateTransactionFn: mockUpdateTransactionFn, diff --git a/packages/bridge-status-controller/src/utils/transaction.ts b/packages/bridge-status-controller/src/utils/transaction.ts index af5eab2c912..368b19167cf 100644 --- a/packages/bridge-status-controller/src/utils/transaction.ts +++ b/packages/bridge-status-controller/src/utils/transaction.ts @@ -294,7 +294,7 @@ export const toBatchTxParams = ( }; export const getAddTransactionBatchParams = async ({ - messagingSystem, + messenger, isBridgeTx, approval, resetApproval, @@ -311,7 +311,7 @@ export const getAddTransactionBatchParams = async ({ requireApproval = false, estimateGasFeeFn, }: { - messagingSystem: BridgeStatusControllerMessenger; + messenger: BridgeStatusControllerMessenger; isBridgeTx: boolean; trade: TxData; quoteResponse: Omit & @@ -322,7 +322,7 @@ export const getAddTransactionBatchParams = async ({ requireApproval?: boolean; }) => { const isGasless = gasIncluded || gasIncluded7702; - const selectedAccount = messagingSystem.call( + const selectedAccount = messenger.call( 'AccountsController:getAccountByAddress', trade.from, ); @@ -332,7 +332,7 @@ export const getAddTransactionBatchParams = async ({ ); } const hexChainId = formatChainIdToHex(trade.chainId); - const networkClientId = messagingSystem.call( + const networkClientId = messenger.call( 'NetworkController:findNetworkClientIdByChainId', hexChainId, ); @@ -344,7 +344,7 @@ export const getAddTransactionBatchParams = async ({ if (resetApproval) { const gasFees = await calculateGasFees( disable7702, - messagingSystem, + messenger, estimateGasFeeFn, resetApproval, networkClientId, @@ -361,7 +361,7 @@ export const getAddTransactionBatchParams = async ({ if (approval) { const gasFees = await calculateGasFees( disable7702, - messagingSystem, + messenger, estimateGasFeeFn, approval, networkClientId, @@ -377,7 +377,7 @@ export const getAddTransactionBatchParams = async ({ } const gasFees = await calculateGasFees( disable7702, - messagingSystem, + messenger, estimateGasFeeFn, trade, networkClientId, @@ -408,19 +408,17 @@ export const getAddTransactionBatchParams = async ({ }; export const findAndUpdateTransactionsInBatch = ({ - messagingSystem, + messenger, updateTransactionFn, batchId, txDataByType, }: { - messagingSystem: BridgeStatusControllerMessenger; + messenger: BridgeStatusControllerMessenger; updateTransactionFn: typeof TransactionController.prototype.updateTransaction; batchId: string; txDataByType: { [key in TransactionType]?: string }; }) => { - const txs = messagingSystem.call( - 'TransactionController:getState', - ).transactions; + const txs = messenger.call('TransactionController:getState').transactions; const txBatch: { approvalMeta?: TransactionMeta; tradeMeta?: TransactionMeta; diff --git a/packages/delegation-controller/CHANGELOG.md b/packages/delegation-controller/CHANGELOG.md index 0cffa5bc98c..8b458e34aa7 100644 --- a/packages/delegation-controller/CHANGELOG.md +++ b/packages/delegation-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6459](https://github.com/MetaMask/core/pull/6459)) + - Previously, `DelegationController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [0.8.0] ### Added diff --git a/packages/delegation-controller/package.json b/packages/delegation-controller/package.json index cc6a3a3bc94..cabfdb39561 100644 --- a/packages/delegation-controller/package.json +++ b/packages/delegation-controller/package.json @@ -48,6 +48,7 @@ }, "dependencies": { "@metamask/base-controller": "^8.4.1", + "@metamask/messenger": "^0.3.0", "@metamask/utils": "^11.8.1" }, "devDependencies": { diff --git a/packages/delegation-controller/src/DelegationController.test.ts b/packages/delegation-controller/src/DelegationController.test.ts index ba7ee483b84..6c701639968 100644 --- a/packages/delegation-controller/src/DelegationController.test.ts +++ b/packages/delegation-controller/src/DelegationController.test.ts @@ -1,9 +1,12 @@ -import type { AccountsControllerGetSelectedAccountAction } from '@metamask/accounts-controller'; -import { deriveStateFromMetadata, Messenger } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; +import { SignTypedDataVersion } from '@metamask/keyring-controller'; import { - type KeyringControllerSignTypedMessageAction, - SignTypedDataVersion, -} from '@metamask/keyring-controller'; + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { hexToNumber } from '@metamask/utils'; import { ROOT_AUTHORITY } from './constants'; @@ -11,7 +14,7 @@ import { controllerName, DelegationController } from './DelegationController'; import type { Address, Delegation, - DelegationControllerEvents, + DelegationControllerMessenger, DelegationControllerState, DelegationEntry, DeleGatorEnvironment, @@ -19,6 +22,18 @@ import type { } from './types'; import { toDelegationStruct } from './utils'; +type AllDelegationControllerActions = + MessengerActions; + +type AllDelegationControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllDelegationControllerActions, + AllDelegationControllerEvents +>; + const FROM_MOCK = '0x2234567890123456789012345678901234567890' as Address; const SIGNATURE_HASH_MOCK = '0x123ABC'; @@ -60,11 +75,9 @@ class TestDelegationController extends DelegationController { * @returns The mock messenger instance plus individual mock functions for each action. */ function createMessengerMock() { - const messenger = new Messenger< - | KeyringControllerSignTypedMessageAction - | AccountsControllerGetSelectedAccountAction, - DelegationControllerEvents - >(); + const messenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const accountsControllerGetSelectedAccountMock = jest.fn(); const keyringControllerSignTypedMessageMock = jest.fn(); @@ -84,19 +97,27 @@ function createMessengerMock() { keyringControllerSignTypedMessageMock, ); - const restrictedMessenger = messenger.getRestricted({ - name: `${controllerName}`, - allowedActions: [ + const delegationControllerMessenger = new Messenger< + 'DelegationController', + AllDelegationControllerActions, + AllDelegationControllerEvents, + RootMessenger + >({ + namespace: controllerName, + parent: messenger, + }); + messenger.delegate({ + messenger: delegationControllerMessenger, + actions: [ 'AccountsController:getSelectedAccount', 'KeyringController:signTypedMessage', ], - allowedEvents: [], }); return { accountsControllerGetSelectedAccountMock, keyringControllerSignTypedMessageMock, - messenger: restrictedMessenger, + messenger: delegationControllerMessenger, }; } @@ -679,7 +700,7 @@ describe(`${controllerName}`, () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/delegation-controller/src/DelegationController.ts b/packages/delegation-controller/src/DelegationController.ts index 28978762cc7..95a149ad3c7 100644 --- a/packages/delegation-controller/src/DelegationController.ts +++ b/packages/delegation-controller/src/DelegationController.ts @@ -1,5 +1,5 @@ -import type { StateMetadata } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +import type { StateMetadata } from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import { SignTypedDataVersion } from '@metamask/keyring-controller'; import { hexToNumber } from '@metamask/utils'; @@ -23,7 +23,7 @@ const delegationControllerMetadata = { delegations: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, } satisfies StateMetadata; @@ -115,7 +115,7 @@ export class DelegationController extends BaseController< // TODO:: Replace with `SignatureController:newUnsignedTypedMessage`. // Waiting on confirmations team to implement this. - const signature: string = await this.messagingSystem.call( + const signature: string = await this.messenger.call( 'KeyringController:signTypedMessage', data, SignTypedDataVersion.V4, @@ -154,7 +154,7 @@ export class DelegationController extends BaseController< * @returns A list of delegation entries that match the filter. */ list(filter?: DelegationFilter) { - const account = this.messagingSystem.call( + const account = this.messenger.call( 'AccountsController:getSelectedAccount', ); const requester = account.address as Address; diff --git a/packages/delegation-controller/src/types.ts b/packages/delegation-controller/src/types.ts index 20c73de1578..453a826be01 100644 --- a/packages/delegation-controller/src/types.ts +++ b/packages/delegation-controller/src/types.ts @@ -2,9 +2,9 @@ import type { AccountsControllerGetSelectedAccountAction } from '@metamask/accou import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; import type { KeyringControllerSignTypedMessageAction } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import type { controllerName, @@ -149,10 +149,8 @@ type AllowedActions = type AllowedEvents = never; -export type DelegationControllerMessenger = RestrictedMessenger< +export type DelegationControllerMessenger = Messenger< typeof controllerName, DelegationControllerActions | AllowedActions, - DelegationControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + DelegationControllerEvents | AllowedEvents >; diff --git a/packages/delegation-controller/tsconfig.build.json b/packages/delegation-controller/tsconfig.build.json index 573b24248e1..6f7018d977e 100644 --- a/packages/delegation-controller/tsconfig.build.json +++ b/packages/delegation-controller/tsconfig.build.json @@ -8,7 +8,8 @@ "references": [ { "path": "../base-controller/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, - { "path": "../accounts-controller/tsconfig.build.json" } + { "path": "../accounts-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] } diff --git a/packages/delegation-controller/tsconfig.json b/packages/delegation-controller/tsconfig.json index e766ef509b6..2808844b345 100644 --- a/packages/delegation-controller/tsconfig.json +++ b/packages/delegation-controller/tsconfig.json @@ -6,7 +6,8 @@ "references": [ { "path": "../base-controller" }, { "path": "../keyring-controller" }, - { "path": "../accounts-controller" } + { "path": "../accounts-controller" }, + { "path": "../messenger" } ], "include": ["../../types", "./src"] } diff --git a/packages/earn-controller/CHANGELOG.md b/packages/earn-controller/CHANGELOG.md index f6fc2a32783..412512b07ed 100644 --- a/packages/earn-controller/CHANGELOG.md +++ b/packages/earn-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6445](https://github.com/MetaMask/core/pull/6445)) + - Previously, `EarnController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [8.0.1] ### Changed diff --git a/packages/earn-controller/package.json b/packages/earn-controller/package.json index f7097b29338..e4f78344179 100644 --- a/packages/earn-controller/package.json +++ b/packages/earn-controller/package.json @@ -52,6 +52,7 @@ "@metamask/base-controller": "^8.4.1", "@metamask/controller-utils": "^11.14.1", "@metamask/keyring-api": "^21.0.0", + "@metamask/messenger": "^0.3.0", "@metamask/stake-sdk": "^3.2.1", "reselect": "^5.1.1" }, diff --git a/packages/earn-controller/src/EarnController.test.ts b/packages/earn-controller/src/EarnController.test.ts index 1920646043e..85996af48f6 100644 --- a/packages/earn-controller/src/EarnController.test.ts +++ b/packages/earn-controller/src/EarnController.test.ts @@ -1,7 +1,14 @@ /* eslint-disable jest/no-conditional-in-test */ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { toHex } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { getDefaultNetworkControllerState } from '@metamask/network-controller'; import { EarnSdk, @@ -17,10 +24,6 @@ import { EarnController, type EarnControllerState, type EarnControllerMessenger, - type EarnControllerEvents, - type EarnControllerActions, - type AllowedActions, - type AllowedEvents, DEFAULT_POOLED_STAKING_CHAIN_STATE, } from './EarnController'; import type { TransactionMeta } from '../../transaction-controller/src'; @@ -29,6 +32,16 @@ import { TransactionType, } from '../../transaction-controller/src'; +type AllEarnControllerActions = MessengerActions; + +type AllEarnControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllEarnControllerActions, + AllEarnControllerEvents +>; + jest.mock('@metamask/stake-sdk', () => ({ EarnSdk: { create: jest.fn().mockImplementation(() => ({ @@ -81,39 +94,45 @@ jest.mock('@metamask/stake-sdk', () => ({ })); /** - * Builds a new instance of the Messenger class for the EarnController. + * Builds a new instance of the root messenger. * - * @returns A new instance of the Messenger class for the EarnController. + * @returns A new instance of the root messenger. */ -function buildMessenger() { - return new Messenger< - EarnControllerActions | AllowedActions, - EarnControllerEvents | AllowedEvents - >(); +function buildMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** - * Constructs the messenger which is restricted to relevant EarnController - * actions and events. + * Constructs the messenger for EarnController. * - * @param rootMessenger - The root messenger to restrict. + * @param rootMessenger - The root messenger to set as parent. * @returns The restricted messenger. */ function getEarnControllerMessenger( rootMessenger = buildMessenger(), ): EarnControllerMessenger { - return rootMessenger.getRestricted({ - name: 'EarnController', - allowedActions: [ + const earnControllerMessenger = new Messenger< + 'EarnController', + AllEarnControllerActions, + AllEarnControllerEvents, + RootMessenger + >({ + namespace: 'EarnController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: earnControllerMessenger, + actions: [ 'NetworkController:getNetworkClientById', 'AccountTreeController:getAccountsFromSelectedAccountGroup', ], - allowedEvents: [ + events: [ 'NetworkController:networkDidChange', 'AccountTreeController:selectedAccountGroupChange', 'TransactionController:transactionConfirmed', ], }); + return earnControllerMessenger; } const mockAccount1Address = '0x1234'; @@ -1461,10 +1480,7 @@ describe('EarnController', () => { describe('On transaction confirmed', () => { let controller: EarnController; - let messenger: Messenger< - EarnControllerActions | AllowedActions, - EarnControllerEvents | AllowedEvents - >; + let messenger: RootMessenger; beforeEach(async () => { const earnController = await setupController(); @@ -2575,7 +2591,7 @@ describe('EarnController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { diff --git a/packages/earn-controller/src/EarnController.ts b/packages/earn-controller/src/EarnController.ts index 90bf5387fe0..1a3c367b620 100644 --- a/packages/earn-controller/src/EarnController.ts +++ b/packages/earn-controller/src/EarnController.ts @@ -6,13 +6,13 @@ import type { import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, StateMetadata, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import { convertHexToDecimal, toHex } from '@metamask/controller-utils'; import { isEvmAccountType } from '@metamask/keyring-api'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerNetworkDidChangeEvent, @@ -117,19 +117,19 @@ const earnControllerMetadata: StateMetadata = { pooled_staking: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, lending: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, lastUpdated: { includeInStateLogs: true, persist: false, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: false, }, }; @@ -273,12 +273,10 @@ export type AllowedEvents = * The messenger which is restricted to actions and events accessed by * EarnController. */ -export type EarnControllerMessenger = RestrictedMessenger< +export type EarnControllerMessenger = Messenger< typeof controllerName, EarnControllerActions | AllowedActions, - EarnControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + EarnControllerEvents | AllowedEvents >; // === CONTROLLER DEFINITION === @@ -344,7 +342,7 @@ export class EarnController extends BaseController< this.refreshLendingData().catch(console.error); // Listen for network changes - this.messagingSystem.subscribe( + this.messenger.subscribe( 'NetworkController:networkDidChange', (networkControllerState: NetworkState) => { this.#selectedNetworkClientId = @@ -365,7 +363,7 @@ export class EarnController extends BaseController< ); // Listen for account group changes - this.messagingSystem.subscribe( + this.messenger.subscribe( 'AccountTreeController:selectedAccountGroupChange', () => { const address = this.#getSelectedEvmAccountAddress(); @@ -379,7 +377,7 @@ export class EarnController extends BaseController< ); // Listen for confirmed staking transactions - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TransactionController:transactionConfirmed', (transactionMeta: TransactionMeta) => { /** @@ -419,7 +417,7 @@ export class EarnController extends BaseController< * @param networkClientId - The network client id to initialize the Earn SDK for. */ async #initializeSDK(networkClientId: string) { - const networkClient = this.messagingSystem.call( + const networkClient = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, ); @@ -460,7 +458,7 @@ export class EarnController extends BaseController< * @returns The EVM account or undefined if no EVM account is found. */ #getSelectedEvmAccount(): InternalAccount | undefined { - return this.messagingSystem + return this.messenger .call('AccountTreeController:getAccountsFromSelectedAccountGroup') .find((account: InternalAccount) => isEvmAccountType(account.type)); } diff --git a/packages/earn-controller/tsconfig.build.json b/packages/earn-controller/tsconfig.build.json index 439abdd5ef5..fe81e33f321 100644 --- a/packages/earn-controller/tsconfig.build.json +++ b/packages/earn-controller/tsconfig.build.json @@ -17,6 +17,9 @@ }, { "path": "../account-tree-controller/tsconfig.build.json" + }, + { + "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] diff --git a/packages/earn-controller/tsconfig.json b/packages/earn-controller/tsconfig.json index 1b34af0ba0f..8bcc4e52ff3 100644 --- a/packages/earn-controller/tsconfig.json +++ b/packages/earn-controller/tsconfig.json @@ -16,6 +16,9 @@ }, { "path": "../account-tree-controller" + }, + { + "path": "../messenger" } ] } diff --git a/packages/ens-controller/CHANGELOG.md b/packages/ens-controller/CHANGELOG.md index 09fd75e8d8c..60a3570ceb9 100644 --- a/packages/ens-controller/CHANGELOG.md +++ b/packages/ens-controller/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6459](https://github.com/MetaMask/core/pull/6460)) + - Previously, `EnsController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/base-controller` from `^8.0.1` to `^8.4.1` ([#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) - Bump `@metamask/controller-utils` from `^11.11.0` to `^11.14.1` ([#6303](https://github.com/MetaMask/core/pull/6303), [#6620](https://github.com/MetaMask/core/pull/6620), [#6629](https://github.com/MetaMask/core/pull/6629), [#6807](https://github.com/MetaMask/core/pull/6807)) - Bump `@metamask/utils` from `^11.4.2` to `^11.8.1` ([#6588](https://github.com/MetaMask/core/pull/6588), [#6708](https://github.com/MetaMask/core/pull/6708)) diff --git a/packages/ens-controller/package.json b/packages/ens-controller/package.json index db3e6f59276..f0b3c0390ae 100644 --- a/packages/ens-controller/package.json +++ b/packages/ens-controller/package.json @@ -50,6 +50,7 @@ "@ethersproject/providers": "^5.7.0", "@metamask/base-controller": "^8.4.1", "@metamask/controller-utils": "^11.14.1", + "@metamask/messenger": "^0.3.0", "@metamask/utils": "^11.8.1", "punycode": "^2.1.1" }, diff --git a/packages/ens-controller/src/EnsController.test.ts b/packages/ens-controller/src/EnsController.test.ts index 546fbbc0195..52bd47d6875 100644 --- a/packages/ens-controller/src/EnsController.test.ts +++ b/packages/ens-controller/src/EnsController.test.ts @@ -1,20 +1,23 @@ import * as providersModule from '@ethersproject/providers'; -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { toChecksumHexAddress, toHex, InfuraNetworkType, } from '@metamask/controller-utils'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { type NetworkController, type NetworkState, getDefaultNetworkControllerState, } from '@metamask/network-controller'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../base-controller/tests/helpers'; import { buildMockGetNetworkClientById, buildCustomNetworkClientConfiguration, @@ -23,7 +26,6 @@ import { EnsController, DEFAULT_ENS_NETWORK_MAP } from './EnsController'; import type { EnsControllerState, EnsControllerMessenger, - AllowedActions, } from './EnsController'; const defaultState: EnsControllerState = { @@ -54,9 +56,14 @@ jest.mock('@ethersproject/providers', () => { }; }); +type AllEnsControllerActions = MessengerActions; + +type AllEnsControllerEvents = MessengerEvents; + type RootMessenger = Messenger< - ExtractAvailableAction, - ExtractAvailableEvent + MockAnyNamespace, + AllEnsControllerActions, + AllEnsControllerEvents >; const ZERO_X_ERROR_ADDRESS = '0x'; @@ -76,27 +83,24 @@ const name = 'EnsController'; /** * Constructs the root messenger. * - * @returns A restricted messenger. + * @returns A root messenger. */ function getRootMessenger(): RootMessenger { - return new Messenger< - ExtractAvailableAction | AllowedActions, - ExtractAvailableEvent | never - >(); + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** - * Constructs the messenger restricted to EnsController actions and events. + * Constructs the messenger for EnsController actions and events. * - * @param rootMessenger - The root messenger to base the restricted messenger + * @param rootMessenger - The root messenger to base the controller messenger * off of. * @param getNetworkClientByIdMock - Optional mock version of `getNetworkClientById`. - * @returns A restricted messenger. + * @returns A controller messenger for EnsController. */ -function getRestrictedMessenger( +function getEnsControllerMessenger( rootMessenger: RootMessenger, getNetworkClientByIdMock?: NetworkController['getNetworkClientById'], -) { +): EnsControllerMessenger { const mockNetworkState = jest.fn().mockReturnValue({ ...getDefaultNetworkControllerState(), selectedNetworkClientId: InfuraNetworkType.mainnet, @@ -115,14 +119,23 @@ function getRestrictedMessenger( getNetworkClientByIdMock, ); - return rootMessenger.getRestricted<'EnsController', AllowedActions['type']>({ - name, - allowedActions: [ + const ensControllerMessenger = new Messenger< + 'EnsController', + AllEnsControllerActions, + AllEnsControllerEvents, + RootMessenger + >({ + namespace: name, + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: ensControllerMessenger, + actions: [ 'NetworkController:getNetworkClientById', 'NetworkController:getState', ], - allowedEvents: [], }); + return ensControllerMessenger; } /** @@ -137,7 +150,7 @@ function getProvider() { describe('EnsController', () => { it('should set default state', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -146,7 +159,7 @@ describe('EnsController', () => { it('should return registry address for `.`', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -159,7 +172,7 @@ describe('EnsController', () => { it('should not return registry address for unrecognized chains', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -168,7 +181,7 @@ describe('EnsController', () => { it('should add a new ENS entry and return true', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -182,7 +195,7 @@ describe('EnsController', () => { it('should clear ensResolutionsByAddress state propery when resetState is called', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, state: { @@ -203,7 +216,7 @@ describe('EnsController', () => { it('should clear ensResolutionsByAddress state propery on networkDidChange', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, state: { @@ -224,7 +237,7 @@ describe('EnsController', () => { it('should add a new ENS entry with null address and return true', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -238,7 +251,7 @@ describe('EnsController', () => { it('should update an ENS entry and return true', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -253,7 +266,7 @@ describe('EnsController', () => { it('should update an ENS entry with null address and return true', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -268,7 +281,7 @@ describe('EnsController', () => { it('should not update an ENS entry if the address is the same (valid address) and return false', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -283,7 +296,7 @@ describe('EnsController', () => { it('should not update an ENS entry if the address is the same (null) and return false', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -298,7 +311,7 @@ describe('EnsController', () => { it('should add multiple ENS entries and update without side effects', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -325,7 +338,7 @@ describe('EnsController', () => { it('should get ENS default registry by chainId when asking for `.`', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -339,7 +352,7 @@ describe('EnsController', () => { it('should get ENS entry by chainId and ensName', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -353,7 +366,7 @@ describe('EnsController', () => { it('should return null when getting nonexistent name', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -363,7 +376,7 @@ describe('EnsController', () => { it('should return null when getting nonexistent chainId', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -373,7 +386,7 @@ describe('EnsController', () => { it('should throw on attempt to set invalid ENS entry: chainId', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -388,7 +401,7 @@ describe('EnsController', () => { it('should throw on attempt to set invalid ENS entry: ENS name', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -400,7 +413,7 @@ describe('EnsController', () => { it('should throw on attempt to set invalid ENS entry: address', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -414,7 +427,7 @@ describe('EnsController', () => { it('should remove an ENS entry and return true', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -425,7 +438,7 @@ describe('EnsController', () => { it('should remove chain entries completely when all entries are removed', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -440,7 +453,7 @@ describe('EnsController', () => { it('should return false if an ENS entry was NOT deleted due to unsafe input', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -451,7 +464,7 @@ describe('EnsController', () => { it('should return false if an ENS entry was NOT deleted', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -467,7 +480,7 @@ describe('EnsController', () => { it('should add multiple ENS entries and remove without side effects', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -489,7 +502,7 @@ describe('EnsController', () => { it('should clear all ENS entries', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -506,7 +519,7 @@ describe('EnsController', () => { describe('reverseResolveName', () => { it('should return undefined when eth provider is not defined', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ens = new EnsController({ messenger: ensControllerMessenger, }); @@ -515,7 +528,7 @@ describe('EnsController', () => { it('should return undefined when network is loading', async function () { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ens = new EnsController({ messenger: ensControllerMessenger, onNetworkDidChange: (listener) => { @@ -535,7 +548,7 @@ describe('EnsController', () => { chainId: '0x9999999', }), }); - const ensControllerMessenger = getRestrictedMessenger( + const ensControllerMessenger = getEnsControllerMessenger( rootMessenger, getNetworkClientById, ); @@ -553,7 +566,7 @@ describe('EnsController', () => { it('should only resolve an ENS name once', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest.spyOn(ethProvider, 'resolveName').mockResolvedValue(address1); jest @@ -577,7 +590,7 @@ describe('EnsController', () => { it('should fail if lookupAddress through an error', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest.spyOn(ethProvider, 'lookupAddress').mockRejectedValue('error'); jest.spyOn(providersModule, 'Web3Provider').mockReturnValue(ethProvider); @@ -596,7 +609,7 @@ describe('EnsController', () => { it('should fail if lookupAddress returns a null value', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest.spyOn(ethProvider, 'lookupAddress').mockResolvedValue(null); jest.spyOn(providersModule, 'Web3Provider').mockReturnValue(ethProvider); @@ -615,7 +628,7 @@ describe('EnsController', () => { it('should fail if resolveName through an error', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest .spyOn(ethProvider, 'lookupAddress') @@ -637,7 +650,7 @@ describe('EnsController', () => { it('should fail if resolveName returns a null value', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest.spyOn(ethProvider, 'resolveName').mockResolvedValue(null); jest @@ -659,7 +672,7 @@ describe('EnsController', () => { it('should fail if registred address is zero x error address', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest .spyOn(ethProvider, 'resolveName') @@ -683,7 +696,7 @@ describe('EnsController', () => { it('should fail if the name is registered to a different address than the reverse resolved', async () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const ethProvider = new providersModule.Web3Provider(getProvider()); jest.spyOn(ethProvider, 'resolveName').mockResolvedValue(address2); @@ -708,7 +721,7 @@ describe('EnsController', () => { describe('metadata', () => { it('includes expected state in debug snapshots', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -717,14 +730,14 @@ describe('EnsController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); it('includes expected state in state logs', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -788,7 +801,7 @@ describe('EnsController', () => { it('persists expected state', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); @@ -852,7 +865,7 @@ describe('EnsController', () => { it('exposes expected state to UI', () => { const rootMessenger = getRootMessenger(); - const ensControllerMessenger = getRestrictedMessenger(rootMessenger); + const ensControllerMessenger = getEnsControllerMessenger(rootMessenger); const controller = new EnsController({ messenger: ensControllerMessenger, }); diff --git a/packages/ens-controller/src/EnsController.ts b/packages/ens-controller/src/EnsController.ts index 14023726482..0f8f6aa79b5 100644 --- a/packages/ens-controller/src/EnsController.ts +++ b/packages/ens-controller/src/EnsController.ts @@ -1,6 +1,10 @@ import { Web3Provider } from '@ethersproject/providers'; -import type { RestrictedMessenger } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +import { + BaseController, + StateMetadata, + type ControllerGetStateAction, + type ControllerStateChangeEvent, +} from '@metamask/base-controller/next'; import type { ChainId } from '@metamask/controller-utils'; import { normalizeEnsName, @@ -11,6 +15,7 @@ import { convertHexToDecimal, toHex, } from '@metamask/controller-utils'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction, @@ -69,29 +74,37 @@ export type EnsControllerState = { ensResolutionsByAddress: { [key: string]: string }; }; +export type EnsControllerActions = ControllerGetStateAction< + typeof name, + EnsControllerState +>; + +export type EnsControllerEvents = ControllerStateChangeEvent< + typeof name, + EnsControllerState +>; + export type AllowedActions = | NetworkControllerGetNetworkClientByIdAction | NetworkControllerGetStateAction; -export type EnsControllerMessenger = RestrictedMessenger< +export type EnsControllerMessenger = Messenger< typeof name, - AllowedActions, - never, - AllowedActions['type'], - never + EnsControllerActions | AllowedActions, + EnsControllerEvents >; -const metadata = { +const metadata: StateMetadata = { ensEntries: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, ensResolutionsByAddress: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }; @@ -288,7 +301,7 @@ export class EnsController extends BaseController< } #setDefaultEthProvider(registriesByChainId?: Record) { - const { selectedNetworkClientId } = this.messagingSystem.call( + const { selectedNetworkClientId } = this.messenger.call( 'NetworkController:getState', ); this.#setEthProvider(selectedNetworkClientId, registriesByChainId); @@ -301,7 +314,7 @@ export class EnsController extends BaseController< const { configuration: { chainId: currentChainId }, provider, - } = this.messagingSystem.call( + } = this.messenger.call( 'NetworkController:getNetworkClientById', selectedNetworkClientId, ); diff --git a/packages/ens-controller/tsconfig.build.json b/packages/ens-controller/tsconfig.build.json index ac0df4920c6..c55f67af5af 100644 --- a/packages/ens-controller/tsconfig.build.json +++ b/packages/ens-controller/tsconfig.build.json @@ -8,7 +8,8 @@ "references": [ { "path": "../base-controller/tsconfig.build.json" }, { "path": "../controller-utils/tsconfig.build.json" }, - { "path": "../network-controller/tsconfig.build.json" } + { "path": "../network-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] } diff --git a/packages/ens-controller/tsconfig.json b/packages/ens-controller/tsconfig.json index 4bbb0be81b1..f62c7c2e078 100644 --- a/packages/ens-controller/tsconfig.json +++ b/packages/ens-controller/tsconfig.json @@ -6,7 +6,8 @@ "references": [ { "path": "../base-controller" }, { "path": "../controller-utils" }, - { "path": "../network-controller" } + { "path": "../network-controller" }, + { "path": "../messenger" }, ], "include": ["../../types", "./src"] } diff --git a/packages/error-reporting-service/CHANGELOG.md b/packages/error-reporting-service/CHANGELOG.md index 522c89d8669..7e1f7733e43 100644 --- a/packages/error-reporting-service/CHANGELOG.md +++ b/packages/error-reporting-service/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6462](https://github.com/MetaMask/core/pull/6462)) + - Previously, `ErrorReportingService` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/base-controller` from `^8.0.1` to `^8.4.0` ([#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632)) ## [2.0.0] diff --git a/packages/error-reporting-service/package.json b/packages/error-reporting-service/package.json index 26b505cca29..537e72fc6b0 100644 --- a/packages/error-reporting-service/package.json +++ b/packages/error-reporting-service/package.json @@ -47,7 +47,8 @@ "since-latest-release": "../../scripts/since-latest-release.sh" }, "dependencies": { - "@metamask/base-controller": "^8.4.1" + "@metamask/base-controller": "^8.4.1", + "@metamask/messenger": "^0.3.0" }, "devDependencies": { "@metamask/auto-changelog": "^3.4.4", diff --git a/packages/error-reporting-service/src/error-reporting-service.test.ts b/packages/error-reporting-service/src/error-reporting-service.test.ts index 1b3afe292d7..47ddaeb2faf 100644 --- a/packages/error-reporting-service/src/error-reporting-service.test.ts +++ b/packages/error-reporting-service/src/error-reporting-service.test.ts @@ -1,4 +1,8 @@ -import { Messenger } from '@metamask/base-controller'; +import { + Messenger, + type MessengerActions, + type MessengerEvents, +} from '@metamask/messenger'; import { captureException as sentryCaptureException } from '@sentry/core'; import type { ErrorReportingServiceMessenger } from './error-reporting-service'; @@ -68,9 +72,11 @@ describe('ErrorReportingService', () => { * @returns The messenger. */ function buildMessenger(): ErrorReportingServiceMessenger { - return new Messenger().getRestricted({ - name: 'ErrorReportingService', - allowedActions: [], - allowedEvents: [], + return new Messenger< + 'ErrorReportingService', + MessengerActions, + MessengerEvents + >({ + namespace: 'ErrorReportingService', }); } diff --git a/packages/error-reporting-service/src/error-reporting-service.ts b/packages/error-reporting-service/src/error-reporting-service.ts index c3633d098e4..a1cbf903f91 100644 --- a/packages/error-reporting-service/src/error-reporting-service.ts +++ b/packages/error-reporting-service/src/error-reporting-service.ts @@ -1,4 +1,4 @@ -import type { RestrictedMessenger } from '@metamask/base-controller'; +import type { Messenger } from '@metamask/messenger'; /** * The action which can be used to report an error. @@ -37,12 +37,10 @@ type AllowedEvents = never; * The messenger restricted to actions and events that * {@link ErrorReportingService} needs to access. */ -export type ErrorReportingServiceMessenger = RestrictedMessenger< +export type ErrorReportingServiceMessenger = Messenger< 'ErrorReportingService', ErrorReportingServiceActions | AllowedActions, - ErrorReportingServiceEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + ErrorReportingServiceEvents | AllowedEvents >; /** @@ -69,12 +67,10 @@ type ErrorReportingServiceOptions = { * * // Define the messenger type for the controller. * type AllowedActions = ErrorReportingServiceCaptureExceptionAction; - * type ExampleControllerMessenger = RestrictedMessenger< + * type ExampleControllerMessenger = Messenger< * 'ExampleController', * AllowedActions, * never, - * AllowedActions['type'], - * never * >; * * // Define the controller. @@ -86,7 +82,7 @@ type ErrorReportingServiceOptions = { * doSomething() { * // Imagine that we do something that produces an error and we want to * // report the error. - * this.messagingSystem.call( + * this.messenger.call( * 'ErrorReportingService:captureException', * new Error('Something went wrong'), * ); @@ -99,23 +95,43 @@ type ErrorReportingServiceOptions = { * import { ErrorReportingService } from '@metamask/error-reporting-service'; * import { ExampleController } from './example-controller'; * + * type AllActions = MessengerActions; + * + * type AllEvents = MessengerEvents; + * + * type RootMessenger = Messenger<'Root', AllActions, AllEvents>; + * * // Create a global messenger. * const globalMessenger = new Messenger(); * * // Register handler for the `ErrorReportingService:captureException` * // action in the global messenger. - * const errorReportingServiceMessenger = globalMessenger.getRestricted({ - * allowedActions: [], - * allowedEvents: [], + * const errorReportingServiceMessenger = new Messenger< + * 'ErrorReportingService', + * MessengerActions, + * MessengerEvents, + * RootMessenger + * >({ + * namespace: 'ErrorReportingService', + * parent: globalMessenger, * }); * const errorReportingService = new ErrorReportingService({ * messenger: errorReportingServiceMessenger, * captureException, * }); * - * const exampleControllerMessenger = globalMessenger.getRestricted({ - * allowedActions: ['ErrorReportingService:captureException'], - * allowedEvents: [], + * const exampleControllerMessenger = new Messenger< + * 'ExampleController', + * MessengerActions, + * MessengerEvents, + * RootMessenger + * >({ + * namespace: 'ExampleController', + * parent: globalMessenger, + * }); + * globalMessenger.delegate({ + * messenger: exampleControllerMessenger, + * actions: ['ErrorReportingService:captureException'], * }); * const exampleController = new ExampleController({ * messenger: exampleControllerMessenger, diff --git a/packages/gas-fee-controller/CHANGELOG.md b/packages/gas-fee-controller/CHANGELOG.md index 6a1c286bd2e..fa5db3e03e9 100644 --- a/packages/gas-fee-controller/CHANGELOG.md +++ b/packages/gas-fee-controller/CHANGELOG.md @@ -12,9 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add two new controller state metadata properties: `includeInStateLogs` and `usedInUi` ([#6473](https://github.com/MetaMask/core/pull/6473)) +- Export `GasFeeMessenger` type ([#6386](https://github.com/MetaMask/core/pull/6386), [#6444](https://github.com/MetaMask/core/pull/6444)) ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6386](https://github.com/MetaMask/core/pull/6386)) + - Previously, `GasFeeController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. - Bump `@metamask/base-controller` from `^8.0.1` to `^8.4.1` ([#6284](https://github.com/MetaMask/core/pull/6284), [#6355](https://github.com/MetaMask/core/pull/6355), [#6465](https://github.com/MetaMask/core/pull/6465), [#6632](https://github.com/MetaMask/core/pull/6632), [#6807](https://github.com/MetaMask/core/pull/6807)) - Bump `@metamask/controller-utils` from `^11.10.0` to `^11.14.1` ([#6069](https://github.com/MetaMask/core/pull/6069), [#6303](https://github.com/MetaMask/core/pull/6303), [#6620](https://github.com/MetaMask/core/pull/6620), [#6629](https://github.com/MetaMask/core/pull/6629), [#6807](https://github.com/MetaMask/core/pull/6807)) - Bump `@metamask/utils` from `^11.2.0` to `^11.8.1` ([#6054](https://github.com/MetaMask/core/pull/6054), [#6588](https://github.com/MetaMask/core/pull/6588), [#6708](https://github.com/MetaMask/core/pull/6708)) diff --git a/packages/gas-fee-controller/src/GasFeeController.test.ts b/packages/gas-fee-controller/src/GasFeeController.test.ts index 4153f3829b2..9e736d00018 100644 --- a/packages/gas-fee-controller/src/GasFeeController.test.ts +++ b/packages/gas-fee-controller/src/GasFeeController.test.ts @@ -1,16 +1,20 @@ -import { deriveStateFromMetadata, Messenger } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { ChainId, convertHexToDecimal, toHex, } from '@metamask/controller-utils'; import EthQuery from '@metamask/eth-query'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { NetworkController, NetworkStatus } from '@metamask/network-controller'; import type { - NetworkControllerGetEIP1559CompatibilityAction, - NetworkControllerGetNetworkClientByIdAction, - NetworkControllerGetStateAction, - NetworkControllerNetworkDidChangeEvent, + NetworkControllerMessenger, NetworkState, } from '@metamask/network-controller'; import type { Hex } from '@metamask/utils'; @@ -30,12 +34,11 @@ import { } from './gas-util'; import { GAS_ESTIMATE_TYPES, GasFeeController } from './GasFeeController'; import type { + GasFeeMessenger, GasFeeState, - GasFeeStateChange, GasFeeStateEthGasPrice, GasFeeStateFeeMarket, GasFeeStateLegacy, - GetGasFeeState, } from './GasFeeController'; jest.mock('./determineGasFeeCalculations'); @@ -48,39 +51,46 @@ const mockedDetermineGasFeeCalculations = const name = 'GasFeeController'; -type MainMessenger = Messenger< - | GetGasFeeState - | NetworkControllerGetStateAction - | NetworkControllerGetNetworkClientByIdAction - | NetworkControllerGetEIP1559CompatibilityAction, - GasFeeStateChange | NetworkControllerNetworkDidChangeEvent ->; +type AllGasFeeControllerActions = MessengerActions; +type AllGasFeeControllerEvents = MessengerEvents; + +type AllNetworkControllerActions = MessengerActions; +type AllNetworkControllerEvents = MessengerEvents; + +type AllActions = AllGasFeeControllerActions | AllNetworkControllerActions; +type AllEvents = AllGasFeeControllerEvents | AllNetworkControllerEvents; -const getMessenger = (): MainMessenger => { - return new Messenger(); +type RootMessenger = Messenger; + +const getRootMessenger = (): RootMessenger => { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); }; const setupNetworkController = async ({ - unrestrictedMessenger, + rootMessenger, state, clock, initializeProvider = true, }: { - unrestrictedMessenger: MainMessenger; + rootMessenger: RootMessenger; state: Partial; clock: sinon.SinonFakeTimers; initializeProvider?: boolean; }) => { - const restrictedMessenger = unrestrictedMessenger.getRestricted({ - name: 'NetworkController', - allowedActions: [], - allowedEvents: [], + const networkControllerMessenger = new Messenger< + 'NetworkController', + MessengerActions, + MessengerEvents, + typeof rootMessenger + >({ + namespace: 'NetworkController', + parent: rootMessenger, }); const infuraProjectId = '123'; const networkController = new NetworkController({ - messenger: restrictedMessenger, + messenger: networkControllerMessenger, state, infuraProjectId, getRpcServiceOptions: () => ({ @@ -117,16 +127,26 @@ const setupNetworkController = async ({ return networkController; }; -const getRestrictedMessenger = (messenger: MainMessenger) => { - return messenger.getRestricted({ - name, - allowedActions: [ +const getGasFeeControllerMessenger = (rootMessenger: RootMessenger) => { + const gasFeeControllerMessenger = new Messenger< + 'GasFeeController', + AllGasFeeControllerActions, + AllGasFeeControllerEvents, + typeof rootMessenger + >({ + namespace: 'GasFeeController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: gasFeeControllerMessenger, + actions: [ 'NetworkController:getState', 'NetworkController:getNetworkClientById', 'NetworkController:getEIP1559Compatibility', ], - allowedEvents: ['NetworkController:networkDidChange'], + events: ['NetworkController:networkDidChange'], }); + return gasFeeControllerMessenger; }; /** @@ -282,14 +302,14 @@ describe('GasFeeController', () => { interval?: number; initializeNetworkProvider?: boolean; } = {}) { - const messenger = getMessenger(); + const rootMessenger = getRootMessenger(); networkController = await setupNetworkController({ - unrestrictedMessenger: messenger, + rootMessenger, state: networkControllerState, clock, initializeProvider: initializeNetworkProvider, }); - const restrictedMessenger = getRestrictedMessenger(messenger); + const restrictedMessenger = getGasFeeControllerMessenger(rootMessenger); gasFeeController = new GasFeeController({ getProvider: jest.fn(), getChainId, @@ -1277,7 +1297,7 @@ describe('GasFeeController', () => { deriveStateFromMetadata( gasFeeController.state, gasFeeController.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/gas-fee-controller/src/GasFeeController.ts b/packages/gas-fee-controller/src/GasFeeController.ts index 6a50f0cfbdf..9daf3a70858 100644 --- a/packages/gas-fee-controller/src/GasFeeController.ts +++ b/packages/gas-fee-controller/src/GasFeeController.ts @@ -1,14 +1,15 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; import { convertHexToDecimal, safelyExecute, toHex, } from '@metamask/controller-utils'; import EthQuery from '@metamask/eth-query'; +import type { Messenger } from '@metamask/messenger'; import type { NetworkClientId, NetworkControllerGetEIP1559CompatibilityAction, @@ -160,35 +161,35 @@ type FallbackGasFeeEstimates = { networkCongestion: null; }; -const metadata = { +const metadata: StateMetadata = { gasFeeEstimatesByChainId: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, gasFeeEstimates: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, estimatedGasFeeTimeBounds: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, gasEstimateType: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, nonRPCGasFeeApisDisabled: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, }; @@ -262,12 +263,10 @@ type AllowedActions = | NetworkControllerGetNetworkClientByIdAction | NetworkControllerGetEIP1559CompatibilityAction; -type GasFeeMessenger = RestrictedMessenger< +export type GasFeeMessenger = Messenger< typeof name, GasFeeControllerActions | AllowedActions, - GasFeeControllerEvents | NetworkControllerNetworkDidChangeEvent, - AllowedActions['type'], - NetworkControllerNetworkDidChangeEvent['type'] + GasFeeControllerEvents | NetworkControllerNetworkDidChangeEvent >; const defaultState: GasFeeState = { @@ -398,14 +397,14 @@ export class GasFeeController extends StaticIntervalPollingController { describe('constructor', () => { it('creates GatorPermissionsController with default state', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); expect(controller.state.isGatorPermissionsEnabled).toBe(false); @@ -113,7 +116,7 @@ describe('GatorPermissionsController', () => { }; const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), state: customState, }); @@ -128,7 +131,7 @@ describe('GatorPermissionsController', () => { it('creates GatorPermissionsController with default config', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); expect(controller.permissionsProviderSnapId).toBe( @@ -140,7 +143,7 @@ describe('GatorPermissionsController', () => { it('isFetchingGatorPermissions is false on initialization', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), state: { isFetchingGatorPermissions: true, }, @@ -153,7 +156,7 @@ describe('GatorPermissionsController', () => { describe('disableGatorPermissions', () => { it('disables gator permissions successfully', async () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); await controller.enableGatorPermissions(); @@ -177,7 +180,7 @@ describe('GatorPermissionsController', () => { describe('fetchAndUpdateGatorPermissions', () => { it('fetches and updates gator permissions successfully', async () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); await controller.enableGatorPermissions(); @@ -224,7 +227,7 @@ describe('GatorPermissionsController', () => { it('throws error when gator permissions are not enabled', async () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); await controller.disableGatorPermissions(); @@ -240,7 +243,7 @@ describe('GatorPermissionsController', () => { }); const controller = new GatorPermissionsController({ - messenger: getMessenger(rootMessenger), + messenger: getGatorPermissionsControllerMessenger(rootMessenger), }); await controller.enableGatorPermissions(); @@ -262,7 +265,7 @@ describe('GatorPermissionsController', () => { }); const controller = new GatorPermissionsController({ - messenger: getMessenger(rootMessenger), + messenger: getGatorPermissionsControllerMessenger(rootMessenger), }); await controller.enableGatorPermissions(); @@ -286,7 +289,7 @@ describe('GatorPermissionsController', () => { }); const controller = new GatorPermissionsController({ - messenger: getMessenger(rootMessenger), + messenger: getGatorPermissionsControllerMessenger(rootMessenger), }); await controller.enableGatorPermissions(); @@ -302,7 +305,7 @@ describe('GatorPermissionsController', () => { describe('gatorPermissionsMap getter tests', () => { it('returns parsed gator permissions map', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); const { gatorPermissionsMap } = controller; @@ -340,7 +343,7 @@ describe('GatorPermissionsController', () => { }; const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), state: { gatorPermissionsMapSerialized: JSON.stringify(mockState), }, @@ -354,7 +357,7 @@ describe('GatorPermissionsController', () => { describe('message handlers tests', () => { it('registers all message handlers', () => { - const messenger = getMessenger(); + const messenger = getGatorPermissionsControllerMessenger(); const mockRegisterActionHandler = jest.spyOn( messenger, 'registerActionHandler', @@ -382,7 +385,7 @@ describe('GatorPermissionsController', () => { describe('enableGatorPermissions', () => { it('enables gator permissions successfully', async () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); await controller.enableGatorPermissions(); @@ -394,21 +397,21 @@ describe('GatorPermissionsController', () => { describe('metadata', () => { it('includes expected state in debug snapshots', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); expect( deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); it('includes expected state in state logs', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); expect( @@ -429,7 +432,7 @@ describe('GatorPermissionsController', () => { it('persists expected state', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); expect( @@ -448,7 +451,7 @@ describe('GatorPermissionsController', () => { it('exposes expected state to UI', () => { const controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); expect( @@ -484,7 +487,7 @@ describe('GatorPermissionsController', () => { beforeEach(() => { controller = new GatorPermissionsController({ - messenger: getMessenger(), + messenger: getGatorPermissionsControllerMessenger(), }); }); @@ -693,15 +696,23 @@ describe('GatorPermissionsController', () => { /** * The union of actions that the root messenger allows. */ -type RootAction = ExtractAvailableAction; +type AllGatorPermissionsControllerActions = + MessengerActions; /** * The union of events that the root messenger allows. */ -type RootEvent = ExtractAvailableEvent; +type AllGatorPermissionsControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllGatorPermissionsControllerActions, + AllGatorPermissionsControllerEvents +>; /** - * Constructs the unrestricted messenger. This can be used to call actions and + * Constructs the root messenger. This can be used to call actions and * publish events within the tests for this controller. * * @param args - The arguments to this function. @@ -725,8 +736,10 @@ function getRootMessenger({ }: { snapControllerHandleRequestActionHandler?: HandleSnapRequest['handler']; snapControllerHasActionHandler?: HasSnap['handler']; -} = {}): Messenger { - const rootMessenger = new Messenger(); +} = {}): RootMessenger { + const rootMessenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); rootMessenger.registerActionHandler( 'SnapController:handleRequest', @@ -740,18 +753,27 @@ function getRootMessenger({ } /** - * Constructs the messenger which is restricted to relevant SampleGasPricesController + * Constructs the messenger supporting relevant SampleGasPricesController * actions and events. * * @param rootMessenger - The root messenger to restrict. - * @returns The restricted messenger. + * @returns The controller messenger. */ -function getMessenger( +function getGatorPermissionsControllerMessenger( rootMessenger = getRootMessenger(), ): GatorPermissionsControllerMessenger { - return rootMessenger.getRestricted({ - name: 'GatorPermissionsController', - allowedActions: ['SnapController:handleRequest', 'SnapController:has'], - allowedEvents: [], + const gatorPermissionsControllerMessenger = new Messenger< + 'GatorPermissionsController', + AllGatorPermissionsControllerActions, + AllGatorPermissionsControllerEvents, + RootMessenger + >({ + namespace: 'GatorPermissionsController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: gatorPermissionsControllerMessenger, + actions: ['SnapController:handleRequest', 'SnapController:has'], }); + return gatorPermissionsControllerMessenger; } diff --git a/packages/gator-permissions-controller/src/GatorPermissionsController.ts b/packages/gator-permissions-controller/src/GatorPermissionsController.ts index aeaa9886681..90122bea62d 100644 --- a/packages/gator-permissions-controller/src/GatorPermissionsController.ts +++ b/packages/gator-permissions-controller/src/GatorPermissionsController.ts @@ -1,12 +1,12 @@ import type { Signer } from '@metamask/7715-permission-types'; import type { - RestrictedMessenger, ControllerGetStateAction, ControllerStateChangeEvent, StateMetadata, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import { DELEGATOR_CONTRACTS } from '@metamask/delegation-deployments'; +import type { Messenger } from '@metamask/messenger'; import type { HandleSnapRequest, HasSnap } from '@metamask/snaps-controllers'; import type { SnapId } from '@metamask/snaps-sdk'; import { HandlerType } from '@metamask/snaps-utils'; @@ -92,32 +92,33 @@ export type GatorPermissionsControllerState = { gatorPermissionsProviderSnapId: SnapId; }; -const gatorPermissionsControllerMetadata = { - isGatorPermissionsEnabled: { - includeInStateLogs: true, - persist: true, - anonymous: false, - usedInUi: false, - }, - gatorPermissionsMapSerialized: { - includeInStateLogs: true, - persist: true, - anonymous: false, - usedInUi: true, - }, - isFetchingGatorPermissions: { - includeInStateLogs: true, - persist: false, - anonymous: false, - usedInUi: false, - }, - gatorPermissionsProviderSnapId: { - includeInStateLogs: true, - persist: false, - anonymous: false, - usedInUi: false, - }, -} satisfies StateMetadata; +const gatorPermissionsControllerMetadata: StateMetadata = + { + isGatorPermissionsEnabled: { + includeInStateLogs: true, + persist: true, + includeInDebugSnapshot: false, + usedInUi: false, + }, + gatorPermissionsMapSerialized: { + includeInStateLogs: true, + persist: true, + includeInDebugSnapshot: false, + usedInUi: true, + }, + isFetchingGatorPermissions: { + includeInStateLogs: true, + persist: false, + includeInDebugSnapshot: false, + usedInUi: false, + }, + gatorPermissionsProviderSnapId: { + includeInStateLogs: true, + persist: false, + includeInDebugSnapshot: false, + usedInUi: false, + }, + } satisfies StateMetadata; /** * Constructs the default {@link GatorPermissionsController} state. This allows @@ -222,12 +223,10 @@ type AllowedEvents = GatorPermissionsControllerStateChangeEvent; /** * Messenger type for the GatorPermissionsController. */ -export type GatorPermissionsControllerMessenger = RestrictedMessenger< +export type GatorPermissionsControllerMessenger = Messenger< typeof controllerName, GatorPermissionsControllerActions | AllowedActions, - GatorPermissionsControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + GatorPermissionsControllerEvents | AllowedEvents >; /** @@ -279,22 +278,22 @@ export default class GatorPermissionsController extends BaseController< } #registerMessageHandlers(): void { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:fetchAndUpdateGatorPermissions`, this.fetchAndUpdateGatorPermissions.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:enableGatorPermissions`, this.enableGatorPermissions.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:disableGatorPermissions`, this.disableGatorPermissions.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:decodePermissionFromPermissionContextForOrigin`, this.decodePermissionFromPermissionContextForOrigin.bind(this), ); @@ -326,7 +325,7 @@ export default class GatorPermissionsController extends BaseController< StoredGatorPermission[] | null > { try { - const response = (await this.messagingSystem.call( + const response = (await this.messenger.call( 'SnapController:handleRequest', { snapId, diff --git a/packages/gator-permissions-controller/tsconfig.build.json b/packages/gator-permissions-controller/tsconfig.build.json index e5fd7422b9a..931c4d6594b 100644 --- a/packages/gator-permissions-controller/tsconfig.build.json +++ b/packages/gator-permissions-controller/tsconfig.build.json @@ -5,6 +5,9 @@ "outDir": "./dist", "rootDir": "./src" }, - "references": [{ "path": "../base-controller/tsconfig.build.json" }], + "references": [ + { "path": "../base-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } + ], "include": ["../../types", "./src"] } diff --git a/packages/gator-permissions-controller/tsconfig.json b/packages/gator-permissions-controller/tsconfig.json index 34354c4b09d..68c3ddfc2cd 100644 --- a/packages/gator-permissions-controller/tsconfig.json +++ b/packages/gator-permissions-controller/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "baseUrl": "./" }, - "references": [{ "path": "../base-controller" }], + "references": [{ "path": "../base-controller" }, { "path": "../messenger" }], "include": ["../../types", "./src"] } diff --git a/packages/keyring-controller/CHANGELOG.md b/packages/keyring-controller/CHANGELOG.md index 088d250220c..6fe65a7489d 100644 --- a/packages/keyring-controller/CHANGELOG.md +++ b/packages/keyring-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6370](https://github.com/MetaMask/core/pull/6370)) + - Previously, `KeyringController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [23.1.1] ### Changed diff --git a/packages/keyring-controller/package.json b/packages/keyring-controller/package.json index 782b40be41b..f5e11b43a83 100644 --- a/packages/keyring-controller/package.json +++ b/packages/keyring-controller/package.json @@ -55,6 +55,7 @@ "@metamask/eth-simple-keyring": "^11.0.0", "@metamask/keyring-api": "^21.0.0", "@metamask/keyring-internal-api": "^9.0.0", + "@metamask/messenger": "^0.3.0", "@metamask/utils": "^11.8.1", "async-mutex": "^0.5.0", "ethereumjs-wallet": "^1.0.1", diff --git a/packages/keyring-controller/src/KeyringController.test.ts b/packages/keyring-controller/src/KeyringController.test.ts index eab73e98fc2..681f2c4f714 100644 --- a/packages/keyring-controller/src/KeyringController.test.ts +++ b/packages/keyring-controller/src/KeyringController.test.ts @@ -1,7 +1,7 @@ import { Chain, Common, Hardfork } from '@ethereumjs/common'; import type { TypedTxData } from '@ethereumjs/tx'; import { TransactionFactory } from '@ethereumjs/tx'; -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { HdKeyring } from '@metamask/eth-hd-keyring'; import { normalize, @@ -14,6 +14,13 @@ import { import SimpleKeyring from '@metamask/eth-simple-keyring'; import type { EthKeyring } from '@metamask/keyring-internal-api'; import type { KeyringClass } from '@metamask/keyring-utils'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; import { bytesToHex, isValidHexAddress, type Hex } from '@metamask/utils'; import sinon from 'sinon'; @@ -44,6 +51,16 @@ import { MockKeyring } from '../tests/mocks/mockKeyring'; import MockShallowKeyring from '../tests/mocks/mockShallowKeyring'; import { buildMockTransaction } from '../tests/mocks/mockTransaction'; +type AllKeyringControllerActions = MessengerActions; + +type AllKeyringControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllKeyringControllerActions, + AllKeyringControllerEvents +>; + jest.mock('uuid', () => { return { ...jest.requireActual('uuid'), @@ -4272,7 +4289,7 @@ describe('KeyringController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(` Object { @@ -4356,7 +4373,7 @@ type WithControllerCallback = ({ controller: KeyringController; encryptor: MockEncryptor; initialState: KeyringControllerState; - messenger: KeyringControllerMessenger; + messenger: RootMessenger; }) => Promise | ReturnValue; type WithControllerOptions = Partial & { @@ -4387,27 +4404,28 @@ function stubKeyringClassWithAccount( } /** - * Build a messenger that includes all events used by the keyring - * controller. + * Build a root messenger. * - * @returns The messenger. + * @returns The root messenger. */ -function buildMessenger() { - return new Messenger(); +function buildRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** - * Build a restricted messenger for the keyring controller. + * Build a messenger for the keyring controller. * - * @param messenger - A messenger. + * @param messenger - An optional root messenger to use as the base for the + * controller messenger * @returns The keyring controller restricted messenger. */ -function buildKeyringControllerMessenger(messenger = buildMessenger()) { - return messenger.getRestricted({ - name: 'KeyringController', - allowedActions: [], - allowedEvents: [], - }); +function buildKeyringControllerMessenger(messenger = buildRootMessenger()) { + return new Messenger< + 'KeyringController', + KeyringControllerActions, + KeyringControllerEvents, + typeof messenger + >({ namespace: 'KeyringController', parent: messenger }); } /** @@ -4425,10 +4443,11 @@ async function withController( ): Promise { const [{ ...rest }, fn] = args.length === 2 ? args : [{}, args[0]]; const encryptor = new MockEncryptor(); - const messenger = buildKeyringControllerMessenger(); + const messenger = buildRootMessenger(); + const keyringControllerMessenger = buildKeyringControllerMessenger(messenger); const controller = new KeyringController({ encryptor, - messenger, + messenger: keyringControllerMessenger, ...rest, }); if (!rest.skipVaultCreation) { diff --git a/packages/keyring-controller/src/KeyringController.ts b/packages/keyring-controller/src/KeyringController.ts index 30cd02020fd..c21b09d1136 100644 --- a/packages/keyring-controller/src/KeyringController.ts +++ b/packages/keyring-controller/src/KeyringController.ts @@ -1,7 +1,6 @@ import type { TypedTransaction, TypedTxData } from '@ethereumjs/tx'; import { isValidPrivate, getBinarySize } from '@ethereumjs/util'; -import type { RestrictedMessenger } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +import { BaseController } from '@metamask/base-controller/next'; import * as encryptorUtils from '@metamask/browser-passworder'; import { HdKeyring } from '@metamask/eth-hd-keyring'; import { normalize as ethNormalize } from '@metamask/eth-sig-util'; @@ -15,6 +14,7 @@ import type { } from '@metamask/keyring-api'; import type { EthKeyring } from '@metamask/keyring-internal-api'; import type { KeyringClass } from '@metamask/keyring-utils'; +import type { Messenger } from '@metamask/messenger'; import type { Eip1024EncryptedData, Hex, Json } from '@metamask/utils'; import { add0x, @@ -234,12 +234,10 @@ export type KeyringControllerEvents = | KeyringControllerUnlockEvent | KeyringControllerAccountRemovedEvent; -export type KeyringControllerMessenger = RestrictedMessenger< +export type KeyringControllerMessenger = Messenger< typeof name, KeyringControllerActions, - KeyringControllerEvents, - never, - never + KeyringControllerEvents >; export type KeyringControllerOptions = { @@ -682,31 +680,31 @@ export class KeyringController extends BaseController< vault: { includeInStateLogs: false, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, isUnlocked: { includeInStateLogs: true, persist: false, - anonymous: true, + includeInDebugSnapshot: true, usedInUi: true, }, keyrings: { includeInStateLogs: true, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, encryptionKey: { includeInStateLogs: false, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, encryptionSalt: { includeInStateLogs: false, persist: false, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, }, @@ -1179,7 +1177,7 @@ export class KeyringController extends BaseController< } }); - this.messagingSystem.publish(`${name}:accountRemoved`, address); + this.messenger.publish(`${name}:accountRemoved`, address); } /** @@ -1201,7 +1199,7 @@ export class KeyringController extends BaseController< delete state.encryptionSalt; }); - this.messagingSystem.publish(`${name}:lock`); + this.messenger.publish(`${name}:lock`); }); } @@ -1697,86 +1695,86 @@ export class KeyringController extends BaseController< } /** - * Constructor helper for registering this controller's messaging system + * Constructor helper for registering this controller's messeger * actions. */ #registerMessageHandlers() { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:signMessage`, this.signMessage.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:signPersonalMessage`, this.signPersonalMessage.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:signTypedMessage`, this.signTypedMessage.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:decryptMessage`, this.decryptMessage.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:getEncryptionPublicKey`, this.getEncryptionPublicKey.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:getAccounts`, this.getAccounts.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:getKeyringsByType`, this.getKeyringsByType.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:getKeyringForAccount`, this.getKeyringForAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:persistAllKeyrings`, this.persistAllKeyrings.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:prepareUserOperation`, this.prepareUserOperation.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:patchUserOperation`, this.patchUserOperation.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:signUserOperation`, this.signUserOperation.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:addNewAccount`, this.addNewAccount.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:withKeyring`, this.withKeyring.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${name}:addNewKeyring`, this.addNewKeyring.bind(this), ); @@ -2450,7 +2448,7 @@ export class KeyringController extends BaseController< this.update((state) => { state.isUnlocked = true; }); - this.messagingSystem.publish(`${name}:unlock`); + this.messenger.publish(`${name}:unlock`); } /** diff --git a/packages/keyring-controller/tsconfig.build.json b/packages/keyring-controller/tsconfig.build.json index 38d8a31843f..0e0e00fc987 100644 --- a/packages/keyring-controller/tsconfig.build.json +++ b/packages/keyring-controller/tsconfig.build.json @@ -11,6 +11,9 @@ }, { "path": "../message-manager/tsconfig.build.json" + }, + { + "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] diff --git a/packages/keyring-controller/tsconfig.json b/packages/keyring-controller/tsconfig.json index 831b2ae3b47..aae4c04c485 100644 --- a/packages/keyring-controller/tsconfig.json +++ b/packages/keyring-controller/tsconfig.json @@ -9,6 +9,9 @@ }, { "path": "../message-manager" + }, + { + "path": "../messenger" } ], "include": ["../../types", "./src", "./tests"] diff --git a/packages/logging-controller/CHANGELOG.md b/packages/logging-controller/CHANGELOG.md index af94fed0abb..e8c20d6499f 100644 --- a/packages/logging-controller/CHANGELOG.md +++ b/packages/logging-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6463](https://github.com/MetaMask/core/pull/6463)) + - Previously, `LoggingController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [6.1.0] ### Added diff --git a/packages/logging-controller/package.json b/packages/logging-controller/package.json index 508b1a3c96b..8e7cc140265 100644 --- a/packages/logging-controller/package.json +++ b/packages/logging-controller/package.json @@ -49,6 +49,7 @@ "dependencies": { "@metamask/base-controller": "^8.4.1", "@metamask/controller-utils": "^11.14.1", + "@metamask/messenger": "^0.1.0", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/packages/logging-controller/src/LoggingController.test.ts b/packages/logging-controller/src/LoggingController.test.ts index 7c7d89023ab..38aa455fc42 100644 --- a/packages/logging-controller/src/LoggingController.test.ts +++ b/packages/logging-controller/src/LoggingController.test.ts @@ -1,7 +1,14 @@ -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import * as uuid from 'uuid'; -import type { LoggingControllerActions } from './LoggingController'; +import type { LoggingControllerMessenger } from './LoggingController'; import { LoggingController } from './LoggingController'; import { LogType } from './logTypes'; import { SigningMethod, SigningStage } from './logTypes/EthSignLog'; @@ -15,44 +22,56 @@ jest.mock('uuid', () => { }; }); -const name = 'LoggingController'; +type AllLoggingControllerActions = MessengerActions; + +type AllLoggingControllerEvents = MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllLoggingControllerActions, + AllLoggingControllerEvents +>; + +const namespace = 'LoggingController'; /** - * Constructs a unrestricted messenger. + * Constructs a root messenger instance. * - * @returns A unrestricted messenger. + * @returns A root messenger. */ -function getUnrestrictedMessenger() { - return new Messenger(); +function getRootMessenger(): RootMessenger { + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** - * Constructs a restricted messenger. + * Constructs a messenger instance for LoggingController. * - * @param messenger - An optional unrestricted messenger - * @returns A restricted messenger. + * @param messenger - An optional root messenger + * @returns A controller messenger. */ -function getRestrictedMessenger(messenger = getUnrestrictedMessenger()) { - return messenger.getRestricted({ - name, - allowedActions: [], - allowedEvents: [], +function getLoggingControllerMessenger(messenger = getRootMessenger()) { + return new Messenger< + typeof namespace, + AllLoggingControllerActions, + AllLoggingControllerEvents, + RootMessenger + >({ + namespace, + parent: messenger, }); } describe('LoggingController', () => { it('action: LoggingController:add with generic log', async () => { - const unrestricted = getUnrestrictedMessenger(); - const messenger = getRestrictedMessenger(unrestricted); + const rootMessenger = getRootMessenger(); + const messenger = getLoggingControllerMessenger(rootMessenger); const controller = new LoggingController({ messenger, }); expect( - // TODO: Either fix this lint violation or explain why it's necessary to ignore. - // eslint-disable-next-line @typescript-eslint/await-thenable - await unrestricted.call('LoggingController:add', { + rootMessenger.call('LoggingController:add', { type: LogType.GenericLog, data: `Generic log`, }), @@ -70,17 +89,15 @@ describe('LoggingController', () => { }); it('action: LoggingController:add for a signing request', async () => { - const unrestricted = getUnrestrictedMessenger(); - const messenger = getRestrictedMessenger(unrestricted); + const rootMessenger = getRootMessenger(); + const messenger = getLoggingControllerMessenger(rootMessenger); const controller = new LoggingController({ messenger, }); expect( - // TODO: Either fix this lint violation or explain why it's necessary to ignore. - // eslint-disable-next-line @typescript-eslint/await-thenable - await unrestricted.call('LoggingController:add', { + rootMessenger.call('LoggingController:add', { type: LogType.EthSignLog, data: { signingMethod: SigningMethod.PersonalSign, @@ -106,8 +123,8 @@ describe('LoggingController', () => { }); it('action: LoggingController:add prevents possible collision of ids', async () => { - const unrestricted = getUnrestrictedMessenger(); - const messenger = getRestrictedMessenger(unrestricted); + const rootMessenger = getRootMessenger(); + const messenger = getLoggingControllerMessenger(rootMessenger); const uuidV1Spy = jest.spyOn(uuid, 'v1'); const controller = new LoggingController({ @@ -115,9 +132,7 @@ describe('LoggingController', () => { }); expect( - // TODO: Either fix this lint violation or explain why it's necessary to ignore. - // eslint-disable-next-line @typescript-eslint/await-thenable - await unrestricted.call('LoggingController:add', { + rootMessenger.call('LoggingController:add', { type: LogType.GenericLog, data: `Generic log`, }), @@ -128,9 +143,7 @@ describe('LoggingController', () => { uuidV1Spy.mockReturnValueOnce(id); expect( - // TODO: Either fix this lint violation or explain why it's necessary to ignore. - // eslint-disable-next-line @typescript-eslint/await-thenable - await unrestricted.call('LoggingController:add', { + rootMessenger.call('LoggingController:add', { type: LogType.GenericLog, data: `Generic log 2`, }), @@ -159,17 +172,15 @@ describe('LoggingController', () => { }); it('internal method: clear', async () => { - const unrestricted = getUnrestrictedMessenger(); - const messenger = getRestrictedMessenger(unrestricted); + const rootMessenger = getRootMessenger(); + const messenger = getLoggingControllerMessenger(rootMessenger); const controller = new LoggingController({ messenger, }); expect( - // TODO: Either fix this lint violation or explain why it's necessary to ignore. - // eslint-disable-next-line @typescript-eslint/await-thenable - await unrestricted.call('LoggingController:add', { + rootMessenger.call('LoggingController:add', { type: LogType.EthSignLog, data: { signingMethod: SigningMethod.PersonalSign, diff --git a/packages/logging-controller/src/LoggingController.ts b/packages/logging-controller/src/LoggingController.ts index 538b201a74b..6d1f74ac77a 100644 --- a/packages/logging-controller/src/LoggingController.ts +++ b/packages/logging-controller/src/LoggingController.ts @@ -1,9 +1,9 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; +import type { Messenger } from '@metamask/messenger'; import { v1 as random } from 'uuid'; import type { Log } from './logTypes'; @@ -54,12 +54,10 @@ export type LoggingControllerStateChangeEvent = ControllerStateChangeEvent< export type LoggingControllerEvents = LoggingControllerStateChangeEvent; -export type LoggingControllerMessenger = RestrictedMessenger< +export type LoggingControllerMessenger = Messenger< typeof name, LoggingControllerActions, - LoggingControllerEvents, - never, - never + LoggingControllerEvents >; const metadata = { @@ -107,9 +105,8 @@ export class LoggingController extends BaseController< }, }); - this.messagingSystem.registerActionHandler( - `${name}:add` as const, - (log: Log) => this.add(log), + this.messenger.registerActionHandler(`${name}:add` as const, (log: Log) => + this.add(log), ); } diff --git a/packages/network-controller/CHANGELOG.md b/packages/network-controller/CHANGELOG.md index ac869187450..96b428ece7d 100644 --- a/packages/network-controller/CHANGELOG.md +++ b/packages/network-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6386](https://github.com/MetaMask/core/pull/6386)) + - Previously, `NetworkController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [24.2.1] ### Changed diff --git a/packages/network-controller/package.json b/packages/network-controller/package.json index 2daa4e84ef9..d61ef4ea301 100644 --- a/packages/network-controller/package.json +++ b/packages/network-controller/package.json @@ -55,6 +55,7 @@ "@metamask/eth-json-rpc-provider": "^5.0.1", "@metamask/eth-query": "^4.0.0", "@metamask/json-rpc-engine": "^10.1.1", + "@metamask/messenger": "^0.3.0", "@metamask/rpc-errors": "^7.0.2", "@metamask/swappable-obj-proxy": "^2.3.0", "@metamask/utils": "^11.8.1", diff --git a/packages/network-controller/src/NetworkController.ts b/packages/network-controller/src/NetworkController.ts index 00ad77d0dea..5ddfc752c3e 100644 --- a/packages/network-controller/src/NetworkController.ts +++ b/packages/network-controller/src/NetworkController.ts @@ -1,9 +1,8 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import type { Partialize } from '@metamask/controller-utils'; import { InfuraNetworkType, @@ -20,6 +19,7 @@ import { import type { ErrorReportingServiceCaptureExceptionAction } from '@metamask/error-reporting-service'; import type { PollingBlockTrackerOptions } from '@metamask/eth-block-tracker'; import EthQuery from '@metamask/eth-query'; +import type { Messenger } from '@metamask/messenger'; import { errorCodes } from '@metamask/rpc-errors'; import { createEventEmitterProxy } from '@metamask/swappable-obj-proxy'; import type { SwappableProxy } from '@metamask/swappable-obj-proxy'; @@ -603,12 +603,10 @@ export type NetworkControllerActions = */ type AllowedActions = ErrorReportingServiceCaptureExceptionAction; -export type NetworkControllerMessenger = RestrictedMessenger< +export type NetworkControllerMessenger = Messenger< typeof controllerName, NetworkControllerActions | AllowedActions, - NetworkControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + NetworkControllerEvents | AllowedEvents >; /** @@ -1202,19 +1200,19 @@ export class NetworkController extends BaseController< selectedNetworkClientId: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, networksMetadata: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, networkConfigurationsByChainId: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, }, @@ -1235,7 +1233,7 @@ export class NetworkController extends BaseController< this.state.networkConfigurationsByChainId, ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:getEthQuery`, @@ -1244,80 +1242,80 @@ export class NetworkController extends BaseController< }, ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:getNetworkClientById`, this.getNetworkClientById.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:getEIP1559Compatibility`, this.getEIP1559Compatibility.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:setActiveNetwork`, this.setActiveNetwork.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:setProviderType`, this.setProviderType.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:findNetworkClientIdByChainId`, this.findNetworkClientIdByChainId.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // TODO: Either fix this lint violation or explain why it's necessary to ignore. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:getNetworkConfigurationByChainId`, this.getNetworkConfigurationByChainId.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // ESLint is mistaken here; `name` is a string. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:getNetworkConfigurationByNetworkClientId`, this.getNetworkConfigurationByNetworkClientId.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${this.name}:getSelectedNetworkClient`, this.getSelectedNetworkClient.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${this.name}:getSelectedChainId`, this.getSelectedChainId.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // ESLint is mistaken here; `name` is a string. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:addNetwork`, this.addNetwork.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // ESLint is mistaken here; `name` is a string. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:removeNetwork`, this.removeNetwork.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( // ESLint is mistaken here; `name` is a string. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `${this.name}:updateNetwork`, @@ -1541,15 +1539,9 @@ export class NetworkController extends BaseController< updateState?: (state: Draft) => void; } = {}, ) { - this.messagingSystem.publish( - 'NetworkController:networkWillChange', - this.state, - ); + this.messenger.publish('NetworkController:networkWillChange', this.state); this.#applyNetworkSelection(networkClientId, options); - this.messagingSystem.publish( - 'NetworkController:networkDidChange', - this.state, - ); + this.messenger.publish('NetworkController:networkDidChange', this.state); await this.lookupNetwork(); } @@ -1768,7 +1760,7 @@ export class NetworkController extends BaseController< const listener = () => { networkChanged = true; try { - this.messagingSystem.unsubscribe( + this.messenger.unsubscribe( 'NetworkController:networkDidChange', listener, ); @@ -1792,10 +1784,7 @@ export class NetworkController extends BaseController< } } }; - this.messagingSystem.subscribe( - 'NetworkController:networkDidChange', - listener, - ); + this.messenger.subscribe('NetworkController:networkDidChange', listener); const { isInfura, networkStatus, isEIP1559Compatible } = await this.#determineNetworkMetadata(this.state.selectedNetworkClientId); @@ -1807,7 +1796,7 @@ export class NetworkController extends BaseController< } try { - this.messagingSystem.unsubscribe( + this.messenger.unsubscribe( 'NetworkController:networkDidChange', listener, ); @@ -1829,15 +1818,15 @@ export class NetworkController extends BaseController< if (isInfura) { if (networkStatus === NetworkStatus.Available) { - this.messagingSystem.publish('NetworkController:infuraIsUnblocked'); + this.messenger.publish('NetworkController:infuraIsUnblocked'); } else if (networkStatus === NetworkStatus.Blocked) { - this.messagingSystem.publish('NetworkController:infuraIsBlocked'); + this.messenger.publish('NetworkController:infuraIsBlocked'); } } else { // Always publish infuraIsUnblocked regardless of network status to // prevent consumers from being stuck in a blocked state if they were // previously connected to an Infura network that was blocked - this.messagingSystem.publish('NetworkController:infuraIsUnblocked'); + this.messenger.publish('NetworkController:infuraIsUnblocked'); } } @@ -2108,7 +2097,7 @@ export class NetworkController extends BaseController< }); }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:networkAdded`, newNetworkConfiguration, ); @@ -2445,7 +2434,7 @@ export class NetworkController extends BaseController< }); }); - this.messagingSystem.publish( + this.messenger.publish( 'NetworkController:networkRemoved', existingNetworkConfiguration, ); @@ -2849,7 +2838,7 @@ export class NetworkController extends BaseController< }, getRpcServiceOptions: this.#getRpcServiceOptions, getBlockTrackerOptions: this.#getBlockTrackerOptions, - messenger: this.messagingSystem, + messenger: this.messenger, isRpcFailoverEnabled: this.#isRpcFailoverEnabled, logger: this.#log, }); @@ -2866,7 +2855,7 @@ export class NetworkController extends BaseController< }, getRpcServiceOptions: this.#getRpcServiceOptions, getBlockTrackerOptions: this.#getBlockTrackerOptions, - messenger: this.messagingSystem, + messenger: this.messenger, isRpcFailoverEnabled: this.#isRpcFailoverEnabled, logger: this.#log, }); @@ -3029,7 +3018,7 @@ export class NetworkController extends BaseController< }, getRpcServiceOptions: this.#getRpcServiceOptions, getBlockTrackerOptions: this.#getBlockTrackerOptions, - messenger: this.messagingSystem, + messenger: this.messenger, isRpcFailoverEnabled: this.#isRpcFailoverEnabled, logger: this.#log, }), @@ -3047,7 +3036,7 @@ export class NetworkController extends BaseController< }, getRpcServiceOptions: this.#getRpcServiceOptions, getBlockTrackerOptions: this.#getBlockTrackerOptions, - messenger: this.messagingSystem, + messenger: this.messenger, isRpcFailoverEnabled: this.#isRpcFailoverEnabled, logger: this.#log, }), diff --git a/packages/network-controller/src/create-auto-managed-network-client.test.ts b/packages/network-controller/src/create-auto-managed-network-client.test.ts index 662b0f1a7df..bf555303429 100644 --- a/packages/network-controller/src/create-auto-managed-network-client.test.ts +++ b/packages/network-controller/src/create-auto-managed-network-client.test.ts @@ -1,18 +1,14 @@ -import { Messenger } from '@metamask/base-controller'; import { BUILT_IN_NETWORKS, NetworkType } from '@metamask/controller-utils'; import { createAutoManagedNetworkClient } from './create-auto-managed-network-client'; import * as createNetworkClientModule from './create-network-client'; -import type { - NetworkControllerActions, - NetworkControllerEvents, -} from './NetworkController'; import type { CustomNetworkClientConfiguration, InfuraNetworkClientConfiguration, } from './types'; import { NetworkClientType } from './types'; import { mockNetwork } from '../../../tests/mock-network'; +import { buildNetworkControllerMessenger } from '../tests/helpers'; describe('createAutoManagedNetworkClient', () => { const networkClientConfigurations: [ @@ -44,7 +40,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); @@ -60,7 +56,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); }).not.toThrow(); @@ -73,7 +69,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); @@ -121,7 +117,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); @@ -161,7 +157,7 @@ describe('createAutoManagedNetworkClient', () => { const getBlockTrackerOptions = () => ({ pollingInterval: 5000, }); - const messenger = getNetworkControllerMessenger(); + const messenger = buildNetworkControllerMessenger(); const { provider } = createAutoManagedNetworkClient({ networkClientConfiguration, @@ -220,7 +216,7 @@ describe('createAutoManagedNetworkClient', () => { const getBlockTrackerOptions = () => ({ pollingInterval: 5000, }); - const messenger = getNetworkControllerMessenger(); + const messenger = buildNetworkControllerMessenger(); const autoManagedNetworkClient = createAutoManagedNetworkClient({ networkClientConfiguration, @@ -288,7 +284,7 @@ describe('createAutoManagedNetworkClient', () => { const getBlockTrackerOptions = () => ({ pollingInterval: 5000, }); - const messenger = getNetworkControllerMessenger(); + const messenger = buildNetworkControllerMessenger(); const autoManagedNetworkClient = createAutoManagedNetworkClient({ networkClientConfiguration, @@ -337,7 +333,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); @@ -396,7 +392,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); @@ -457,7 +453,7 @@ describe('createAutoManagedNetworkClient', () => { const getBlockTrackerOptions = () => ({ pollingInterval: 5000, }); - const messenger = getNetworkControllerMessenger(); + const messenger = buildNetworkControllerMessenger(); const { blockTracker } = createAutoManagedNetworkClient({ networkClientConfiguration, @@ -512,7 +508,7 @@ describe('createAutoManagedNetworkClient', () => { const getBlockTrackerOptions = () => ({ pollingInterval: 5000, }); - const messenger = getNetworkControllerMessenger(); + const messenger = buildNetworkControllerMessenger(); const autoManagedNetworkClient = createAutoManagedNetworkClient({ networkClientConfiguration, @@ -574,7 +570,7 @@ describe('createAutoManagedNetworkClient', () => { const getBlockTrackerOptions = () => ({ pollingInterval: 5000, }); - const messenger = getNetworkControllerMessenger(); + const messenger = buildNetworkControllerMessenger(); const autoManagedNetworkClient = createAutoManagedNetworkClient({ networkClientConfiguration, @@ -632,7 +628,7 @@ describe('createAutoManagedNetworkClient', () => { fetch, btoa, }), - messenger: getNetworkControllerMessenger(), + messenger: buildNetworkControllerMessenger(), isRpcFailoverEnabled: false, }); // Start the block tracker @@ -646,19 +642,3 @@ describe('createAutoManagedNetworkClient', () => { }); } }); - -/** - * Constructs a NetworkController messenger. - * - * @returns The NetworkController messenger. - */ -function getNetworkControllerMessenger() { - return new Messenger< - NetworkControllerActions, - NetworkControllerEvents - >().getRestricted({ - name: 'NetworkController', - allowedActions: [], - allowedEvents: [], - }); -} diff --git a/packages/network-controller/tests/NetworkController.test.ts b/packages/network-controller/tests/NetworkController.test.ts index 358fbb79e2d..4841f92b647 100644 --- a/packages/network-controller/tests/NetworkController.test.ts +++ b/packages/network-controller/tests/NetworkController.test.ts @@ -1,7 +1,7 @@ // A lot of the tests in this file have conditionals. /* eslint-disable jest/no-conditional-in-test */ -import { deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { BuiltInNetworkName, ChainId, @@ -166,11 +166,11 @@ describe('NetworkController', () => { describe('constructor', () => { it('throws given an empty networkConfigurationsByChainId collection', () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { networkConfigurationsByChainId: {}, }, @@ -187,11 +187,11 @@ describe('NetworkController', () => { it('throws if the key under which a network configuration is filed does not match the chain ID of that network configuration', () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { networkConfigurationsByChainId: { '0x1337': buildCustomNetworkConfiguration({ @@ -213,11 +213,11 @@ describe('NetworkController', () => { it('throws if a network configuration has a defaultBlockExplorerUrlIndex that does not refer to an entry in blockExplorerUrls', () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { networkConfigurationsByChainId: { '0x1337': buildCustomNetworkConfiguration({ @@ -246,11 +246,11 @@ describe('NetworkController', () => { it('throws if a network configuration has a non-empty blockExplorerUrls but an absent defaultBlockExplorerUrlIndex', () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { networkConfigurationsByChainId: { '0x1337': buildCustomNetworkConfiguration({ @@ -278,11 +278,11 @@ describe('NetworkController', () => { it('throws if a network configuration has an invalid defaultRpcEndpointIndex', () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { networkConfigurationsByChainId: { '0x1337': buildCustomNetworkConfiguration({ @@ -310,11 +310,11 @@ describe('NetworkController', () => { it('throws if more than one RPC endpoint across network configurations has the same networkClientId', () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { networkConfigurationsByChainId: { '0x1337': buildCustomNetworkConfiguration({ @@ -357,9 +357,9 @@ describe('NetworkController', () => { 'ErrorReportingService:captureException', jest.fn(), ); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); const controller = new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { selectedNetworkClientId: 'nonexistent', networkConfigurationsByChainId: { @@ -398,10 +398,10 @@ describe('NetworkController', () => { 'ErrorReportingService:captureException', captureExceptionMock, ); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: { selectedNetworkClientId: 'nonexistent', networkConfigurationsByChainId: { @@ -442,11 +442,11 @@ describe('NetworkController', () => { invalidProjectId, )}"`, () => { const messenger = buildRootMessenger(); - const restrictedMessenger = buildNetworkControllerMessenger(messenger); + const controllerMessenger = buildNetworkControllerMessenger(messenger); expect( () => new NetworkController({ - messenger: restrictedMessenger, + messenger: controllerMessenger, state: {}, // @ts-expect-error We are intentionally passing bad input. infuraProjectId: invalidProjectId, @@ -2385,7 +2385,7 @@ describe('NetworkController', () => { }, infuraProjectId, }, - async ({ controller, messenger }) => { + async ({ controller, networkControllerMessenger }) => { const fakeProvider = buildFakeProvider([ // Called during provider initialization { @@ -2409,7 +2409,7 @@ describe('NetworkController', () => { const lookupNetworkPromise = controller.lookupNetwork(); const error = new Error('oops'); jest - .spyOn(messenger, 'unsubscribe') + .spyOn(networkControllerMessenger, 'unsubscribe') .mockImplementation((eventType) => { // This is okay. // eslint-disable-next-line jest/no-conditional-in-test @@ -2896,7 +2896,7 @@ describe('NetworkController', () => { }, infuraProjectId, }, - async ({ controller, messenger }) => { + async ({ controller, networkControllerMessenger }) => { const fakeProvider = buildFakeProvider([ // Called during provider initialization { @@ -2920,7 +2920,7 @@ describe('NetworkController', () => { const lookupNetworkPromise = controller.lookupNetwork(); const error = new Error('oops'); jest - .spyOn(messenger, 'unsubscribe') + .spyOn(networkControllerMessenger, 'unsubscribe') .mockImplementation((eventType) => { // This is okay. // eslint-disable-next-line jest/no-conditional-in-test @@ -14507,7 +14507,7 @@ describe('NetworkController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/network-controller/tests/helpers.ts b/packages/network-controller/tests/helpers.ts index 77d6100549b..bff0d7f5010 100644 --- a/packages/network-controller/tests/helpers.ts +++ b/packages/network-controller/tests/helpers.ts @@ -1,4 +1,3 @@ -import { Messenger } from '@metamask/base-controller'; import { ChainId, InfuraNetworkType, @@ -6,6 +5,13 @@ import { NetworksTicker, toHex, } from '@metamask/controller-utils'; +import { + Messenger, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, + MOCK_ANY_NAMESPACE, +} from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; import { v4 as uuidV4 } from 'uuid'; @@ -13,10 +19,6 @@ import { FakeBlockTracker } from '../../../tests/fake-block-tracker'; import { FakeProvider } from '../../../tests/fake-provider'; import type { FakeProviderStub } from '../../../tests/fake-provider'; import { buildTestObject } from '../../../tests/helpers'; -import type { - ExtractAvailableAction, - ExtractAvailableEvent, -} from '../../base-controller/tests/helpers'; import { type BuiltInNetworkClientId, type CustomNetworkClientId, @@ -42,9 +44,16 @@ import type { } from '../src/types'; import { NetworkClientType } from '../src/types'; +export type AllNetworkControllerActions = + MessengerActions; + +export type AllNetworkControllerEvents = + MessengerEvents; + export type RootMessenger = Messenger< - ExtractAvailableAction, - ExtractAvailableEvent + MockAnyNamespace, + AllNetworkControllerActions, + AllNetworkControllerEvents >; /** @@ -76,23 +85,32 @@ export const TESTNET = { * @returns The messenger. */ export function buildRootMessenger(): RootMessenger { - return new Messenger(); + return new Messenger({ namespace: MOCK_ANY_NAMESPACE }); } /** - * Build a restricted messenger for the network controller. + * Build a messenger for the network controller. * - * @param messenger - A messenger. - * @returns The network controller restricted messenger. + * @param rootMessenger - The root messenger. + * @returns The network controller messenger. */ export function buildNetworkControllerMessenger( - messenger = buildRootMessenger(), + rootMessenger = buildRootMessenger(), ): NetworkControllerMessenger { - return messenger.getRestricted({ - name: 'NetworkController', - allowedActions: ['ErrorReportingService:captureException'], - allowedEvents: [], + const networkControllerMessenger = new Messenger< + 'NetworkController', + AllNetworkControllerActions, + AllNetworkControllerEvents, + typeof rootMessenger + >({ + namespace: 'NetworkController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: networkControllerMessenger, + actions: ['ErrorReportingService:captureException'], }); + return networkControllerMessenger; } /** diff --git a/packages/network-controller/tsconfig.build.json b/packages/network-controller/tsconfig.build.json index fb5b1cb08e5..894e58c9650 100644 --- a/packages/network-controller/tsconfig.build.json +++ b/packages/network-controller/tsconfig.build.json @@ -10,7 +10,8 @@ { "path": "../controller-utils/tsconfig.build.json" }, { "path": "../eth-json-rpc-provider/tsconfig.build.json" }, { "path": "../json-rpc-engine/tsconfig.build.json" }, - { "path": "../error-reporting-service/tsconfig.build.json" } + { "path": "../error-reporting-service/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] } diff --git a/packages/network-controller/tsconfig.json b/packages/network-controller/tsconfig.json index cc0926fbd0c..6542199fa4f 100644 --- a/packages/network-controller/tsconfig.json +++ b/packages/network-controller/tsconfig.json @@ -9,7 +9,8 @@ { "path": "../controller-utils" }, { "path": "../eth-json-rpc-provider" }, { "path": "../json-rpc-engine" }, - { "path": "../error-reporting-service" } + { "path": "../error-reporting-service" }, + { "path": "../messenger" } ], "include": ["../../types", "../../tests", "./src", "./tests"] } diff --git a/packages/polling-controller/CHANGELOG.md b/packages/polling-controller/CHANGELOG.md index c47d3fbc1f3..bc9a31b9efd 100644 --- a/packages/polling-controller/CHANGELOG.md +++ b/packages/polling-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` for `StaticIntervalPollingController` and `BlockTrackerPollingController` ([#6444](https://github.com/MetaMask/core/pull/6444)) + - Previously, `StaticIntervalPollingController` and `BlockTrackerPollingController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [14.0.1] ### Changed diff --git a/packages/polling-controller/src/BlockTrackerPollingController.test.ts b/packages/polling-controller/src/BlockTrackerPollingController.test.ts index d5c8615a3ff..88321e80b97 100644 --- a/packages/polling-controller/src/BlockTrackerPollingController.test.ts +++ b/packages/polling-controller/src/BlockTrackerPollingController.test.ts @@ -1,4 +1,8 @@ -import { Messenger } from '@metamask/base-controller'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { NetworkClient } from '@metamask/network-controller'; import EventEmitter from 'events'; import { useFakeTimers } from 'sinon'; @@ -43,17 +47,13 @@ class TestBlockTracker extends EventEmitter { describe('BlockTrackerPollingController', () => { let clock: sinon.SinonFakeTimers; - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let mockMessenger: any; + let mockMessenger: Messenger; let controller: ChildBlockTrackerPollingController; let mainnetBlockTracker: TestBlockTracker; let goerliBlockTracker: TestBlockTracker; let sepoliaBlockTracker: TestBlockTracker; beforeEach(() => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - mockMessenger = new Messenger(); + mockMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); controller = new ChildBlockTrackerPollingController({ messenger: mockMessenger, metadata: {}, diff --git a/packages/polling-controller/src/BlockTrackerPollingController.ts b/packages/polling-controller/src/BlockTrackerPollingController.ts index f7221768f90..6f4725577e3 100644 --- a/packages/polling-controller/src/BlockTrackerPollingController.ts +++ b/packages/polling-controller/src/BlockTrackerPollingController.ts @@ -1,4 +1,4 @@ -import { BaseController } from '@metamask/base-controller'; +import { BaseController } from '@metamask/base-controller/next'; import type { NetworkClientId, NetworkClient, diff --git a/packages/polling-controller/src/StaticIntervalPollingController.test.ts b/packages/polling-controller/src/StaticIntervalPollingController.test.ts index 797f431bc88..380465867e8 100644 --- a/packages/polling-controller/src/StaticIntervalPollingController.test.ts +++ b/packages/polling-controller/src/StaticIntervalPollingController.test.ts @@ -1,4 +1,8 @@ -import { Messenger } from '@metamask/base-controller'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MockAnyNamespace, +} from '@metamask/messenger'; import { createDeferredPromise } from '@metamask/utils'; import { useFakeTimers } from 'sinon'; @@ -39,14 +43,10 @@ class ChildBlockTrackerPollingController extends StaticIntervalPollingController describe('StaticIntervalPollingController', () => { let clock: sinon.SinonFakeTimers; - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let mockMessenger: any; + let mockMessenger: Messenger; let controller: ChildBlockTrackerPollingController; beforeEach(() => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - mockMessenger = new Messenger(); + mockMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); controller = new ChildBlockTrackerPollingController({ messenger: mockMessenger, metadata: {}, diff --git a/packages/polling-controller/src/StaticIntervalPollingController.ts b/packages/polling-controller/src/StaticIntervalPollingController.ts index 5076dfcffdf..e71f3e44417 100644 --- a/packages/polling-controller/src/StaticIntervalPollingController.ts +++ b/packages/polling-controller/src/StaticIntervalPollingController.ts @@ -1,4 +1,4 @@ -import { BaseController } from '@metamask/base-controller'; +import { BaseController } from '@metamask/base-controller/next'; import type { Json } from '@metamask/utils'; import { diff --git a/packages/polling-controller/tsconfig.build.json b/packages/polling-controller/tsconfig.build.json index ac0df4920c6..c55f67af5af 100644 --- a/packages/polling-controller/tsconfig.build.json +++ b/packages/polling-controller/tsconfig.build.json @@ -8,7 +8,8 @@ "references": [ { "path": "../base-controller/tsconfig.build.json" }, { "path": "../controller-utils/tsconfig.build.json" }, - { "path": "../network-controller/tsconfig.build.json" } + { "path": "../network-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" } ], "include": ["../../types", "./src"] } diff --git a/packages/polling-controller/tsconfig.json b/packages/polling-controller/tsconfig.json index 9f1187b22dc..ca0d50a83f4 100644 --- a/packages/polling-controller/tsconfig.json +++ b/packages/polling-controller/tsconfig.json @@ -7,7 +7,8 @@ "references": [ { "path": "../base-controller" }, { "path": "../controller-utils" }, - { "path": "../network-controller" } + { "path": "../network-controller" }, + { "path": "../messenger" } ], "include": ["../../types", "./src", "../../tests"] } diff --git a/packages/remote-feature-flag-controller/CHANGELOG.md b/packages/remote-feature-flag-controller/CHANGELOG.md index b3713adb390..f01a3cefafa 100644 --- a/packages/remote-feature-flag-controller/CHANGELOG.md +++ b/packages/remote-feature-flag-controller/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Export additional controller types from package index ([#6835](https://github.com/MetaMask/core/pull/6835)) + - Export `RemoteFeatureFlagControllerActions` - union type of all controller actions + - Export `RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction` - action type for updating feature flags + - Export `RemoteFeatureFlagControllerEvents` - union type of all controller events + - Export `RemoteFeatureFlagControllerStateChangeEvent` - state change event type + ## [1.8.0] ### Added diff --git a/packages/remote-feature-flag-controller/src/index.ts b/packages/remote-feature-flag-controller/src/index.ts index 2c5e2cd8025..420a92b9c68 100644 --- a/packages/remote-feature-flag-controller/src/index.ts +++ b/packages/remote-feature-flag-controller/src/index.ts @@ -1,5 +1,12 @@ export { RemoteFeatureFlagController } from './remote-feature-flag-controller'; -export type { RemoteFeatureFlagControllerMessenger } from './remote-feature-flag-controller'; +export type { + RemoteFeatureFlagControllerMessenger, + RemoteFeatureFlagControllerActions, + RemoteFeatureFlagControllerGetStateAction, + RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction, + RemoteFeatureFlagControllerEvents, + RemoteFeatureFlagControllerStateChangeEvent, +} from './remote-feature-flag-controller'; export { ClientType, DistributionType, @@ -8,7 +15,6 @@ export { export type { RemoteFeatureFlagControllerState, - RemoteFeatureFlagControllerGetStateAction, FeatureFlags, } from './remote-feature-flag-controller-types'; export { ClientConfigApiService } from './client-config-api-service/client-config-api-service'; diff --git a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller-types.ts b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller-types.ts index 56fed8f1e8e..1b7d5343b8d 100644 --- a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller-types.ts +++ b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller-types.ts @@ -1,4 +1,3 @@ -import type { ControllerGetStateAction } from '@metamask/base-controller'; import type { Json } from '@metamask/utils'; // Define accepted values for client, distribution, and environment @@ -61,12 +60,3 @@ export type RemoteFeatureFlagControllerState = { */ cacheTimestamp: number; }; - -/** - * The action to retrieve the state of the {@link RemoteFeatureFlagController}. - */ -export type RemoteFeatureFlagControllerGetStateAction = - ControllerGetStateAction< - 'RemoteFeatureFlagController', - RemoteFeatureFlagControllerState - >; diff --git a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts index 640d5cac700..d12797ce148 100644 --- a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts +++ b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts @@ -1,9 +1,9 @@ +import { BaseController } from '@metamask/base-controller'; import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMessenger, } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; import type { AbstractClientConfigApiService } from './client-config-api-service/abstract-client-config-api-service'; import type { @@ -45,19 +45,23 @@ const remoteFeatureFlagControllerMetadata = { // === MESSENGER === +/** + * The action to retrieve the state of the {@link RemoteFeatureFlagController}. + */ export type RemoteFeatureFlagControllerGetStateAction = ControllerGetStateAction< typeof controllerName, RemoteFeatureFlagControllerState >; -export type RemoteFeatureFlagControllerGetRemoteFeatureFlagAction = { +export type RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction = { type: `${typeof controllerName}:updateRemoteFeatureFlags`; handler: RemoteFeatureFlagController['updateRemoteFeatureFlags']; }; export type RemoteFeatureFlagControllerActions = - RemoteFeatureFlagControllerGetStateAction; + | RemoteFeatureFlagControllerGetStateAction + | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction; export type AllowedActions = never; diff --git a/packages/transaction-controller/CHANGELOG.md b/packages/transaction-controller/CHANGELOG.md index 6953472e74b..bf0cbaf1eca 100644 --- a/packages/transaction-controller/CHANGELOG.md +++ b/packages/transaction-controller/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `txMeta` property to `GetSimulationConfig` callback ([#6833](https://github.com/MetaMask/core/pull/6833)) +### Changed + +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6386](https://github.com/MetaMask/core/pull/6386)) + - Previously, `TransactionController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. + ## [60.6.1] ### Changed diff --git a/packages/transaction-controller/package.json b/packages/transaction-controller/package.json index 09f412b7d6c..9c38caee5d8 100644 --- a/packages/transaction-controller/package.json +++ b/packages/transaction-controller/package.json @@ -57,6 +57,7 @@ "@metamask/base-controller": "^8.4.1", "@metamask/controller-utils": "^11.14.1", "@metamask/eth-query": "^4.0.0", + "@metamask/messenger": "^0.3.0", "@metamask/metamask-eth-abis": "^3.1.1", "@metamask/nonce-tracker": "^6.0.0", "@metamask/rpc-errors": "^7.0.2", diff --git a/packages/transaction-controller/src/TransactionController.test.ts b/packages/transaction-controller/src/TransactionController.test.ts index bf17aff42c8..3744b8ad49e 100644 --- a/packages/transaction-controller/src/TransactionController.test.ts +++ b/packages/transaction-controller/src/TransactionController.test.ts @@ -4,7 +4,7 @@ import type { AddApprovalRequest, AddResult, } from '@metamask/approval-controller'; -import { Messenger, deriveStateFromMetadata } from '@metamask/base-controller'; +import { deriveStateFromMetadata } from '@metamask/base-controller/next'; import { ChainId, NetworkType, @@ -15,6 +15,13 @@ import { import type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider'; import EthQuery from '@metamask/eth-query'; import HttpProvider from '@metamask/ethjs-provider-http'; +import { + Messenger, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, + MOCK_ANY_NAMESPACE, +} from '@metamask/messenger'; import type { BlockTracker, NetworkClientConfiguration, @@ -50,11 +57,8 @@ import { PendingTransactionTracker } from './helpers/PendingTransactionTracker'; import { shouldResimulate } from './helpers/ResimulateHelper'; import { ExtraTransactionsPublishHook } from './hooks/ExtraTransactionsPublishHook'; import type { - AllowedActions, - AllowedEvents, MethodData, - TransactionControllerActions, - TransactionControllerEvents, + TransactionControllerMessenger, TransactionControllerOptions, } from './TransactionController'; import { TransactionController } from './TransactionController'; @@ -111,9 +115,16 @@ import { buildMockGetNetworkClientById, } from '../../network-controller/tests/helpers'; -type UnrestrictedMessenger = Messenger< - TransactionControllerActions | AllowedActions, - TransactionControllerEvents | AllowedEvents +type AllTransactionControllerActions = + MessengerActions; + +type AllTransactionControllerEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllTransactionControllerActions, + AllTransactionControllerEvents >; const MOCK_V1_UUID = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'; @@ -329,10 +340,7 @@ function buildMockGasFeeFlow(): jest.Mocked { * @returns A promise that resolves with the transaction meta when the transaction is finished. */ function waitForTransactionFinished( - messenger: Messenger< - TransactionControllerActions | AllowedActions, - TransactionControllerEvents | AllowedEvents - >, + messenger: TransactionControllerMessenger | RootMessenger, { confirmed = false } = {}, ): Promise { const eventName = confirmed @@ -662,11 +670,13 @@ describe('TransactionController', () => { listener(networkState); }); }; - const unrestrictedMessenger: UnrestrictedMessenger = new Messenger(); + const rootMessenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); const getNetworkClientById = buildMockGetNetworkClientById( mockNetworkClientConfigurationsByNetworkClientId, ); - unrestrictedMessenger.registerActionHandler( + rootMessenger.registerActionHandler( 'NetworkController:getNetworkClientById', getNetworkClientById, ); @@ -674,7 +684,7 @@ describe('TransactionController', () => { const { addTransactionApprovalRequest = { state: 'pending' } } = messengerOptions; const mockTransactionApprovalRequest = mockAddTransactionApprovalRequest( - unrestrictedMessenger, + rootMessenger, addTransactionApprovalRequest, ); @@ -699,28 +709,31 @@ describe('TransactionController', () => { ...givenOptions, }; - const restrictedMessenger = + const transactionControllerMessenger: TransactionControllerMessenger = givenRestrictedMessenger ?? - unrestrictedMessenger.getRestricted({ - name: 'TransactionController', - allowedActions: [ - 'AccountsController:getSelectedAccount', - 'AccountsController:getState', - 'ApprovalController:addRequest', - 'NetworkController:getNetworkClientById', - 'NetworkController:findNetworkClientIdByChainId', - 'RemoteFeatureFlagController:getState', - ], - allowedEvents: [], - }); + new Messenger({ + namespace: 'TransactionController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: transactionControllerMessenger, + actions: [ + 'AccountsController:getSelectedAccount', + 'AccountsController:getState', + 'ApprovalController:addRequest', + 'NetworkController:getNetworkClientById', + 'NetworkController:findNetworkClientIdByChainId', + 'RemoteFeatureFlagController:getState', + ], + }); const mockGetSelectedAccount = jest.fn().mockReturnValue(selectedAccount); - unrestrictedMessenger.registerActionHandler( + rootMessenger.registerActionHandler( 'AccountsController:getSelectedAccount', mockGetSelectedAccount, ); - unrestrictedMessenger.registerActionHandler( + rootMessenger.registerActionHandler( 'AccountsController:getState', () => ({}) as never, ); @@ -729,14 +742,14 @@ describe('TransactionController', () => { featureFlags: {}, }); - unrestrictedMessenger.registerActionHandler( + rootMessenger.registerActionHandler( 'RemoteFeatureFlagController:getState', remoteFeatureFlagControllerGetStateMock, ); const controller = new TransactionController({ ...otherOptions, - messenger: restrictedMessenger, + messenger: transactionControllerMessenger, } as TransactionControllerOptions); const state = givenOptions?.state; @@ -759,7 +772,8 @@ describe('TransactionController', () => { return { controller, - messenger: unrestrictedMessenger, + messenger: transactionControllerMessenger, + rootMessenger, mockTransactionApprovalRequest, mockGetSelectedAccount, changeNetwork, @@ -788,7 +802,7 @@ describe('TransactionController', () => { * finally the mocked version of the action handler itself. */ function mockAddTransactionApprovalRequest( - messenger: UnrestrictedMessenger, + messenger: RootMessenger, options: | { state: 'approved'; @@ -6048,8 +6062,8 @@ describe('TransactionController', () => { }); it('uses the nonceTracker for the networkClientId matching the chainId', async () => { - const { controller, messenger } = setupController(); - messenger.registerActionHandler( + const { controller, rootMessenger } = setupController(); + rootMessenger.registerActionHandler( 'NetworkController:findNetworkClientIdByChainId', () => 'sepolia', ); @@ -7982,7 +7996,7 @@ describe('TransactionController', () => { deriveStateFromMetadata( controller.state, controller.metadata, - 'anonymous', + 'includeInDebugSnapshot', ), ).toMatchInlineSnapshot(`Object {}`); }); diff --git a/packages/transaction-controller/src/TransactionController.ts b/packages/transaction-controller/src/TransactionController.ts index 0e2b5422bc9..f655bbc5799 100644 --- a/packages/transaction-controller/src/TransactionController.ts +++ b/packages/transaction-controller/src/TransactionController.ts @@ -11,9 +11,9 @@ import type { import type { ControllerGetStateAction, ControllerStateChangeEvent, - RestrictedMessenger, -} from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; + StateMetadata, +} from '@metamask/base-controller/next'; +import { BaseController } from '@metamask/base-controller/next'; import { query, ApprovalType, @@ -27,6 +27,7 @@ import type { GasFeeState, } from '@metamask/gas-fee-controller'; import type { KeyringControllerSignEip7702AuthorizationAction } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import type { BlockTracker, NetworkClientId, @@ -176,35 +177,35 @@ import { * Metadata for the TransactionController state, describing how to "anonymize" * the state and which parts should be persisted. */ -const metadata = { +const metadata: StateMetadata = { transactions: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, transactionBatches: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, methodData: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: true, }, lastFetchedBlockNumbers: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, submitHistory: { includeInStateLogs: true, persist: true, - anonymous: false, + includeInDebugSnapshot: false, usedInUi: false, }, }; @@ -735,12 +736,10 @@ export type TransactionControllerEvents = /** * The messenger of the {@link TransactionController}. */ -export type TransactionControllerMessenger = RestrictedMessenger< +export type TransactionControllerMessenger = Messenger< typeof controllerName, TransactionControllerActions | AllowedActions, - TransactionControllerEvents | AllowedEvents, - AllowedActions['type'], - AllowedEvents['type'] + TransactionControllerEvents | AllowedEvents >; /** @@ -932,7 +931,7 @@ export class TransactionController extends BaseController< }, }); - this.messagingSystem = messenger; + this.messenger = messenger; this.#afterAdd = hooks?.afterAdd ?? (() => Promise.resolve({})); this.#afterSign = hooks?.afterSign ?? (() => true); @@ -980,7 +979,7 @@ export class TransactionController extends BaseController< this.#transactionHistoryLimit = transactionHistoryLimit; const findNetworkClientIdByChainId = (chainId: Hex) => { - return this.messagingSystem.call( + return this.messenger.call( `NetworkController:findNetworkClientIdByChainId`, chainId, ); @@ -989,7 +988,7 @@ export class TransactionController extends BaseController< this.#multichainTrackingHelper = new MultichainTrackingHelper({ findNetworkClientIdByChainId, getNetworkClientById: ((networkClientId: NetworkClientId) => { - return this.messagingSystem.call( + return this.messenger.call( `NetworkController:getNetworkClientById`, networkClientId, ); @@ -1001,10 +1000,7 @@ export class TransactionController extends BaseController< createPendingTransactionTracker: this.#createPendingTransactionTracker.bind(this), onNetworkStateChange: (listener) => { - this.messagingSystem.subscribe( - 'NetworkController:stateChange', - listener, - ); + this.messenger.subscribe('NetworkController:stateChange', listener); }, }); @@ -1020,12 +1016,9 @@ export class TransactionController extends BaseController< getTransactions: () => this.state.transactions, getTransactionBatches: () => this.state.transactionBatches, layer1GasFeeFlows: this.#layer1GasFeeFlows, - messenger: this.messagingSystem, + messenger: this.messenger, onStateChange: (listener) => { - this.messagingSystem.subscribe( - 'TransactionController:stateChange', - listener, - ); + this.messenger.subscribe('TransactionController:stateChange', listener); }, }); @@ -1060,7 +1053,7 @@ export class TransactionController extends BaseController< includeTokenTransfers: this.#incomingTransactionOptions.includeTokenTransfers, isEnabled: this.#incomingTransactionOptions.isEnabled, - messenger: this.messagingSystem, + messenger: this.messenger, remoteTransactionSource: new AccountsApiRemoteTransactionSource(), trimTransactions: this.#trimTransactionsForState.bind(this), updateTransactions: this.#incomingTransactionOptions.updateTransactions, @@ -1072,7 +1065,7 @@ export class TransactionController extends BaseController< // when transactionsController state changes // check for pending transactions and start polling if there are any - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TransactionController:stateChange', this.#checkForPendingTransactionAndStartPolling, ); @@ -1080,7 +1073,7 @@ export class TransactionController extends BaseController< new ResimulateHelper({ simulateTransaction: this.#updateSimulationData.bind(this), onTransactionsUpdate: (listener) => { - this.messagingSystem.subscribe( + this.messenger.subscribe( 'TransactionController:stateChange', listener, (controllerState) => controllerState.transactions, @@ -1124,7 +1117,7 @@ export class TransactionController extends BaseController< async addTransactionBatch( request: TransactionBatchRequest, ): Promise { - const { blockTracker } = this.messagingSystem.call( + const { blockTracker } = this.messenger.call( `NetworkController:getNetworkClientById`, request.networkClientId, ); @@ -1146,7 +1139,7 @@ export class TransactionController extends BaseController< getTransaction: (transactionId) => this.#getTransactionOrThrow(transactionId), isSimulationEnabled: this.#isSimulationEnabled, - messenger: this.messagingSystem, + messenger: this.messenger, publishBatchHook: this.#publishBatchHook, publicKeyEIP7702: this.#publicKeyEIP7702, publishTransaction: ( @@ -1172,7 +1165,7 @@ export class TransactionController extends BaseController< return isAtomicBatchSupported({ ...request, getEthQuery: (chainId) => this.#getEthQuery({ chainId }), - messenger: this.messagingSystem, + messenger: this.messenger, publicKeyEIP7702: this.#publicKeyEIP7702, }); } @@ -1360,7 +1353,7 @@ export class TransactionController extends BaseController< { isSwapsDisabled: this.#isSwapsDisabled, cancelTransaction: this.#rejectTransaction.bind(this), - messenger: this.messagingSystem, + messenger: this.messenger, }, ); @@ -1392,7 +1385,7 @@ export class TransactionController extends BaseController< ); } - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:unapprovedTransactionAdded`, addedTransactionMeta, ); @@ -1460,7 +1453,7 @@ export class TransactionController extends BaseController< txParams.value = '0x0'; }, afterSubmit: (newTransactionMeta) => { - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionFinished`, newTransactionMeta, ); @@ -1499,7 +1492,7 @@ export class TransactionController extends BaseController< transactionId, transactionType: TransactionType.retry, afterSubmit: (newTransactionMeta) => { - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:speedupTransactionAdded`, newTransactionMeta, ); @@ -1615,12 +1608,12 @@ export class TransactionController extends BaseController< this.#addMetadata(newTransactionMeta); // speedUpTransaction has no approval request, so we assume the user has already approved the transaction - this.messagingSystem.publish(`${controllerName}:transactionApproved`, { + this.messenger.publish(`${controllerName}:transactionApproved`, { transactionMeta: newTransactionMeta, actionId, }); - this.messagingSystem.publish(`${controllerName}:transactionSubmitted`, { + this.messenger.publish(`${controllerName}:transactionSubmitted`, { transactionMeta: newTransactionMeta, actionId, }); @@ -1656,7 +1649,7 @@ export class TransactionController extends BaseController< ignoreDelegationSignatures, isSimulationEnabled: this.#isSimulationEnabled(), getSimulationConfig: this.#getSimulationConfig, - messenger: this.messagingSystem, + messenger: this.messenger, txParams: transaction, }); @@ -1685,7 +1678,7 @@ export class TransactionController extends BaseController< ethQuery, isSimulationEnabled: this.#isSimulationEnabled(), getSimulationConfig: this.#getSimulationConfig, - messenger: this.messagingSystem, + messenger: this.messenger, txParams: transaction, }); @@ -1832,7 +1825,7 @@ export class TransactionController extends BaseController< throw error; }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionConfirmed`, updatedTransactionMeta, ); @@ -2176,7 +2169,7 @@ export class TransactionController extends BaseController< await updateTransactionLayer1GasFee({ layer1GasFeeFlows: this.#layer1GasFeeFlows, - messenger: this.messagingSystem, + messenger: this.messenger, provider, transactionMeta: updatedTransaction, }); @@ -2370,7 +2363,7 @@ export class TransactionController extends BaseController< status as TransactionStatus, ) ) { - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionFinished`, updatedTransactionMeta, ); @@ -2504,7 +2497,7 @@ export class TransactionController extends BaseController< const gasFeeFlow = getGasFeeFlow( transactionMeta, this.#gasFeeFlows, - this.messagingSystem, + this.messenger, ) as GasFeeFlow; const ethQuery = new EthQuery(provider); @@ -2516,7 +2509,7 @@ export class TransactionController extends BaseController< return gasFeeFlow.getGasFees({ ethQuery, gasFeeControllerData, - messenger: this.messagingSystem, + messenger: this.messenger, transactionMeta, }); } @@ -2546,7 +2539,7 @@ export class TransactionController extends BaseController< return await getTransactionLayer1GasFee({ layer1GasFeeFlows: this.#layer1GasFeeFlows, - messenger: this.messagingSystem, + messenger: this.messenger, provider, transactionMeta: { txParams: transactionParams, @@ -2822,7 +2815,7 @@ export class TransactionController extends BaseController< gasFeeFlows: this.#gasFeeFlows, getGasFeeEstimates: this.#getGasFeeEstimates, getSavedGasFees: this.#getSavedGasFees.bind(this), - messenger: this.messagingSystem, + messenger: this.messenger, txMeta: transactionMeta, }), ); @@ -2832,7 +2825,7 @@ export class TransactionController extends BaseController< async () => await updateTransactionLayer1GasFee({ layer1GasFeeFlows: this.#layer1GasFeeFlows, - messenger: this.messagingSystem, + messenger: this.messenger, provider, transactionMeta, }), @@ -2939,13 +2932,10 @@ export class TransactionController extends BaseController< const updatedTransactionMeta = this.#getTransaction( transactionId, ) as TransactionMeta; - this.messagingSystem.publish( - `${controllerName}:transactionApproved`, - { - transactionMeta: updatedTransactionMeta, - actionId, - }, - ); + this.messenger.publish(`${controllerName}:transactionApproved`, { + transactionMeta: updatedTransactionMeta, + actionId, + }); } } catch (rawError: unknown) { const error = rawError as Error & { code?: number; data?: Json }; @@ -3077,7 +3067,7 @@ export class TransactionController extends BaseController< if (!(await this.#beforePublish(transactionMeta))) { log('Skipping publishing transaction based on hook'); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionPublishingSkipped`, transactionMeta, ); @@ -3157,11 +3147,11 @@ export class TransactionController extends BaseController< }, ); - this.messagingSystem.publish(`${controllerName}:transactionSubmitted`, { + this.messenger.publish(`${controllerName}:transactionSubmitted`, { transactionMeta, }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionFinished`, transactionMeta, ); @@ -3219,7 +3209,7 @@ export class TransactionController extends BaseController< error: normalizeTxError(error ?? providerErrors.userRejectedRequest()), }; - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionFinished`, updatedTransactionMeta, ); @@ -3229,7 +3219,7 @@ export class TransactionController extends BaseController< updatedTransactionMeta, ); - this.messagingSystem.publish(`${controllerName}:transactionRejected`, { + this.messenger.publish(`${controllerName}:transactionRejected`, { transactionMeta: updatedTransactionMeta, actionId, }); @@ -3331,7 +3321,7 @@ export class TransactionController extends BaseController< parentContext: traceContext, }); - return (await this.messagingSystem.call( + return (await this.messenger.call( 'ApprovalController:addRequest', { id, @@ -3467,7 +3457,7 @@ export class TransactionController extends BaseController< ); }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:incomingTransactionsReceived`, finalTransactions, ); @@ -3616,7 +3606,7 @@ export class TransactionController extends BaseController< ...transactionMeta, status: TransactionStatus.dropped as const, }; - this.messagingSystem.publish(`${controllerName}:transactionDropped`, { + this.messenger.publish(`${controllerName}:transactionDropped`, { transactionMeta: updatedTransactionMeta, }); this.updateTransaction( @@ -3706,7 +3696,7 @@ export class TransactionController extends BaseController< const signedAuthorizationList = await signAuthorizationList({ authorizationList, - messenger: this.messagingSystem, + messenger: this.messenger, transactionMeta, }); @@ -3798,7 +3788,7 @@ export class TransactionController extends BaseController< } #onTransactionStatusChange(transactionMeta: TransactionMeta) { - this.messagingSystem.publish(`${controllerName}:transactionStatusUpdated`, { + this.messenger.publish(`${controllerName}:transactionStatusUpdated`, { transactionMeta, }); } @@ -3821,7 +3811,7 @@ export class TransactionController extends BaseController< this.#markNonceDuplicatesDropped(transactionMeta.id); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionConfirmed`, transactionMeta, ); @@ -3852,7 +3842,7 @@ export class TransactionController extends BaseController< updateTransaction: this.updateTransaction.bind(this), }); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:postTransactionBalanceUpdated`, { transactionMeta: updatedTransactionMeta, @@ -3916,7 +3906,7 @@ export class TransactionController extends BaseController< this.#multichainTrackingHelper.acquireNonceLockForChainIdKey({ chainId, }), - messenger: this.messagingSystem, + messenger: this.messenger, publishTransaction: (_ethQuery, transactionMeta) => this.#publishTransaction(_ethQuery, transactionMeta, { skipSubmitHistory: true, @@ -4192,7 +4182,7 @@ export class TransactionController extends BaseController< chainId, getSimulationConfig: this.#getSimulationConfig, isEIP7702GasFeeTokensEnabled: this.#isEIP7702GasFeeTokensEnabled, - messenger: this.messagingSystem, + messenger: this.messenger, publicKeyEIP7702: this.#publicKeyEIP7702, transactionMeta, }); @@ -4291,11 +4281,11 @@ export class TransactionController extends BaseController< } #getSelectedAccount() { - return this.messagingSystem.call('AccountsController:getSelectedAccount'); + return this.messenger.call('AccountsController:getSelectedAccount'); } #getInternalAccounts(): Hex[] { - const state = this.messagingSystem.call('AccountsController:getState'); + const state = this.messenger.call('AccountsController:getState'); return Object.values(state.internalAccounts?.accounts ?? {}) .filter((account) => account.type === 'eip155:eoa') @@ -4355,48 +4345,48 @@ export class TransactionController extends BaseController< isCustomNetwork, isSimulationEnabled: this.#isSimulationEnabled(), getSimulationConfig: this.#getSimulationConfig, - messenger: this.messagingSystem, + messenger: this.messenger, txMeta: transactionMeta, }); } #registerActionHandlers(): void { - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:addTransaction`, this.addTransaction.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:addTransactionBatch`, this.addTransactionBatch.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:confirmExternalTransaction`, this.confirmExternalTransaction.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:estimateGas`, this.estimateGas.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getNonceLock`, this.getNonceLock.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:getTransactions`, this.getTransactions.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:updateCustodialTransaction`, this.updateCustodialTransaction.bind(this), ); - this.messagingSystem.registerActionHandler( + this.messenger.registerActionHandler( `${controllerName}:updateTransaction`, this.updateTransaction.bind(this), ); @@ -4470,7 +4460,7 @@ export class TransactionController extends BaseController< }; } - this.messagingSystem.publish(`${controllerName}:transactionFailed`, { + this.messenger.publish(`${controllerName}:transactionFailed`, { actionId, error: error.message, transactionMeta: newTransactionMeta, @@ -4478,7 +4468,7 @@ export class TransactionController extends BaseController< this.#onTransactionStatusChange(newTransactionMeta); - this.messagingSystem.publish( + this.messenger.publish( `${controllerName}:transactionFinished`, newTransactionMeta, ); diff --git a/packages/transaction-controller/src/TransactionControllerIntegration.test.ts b/packages/transaction-controller/src/TransactionControllerIntegration.test.ts index 3539d6b7982..48e94d4e685 100644 --- a/packages/transaction-controller/src/TransactionControllerIntegration.test.ts +++ b/packages/transaction-controller/src/TransactionControllerIntegration.test.ts @@ -5,7 +5,6 @@ import type { ApprovalControllerEvents, } from '@metamask/approval-controller'; import { ApprovalController } from '@metamask/approval-controller'; -import { Messenger } from '@metamask/base-controller'; import { ApprovalType, BUILT_IN_NETWORKS, @@ -13,6 +12,13 @@ import { InfuraNetworkType, NetworkType, } from '@metamask/controller-utils'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, +} from '@metamask/messenger'; import { NetworkController, NetworkClientType, @@ -23,14 +29,14 @@ import type { NetworkControllerEvents, NetworkClientId, } from '@metamask/network-controller'; +import type { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller'; import assert from 'assert'; import type { SinonFakeTimers } from 'sinon'; import { useFakeTimers } from 'sinon'; import { v4 as uuidV4 } from 'uuid'; import type { - TransactionControllerActions, - TransactionControllerEvents, + TransactionControllerMessenger, TransactionControllerOptions, } from './TransactionController'; import { TransactionController } from './TransactionController'; @@ -43,7 +49,6 @@ import { buildCustomNetworkClientConfiguration, buildUpdateNetworkCustomRpcEndpointFields, } from '../../network-controller/tests/helpers'; -import type { RemoteFeatureFlagControllerGetStateAction } from '../../remote-feature-flag-controller/src'; import { buildEthGasPriceRequestMock, buildEthBlockNumberRequestMock, @@ -65,16 +70,25 @@ jest.mock('uuid', () => { }; }); -type UnrestrictedMessenger = Messenger< - | AccountsControllerActions - | ApprovalControllerActions +type AllTransactionControllerActions = + MessengerActions; + +type AllTransactionControllerEvents = + MessengerEvents; + +type AllActions = + | AllTransactionControllerActions | NetworkControllerActions - | TransactionControllerActions - | RemoteFeatureFlagControllerGetStateAction, - | ApprovalControllerEvents + | ApprovalControllerActions + | AccountsControllerActions + | RemoteFeatureFlagControllerGetStateAction; + +type AllEvents = + | AllTransactionControllerEvents | NetworkControllerEvents - | TransactionControllerEvents ->; + | ApprovalControllerEvents; + +type RootMessenger = Messenger; const uuidV4Mock = jest.mocked(uuidV4); @@ -158,13 +172,21 @@ const setupController = async ( ], }); - const unrestrictedMessenger: UnrestrictedMessenger = new Messenger(); + const rootMessenger: RootMessenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); + + const networkControllerMessenger = new Messenger< + 'NetworkController', + NetworkControllerActions, + NetworkControllerEvents, + typeof rootMessenger + >({ + namespace: 'NetworkController', + parent: rootMessenger, + }); const networkController = new NetworkController({ - messenger: unrestrictedMessenger.getRestricted({ - name: 'NetworkController', - allowedActions: [], - allowedEvents: [], - }), + messenger: networkControllerMessenger, infuraProjectId, getRpcServiceOptions: () => ({ fetch, @@ -177,19 +199,33 @@ const setupController = async ( assert(provider, 'Provider must be available'); assert(blockTracker, 'Provider must be available'); + const approvalControllerMessenger = new Messenger< + 'ApprovalController', + ApprovalControllerActions, + ApprovalControllerEvents, + typeof rootMessenger + >({ + namespace: 'ApprovalController', + parent: rootMessenger, + }); const approvalController = new ApprovalController({ - messenger: unrestrictedMessenger.getRestricted({ - name: 'ApprovalController', - allowedActions: [], - allowedEvents: [], - }), + messenger: approvalControllerMessenger, showApprovalRequest: jest.fn(), typesExcludedFromRateLimiting: [ApprovalType.Transaction], }); - const messenger = unrestrictedMessenger.getRestricted({ - name: 'TransactionController', - allowedActions: [ + const messenger = new Messenger< + 'TransactionController', + MessengerActions, + MessengerEvents, + typeof rootMessenger + >({ + namespace: 'TransactionController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger, + actions: [ 'AccountsController:getSelectedAccount', 'AccountsController:getState', 'ApprovalController:addRequest', @@ -197,24 +233,42 @@ const setupController = async ( 'NetworkController:findNetworkClientIdByChainId', 'RemoteFeatureFlagController:getState', ], - allowedEvents: ['NetworkController:stateChange'], + events: ['NetworkController:stateChange'], }); const mockGetSelectedAccount = jest .fn() .mockReturnValue(mockData.selectedAccount); - unrestrictedMessenger.registerActionHandler( + const accountsControllerMessenger = new Messenger< + 'AccountsController', + AccountsControllerActions, + never, + typeof rootMessenger + >({ + namespace: 'AccountsController', + parent: rootMessenger, + }); + accountsControllerMessenger.registerActionHandler( 'AccountsController:getSelectedAccount', mockGetSelectedAccount, ); - - unrestrictedMessenger.registerActionHandler( + accountsControllerMessenger.registerActionHandler( 'AccountsController:getState', () => ({}) as never, ); - unrestrictedMessenger.registerActionHandler( + const remoteFeatureFlagControllerMessenger = new Messenger< + 'RemoteFeatureFlagController', + RemoteFeatureFlagControllerGetStateAction, + never, + typeof rootMessenger + >({ + namespace: 'RemoteFeatureFlagController', + parent: rootMessenger, + }); + + remoteFeatureFlagControllerMessenger.registerActionHandler( 'RemoteFeatureFlagController:getState', () => ({ cacheTimestamp: 0, remoteFeatureFlags: {} }), ); diff --git a/packages/transaction-controller/src/utils/eip7702.test.ts b/packages/transaction-controller/src/utils/eip7702.test.ts index 1b70fa09db1..323ff64a120 100644 --- a/packages/transaction-controller/src/utils/eip7702.test.ts +++ b/packages/transaction-controller/src/utils/eip7702.test.ts @@ -1,6 +1,12 @@ import { query } from '@metamask/controller-utils'; import type EthQuery from '@metamask/eth-query'; -import type { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller'; +import { + Messenger, + MockAnyNamespace, + type MessengerActions, + type MessengerEvents, + MOCK_ANY_NAMESPACE, +} from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; import { remove0x } from '@metamask/utils'; @@ -16,7 +22,6 @@ import { getEIP7702ContractAddresses, getEIP7702SupportedChains, } from './feature-flags'; -import { Messenger } from '../../../base-controller/src'; import type { KeyringControllerSignEip7702AuthorizationAction } from '../../../keyring-controller/src'; import type { TransactionControllerMessenger } from '../TransactionController'; import type { AuthorizationList } from '../types'; @@ -73,10 +78,10 @@ const AUTHORIZATION_LIST_MOCK: AuthorizationList = [ ]; describe('EIP-7702 Utils', () => { - let baseMessenger: Messenger< - | KeyringControllerSignEip7702AuthorizationAction - | RemoteFeatureFlagControllerGetStateAction, - never + let rootMessenger: Messenger< + MockAnyNamespace, + MessengerActions, + MessengerEvents >; const getCodeMock = jest.mocked(query); @@ -95,21 +100,33 @@ describe('EIP-7702 Utils', () => { beforeEach(() => { jest.resetAllMocks(); - baseMessenger = new Messenger(); + rootMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); signAuthorizationMock = jest .fn() .mockResolvedValue(AUTHORIZATION_SIGNATURE_MOCK); - baseMessenger.registerActionHandler( + const keyringControllerMessenger = new Messenger< + 'KeyringController', + KeyringControllerSignEip7702AuthorizationAction, + never, + typeof rootMessenger + >({ + namespace: 'KeyringController', + parent: rootMessenger, + }); + keyringControllerMessenger.registerActionHandler( 'KeyringController:signEip7702Authorization', signAuthorizationMock, ); - controllerMessenger = baseMessenger.getRestricted({ - name: 'TransactionController', - allowedActions: ['KeyringController:signEip7702Authorization'], - allowedEvents: [], + controllerMessenger = new Messenger({ + namespace: 'TransactionController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: controllerMessenger, + actions: ['KeyringController:signEip7702Authorization'], }); }); diff --git a/packages/transaction-controller/src/utils/feature-flags.test.ts b/packages/transaction-controller/src/utils/feature-flags.test.ts index 84bc2e1922a..1d1e8c91b93 100644 --- a/packages/transaction-controller/src/utils/feature-flags.test.ts +++ b/packages/transaction-controller/src/utils/feature-flags.test.ts @@ -1,4 +1,10 @@ -import { Messenger } from '@metamask/base-controller'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, +} from '@metamask/messenger'; import type { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller'; import type { Hex } from '@metamask/utils'; @@ -36,13 +42,21 @@ const GAS_BUFFER_4_MOCK = 1.4; const GAS_BUFFER_5_MOCK = 1.5; describe('Feature Flags Utils', () => { - let baseMessenger: Messenger< - RemoteFeatureFlagControllerGetStateAction, - never + let rootMessenger: Messenger< + MockAnyNamespace, + MessengerActions, + MessengerEvents >; let controllerMessenger: TransactionControllerMessenger; + let remoteFeatureFlagControllerMessenger: Messenger< + 'RemoteFeatureFlagController', + RemoteFeatureFlagControllerGetStateAction, + never, + typeof rootMessenger + >; + let getFeatureFlagsMock: jest.MockedFn< RemoteFeatureFlagControllerGetStateAction['handler'] >; @@ -66,17 +80,25 @@ describe('Feature Flags Utils', () => { getFeatureFlagsMock = jest.fn(); - baseMessenger = new Messenger(); + rootMessenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); + + remoteFeatureFlagControllerMessenger = new Messenger({ + namespace: 'RemoteFeatureFlagController', + parent: rootMessenger, + }); - baseMessenger.registerActionHandler( + remoteFeatureFlagControllerMessenger.registerActionHandler( 'RemoteFeatureFlagController:getState', getFeatureFlagsMock, ); - controllerMessenger = baseMessenger.getRestricted({ - name: 'TransactionController', - allowedActions: ['RemoteFeatureFlagController:getState'], - allowedEvents: [], + controllerMessenger = new Messenger({ + namespace: 'TransactionController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger: controllerMessenger, + actions: ['RemoteFeatureFlagController:getState'], }); isValidSignatureMock.mockReturnValue(true); diff --git a/packages/transaction-controller/src/utils/swaps.test.ts b/packages/transaction-controller/src/utils/swaps.test.ts index 457aa0134c9..147d9e9174a 100644 --- a/packages/transaction-controller/src/utils/swaps.test.ts +++ b/packages/transaction-controller/src/utils/swaps.test.ts @@ -1,5 +1,11 @@ -import { Messenger } from '@metamask/base-controller'; import { query } from '@metamask/controller-utils'; +import { + MOCK_ANY_NAMESPACE, + Messenger, + type MockAnyNamespace, + type MessengerActions, + type MessengerEvents, +} from '@metamask/messenger'; import { updateSwapsTransaction, @@ -9,13 +15,7 @@ import { } from './swaps'; import { flushPromises } from '../../../../tests/helpers'; import { CHAIN_IDS } from '../constants'; -import type { - AllowedActions, - AllowedEvents, - TransactionControllerActions, - TransactionControllerEvents, - TransactionControllerMessenger, -} from '../TransactionController'; +import type { TransactionControllerMessenger } from '../TransactionController'; import type { TransactionMeta } from '../types'; import { TransactionType, TransactionStatus } from '../types'; @@ -47,17 +47,29 @@ describe('updateSwapsTransaction', () => { destinationTokenSymbol: 'DAI', }, }; + const rootMessenger = new Messenger< + MockAnyNamespace, + MessengerActions, + MessengerEvents + >({ + namespace: MOCK_ANY_NAMESPACE, + }); messenger = new Messenger< - TransactionControllerActions | AllowedActions, - TransactionControllerEvents | AllowedEvents - >().getRestricted({ - name: 'TransactionController', - allowedActions: [ + 'TransactionController', + MessengerActions, + MessengerEvents, + typeof rootMessenger + >({ + namespace: 'TransactionController', + parent: rootMessenger, + }); + rootMessenger.delegate({ + messenger, + actions: [ 'ApprovalController:addRequest', 'NetworkController:getNetworkClientById', 'NetworkController:findNetworkClientIdByChainId', ], - allowedEvents: [], }); request = { isSwapsDisabled: false, diff --git a/packages/transaction-controller/tsconfig.build.json b/packages/transaction-controller/tsconfig.build.json index 716dda8820b..6e04a4ba1d8 100644 --- a/packages/transaction-controller/tsconfig.build.json +++ b/packages/transaction-controller/tsconfig.build.json @@ -12,6 +12,7 @@ { "path": "../controller-utils/tsconfig.build.json" }, { "path": "../gas-fee-controller/tsconfig.build.json" }, { "path": "../network-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" }, { "path": "../remote-feature-flag-controller/tsconfig.build.json" } ], "include": ["../../types", "./src"] diff --git a/packages/transaction-controller/tsconfig.json b/packages/transaction-controller/tsconfig.json index b839b37eed5..1e328031877 100644 --- a/packages/transaction-controller/tsconfig.json +++ b/packages/transaction-controller/tsconfig.json @@ -11,6 +11,7 @@ { "path": "../controller-utils" }, { "path": "../gas-fee-controller" }, { "path": "../network-controller" }, + { "path": "../messenger" }, { "path": "../remote-feature-flag-controller" } ], "include": ["../../types", "./src", "./tests"] diff --git a/yarn.lock b/yarn.lock index 3bea94b26d0..3439e5ed6b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2576,6 +2576,7 @@ __metadata: "@metamask/base-controller": "npm:^8.4.1" "@metamask/keyring-api": "npm:^21.0.0" "@metamask/keyring-controller": "npm:^23.1.1" + "@metamask/messenger": "npm:^0.3.0" "@metamask/multichain-account-service": "npm:^1.6.1" "@metamask/profile-sync-controller": "npm:^25.1.1" "@metamask/providers": "npm:^22.1.0" @@ -2619,6 +2620,7 @@ __metadata: "@metamask/keyring-controller": "npm:^23.1.1" "@metamask/keyring-internal-api": "npm:^9.0.0" "@metamask/keyring-utils": "npm:^3.1.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/network-controller": "npm:^24.2.1" "@metamask/providers": "npm:^22.1.0" "@metamask/snaps-controllers": "npm:^14.0.1" @@ -2666,6 +2668,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" "@metamask/controller-utils": "npm:^11.14.1" + "@metamask/messenger": "npm:^0.3.0" "@metamask/utils": "npm:^11.8.1" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" @@ -2683,6 +2686,7 @@ __metadata: dependencies: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" + "@metamask/messenger": "npm:^0.3.0" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" @@ -2706,6 +2710,7 @@ __metadata: dependencies: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" + "@metamask/messenger": "npm:^0.3.0" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" @@ -2723,6 +2728,7 @@ __metadata: dependencies: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" + "@metamask/messenger": "npm:^0.3.0" "@metamask/rpc-errors": "npm:^7.0.2" "@metamask/utils": "npm:^11.8.1" "@types/jest": "npm:^27.4.1" @@ -2764,6 +2770,7 @@ __metadata: "@metamask/keyring-controller": "npm:^23.1.1" "@metamask/keyring-internal-api": "npm:^9.0.0" "@metamask/keyring-snap-client": "npm:^8.0.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/metamask-eth-abis": "npm:^3.1.1" "@metamask/multichain-account-service": "npm:^1.6.1" "@metamask/network-controller": "npm:^24.2.1" @@ -2905,6 +2912,7 @@ __metadata: "@metamask/eth-json-rpc-provider": "npm:^5.0.1" "@metamask/gas-fee-controller": "npm:^24.1.0" "@metamask/keyring-api": "npm:^21.0.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/metamask-eth-abis": "npm:^3.1.1" "@metamask/multichain-network-controller": "npm:^1.0.1" "@metamask/network-controller": "npm:^24.2.1" @@ -3204,6 +3212,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" "@metamask/keyring-controller": "npm:^23.1.1" + "@metamask/messenger": "npm:^0.3.0" "@metamask/utils": "npm:^11.8.1" "@ts-bridge/cli": "npm:^0.6.1" "@types/jest": "npm:^27.4.1" @@ -3248,6 +3257,7 @@ __metadata: "@metamask/base-controller": "npm:^8.4.1" "@metamask/controller-utils": "npm:^11.14.1" "@metamask/keyring-api": "npm:^21.0.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/network-controller": "npm:^24.2.1" "@metamask/stake-sdk": "npm:^3.2.1" "@metamask/transaction-controller": "npm:^60.6.1" @@ -3318,6 +3328,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" "@metamask/controller-utils": "npm:^11.14.1" + "@metamask/messenger": "npm:^0.3.0" "@metamask/network-controller": "npm:^24.2.1" "@metamask/utils": "npm:^11.8.1" "@types/jest": "npm:^27.4.1" @@ -3339,6 +3350,7 @@ __metadata: dependencies: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" + "@metamask/messenger": "npm:^0.3.0" "@sentry/core": "npm:^9.22.0" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" @@ -3798,6 +3810,7 @@ __metadata: "@metamask/base-controller": "npm:^8.4.1" "@metamask/delegation-core": "npm:^0.2.0" "@metamask/delegation-deployments": "npm:^0.12.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/snaps-controllers": "npm:^14.0.1" "@metamask/snaps-sdk": "npm:^9.0.0" "@metamask/snaps-utils": "npm:^11.0.0" @@ -3901,6 +3914,7 @@ __metadata: "@metamask/keyring-api": "npm:^21.0.0" "@metamask/keyring-internal-api": "npm:^9.0.0" "@metamask/keyring-utils": "npm:^3.1.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/scure-bip39": "npm:^2.1.1" "@metamask/utils": "npm:^11.8.1" "@types/jest": "npm:^27.4.1" @@ -3980,6 +3994,7 @@ __metadata: "@metamask/auto-changelog": "npm:^3.4.4" "@metamask/base-controller": "npm:^8.4.1" "@metamask/controller-utils": "npm:^11.14.1" + "@metamask/messenger": "npm:^0.1.0" "@types/jest": "npm:^27.4.1" deepmerge: "npm:^4.2.2" jest: "npm:^27.5.1" @@ -4013,6 +4028,13 @@ __metadata: languageName: unknown linkType: soft +"@metamask/messenger@npm:^0.1.0": + version: 0.1.0 + resolution: "@metamask/messenger@npm:0.1.0" + checksum: 10/5d6105865255e72571df143c648ebfb42b04ead24cd6bade758f0340eafba3790d9ff0818bd06fbda17799e3253ac05df51d9e13ebfd0c710e68fd1c0d1007a9 + languageName: node + linkType: hard + "@metamask/messenger@npm:^0.3.0, @metamask/messenger@workspace:packages/messenger": version: 0.0.0-use.local resolution: "@metamask/messenger@workspace:packages/messenger" @@ -4209,6 +4231,7 @@ __metadata: "@metamask/eth-json-rpc-provider": "npm:^5.0.1" "@metamask/eth-query": "npm:^4.0.0" "@metamask/json-rpc-engine": "npm:^10.1.1" + "@metamask/messenger": "npm:^0.3.0" "@metamask/rpc-errors": "npm:^7.0.2" "@metamask/swappable-obj-proxy": "npm:^2.3.0" "@metamask/utils": "npm:^11.8.1" @@ -4980,6 +5003,7 @@ __metadata: "@metamask/eth-query": "npm:^4.0.0" "@metamask/ethjs-provider-http": "npm:^0.3.0" "@metamask/gas-fee-controller": "npm:^24.1.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/metamask-eth-abis": "npm:^3.1.1" "@metamask/network-controller": "npm:^24.2.1" "@metamask/nonce-tracker": "npm:^6.0.0"