-
-
Notifications
You must be signed in to change notification settings - Fork 252
refactor: migrate AccountsController to @metamask/messenger
#6426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
3e62633
443a6ee
b25ee8e
3453a8d
3c6828e
4255c39
7db8785
bff1536
74bd264
17359ad
53e3844
86a9e0b
11a662d
6c94ae5
06e5534
7f6b1f2
80e5d01
93bfbf9
b097a4e
74f2117
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| import { Messenger } from '@metamask/base-controller'; | ||
| import { InfuraNetworkType } from '@metamask/controller-utils'; | ||
| import type { | ||
| AccountAssetListUpdatedEventPayload, | ||
|
|
@@ -15,19 +14,23 @@ | |
| } 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'; | ||
| import type { CaipChainId } from '@metamask/utils'; | ||
| 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 +44,17 @@ | |
| keyringTypeToName, | ||
| } from './utils'; | ||
|
|
||
| type AllAccountsControllerActions = | ||
| MessengerActions<AccountsControllerMessenger>; | ||
|
|
||
| type AllAccountsControllerEvents = MessengerEvents<AccountsControllerMessenger>; | ||
|
|
||
| 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,64 +231,66 @@ | |
| } | ||
|
|
||
| /** | ||
| * 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 parent messenger. | ||
mikesposito marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * @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: [ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Delegation Missing for AccountsController EventsThe delegation setup is incomplete. The |
||
| 'SnapController:stateChange', | ||
| 'KeyringController:stateChange', | ||
| 'SnapKeyring:accountAssetListUpdated', | ||
| 'SnapKeyring:accountBalancesUpdated', | ||
| 'SnapKeyring:accountTransactionsUpdated', | ||
| 'MultichainNetworkController:networkDidChange', | ||
| ], | ||
| allowedActions: [ | ||
| 'KeyringController:getState', | ||
| 'KeyringController:getKeyringsByType', | ||
| ], | ||
| }); | ||
| return accountsControllerMessenger; | ||
| } | ||
|
|
||
| /** | ||
| * Sets up an instance of the AccountsController class with the given initial state and callbacks. | ||
| * | ||
| * @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({ | ||
| initialState = {}, | ||
| messenger = buildMessenger(), | ||
| }: { | ||
| initialState?: Partial<AccountsControllerState>; | ||
| 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 +304,12 @@ | |
| const triggerMultichainNetworkChange = (id: NetworkClientId | CaipChainId) => | ||
| messenger.publish('MultichainNetworkController:networkDidChange', id); | ||
|
|
||
| return { accountsController, messenger, triggerMultichainNetworkChange }; | ||
| return { | ||
| accountsController, | ||
| messenger, | ||
| accountsControllerMessenger, | ||
| triggerMultichainNetworkChange, | ||
| }; | ||
| } | ||
|
|
||
| describe('AccountsController', () => { | ||
|
|
@@ -1136,11 +1157,10 @@ | |
|
|
||
| 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 +1172,8 @@ | |
| messenger, | ||
| }); | ||
|
|
||
| const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); | ||
|
|
||
| const mockNewKeyringState = { | ||
| isUnlocked: true, | ||
| keyrings: [ | ||
|
|
@@ -1172,11 +1194,10 @@ | |
| [], | ||
| ); | ||
|
|
||
| // 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 +1458,10 @@ | |
|
|
||
| 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 +1474,8 @@ | |
| messenger, | ||
| }); | ||
|
|
||
| const messengerSpy = jest.spyOn(accountsControllerMessenger, 'publish'); | ||
|
|
||
| const mockNewKeyringState = { | ||
| isUnlocked: true, | ||
| keyrings: [ | ||
|
|
@@ -1473,11 +1495,10 @@ | |
| [], | ||
| ); | ||
|
|
||
| // 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, | ||
| ); | ||
|
|
@@ -3085,19 +3106,20 @@ | |
| }, | ||
| 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); | ||
|
|
||
|
|
@@ -3191,10 +3213,10 @@ | |
| }); | ||
|
|
||
| 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, | ||
|
|
@@ -3269,16 +3291,17 @@ | |
| }); | ||
|
|
||
| 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'); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.