Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions packages/account-tree-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add support for `AccountsController:accountRenamed` event handling for legacy account syncing compatibility ([#6251](https://github.com/MetaMask/core/pull/6251))
- Add persistence support for user customizations ([#6221](https://github.com/MetaMask/core/pull/6221))
- New `accountGroupsMetadata` (of new type `AccountTreeGroupPersistedMetadata`) and `accountWalletsMetadata` (of new type `AccountTreeWalletPersistedMetadata`) state properties to persist custom names, pinning, and hiding states.
- Custom names and metadata survive controller initialization and tree rebuilds.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ function getAccountTreeControllerMessenger(
name: 'AccountTreeController',
allowedEvents: [
'AccountsController:accountAdded',
'AccountsController:accountRenamed',
'AccountsController:accountRemoved',
'AccountsController:selectedAccountChange',
],
Expand Down Expand Up @@ -1017,6 +1018,89 @@ describe('AccountTreeController', () => {
});
});

describe('on AccountsController:accountRenamed', () => {
it('renames an account in the tree if the renamed internal account is of type KeyringTypes.hd', () => {
const { controller, messenger } = setup({
accounts: [MOCK_HD_ACCOUNT_1],
keyrings: [MOCK_HD_KEYRING_1],
});
controller.init();

const newName = 'New Account Name';
messenger.publish('AccountsController:accountRenamed', {
...MOCK_HD_ACCOUNT_1,
metadata: {
...MOCK_HD_ACCOUNT_1.metadata,
name: newName,
},
});

const walletId = toMultichainAccountWalletId(
MOCK_HD_KEYRING_1.metadata.id,
);
const group = toMultichainAccountGroupId(
walletId,
MOCK_HD_ACCOUNT_1.options.entropy.groupIndex,
);

expect(
controller.state.accountTree.wallets[walletId]?.groups[group],
).toBeDefined();
expect(
controller.state.accountTree.wallets[walletId]?.groups[group].metadata
.name,
).toBe(newName);
expect(
controller.state.accountTree.wallets[walletId]?.groups[group].accounts,
).toContain(MOCK_HD_ACCOUNT_1.id);
expect(
controller.state.accountTree.wallets[walletId]?.metadata.name,
).toBe('Wallet 1');
});

it('does not rename an account in the tree if the renamed internal account is not of type KeyringTypes.hd', () => {
const { controller, messenger } = setup({
accounts: [MOCK_HD_ACCOUNT_1],
keyrings: [MOCK_HD_KEYRING_1],
});
controller.init();

const newName = 'New Account Name';
messenger.publish('AccountsController:accountRenamed', {
...MOCK_HD_ACCOUNT_1,
metadata: {
...MOCK_HD_ACCOUNT_1.metadata,
keyring: {
type: KeyringTypes.simple,
},
name: newName,
},
});

const walletId = toMultichainAccountWalletId(
MOCK_HD_KEYRING_1.metadata.id,
);
const group = toMultichainAccountGroupId(
walletId,
MOCK_HD_ACCOUNT_1.options.entropy.groupIndex,
);

expect(
controller.state.accountTree.wallets[walletId]?.groups[group],
).toBeDefined();
expect(
controller.state.accountTree.wallets[walletId]?.groups[group].metadata
.name,
).toBe(MOCK_HD_ACCOUNT_1.metadata.name);
expect(
controller.state.accountTree.wallets[walletId]?.groups[group].accounts,
).toContain(MOCK_HD_ACCOUNT_1.id);
expect(
controller.state.accountTree.wallets[walletId]?.metadata.name,
).toBe('Wallet 1');
});
});

describe('getAccountWallet/getAccountWalletOrThrow', () => {
it('gets a wallet using its ID', () => {
const { controller } = setup({
Expand Down
31 changes: 31 additions & 0 deletions packages/account-tree-controller/src/AccountTreeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { AccountId } from '@metamask/accounts-controller';
import type { StateMetadata } from '@metamask/base-controller';
import { BaseController } from '@metamask/base-controller';
import { isEvmAccountType } from '@metamask/keyring-api';
import { KeyringTypes } from '@metamask/keyring-controller';
import type { InternalAccount } from '@metamask/keyring-internal-api';

import type { AccountGroupObject } from './group';
Expand Down Expand Up @@ -138,6 +139,13 @@ export class AccountTreeController extends BaseController<
},
);

this.messagingSystem.subscribe(
'AccountsController:accountRenamed',
(account) => {
this.#handleAccountRenamed(account);
},
);

this.#registerMessageHandlers();
}

Expand Down Expand Up @@ -316,6 +324,29 @@ export class AccountTreeController extends BaseController<
}
}

#handleAccountRenamed(account: InternalAccount) {
// This method is only there to support legacy account syncing programmatic renames.
// Since legacy account syncing only syncs HD EVM accounts, we only
// handle HD EVM accounts here.
if (account.metadata.keyring.type !== (KeyringTypes.hd as string)) {
return;
}

const context = this.#accountIdToContext.get(account.id);

if (context) {
const { walletId, groupId } = context;

const wallet = this.state.accountTree.wallets[walletId];
if (wallet) {
const group = wallet.groups[groupId];
if (group) {
this.setAccountGroupName(groupId, account.metadata.name);
}
}
}
}

/**
* Helper method to prune a group if it holds no accounts and additionally
* prune the wallet if it holds no groups. This action should take place
Expand Down
2 changes: 2 additions & 0 deletions packages/account-tree-controller/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';
import type {
AccountsControllerAccountAddedEvent,
AccountsControllerAccountRenamedEvent,
AccountsControllerAccountRemovedEvent,
AccountsControllerGetAccountAction,
AccountsControllerGetSelectedAccountAction,
Expand Down Expand Up @@ -95,6 +96,7 @@ export type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<

export type AllowedEvents =
| AccountsControllerAccountAddedEvent
| AccountsControllerAccountRenamedEvent
| AccountsControllerAccountRemovedEvent
| AccountsControllerSelectedAccountChangeEvent;

Expand Down
Loading