From 6014855c6e3071938823cb203b709c3cb9fcd7ee Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Thu, 2 Jul 2026 11:44:52 -0400 Subject: [PATCH] feat(wallet)!: wire `LoggingController` into default initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire `LoggingController` into the default wallet initialization so that `LoggingController:getState`, `LoggingController:add`, and `LoggingController:clear` are exposed on the shared messenger bus. The controller's construction is identical across extension and mobile — it takes only `messenger` and `state` and delegates no external actions/events — so no injectable `instanceOptions` are required. Co-Authored-By: Claude Opus 4.8 --- .github/CODEOWNERS | 1 + README.md | 1 + packages/wallet/CHANGELOG.md | 4 + packages/wallet/package.json | 1 + packages/wallet/src/Wallet.test.ts | 58 +++++++++++++ .../src/initialization/instances/index.ts | 1 + .../logging-controller.test.ts | 87 +++++++++++++++++++ .../logging-controller/logging-controller.ts | 24 +++++ packages/wallet/tsconfig.build.json | 1 + packages/wallet/tsconfig.json | 1 + yarn.lock | 1 + 11 files changed, 180 insertions(+) create mode 100644 packages/wallet/src/initialization/instances/logging-controller/logging-controller.test.ts create mode 100644 packages/wallet/src/initialization/instances/logging-controller/logging-controller.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 288ad5764a..96adff3601 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -143,6 +143,7 @@ /packages/wallet/src/initialization/instances/approval-controller/ @MetaMask/confirmations /packages/wallet/src/initialization/instances/connectivity-controller/ @MetaMask/core-platform /packages/wallet/src/initialization/instances/keyring-controller/ @MetaMask/accounts-engineers @MetaMask/core-platform +/packages/wallet/src/initialization/instances/logging-controller/ @MetaMask/confirmations /packages/wallet/src/initialization/instances/remote-feature-flag-controller/ @MetaMask/extension-platform @MetaMask/mobile-platform @MetaMask/core-platform /packages/wallet/src/initialization/instances/storage-service/ @MetaMask/extension-platform @MetaMask/mobile-platform @MetaMask/core-platform diff --git a/README.md b/README.md index eb5e93fc79..a273d2e556 100644 --- a/README.md +++ b/README.md @@ -620,6 +620,7 @@ linkStyle default opacity:0.5 wallet --> connectivity_controller; wallet --> controller_utils; wallet --> keyring_controller; + wallet --> logging_controller; wallet --> messenger; wallet --> network_controller; wallet --> remote_feature_flag_controller; diff --git a/packages/wallet/CHANGELOG.md b/packages/wallet/CHANGELOG.md index ea64a68972..e11378694b 100644 --- a/packages/wallet/CHANGELOG.md +++ b/packages/wallet/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- **BREAKING:** Wire `LoggingController` into the default wallet initialization ([#9378](https://github.com/MetaMask/core/pull/9378)) + ## [6.0.0] ### Added diff --git a/packages/wallet/package.json b/packages/wallet/package.json index 2845485176..c8a1fdad71 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -61,6 +61,7 @@ "@metamask/connectivity-controller": "^0.2.0", "@metamask/controller-utils": "^12.3.0", "@metamask/keyring-controller": "^27.1.0", + "@metamask/logging-controller": "^8.0.2", "@metamask/messenger": "^1.2.0", "@metamask/network-controller": "^34.0.0", "@metamask/remote-feature-flag-controller": "^4.2.2", diff --git a/packages/wallet/src/Wallet.test.ts b/packages/wallet/src/Wallet.test.ts index 2c39a1544e..b991f7cef8 100644 --- a/packages/wallet/src/Wallet.test.ts +++ b/packages/wallet/src/Wallet.test.ts @@ -1,5 +1,6 @@ import { getDefaultAddressBookControllerState } from '@metamask/address-book-controller'; import { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller'; +import { LogType } from '@metamask/logging-controller'; import { Messenger } from '@metamask/messenger'; import { InMemoryStorageAdapter } from '@metamask/storage-service'; import { Json } from '@metamask/utils'; @@ -319,6 +320,63 @@ describe('Wallet', () => { }); }); + describe('LoggingController', () => { + it('is wired and exposes its state on the wallet messenger', async () => { + const wallet = await setupWallet(); + const { messenger } = wallet; + + expect(messenger.call('LoggingController:getState')).toStrictEqual({ + logs: {}, + }); + }); + + it('applies initial state passed through the Wallet constructor', () => { + const entry = { + id: 'test-id', + timestamp: 0, + log: { type: LogType.GenericLog, data: { message: 'hello' } }, + }; + + const wallet = new Wallet({ + state: { + LoggingController: { + logs: { 'test-id': entry }, + }, + }, + instanceOptions: { + connectivityController: { + connectivityAdapter: new AlwaysOnlineAdapter(), + }, + networkController: { + infuraProjectId: 'fake-infura-project-id', + }, + storageService: { + storage: new InMemoryStorageAdapter(), + }, + remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + }, + }); + + expect(wallet.state.LoggingController.logs['test-id']).toStrictEqual( + entry, + ); + }); + + it('routes its method actions through the wallet messenger', async () => { + const wallet = await setupWallet(); + const { messenger } = wallet; + + messenger.call('LoggingController:add', { + type: LogType.GenericLog, + data: { message: 'hello' }, + }); + + expect(Object.values(wallet.state.LoggingController.logs)).toHaveLength( + 1, + ); + }); + }); + describe('ConnectivityController', () => { it('reports online connectivity status', () => { const wallet = new Wallet({ diff --git a/packages/wallet/src/initialization/instances/index.ts b/packages/wallet/src/initialization/instances/index.ts index ad8d554b67..cdd094e867 100644 --- a/packages/wallet/src/initialization/instances/index.ts +++ b/packages/wallet/src/initialization/instances/index.ts @@ -3,6 +3,7 @@ export { addressBookController } from './address-book-controller/address-book-co export { approvalController } from './approval-controller/approval-controller'; export { connectivityController } from './connectivity-controller/connectivity-controller'; export { keyringController } from './keyring-controller/keyring-controller'; +export { loggingController } from './logging-controller/logging-controller'; export { networkController } from './network-controller/network-controller'; export { remoteFeatureFlagController } from './remote-feature-flag-controller/remote-feature-flag-controller'; export { storageService } from './storage-service/storage-service'; diff --git a/packages/wallet/src/initialization/instances/logging-controller/logging-controller.test.ts b/packages/wallet/src/initialization/instances/logging-controller/logging-controller.test.ts new file mode 100644 index 0000000000..e8ec972b43 --- /dev/null +++ b/packages/wallet/src/initialization/instances/logging-controller/logging-controller.test.ts @@ -0,0 +1,87 @@ +import { LoggingController, LogType } from '@metamask/logging-controller'; +import { Messenger } from '@metamask/messenger'; + +import { defaultConfigurations } from '../../defaults'; +import type { + DefaultActions, + DefaultEvents, + RootMessenger, +} from '../../defaults'; +import { loggingController } from './logging-controller'; + +const DEFAULT_STATE = { logs: {} }; + +/** + * Creates a root messenger for use in tests. + * + * @returns A root messenger. + */ +function getRootMessenger(): RootMessenger { + return new Messenger({ namespace: 'Root' }); +} + +describe('loggingController', () => { + it('is registered as a default initialization configuration', () => { + expect(Object.values(defaultConfigurations)).toContain(loggingController); + }); + + it('initializes a LoggingController with default state', () => { + const messenger = loggingController.getMessenger(getRootMessenger()); + + const instance = loggingController.init({ + state: undefined, + messenger, + options: {}, + }); + + expect(instance).toBeInstanceOf(LoggingController); + expect(instance.state).toStrictEqual(DEFAULT_STATE); + }); + + it('merges provided state over the defaults', () => { + const messenger = loggingController.getMessenger(getRootMessenger()); + + const entry = { + id: 'test-id', + timestamp: 0, + log: { type: LogType.GenericLog, data: { message: 'hello' } }, + }; + + const instance = loggingController.init({ + state: { logs: { 'test-id': entry } }, + messenger, + options: {}, + }); + + expect(instance.state.logs['test-id']).toStrictEqual(entry); + }); + + it('exposes its state through the root messenger', () => { + const rootMessenger = getRootMessenger(); + const messenger = loggingController.getMessenger(rootMessenger); + + loggingController.init({ state: undefined, messenger, options: {} }); + + expect(rootMessenger.call('LoggingController:getState')).toStrictEqual( + DEFAULT_STATE, + ); + }); + + it('registers its method actions on the root messenger', () => { + const rootMessenger = getRootMessenger(); + const messenger = loggingController.getMessenger(rootMessenger); + + const instance = loggingController.init({ + state: undefined, + messenger, + options: {}, + }); + + rootMessenger.call('LoggingController:add', { + type: LogType.GenericLog, + data: { message: 'hello' }, + }); + + expect(Object.values(instance.state.logs)).toHaveLength(1); + }); +}); diff --git a/packages/wallet/src/initialization/instances/logging-controller/logging-controller.ts b/packages/wallet/src/initialization/instances/logging-controller/logging-controller.ts new file mode 100644 index 0000000000..7de102fd05 --- /dev/null +++ b/packages/wallet/src/initialization/instances/logging-controller/logging-controller.ts @@ -0,0 +1,24 @@ +import { + LoggingController, + LoggingControllerMessenger, +} from '@metamask/logging-controller'; +import { Messenger } from '@metamask/messenger'; + +import type { InitializationConfiguration } from '../../types'; + +export const loggingController: InitializationConfiguration< + LoggingController, + LoggingControllerMessenger +> = { + name: 'LoggingController', + init: ({ state, messenger }) => + new LoggingController({ + state, + messenger, + }), + getMessenger: (parent) => + new Messenger({ + namespace: 'LoggingController', + parent, + }), +}; diff --git a/packages/wallet/tsconfig.build.json b/packages/wallet/tsconfig.build.json index bfa1aa578b..950fdced90 100644 --- a/packages/wallet/tsconfig.build.json +++ b/packages/wallet/tsconfig.build.json @@ -13,6 +13,7 @@ { "path": "../connectivity-controller/tsconfig.build.json" }, { "path": "../controller-utils/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, + { "path": "../logging-controller/tsconfig.build.json" }, { "path": "../messenger/tsconfig.build.json" }, { "path": "../network-controller/tsconfig.build.json" }, { "path": "../remote-feature-flag-controller/tsconfig.build.json" }, diff --git a/packages/wallet/tsconfig.json b/packages/wallet/tsconfig.json index 9d52f9fb40..7866f27f0a 100644 --- a/packages/wallet/tsconfig.json +++ b/packages/wallet/tsconfig.json @@ -11,6 +11,7 @@ { "path": "../connectivity-controller/tsconfig.json" }, { "path": "../controller-utils/tsconfig.json" }, { "path": "../keyring-controller/tsconfig.json" }, + { "path": "../logging-controller/tsconfig.json" }, { "path": "../messenger/tsconfig.json" }, { "path": "../network-controller/tsconfig.json" }, { "path": "../remote-feature-flag-controller/tsconfig.json" }, diff --git a/yarn.lock b/yarn.lock index 2d277e4ea2..2807068890 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9015,6 +9015,7 @@ __metadata: "@metamask/connectivity-controller": "npm:^0.2.0" "@metamask/controller-utils": "npm:^12.3.0" "@metamask/keyring-controller": "npm:^27.1.0" + "@metamask/logging-controller": "npm:^8.0.2" "@metamask/messenger": "npm:^1.2.0" "@metamask/network-controller": "npm:^34.0.0" "@metamask/remote-feature-flag-controller": "npm:^4.2.2"