{"version":3,"file":"AccountTreeController.mjs","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountWalletType, select } from '@metamask/account-api';\nimport type {\n  AccountGroupId,\n  AccountWalletId,\n  AccountSelector,\n  MultichainAccountWalletId,\n  AccountGroupType,\n} from '@metamask/account-api';\nimport type { MultichainAccountWalletStatus } from '@metamask/account-api';\nimport type { AccountId } from '@metamask/accounts-controller';\nimport type { StateMetadata } from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { assert } from '@metamask/utils';\n\nimport type { BackupAndSyncEmitAnalyticsEventParams } from './backup-and-sync/analytics';\nimport {\n  formatAnalyticsEvent,\n  traceFallback,\n} from './backup-and-sync/analytics';\nimport { BackupAndSyncService } from './backup-and-sync/service';\nimport type { BackupAndSyncContext } from './backup-and-sync/types';\nimport type { AccountGroupObject, AccountTypeOrderKey } from './group';\nimport {\n  ACCOUNT_TYPE_TO_SORT_ORDER,\n  isAccountGroupNameUnique,\n  isAccountGroupNameUniqueFromWallet,\n  MAX_SORT_ORDER,\n} from './group';\nimport { projectLogger as log } from './logger';\nimport type { Rule } from './rule';\nimport { EntropyRule } from './rules/entropy';\nimport { KeyringRule } from './rules/keyring';\nimport { SnapRule } from './rules/snap';\nimport type {\n  AccountTreeControllerConfig,\n  AccountTreeControllerInternalBackupAndSyncConfig,\n  AccountTreeControllerMessenger,\n  AccountTreeControllerState,\n} from './types';\nimport type { AccountWalletObject, AccountWalletObjectOf } from './wallet';\n\nexport const controllerName = 'AccountTreeController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n  'getSelectedAccountGroup',\n  'setSelectedAccountGroup',\n  'getAccountsFromSelectedAccountGroup',\n  'getAccountContext',\n  'setAccountWalletName',\n  'setAccountGroupName',\n  'setAccountGroupPinned',\n  'setAccountGroupHidden',\n  'getAccountWalletObject',\n  'getAccountWalletObjects',\n  'getAccountGroupObject',\n  'clearState',\n  'syncWithUserStorage',\n  'syncWithUserStorageAtLeastOnce',\n  'init',\n  'reinit',\n] as const;\n\nconst accountTreeControllerMetadata: StateMetadata<AccountTreeControllerState> =\n  {\n    accountTree: {\n      includeInStateLogs: true,\n      persist: true,\n      includeInDebugSnapshot: false,\n      usedInUi: true,\n    },\n    selectedAccountGroup: {\n      includeInStateLogs: true,\n      persist: true,\n      includeInDebugSnapshot: false,\n      usedInUi: true,\n    },\n    isAccountTreeSyncingInProgress: {\n      includeInStateLogs: false,\n      persist: false,\n      includeInDebugSnapshot: false,\n      usedInUi: true,\n    },\n    hasAccountTreeSyncingSyncedAtLeastOnce: {\n      includeInStateLogs: true,\n      persist: true,\n      includeInDebugSnapshot: false,\n      usedInUi: true,\n    },\n    accountGroupsMetadata: {\n      includeInStateLogs: true,\n      persist: true,\n      includeInDebugSnapshot: false,\n      usedInUi: true,\n    },\n    accountWalletsMetadata: {\n      includeInStateLogs: true,\n      persist: true,\n      includeInDebugSnapshot: false,\n      usedInUi: true,\n    },\n  };\n\n/**\n * Gets default state of the `AccountTreeController`.\n *\n * @returns The default state of the `AccountTreeController`.\n */\nexport function getDefaultAccountTreeControllerState(): AccountTreeControllerState {\n  return {\n    accountTree: {\n      wallets: {},\n    },\n    selectedAccountGroup: '',\n    isAccountTreeSyncingInProgress: false,\n    hasAccountTreeSyncingSyncedAtLeastOnce: false,\n    accountGroupsMetadata: {},\n    accountWalletsMetadata: {},\n  };\n}\n\n/**\n * Context for an account.\n */\nexport type AccountContext = {\n  /**\n   * Wallet ID associated to that account.\n   */\n  walletId: AccountWalletObject['id'];\n\n  /**\n   * Account group ID associated to that account.\n   */\n  groupId: AccountGroupObject['id'];\n\n  /**\n   * Sort order of the account.\n   */\n  sortOrder: (typeof ACCOUNT_TYPE_TO_SORT_ORDER)[AccountTypeOrderKey];\n};\n\nexport class AccountTreeController extends BaseController<\n  typeof controllerName,\n  AccountTreeControllerState,\n  AccountTreeControllerMessenger\n> {\n  readonly #accountIdToContext: Map<AccountId, AccountContext>;\n\n  readonly #groupIdToWalletId: Map<AccountGroupId, AccountWalletId>;\n\n  /**\n   * Service responsible for all backup and sync operations.\n   */\n  readonly #backupAndSyncService: BackupAndSyncService;\n\n  readonly #rules: [EntropyRule, SnapRule, KeyringRule];\n\n  readonly #trace: TraceCallback;\n\n  readonly #backupAndSyncConfig: AccountTreeControllerInternalBackupAndSyncConfig;\n\n  /**\n   * Callbacks to migrate hidden and pinned account information from the account order controller\n   */\n  readonly #accountOrderCallbacks:\n    | AccountTreeControllerConfig['accountOrderCallbacks']\n    | undefined;\n\n  #initialized: boolean;\n\n  /**\n   * Constructor for AccountTreeController.\n   *\n   * @param options - The controller options.\n   * @param options.messenger - The messenger object.\n   * @param options.state - Initial state to set on this controller\n   * @param options.config - Optional configuration for the controller.\n   */\n\n  constructor({\n    messenger,\n    state,\n    config,\n  }: {\n    messenger: AccountTreeControllerMessenger;\n    state?: Partial<AccountTreeControllerState>;\n    config?: AccountTreeControllerConfig;\n  }) {\n    super({\n      messenger,\n      name: controllerName,\n      metadata: accountTreeControllerMetadata,\n      state: {\n        ...getDefaultAccountTreeControllerState(),\n        ...state,\n      },\n    });\n\n    // This will be set to true upon the first `init` call.\n    this.#initialized = false;\n\n    // Reverse map to allow fast node access from an account ID.\n    this.#accountIdToContext = new Map();\n\n    // Reverse map to allow fast wallet node access from a group ID.\n    this.#groupIdToWalletId = new Map();\n\n    // Rules to apply to construct the wallets tree.\n    this.#rules = [\n      // 1. We group by entropy-source\n      new EntropyRule(this.messenger),\n      // 2. We group by Snap ID\n      new SnapRule(this.messenger),\n      // 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)\n      new KeyringRule(this.messenger),\n    ];\n\n    // Initialize trace function\n    this.#trace = config?.trace ?? traceFallback;\n\n    // Initialize backup and sync config\n    this.#backupAndSyncConfig = {\n      emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => {\n        return config?.backupAndSync?.onBackupAndSyncEvent?.(\n          formatAnalyticsEvent(event),\n        );\n      },\n    };\n\n    // Used when migrating initial hidden/pinned state for groups (if available).\n    this.#accountOrderCallbacks = config?.accountOrderCallbacks;\n\n    // Initialize the backup and sync service\n    this.#backupAndSyncService = new BackupAndSyncService(\n      this.#createBackupAndSyncContext(),\n    );\n\n    // We build the initial tree (from the state), but this might get updated\n    // after `init` got called. Having it available now, allow our consumers to\n    // re-use the state that was already available before we restart/lock the\n    // wallet.\n    this.#initTreeContext(this.state.accountTree);\n\n    this.messenger.subscribe('AccountsController:accountsAdded', (accounts) => {\n      this.#handleAccountsAdded(accounts);\n    });\n\n    this.messenger.subscribe(\n      'AccountsController:accountsRemoved',\n      (accountIds) => {\n        this.#handleAccountsRemoved(accountIds);\n      },\n    );\n\n    this.messenger.subscribe(\n      'AccountsController:selectedAccountChange',\n      (account) => {\n        this.#handleSelectedAccountChange(account);\n      },\n    );\n\n    this.messenger.subscribe(\n      'UserStorageController:stateChange',\n      (userStorageControllerState) => {\n        this.#backupAndSyncService.handleUserStorageStateChange(\n          userStorageControllerState,\n        );\n      },\n    );\n\n    this.messenger.subscribe(\n      'MultichainAccountService:walletStatusChange',\n      (walletId, status) => {\n        this.#handleMultichainAccountWalletStatusChange(walletId, status);\n      },\n    );\n\n    this.messenger.registerMethodActionHandlers(\n      this,\n      MESSENGER_EXPOSED_METHODS,\n    );\n  }\n\n  /**\n   * Initialize the account tree from the given state.\n   *\n   * @param tree The account tree state to initialize from.\n   */\n  #initTreeContext(tree: AccountTreeControllerState['accountTree']): void {\n    // Fetch persisted accounts from the `AccountsController`.\n    const accounts = new Map(\n      this.#listAccounts().map((account) => [account.id, account]),\n    );\n\n    for (const [walletId, wallet] of Object.entries(tree.wallets) as [\n      AccountWalletId,\n      AccountWalletObject,\n    ][]) {\n      for (const [groupId, group] of Object.entries(wallet.groups) as [\n        AccountGroupId,\n        AccountGroupObject,\n      ][]) {\n        this.#groupIdToWalletId.set(groupId, walletId);\n\n        // We still need to go through accounts for the sort order.\n        for (const accountId of group.accounts) {\n          const account = accounts.get(accountId);\n\n          // NOTE: The account should always be available, but if it is not, we\n          // still let it inside the tree with a max sort order to avoid blocking\n          // the entire tree construction.\n          let sortOrder = MAX_SORT_ORDER;\n          if (account) {\n            sortOrder = ACCOUNT_TYPE_TO_SORT_ORDER[account.type];\n          }\n\n          this.#accountIdToContext.set(accountId, {\n            walletId,\n            groupId,\n            sortOrder,\n          });\n        }\n      }\n    }\n  }\n\n  /**\n   * Initialize the controller's state.\n   *\n   * It constructs the initial state of the account tree (tree nodes, nodes\n   * names, metadata, etc..) and will automatically update the controller's\n   * state with it.\n   */\n  init() {\n    if (this.#initialized) {\n      // We prevent re-initilializing the state multiple times. Though, we can use\n      // `reinit` to re-init everything from scratch.\n      return;\n    }\n\n    log('Initializing...');\n\n    const wallets: AccountTreeControllerState['accountTree']['wallets'] = {};\n\n    // Clear mappings for fresh rebuild.\n    this.#accountIdToContext.clear();\n    this.#groupIdToWalletId.clear();\n\n    // Keep the current selected group to check if it's still part of the tree\n    // after rebuilding it.\n    const previousSelectedAccountGroup = this.state.selectedAccountGroup;\n\n    // There's no guarantee that accounts would be sorted by their import time\n    // with `listMultichainAccounts`. We have to sort them here before constructing\n    // the tree.\n    //\n    // Because of the alignment mecanism, some accounts from the same group might not\n    // have been imported at the same time, but at least of them should have been\n    // imported at the right time, thus, inserting the group at the proper place too.\n    //\n    // Lastly, if one day we allow to have \"gaps\" in between groups, then this `sort`\n    // won't be enough and we would have to use group properties instead (like group\n    // index or maybe introduce a `importTime` at group level).\n    const accounts = this.#listAccounts().sort(\n      (a, b) => a.metadata.importTime - b.metadata.importTime,\n    );\n\n    // For now, we always re-compute all wallets, we do not re-use the existing state.\n    for (const account of accounts) {\n      this.#insert(wallets, account);\n    }\n\n    // Once we have the account tree, we can apply persisted metadata (names + UI states).\n    let previousSelectedAccountGroupStillExists = false;\n    this.update((state) => {\n      state.accountTree.wallets = wallets;\n\n      // Apply group metadata within the state update\n      for (const wallet of Object.values(state.accountTree.wallets)) {\n        this.#applyAccountWalletMetadata(state, wallet.id);\n\n        // Used for default group default names (so we use human-indexing here).\n        let nextNaturalNameIndex = 1;\n        for (const group of Object.values(wallet.groups)) {\n          this.#applyAccountGroupMetadata(state, wallet.id, group.id, {\n            // We allow computed name when initializing the tree.\n            // This will automatically handle account name migration for the very first init of the\n            // tree. Once groups are created, their name will be persisted, thus, taking precedence\n            // over the computed names (even if we re-init).\n            allowComputedName: true,\n            // FIXME: We should not need this kind of logic if we were not inserting accounts\n            // 1 by 1. Instead, we should be inserting wallets and groups directly. This would\n            // allow us to naturally insert a group in the tree AND update its metadata right\n            // away...\n            // But here, we have to wait for the entire group to be ready before updating\n            // its metadata (mainly because we're dealing with single accounts rather than entire\n            // groups).\n            // That is why we need this kind of extra parameter.\n            nextNaturalNameIndex,\n          });\n\n          if (group.id === previousSelectedAccountGroup) {\n            previousSelectedAccountGroupStillExists = true;\n          }\n          nextNaturalNameIndex += 1;\n        }\n      }\n\n      if (\n        !previousSelectedAccountGroupStillExists ||\n        previousSelectedAccountGroup === ''\n      ) {\n        // No group is selected yet OR group no longer exists, re-sync with the\n        // AccountsController.\n        state.selectedAccountGroup = this.#getDefaultSelectedAccountGroup(\n          state.accountTree.wallets, // Re-use updated wallets with metadata here.\n        );\n      }\n    });\n\n    // We always fire the current selected group after init, even if it did not change, to ensure that\n    // all subscribers are aware of it and can react accordingly (e.g. by fetching accounts from\n    // the selected group on startup).\n    log(`Selected (initial) group is: [${this.state.selectedAccountGroup}]`);\n    this.messenger.publish(\n      `${controllerName}:selectedAccountGroupChange`,\n      this.state.selectedAccountGroup,\n      previousSelectedAccountGroup,\n    );\n\n    log('Initialized!');\n    this.#initialized = true;\n  }\n\n  /**\n   * Re-initialize the controller's state.\n   *\n   * This is done in one single (atomic) `update` block to avoid having a temporary\n   * cleared state. Use this when you need to force a full re-init even if already initialized.\n   */\n  reinit() {\n    log('Re-initializing...');\n    this.#initialized = false;\n    this.init();\n  }\n\n  /**\n   * Rule for entropy-base wallets.\n   *\n   * @returns The rule for entropy-based wallets.\n   */\n  #getEntropyRule(): EntropyRule {\n    return this.#rules[0];\n  }\n\n  /**\n   * Rule for Snap-base wallets.\n   *\n   * @returns The rule for snap-based wallets.\n   */\n  #getSnapRule(): SnapRule {\n    return this.#rules[1];\n  }\n\n  /**\n   * Rule for keyring-base wallets.\n   *\n   * This rule acts as a fallback and never fails since all accounts\n   * comes from a keyring anyway.\n   *\n   * @returns The fallback rule for every accounts that did not match\n   * any other rules.\n   */\n  #getKeyringRule(): KeyringRule {\n    return this.#rules[2];\n  }\n\n  /**\n   * Applies wallet metadata updates (name) by checking the persistent state\n   * first, and then fallbacks to default values (based on the wallet's\n   * type).\n   *\n   * @param state Controller state to update for persistence.\n   * @param walletId The wallet ID to update.\n   */\n  #applyAccountWalletMetadata(\n    state: AccountTreeControllerState,\n    walletId: AccountWalletId,\n  ) {\n    const wallet = state.accountTree.wallets[walletId];\n    const persistedMetadata = state.accountWalletsMetadata[walletId];\n\n    // Apply persisted name if available (including empty strings)\n    if (persistedMetadata?.name !== undefined) {\n      wallet.metadata.name = persistedMetadata.name.value;\n    } else if (!wallet.metadata.name) {\n      // Generate default name if none exists\n      if (wallet.type === AccountWalletType.Entropy) {\n        wallet.metadata.name =\n          this.#getEntropyRule().getDefaultAccountWalletName(wallet);\n      } else if (wallet.type === AccountWalletType.Snap) {\n        wallet.metadata.name =\n          this.#getSnapRule().getDefaultAccountWalletName(wallet);\n      } else {\n        wallet.metadata.name =\n          this.#getKeyringRule().getDefaultAccountWalletName(wallet);\n      }\n      log(`[${wallet.id}] Set default name to: \"${wallet.metadata.name}\"`);\n    }\n  }\n\n  /**\n   * Gets the appropriate rule instance for a given wallet type.\n   *\n   * @param wallet - The wallet object to get the rule for.\n   * @returns The rule instance that handles the wallet's type.\n   */\n  #getRuleForWallet<WalletType extends AccountWalletType>(\n    wallet: AccountWalletObjectOf<WalletType>,\n  ): Rule<WalletType, AccountGroupType> {\n    switch (wallet.type) {\n      case AccountWalletType.Entropy:\n        return this.#getEntropyRule() as unknown as Rule<\n          WalletType,\n          AccountGroupType\n        >;\n      case AccountWalletType.Snap:\n        return this.#getSnapRule() as unknown as Rule<\n          WalletType,\n          AccountGroupType\n        >;\n      default:\n        return this.#getKeyringRule() as unknown as Rule<\n          WalletType,\n          AccountGroupType\n        >;\n    }\n  }\n\n  /**\n   * Gets the computed name of a group (using its associated accounts).\n   *\n   * @param wallet The wallet containing the group.\n   * @param group The account group to update.\n   * @returns The computed name for the group or '' if there's no compute named for this group.\n   */\n  #getComputedAccountGroupName(\n    wallet: AccountWalletObject,\n    group: AccountGroupObject,\n  ): string {\n    let proposedName = ''; // Empty means there's no computed name for this group.\n\n    for (const id of group.accounts) {\n      const account = this.messenger.call('AccountsController:getAccount', id);\n      if (!account?.metadata.name.length) {\n        continue;\n      }\n\n      // We only pick a new proposed name if we don't have one yet.\n      if (!proposedName) {\n        proposedName = account.metadata.name;\n      }\n\n      // But EVM accounts take precedence over any other computed names.\n      if (isEvmAccountType(account.type)) {\n        // So we just overwrite the proposed name and stop looping right away.\n        proposedName = account.metadata.name;\n        break;\n      }\n    }\n\n    // If this name already exists for whatever reason, we rename it to resolve this conflict.\n    if (\n      proposedName.length &&\n      !isAccountGroupNameUniqueFromWallet(wallet, group.id, proposedName)\n    ) {\n      proposedName = this.#resolveNameConflict(wallet, group.id, proposedName);\n    }\n\n    return proposedName;\n  }\n\n  /**\n   * Gets the default name of a group.\n   *\n   * @param state Controller state to update for persistence.\n   * @param wallet The wallet containing the group.\n   * @param group The account group to update.\n   * @param nextNaturalNameIndex The next natural name index for this group.\n   * @returns The default name for the group.\n   */\n  #getDefaultAccountGroupName(\n    state: AccountTreeControllerState,\n    wallet: AccountWalletObject,\n    group: AccountGroupObject,\n    nextNaturalNameIndex?: number,\n  ): string {\n    // Get the appropriate rule for this wallet type\n    const rule = this.#getRuleForWallet(wallet);\n\n    // Get the prefix for groups of this wallet\n    const namePrefix = rule.getDefaultAccountGroupPrefix(wallet);\n\n    // Parse the highest account index being used (similar to accounts-controller)\n    let highestNameIndex = 0;\n    for (const { id: otherGroupId } of Object.values(\n      wallet.groups,\n    ) as AccountGroupObject[]) {\n      // Skip the current group being processed\n      if (otherGroupId === group.id) {\n        continue;\n      }\n\n      // We always get the name from the persisted map, since `init` will clear the\n      // `state.accountTree.wallets`, thus, given empty `group.metadata.name`.\n      // NOTE: If the other group has not been named yet, we just use an empty name.\n      const otherGroupName =\n        state.accountGroupsMetadata[otherGroupId]?.name?.value ?? '';\n\n      // Parse the existing group name to extract the numeric index\n      const nameMatch = otherGroupName.match(/account\\s+(\\d+)$/iu);\n      if (nameMatch) {\n        const nameIndex = parseInt(nameMatch[1], 10);\n        if (nameIndex > highestNameIndex) {\n          highestNameIndex = nameIndex;\n        }\n      }\n    }\n\n    // We just use the highest known index no matter the wallet type.\n    //\n    // For entropy-based wallets (bip44), if a multichain account group with group index 1\n    // is inserted before another one with group index 0, then the naming will be:\n    // - \"Account 1\" (group index 1)\n    // - \"Account 2\" (group index 0)\n    // This naming makes more sense for the end-user.\n    //\n    // For other type of wallets, since those wallets can create arbitrary gaps, we still\n    // rely on the highest know index to avoid back-filling account with \"old names\".\n    let proposedNameIndex = Math.max(\n      // Use + 1 to use the next available index.\n      highestNameIndex + 1,\n      // In case all accounts have been renamed differently than the usual \"Account <index>\"\n      // pattern, we want to use the next \"natural\" index, which is just the number of groups\n      // in that wallet (e.g. [\"Account A\", \"Another Account\"], next natural index would be\n      // \"Account 3\" in this case).\n      nextNaturalNameIndex ?? Object.keys(wallet.groups).length,\n    );\n\n    // Find a unique name by checking for conflicts and incrementing if needed\n    let proposedNameExists: boolean;\n    let proposedName = '';\n    do {\n      proposedName = `${namePrefix} ${proposedNameIndex}`;\n\n      // Check if this name already exists in the wallet (excluding current group)\n      proposedNameExists = !isAccountGroupNameUniqueFromWallet(\n        wallet,\n        group.id,\n        proposedName,\n      );\n\n      /* istanbul ignore next */\n      if (proposedNameExists) {\n        proposedNameIndex += 1; // Try next number\n      }\n    } while (proposedNameExists);\n\n    return proposedName;\n  }\n\n  /**\n   * Applies group metadata updates (name, pinned, hidden flags) by checking\n   * the persistent state first, and then fallbacks to default values (based\n   * on the wallet's\n   * type).\n   *\n   * @param state Controller state to update for persistence.\n   * @param walletId The wallet ID containing the group.\n   * @param groupId The account group ID to update.\n   * @param namingOptions Options around account group naming.\n   * @param namingOptions.allowComputedName Allow to use original account names to compute the default name.\n   * @param namingOptions.nextNaturalNameIndex The next natural name index for this group (only used for default names).\n   */\n  #applyAccountGroupMetadata(\n    state: AccountTreeControllerState,\n    walletId: AccountWalletId,\n    groupId: AccountGroupId,\n    {\n      allowComputedName,\n      nextNaturalNameIndex,\n    }: {\n      allowComputedName?: boolean;\n      nextNaturalNameIndex?: number;\n    } = {},\n  ) {\n    const wallet = state.accountTree.wallets[walletId];\n    const group = wallet.groups[groupId];\n    const persistedGroupMetadata = state.accountGroupsMetadata[groupId];\n\n    // Ensure metadata object exists once at the beginning\n    state.accountGroupsMetadata[groupId] ??= {};\n\n    // Apply persisted name if available (including empty strings)\n    if (persistedGroupMetadata?.name !== undefined) {\n      state.accountTree.wallets[walletId].groups[groupId].metadata.name =\n        persistedGroupMetadata.name.value;\n    } else if (!group.metadata.name) {\n      let proposedName = '';\n\n      // Computed names are usually only used for existing/old accounts. So this option\n      // should be used only when we first initialize the tree.\n      if (allowComputedName) {\n        proposedName = this.#getComputedAccountGroupName(wallet, group);\n      }\n\n      // If we still don't have a valid name candidate, we fallback to a default name.\n      if (!proposedName.length) {\n        proposedName = this.#getDefaultAccountGroupName(\n          state,\n          wallet,\n          group,\n          nextNaturalNameIndex,\n        );\n      }\n\n      state.accountTree.wallets[walletId].groups[groupId].metadata.name =\n        proposedName;\n      log(`[${group.id}] Set default name to: \"${group.metadata.name}\"`);\n\n      // Persist the generated name to ensure consistency\n      state.accountGroupsMetadata[groupId].name = {\n        value: proposedName,\n        // The `lastUpdatedAt` field is used for backup and sync, when comparing local names\n        // with backed up names. In this case, the generated name should never take precedence\n        // over a user-defined name, so we set `lastUpdatedAt` to 0.\n        lastUpdatedAt: 0,\n      };\n    }\n\n    // Apply persisted UI states\n    if (persistedGroupMetadata?.pinned?.value !== undefined) {\n      group.metadata.pinned = persistedGroupMetadata.pinned.value;\n    } else {\n      let isPinned = false;\n\n      if (this.#accountOrderCallbacks?.isPinnedAccount) {\n        isPinned = group.accounts.some((account) =>\n          this.#accountOrderCallbacks?.isPinnedAccount?.(account),\n        );\n      }\n      state.accountGroupsMetadata[groupId].pinned = {\n        value: isPinned,\n        lastUpdatedAt: 0,\n      };\n      // If any accounts was previously pinned, then we consider the group to be pinned as well.\n      group.metadata.pinned = isPinned;\n    }\n\n    if (persistedGroupMetadata?.hidden?.value !== undefined) {\n      group.metadata.hidden = persistedGroupMetadata.hidden.value;\n    } else {\n      let isHidden = false;\n\n      if (this.#accountOrderCallbacks?.isHiddenAccount) {\n        isHidden = group.accounts.some((account) =>\n          this.#accountOrderCallbacks?.isHiddenAccount?.(account),\n        );\n      }\n      state.accountGroupsMetadata[groupId].hidden = {\n        value: isHidden,\n        lastUpdatedAt: 0,\n      };\n      // If any accounts was previously hidden, then we consider the group to be hidden as well.\n      group.metadata.hidden = isHidden;\n    }\n\n    // Apply persisted lastSelected (plain number, not synced).\n    if (\n      persistedGroupMetadata?.lastSelected !== undefined &&\n      persistedGroupMetadata.lastSelected >= 0\n    ) {\n      group.metadata.lastSelected = persistedGroupMetadata.lastSelected;\n    } else {\n      // Automatiacally inject default value.\n      state.accountGroupsMetadata[groupId].lastSelected = 0;\n\n      group.metadata.lastSelected = 0;\n    }\n  }\n\n  /**\n   * Gets the account wallet object from its ID.\n   *\n   * @param walletId - Account wallet ID.\n   * @returns The account wallet object if found, undefined otherwise.\n   */\n  getAccountWalletObject(\n    walletId: AccountWalletId,\n  ): AccountWalletObject | undefined {\n    const wallet = this.state.accountTree.wallets[walletId];\n    if (!wallet) {\n      return undefined;\n    }\n\n    return wallet;\n  }\n\n  /**\n   * Gets all account wallet objects.\n   *\n   * @returns All account wallet objects.\n   */\n  getAccountWalletObjects(): AccountWalletObject[] {\n    return Object.values(this.state.accountTree.wallets);\n  }\n\n  /**\n   * Gets all underlying accounts from the currently selected account\n   * group.\n   *\n   * It also support account selector, which allows to filter specific\n   * accounts given some criterias (account type, address, scopes, etc...).\n   *\n   * @param selector - Optional account selector.\n   * @returns Underlying accounts for the currently selected account (filtered\n   * by the selector if provided).\n   */\n  getAccountsFromSelectedAccountGroup(\n    selector?: AccountSelector<InternalAccount>,\n  ) {\n    const groupId = this.getSelectedAccountGroup();\n    if (!groupId) {\n      return [];\n    }\n\n    const group = this.getAccountGroupObject(groupId);\n    // We should never reach this part, so we cannot cover it either.\n    /* istanbul ignore next */\n    if (!group) {\n      return [];\n    }\n\n    const accounts: InternalAccount[] = [];\n    for (const id of group.accounts) {\n      const account = this.messenger.call('AccountsController:getAccount', id);\n\n      // For now, we're filtering undefined account, but I believe\n      // throwing would be more appropriate here.\n      if (account) {\n        accounts.push(account);\n      }\n    }\n\n    return selector ? select(accounts, selector) : accounts;\n  }\n\n  /**\n   * Gets the account group object from its ID.\n   *\n   * @param groupId - Account group ID.\n   * @returns The account group object if found, undefined otherwise.\n   */\n  getAccountGroupObject(\n    groupId: AccountGroupId,\n  ): AccountGroupObject | undefined {\n    const walletId = this.#groupIdToWalletId.get(groupId);\n    if (!walletId) {\n      return undefined;\n    }\n\n    const wallet = this.getAccountWalletObject(walletId);\n    return wallet?.groups[groupId];\n  }\n\n  /**\n   * Gets the account's context which contains its wallet ID, group ID, and sort order.\n   *\n   * @param accountId - Account ID.\n   * @returns The account context if found, undefined otherwise.\n   */\n  getAccountContext(accountId: AccountId): AccountContext | undefined {\n    return this.#accountIdToContext.get(accountId);\n  }\n\n  /**\n   * Handles \"AccountsController:accountsAdded\" event to insert\n   * new accounts into the tree in a single state update.\n   *\n   * @param accounts - New accounts.\n   */\n  #handleAccountsAdded(accounts: InternalAccount[]): void {\n    // We wait for the first `init` to be called to actually build up the tree and\n    // mutate it. We expect the caller to first update the `AccountsController` state\n    // to force the migration of accounts, and then call `init`.\n    if (!this.#initialized) {\n      return;\n    }\n\n    // Filter out accounts already known by the tree to avoid double-insertion.\n    const newAccounts = accounts.filter(\n      (account) => !this.#accountIdToContext.has(account.id),\n    );\n\n    if (newAccounts.length === 0) {\n      return;\n    }\n\n    const createdGroups = new Map<AccountGroupId, AccountWalletId>();\n    const updatedGroups = new Map<AccountGroupId, AccountWalletId>();\n\n    this.update((state) => {\n      for (const account of newAccounts) {\n        const { walletId, groupId, created } = this.#insert(\n          state.accountTree.wallets,\n          account,\n        );\n\n        if (created) {\n          createdGroups.set(groupId, walletId);\n        } else if (!createdGroups.has(groupId)) {\n          // ^ We check that the group has not been created in this same batch before adding it to the `updatedGroups`\n          // map, to avoid sending both created and updated events for the same group:\n          // - Account 1 + Account 2 + Account 3\n          // - Account 1 and 3 belong to the same group\n          // - Account 1 will create the group\n          // - Account 3 will update the group (but we only want to send a created event, not an updated one)\n          updatedGroups.set(groupId, walletId);\n        }\n\n        const wallet = state.accountTree.wallets[walletId];\n        if (wallet) {\n          this.#applyAccountWalletMetadata(state, walletId);\n          this.#applyAccountGroupMetadata(state, walletId, groupId);\n        }\n      }\n    });\n\n    this.messenger.publish(\n      `${controllerName}:accountTreeChange`,\n      this.state.accountTree,\n    );\n\n    for (const [groupId, walletId] of createdGroups) {\n      this.#publishAccountGroupCreated(walletId, groupId);\n    }\n    for (const [groupId, walletId] of updatedGroups) {\n      this.#publishAccountGroupUpdated(walletId, groupId);\n    }\n  }\n\n  /**\n   * Handles \"AccountsController:accountsRemoved\" event to remove\n   * given accounts from the tree in a single state update.\n   *\n   * @param accountIds - Removed account IDs.\n   */\n  #handleAccountsRemoved(accountIds: AccountId[]): void {\n    // We wait for the first `init` to be called to actually build up the tree and\n    // mutate it. We expect the caller to first update the `AccountsController` state\n    // to force the migration of accounts, and then call `init`.\n    if (!this.#initialized) {\n      return;\n    }\n\n    const knownAccounts: { id: AccountId; context: AccountContext }[] = [];\n    for (const id of accountIds) {\n      const context = this.#accountIdToContext.get(id);\n      if (context) {\n        knownAccounts.push({ id, context });\n      }\n    }\n\n    if (knownAccounts.length === 0) {\n      return;\n    }\n\n    const previousSelectedAccountGroup = this.state.selectedAccountGroup;\n    const updatedGroups = new Map<AccountGroupId, AccountWalletId>();\n    const removedGroups = new Set<AccountGroupId>();\n\n    this.update((state) => {\n      for (const { id: accountId, context } of knownAccounts) {\n        const { walletId, groupId } = context;\n        const accounts =\n          state.accountTree.wallets[walletId]?.groups[groupId]?.accounts;\n\n        if (accounts) {\n          const index = accounts.indexOf(accountId);\n          if (index !== -1) {\n            accounts.splice(index, 1);\n\n            if (\n              state.selectedAccountGroup === groupId &&\n              accounts.length === 0\n            ) {\n              state.selectedAccountGroup = this.#getDefaultAccountGroupId(\n                state.accountTree.wallets,\n              );\n            }\n          }\n          if (accounts.length === 0) {\n            this.#pruneEmptyGroupAndWallet(state, walletId, groupId);\n\n            // If the group gets pruned, we should not consider it as updated.\n            updatedGroups.delete(groupId);\n            removedGroups.add(groupId);\n          } else {\n            updatedGroups.set(groupId, walletId);\n          }\n        }\n      }\n    });\n\n    // Clear reverse-mappings after the state update\n    for (const { id } of knownAccounts) {\n      this.#accountIdToContext.delete(id);\n    }\n\n    this.messenger.publish(\n      `${controllerName}:accountTreeChange`,\n      this.state.accountTree,\n    );\n\n    for (const [groupId, walletId] of updatedGroups) {\n      this.#publishAccountGroupUpdated(walletId, groupId);\n    }\n    for (const groupId of removedGroups) {\n      this.#publishAccountGroupRemoved(groupId);\n    }\n\n    const newSelectedAccountGroup = this.state.selectedAccountGroup;\n    if (newSelectedAccountGroup !== previousSelectedAccountGroup) {\n      this.messenger.publish(\n        `${controllerName}:selectedAccountGroupChange`,\n        newSelectedAccountGroup,\n        previousSelectedAccountGroup,\n      );\n    }\n  }\n\n  /**\n   * Helper method to prune a group if it holds no accounts and additionally\n   * prune the wallet if it holds no groups. This action should take place\n   * after a singular account removal.\n   *\n   * NOTE: This method should only be used for a group that we know to be empty.\n   *\n   * @param state - The AccountTreeController state to prune.\n   * @param walletId - The wallet ID to prune, the wallet should be the parent of the associated group that holds the removed account.\n   * @param groupId - The group ID to prune, the group should be the parent of the associated account that was removed.\n   * @returns The updated state.\n   */\n  #pruneEmptyGroupAndWallet(\n    state: AccountTreeControllerState,\n    walletId: AccountWalletId,\n    groupId: AccountGroupId,\n  ) {\n    const { wallets } = state.accountTree;\n\n    delete wallets[walletId].groups[groupId];\n    this.#groupIdToWalletId.delete(groupId);\n\n    // Clean up metadata for the pruned group\n    delete state.accountGroupsMetadata[groupId];\n\n    if (Object.keys(wallets[walletId].groups).length === 0) {\n      delete wallets[walletId];\n      // Clean up metadata for the pruned wallet\n      delete state.accountWalletsMetadata[walletId];\n    }\n    return state;\n  }\n\n  /**\n   * Publishes the `:accountGroupCreated` event for a newly added group.\n   * No-op if the group is not in state (defensive).\n   *\n   * @param walletId - The parent wallet ID.\n   * @param groupId - The newly created group's ID.\n   */\n  #publishAccountGroupCreated(\n    walletId: AccountWalletId,\n    groupId: AccountGroupId,\n  ): void {\n    const group = this.state.accountTree.wallets[walletId]?.groups[groupId];\n    if (group) {\n      this.messenger.publish(`${controllerName}:accountGroupCreated`, group);\n    }\n  }\n\n  /**\n   * Publishes the `:accountGroupUpdated` event for an existing group.\n   * No-op if the group is not in state (e.g. it was pruned).\n   *\n   * @param walletId - The parent wallet ID.\n   * @param groupId - The updated group's ID.\n   */\n  #publishAccountGroupUpdated(\n    walletId: AccountWalletId,\n    groupId: AccountGroupId,\n  ): void {\n    const group = this.state.accountTree.wallets[walletId]?.groups[groupId];\n    if (group) {\n      this.messenger.publish(`${controllerName}:accountGroupUpdated`, group);\n    }\n  }\n\n  /**\n   * Publishes the `:accountGroupRemoved` event for a pruned group.\n   *\n   * @param groupId - The removed group's ID.\n   */\n  #publishAccountGroupRemoved(groupId: AccountGroupId): void {\n    this.messenger.publish(`${controllerName}:accountGroupRemoved`, groupId);\n  }\n\n  /**\n   * Insert an account inside an account tree.\n   *\n   * We go over multiple rules to try to \"match\" the account following\n   * specific criterias. If a rule \"matches\" an account, then this\n   * account get added into its proper account wallet and account group.\n   *\n   * @param wallets - Account tree.\n   * @param account - The account to be inserted.\n   * @returns The wallet ID, group ID, and whether the group has been created or not.\n   */\n  #insert(\n    wallets: AccountTreeControllerState['accountTree']['wallets'],\n    account: InternalAccount,\n  ): { walletId: AccountWalletId; groupId: AccountGroupId; created: boolean } {\n    const result =\n      this.#getEntropyRule().match(account) ??\n      this.#getSnapRule().match(account) ??\n      this.#getKeyringRule().match(account); // This one cannot fail.\n\n    // Update controller's state.\n    const walletId = result.wallet.id;\n    let wallet = wallets[walletId];\n    if (!wallet) {\n      log(`[${walletId}] Added as new wallet`);\n      wallets[walletId] = {\n        ...result.wallet,\n        status: 'ready',\n        groups: {},\n        metadata: {\n          name: '', // Will get updated later.\n          ...result.wallet.metadata,\n        },\n        // We do need to type-cast since we're not narrowing `result` with\n        // the union tag `result.wallet.type`.\n      } as AccountWalletObject;\n      wallet = wallets[walletId];\n\n      // Trigger atomic sync for new wallet (only for entropy wallets)\n      if (wallet.type === AccountWalletType.Entropy) {\n        this.#backupAndSyncService.enqueueSingleWalletSync(walletId);\n      }\n    }\n\n    const groupId = result.group.id;\n    let group = wallet.groups[groupId];\n    const { type, id } = account;\n    const sortOrder = ACCOUNT_TYPE_TO_SORT_ORDER[type];\n    const created = !group;\n\n    if (!group) {\n      log(`[${walletId}] Add new group: [${groupId}]`);\n      wallet.groups[groupId] = {\n        ...result.group,\n        // Type-wise, we are guaranteed to always have at least 1 account.\n        accounts: [id],\n        metadata: {\n          name: '',\n          ...{ pinned: false, hidden: false, lastSelected: 0 }, // Default UI states\n          ...result.group.metadata, // Allow rules to override defaults\n        },\n        // We do need to type-cast since we're not narrowing `result` with\n        // the union tag `result.group.type`.\n      } as AccountGroupObject;\n      group = wallet.groups[groupId];\n\n      // Map group ID to its containing wallet ID for efficient direct access\n      this.#groupIdToWalletId.set(groupId, walletId);\n\n      // Trigger atomic sync for new group (only for entropy wallets)\n      if (wallet.type === AccountWalletType.Entropy) {\n        this.#backupAndSyncService.enqueueSingleGroupSync(groupId);\n      }\n    } else {\n      group.accounts.push(id);\n      // We need to do this at every insertion because race conditions can happen\n      // during the account creation process where one provider completes before the other.\n      // The discovery process in the service can also lead to some accounts being created \"out of order\".\n      const { accounts } = group;\n      accounts.sort(\n        /* istanbul ignore next: Comparator branch execution (a===id vs b===id)\n         * and return attribution vary across engines; final ordering is covered\n         * by behavior tests. Ignoring the entire comparator avoids flaky line\n         * coverage without reducing scenario coverage.\n         */\n        (a, b) => {\n          const aSortOrder =\n            a === id ? sortOrder : this.#accountIdToContext.get(a)?.sortOrder;\n          const bSortOrder =\n            b === id ? sortOrder : this.#accountIdToContext.get(b)?.sortOrder;\n          return (\n            (aSortOrder ?? MAX_SORT_ORDER) - (bSortOrder ?? MAX_SORT_ORDER)\n          );\n        },\n      );\n    }\n    log(\n      `[${groupId}] Add new account: { id: \"${account.id}\", type: \"${account.type}\", address: \"${account.address}\"`,\n    );\n\n    // Update the reverse mapping for this account.\n    this.#accountIdToContext.set(account.id, {\n      walletId: wallet.id,\n      groupId: group.id,\n      sortOrder,\n    });\n\n    return { walletId: wallet.id, groupId: group.id, created };\n  }\n\n  /**\n   * List all internal accounts.\n   *\n   * @returns The list of all internal accounts.\n   */\n  #listAccounts(): InternalAccount[] {\n    return this.messenger.call('AccountsController:listMultichainAccounts');\n  }\n\n  /**\n   * Asserts that a group exists in the current account tree.\n   *\n   * @param groupId - The account group ID to validate.\n   * @throws Error if the group does not exist.\n   */\n  #assertAccountGroupExists(groupId: AccountGroupId): void {\n    const exists = this.#groupIdToWalletId.has(groupId);\n    if (!exists) {\n      throw new Error('Account group not found in tree');\n    }\n  }\n\n  /**\n   * Asserts that a wallet exists in the current account tree.\n   *\n   * @param walletId - The account wallet ID to validate.\n   * @throws Error if the wallet does not exist.\n   */\n  #assertAccountWalletExists(walletId: AccountWalletId): void {\n    const exists = Boolean(this.state.accountTree.wallets[walletId]);\n    if (!exists) {\n      throw new Error('Account wallet not found in tree');\n    }\n  }\n\n  /**\n   * Asserts that an account group name is unique within the same wallet.\n   *\n   * @param groupId - The account group ID to exclude from the check.\n   * @param name - The name to validate for uniqueness.\n   * @throws Error if the name already exists in another group within the same wallet.\n   */\n  #assertAccountGroupNameIsUnique(groupId: AccountGroupId, name: string): void {\n    if (!isAccountGroupNameUnique(this.state, groupId, name)) {\n      throw new Error('Account group name already exists');\n    }\n  }\n\n  /**\n   * Gets the currently selected account group ID.\n   *\n   * @returns The selected account group ID or empty string if none selected.\n   */\n  getSelectedAccountGroup(): AccountGroupId | '' {\n    return this.state.selectedAccountGroup;\n  }\n\n  /**\n   * Sets the selected account group and updates the AccountsController selectedAccount accordingly.\n   *\n   * @param groupId - The account group ID to select.\n   * @param forwardSelectedAccount - Whether to forward the selected account to AccountsController. Defaults to true.\n   */\n  #setSelectedAccountGroup(\n    groupId: AccountGroupId,\n    forwardSelectedAccount: boolean = true,\n  ): void {\n    const previousSelectedAccountGroup = this.state.selectedAccountGroup;\n\n    // Idempotent check - if the same group is already selected, do nothing\n    if (previousSelectedAccountGroup === groupId) {\n      return;\n    }\n\n    // Find the first account in this group to select\n    const accountToSelect = this.#getDefaultAccountFromAccountGroupId(groupId);\n    if (!accountToSelect) {\n      throw new Error('No accounts found in group');\n    }\n\n    this.update((state) => {\n      // Update our selected account group first.\n      state.selectedAccountGroup = groupId;\n\n      // Then update its associated metadata (lastSelected timestamp) to keep\n      // track of the most recently selected groups.\n      const now = Date.now();\n\n      /* istanbul ignore next */\n      if (!state.accountGroupsMetadata[groupId]) {\n        state.accountGroupsMetadata[groupId] = {};\n      }\n      state.accountGroupsMetadata[groupId].lastSelected = now;\n\n      const walletId = this.#groupIdToWalletId.get(groupId);\n      if (walletId) {\n        state.accountTree.wallets[walletId].groups[\n          groupId\n        ].metadata.lastSelected = now;\n      }\n    });\n\n    log(`Selected group is now: [${this.state.selectedAccountGroup}]`);\n\n    this.messenger.publish(\n      `${controllerName}:selectedAccountGroupChange`,\n      groupId,\n      previousSelectedAccountGroup,\n    );\n\n    if (forwardSelectedAccount) {\n      // Update AccountsController - this will trigger selectedAccountChange event,\n      // but our handler is idempotent so it won't cause infinite loop\n      this.messenger.call(\n        'AccountsController:setSelectedAccount',\n        accountToSelect,\n      );\n\n      log(`Selected account is now: ${accountToSelect}`);\n    }\n  }\n\n  /**\n   * Sets the selected account group and updates the AccountsController selectedAccount accordingly.\n   *\n   * @param groupId - The account group ID to select.\n   */\n  setSelectedAccountGroup(groupId: AccountGroupId): void {\n    this.#setSelectedAccountGroup(groupId);\n  }\n\n  /**\n   * Initializes the selectedAccountGroup based on the currently selected account from AccountsController.\n   *\n   * @param wallets - Wallets object to use for fallback logic\n   * @returns The default selected account group ID or empty string if none selected.\n   */\n  #getDefaultSelectedAccountGroup(wallets: {\n    [walletId: AccountWalletId]: AccountWalletObject;\n  }): AccountGroupId | '' {\n    const selectedAccount = this.messenger.call(\n      'AccountsController:getSelectedMultichainAccount',\n    );\n    if (selectedAccount?.id) {\n      const accountMapping = this.#accountIdToContext.get(selectedAccount.id);\n      if (accountMapping) {\n        const { groupId } = accountMapping;\n\n        return groupId;\n      }\n    }\n\n    // Default to the default group in case of errors.\n    return this.#getDefaultAccountGroupId(wallets);\n  }\n\n  /**\n   * Handles selected account change from AccountsController.\n   * Updates selectedAccountGroup to match the selected account.\n   *\n   * @param account - The newly selected account.\n   */\n  #handleSelectedAccountChange(account: InternalAccount): void {\n    const accountMapping = this.#accountIdToContext.get(account.id);\n    if (!accountMapping) {\n      // Account not in tree yet, might be during initialization\n      return;\n    }\n\n    const { groupId } = accountMapping;\n\n    // Avoid infinite loop since this method is triggered by selected account change.\n    const forwardSelectedAccount = false;\n    this.#setSelectedAccountGroup(groupId, forwardSelectedAccount);\n  }\n\n  /**\n   * Handles multichain account wallet status change from\n   * the MultichainAccountService.\n   *\n   * @param walletId - Multichain account wallet ID.\n   * @param walletStatus - New multichain account wallet status.\n   */\n  #handleMultichainAccountWalletStatusChange(\n    walletId: MultichainAccountWalletId,\n    walletStatus: MultichainAccountWalletStatus,\n  ): void {\n    this.update((state) => {\n      const wallet = state.accountTree.wallets[walletId];\n\n      if (wallet) {\n        wallet.status = walletStatus;\n      }\n    });\n  }\n\n  /**\n   * Gets account group object.\n   *\n   * @param groupId - The account group ID.\n   * @returns The account group or undefined if not found.\n   */\n  #getAccountGroup(groupId: AccountGroupId): AccountGroupObject | undefined {\n    const found = Object.values(this.state.accountTree.wallets).find(\n      (wallet) => wallet.groups[groupId] !== undefined,\n    );\n\n    return found?.groups[groupId];\n  }\n\n  /**\n   * Gets the default account for specified group.\n   *\n   * @param groupId - The account group ID.\n   * @returns The first account ID in the group, or undefined if no accounts found.\n   */\n  #getDefaultAccountFromAccountGroupId(\n    groupId: AccountGroupId,\n  ): AccountId | undefined {\n    const group = this.#getAccountGroup(groupId);\n\n    if (group) {\n      let candidate;\n      for (const id of group.accounts) {\n        const account = this.messenger.call(\n          'AccountsController:getAccount',\n          id,\n        );\n\n        if (!candidate) {\n          candidate = id;\n        }\n        if (account && isEvmAccountType(account.type)) {\n          // EVM accounts have a higher priority, so if we find any, we just\n          // use that account!\n          return account.id;\n        }\n      }\n\n      return candidate;\n    }\n\n    return undefined;\n  }\n\n  /**\n   * Gets the default group id by selecting the most recently selected non-empty group.\n   * Groups that have never been explicitly selected (lastSelected === 0) are still\n   * considered as fallbacks. When timestamps are equal, groups containing EVM accounts\n   * are preferred as a tiebreaker.\n   *\n   * @param wallets - The wallets object to search.\n   * @returns The ID of the most recently selected non-empty group, or an empty string if none found.\n   */\n  #getDefaultAccountGroupId(wallets: {\n    [walletId: AccountWalletId]: AccountWalletObject;\n  }): AccountGroupId | '' {\n    let candidate: AccountGroupObject | undefined;\n\n    for (const wallet of Object.values(wallets)) {\n      for (const group of Object.values(wallet.groups)) {\n        if (group.accounts.length === 0) {\n          continue;\n        }\n        if (!candidate) {\n          candidate = group;\n          continue;\n        }\n        if (group.metadata.lastSelected > candidate.metadata.lastSelected) {\n          candidate = group;\n        } else if (\n          group.metadata.lastSelected === candidate.metadata.lastSelected &&\n          this.#hasEvmAccount(group) &&\n          !this.#hasEvmAccount(candidate)\n        ) {\n          candidate = group;\n        }\n      }\n    }\n    return candidate?.id ?? '';\n  }\n\n  /**\n   * Checks if a group contains at least one EVM account.\n   *\n   * @param group - The account group to check.\n   * @returns True if the group contains an EVM account, false otherwise.\n   */\n  #hasEvmAccount(group: AccountGroupObject): boolean {\n    for (const id of group.accounts) {\n      const account = this.messenger.call('AccountsController:getAccount', id);\n      if (account && isEvmAccountType(account.type)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Resolves name conflicts by adding a suffix to make the name unique.\n   *\n   * @internal\n   * @param wallet - The wallet to check within.\n   * @param groupId - The account group ID to exclude from the check.\n   * @param name - The desired name that has a conflict.\n   * @returns A unique name with suffix added if necessary.\n   */\n  #resolveNameConflict(\n    wallet: AccountWalletObject,\n    groupId: AccountGroupId,\n    name: string,\n  ): string {\n    let suffix = 2;\n    let candidateName = `${name} (${suffix})`;\n\n    // Keep incrementing suffix until we find a unique name\n    while (\n      !isAccountGroupNameUniqueFromWallet(wallet, groupId, candidateName)\n    ) {\n      suffix += 1;\n      candidateName = `${name} (${suffix})`;\n    }\n\n    return candidateName;\n  }\n\n  /**\n   * Sets a custom name for an account group.\n   *\n   * @param groupId - The account group ID.\n   * @param name - The custom name to set.\n   * @param autoHandleConflict - If true, automatically resolves name conflicts by adding a suffix. If false, throws on conflicts.\n   * @throws If the account group ID is not found in the current tree.\n   * @throws If the account group name already exists and autoHandleConflict is false.\n   */\n  setAccountGroupName(\n    groupId: AccountGroupId,\n    name: string,\n    autoHandleConflict: boolean = false,\n  ): void {\n    // Validate that the group exists in the current tree\n    this.#assertAccountGroupExists(groupId);\n\n    const walletId = this.#groupIdToWalletId.get(groupId);\n    assert(walletId, 'Account group not found in tree');\n\n    const wallet = this.state.accountTree.wallets[walletId];\n    let finalName = name;\n\n    // Handle name conflicts based on the autoHandleConflict flag\n    if (\n      autoHandleConflict &&\n      !isAccountGroupNameUniqueFromWallet(wallet, groupId, name)\n    ) {\n      finalName = this.#resolveNameConflict(wallet, groupId, name);\n    } else {\n      // Validate that the name is unique\n      this.#assertAccountGroupNameIsUnique(groupId, finalName);\n    }\n\n    log(\n      `[${groupId}] Set new name to: \"${finalName}\" (auto handle conflict: ${autoHandleConflict})`,\n    );\n\n    this.update((state) => {\n      /* istanbul ignore next */\n      if (!state.accountGroupsMetadata[groupId]) {\n        state.accountGroupsMetadata[groupId] = {};\n      }\n\n      // Update persistent metadata\n      state.accountGroupsMetadata[groupId].name = {\n        value: finalName,\n        lastUpdatedAt: Date.now(),\n      };\n\n      // Update tree node directly using efficient mapping\n      state.accountTree.wallets[walletId].groups[groupId].metadata.name =\n        finalName;\n    });\n\n    this.#publishAccountGroupUpdated(walletId, groupId);\n\n    // Trigger atomic sync for group rename (only for groups from entropy wallets)\n    if (wallet.type === AccountWalletType.Entropy) {\n      this.#backupAndSyncService.enqueueSingleGroupSync(groupId);\n    }\n  }\n\n  /**\n   * Sets a custom name for an account wallet.\n   *\n   * @param walletId - The account wallet ID.\n   * @param name - The custom name to set.\n   * @throws If the account wallet ID is not found in the current tree.\n   */\n  setAccountWalletName(walletId: AccountWalletId, name: string): void {\n    // Validate that the wallet exists in the current tree\n    this.#assertAccountWalletExists(walletId);\n\n    this.update((state) => {\n      // Update persistent metadata\n      state.accountWalletsMetadata[walletId] ??= {};\n      state.accountWalletsMetadata[walletId].name = {\n        value: name,\n        lastUpdatedAt: Date.now(),\n      };\n\n      // Update tree node directly\n      state.accountTree.wallets[walletId].metadata.name = name;\n    });\n\n    // Trigger atomic sync for wallet rename (only for groups from entropy wallets)\n    if (\n      this.state.accountTree.wallets[walletId].type ===\n      AccountWalletType.Entropy\n    ) {\n      this.#backupAndSyncService.enqueueSingleWalletSync(walletId);\n    }\n  }\n\n  /**\n   * Toggles the pinned state of an account group.\n   *\n   * @param groupId - The account group ID.\n   * @param pinned - Whether the group should be pinned.\n   * @throws If the account group ID is not found in the current tree.\n   */\n  setAccountGroupPinned(groupId: AccountGroupId, pinned: boolean): void {\n    // Validate that the group exists in the current tree\n    this.#assertAccountGroupExists(groupId);\n\n    const walletId = this.#groupIdToWalletId.get(groupId);\n\n    this.update((state) => {\n      /* istanbul ignore next */\n      if (!state.accountGroupsMetadata[groupId]) {\n        state.accountGroupsMetadata[groupId] = {};\n      }\n\n      // Update persistent metadata\n      state.accountGroupsMetadata[groupId].pinned = {\n        value: pinned,\n        lastUpdatedAt: Date.now(),\n      };\n\n      // Update tree node directly using efficient mapping\n      if (walletId) {\n        state.accountTree.wallets[walletId].groups[groupId].metadata.pinned =\n          pinned;\n      }\n    });\n\n    if (walletId) {\n      this.#publishAccountGroupUpdated(walletId, groupId);\n    }\n\n    // Trigger atomic sync for group pinning (only for groups from entropy wallets)\n    if (\n      walletId &&\n      this.state.accountTree.wallets[walletId].type ===\n        AccountWalletType.Entropy\n    ) {\n      this.#backupAndSyncService.enqueueSingleGroupSync(groupId);\n    }\n  }\n\n  /**\n   * Toggles the hidden state of an account group.\n   *\n   * @param groupId - The account group ID.\n   * @param hidden - Whether the group should be hidden.\n   * @throws If the account group ID is not found in the current tree.\n   */\n  setAccountGroupHidden(groupId: AccountGroupId, hidden: boolean): void {\n    // Validate that the group exists in the current tree\n    this.#assertAccountGroupExists(groupId);\n\n    const walletId = this.#groupIdToWalletId.get(groupId);\n\n    this.update((state) => {\n      /* istanbul ignore next */\n      if (!state.accountGroupsMetadata[groupId]) {\n        state.accountGroupsMetadata[groupId] = {};\n      }\n\n      // Update persistent metadata\n      state.accountGroupsMetadata[groupId].hidden = {\n        value: hidden,\n        lastUpdatedAt: Date.now(),\n      };\n\n      // Update tree node directly using efficient mapping\n      if (walletId) {\n        state.accountTree.wallets[walletId].groups[groupId].metadata.hidden =\n          hidden;\n      }\n    });\n\n    if (walletId) {\n      this.#publishAccountGroupUpdated(walletId, groupId);\n    }\n\n    // Trigger atomic sync for group hiding (only for groups from entropy wallets)\n    if (\n      walletId &&\n      this.state.accountTree.wallets[walletId].type ===\n        AccountWalletType.Entropy\n    ) {\n      this.#backupAndSyncService.enqueueSingleGroupSync(groupId);\n    }\n  }\n\n  /**\n   * Clears the controller state and resets to default values.\n   * Also clears the backup and sync service state.\n   */\n  clearState(): void {\n    log('Clearing state');\n\n    this.update(() => {\n      return {\n        ...getDefaultAccountTreeControllerState(),\n      };\n    });\n    this.#backupAndSyncService.clearState();\n\n    // So we know we have to call `init` again.\n    this.#initialized = false;\n  }\n\n  /**\n   * Bi-directionally syncs the account tree with user storage.\n   * This will perform a full sync, including both pulling updates\n   * from user storage and pushing local changes to user storage.\n   * This also performs legacy account syncing if needed.\n   *\n   * IMPORTANT:\n   * If a full sync is already in progress, it will return the ongoing promise.\n   *\n   * @returns A promise that resolves when the sync is complete.\n   */\n  async syncWithUserStorage(): Promise<void> {\n    return this.#backupAndSyncService.performFullSync();\n  }\n\n  /**\n   * Bi-directionally syncs the account tree with user storage.\n   * This will ensure at least one full sync is ran, including both pulling updates\n   * from user storage and pushing local changes to user storage.\n   * This also performs legacy account syncing if needed.\n   *\n   * IMPORTANT:\n   * If the first ever full sync is already in progress, it will return the ongoing promise.\n   * If the first ever full sync was previously completed, it will NOT start a new sync, and will resolve immediately.\n   *\n   * @returns A promise that resolves when the first ever full sync is complete.\n   */\n  async syncWithUserStorageAtLeastOnce(): Promise<void> {\n    return this.#backupAndSyncService.performFullSyncAtLeastOnce();\n  }\n\n  /**\n   * Creates an backup and sync context for sync operations.\n   * Used by the backup and sync service.\n   *\n   * @returns The backup and sync context.\n   */\n  #createBackupAndSyncContext(): BackupAndSyncContext {\n    return {\n      ...this.#backupAndSyncConfig,\n      controller: this,\n      messenger: this.messenger,\n      controllerStateUpdateFn: this.update.bind(this),\n      traceFn: this.#trace.bind(this),\n      groupIdToWalletId: this.#groupIdToWalletId,\n    };\n  }\n}\n"]}