Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/account-tree-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Always fire `:selectedAccountGroupChange` during `init` call ([#8427](https://github.com/MetaMask/core/pull/8427))
- Many controllers were actually relying on this behavior when this used to be dynamic, so we re-introduce this behavior.
- Now persist `accounTree` ([#8437](https://github.com/MetaMask/core/pull/8437))
- The tree is not persisted and can be used before `init` is called.
- This allow consumers (like the assets controllers) to rely on the selected group's accounts right away.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4586,6 +4586,48 @@ describe('AccountTreeController', () => {
);
});

it('always emits selectedAccountGroupChange on init even if the selected group did not change', () => {
const { controller, messenger, mocks } = setup({
accounts: [MOCK_HD_ACCOUNT_1],
keyrings: [MOCK_HD_KEYRING_1],
});

mocks.AccountsController.getSelectedMultichainAccount.mockImplementation(
() => MOCK_HD_ACCOUNT_1,
);

controller.init();

const defaultAccountGroupId = toMultichainAccountGroupId(
toMultichainAccountWalletId(MOCK_HD_ACCOUNT_1.options.entropy.id),
MOCK_HD_ACCOUNT_1.options.entropy.groupIndex,
);

expect(controller.state.selectedAccountGroup).toStrictEqual(
defaultAccountGroupId,
);

const selectedAccountGroupChangeListener = jest.fn();
messenger.subscribe(
'AccountTreeController:selectedAccountGroupChange',
selectedAccountGroupChangeListener,
);

// Re-init with the same accounts — the selected group still exists and has not changed.
controller.reinit();

expect(controller.state.selectedAccountGroup).toStrictEqual(
defaultAccountGroupId,
);
// The event must fire even though the group did not change, so that
// subscribers that missed the first init can still react accordingly.
expect(selectedAccountGroupChangeListener).toHaveBeenCalledWith(
defaultAccountGroupId,
defaultAccountGroupId,
);
expect(selectedAccountGroupChangeListener).toHaveBeenCalledTimes(1);
});

it('emits selectedAccountGroupChange when setSelectedAccountGroup is called', () => {
// Use different keyring types to ensure different groups
const { controller, messenger } = setup({
Expand Down
21 changes: 9 additions & 12 deletions packages/account-tree-controller/src/AccountTreeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,18 +418,15 @@ export class AccountTreeController extends BaseController<
}
});

// We still compare the previous and new value, the previous one could have been
// an empty string and `#getDefaultSelectedAccountGroup` could also return an
// empty string too, thus, we would re-use the same value here again. In that
// case, no need to fire any event.
if (previousSelectedAccountGroup !== this.state.selectedAccountGroup) {
log(`Selected (initial) group is: [${this.state.selectedAccountGroup}]`);
this.messenger.publish(
`${controllerName}:selectedAccountGroupChange`,
this.state.selectedAccountGroup,
previousSelectedAccountGroup,
);
}
// We always fire the current selected group after init, even if it did not change, to ensure that
// all subscribers are aware of it and can react accordingly (e.g. by fetching accounts from
// the selected group on startup).
log(`Selected (initial) group is: [${this.state.selectedAccountGroup}]`);
this.messenger.publish(
`${controllerName}:selectedAccountGroupChange`,
this.state.selectedAccountGroup,
previousSelectedAccountGroup,
);

log('Initialized!');
this.#initialized = true;
Expand Down
Loading