{"version":3,"file":"EvmAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmD;AASnD,uDAK+B;AAE/B,qEAA4D;AAI5D,2CAA+E;AAG/E,sDAA6C;AAC7C,oDAAgD;AAChD,0CAAiE;AAEjE,6EAIoC;AACpC,uCAAiD;AAEjD,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC;;;;;GAKG;AACH,SAAS,2BAA2B,CAClC,OAAoC;IAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAWY,QAAA,yBAAyB,GAAG,KAAK,CAAC;AAElC,QAAA,mCAAmC,GAAG;IACjD,SAAS,EAAE;QACT,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACf;CACF,CAAC;AAEF,MAAa,kBAAmB,SAAQ,mDAAwB;IAe9D,YACE,SAA4C,EAC5C,SAAmC,2CAAmC,EACtE,KAAqB;QAErB,KAAK,CAAC,SAAS,CAAC,CAAC;;QAjBV,6CAAkC;QAElC,4CAAsB;QAEtB,iBAAY,GAAwB;YAC3C,MAAM,EAAE,CAAC,sBAAQ,CAAC,GAAG,CAAC;YACtB,KAAK,EAAE;gBACL,WAAW,EAAE,IAAI;gBACjB,gBAAgB,EAAE,IAAI;aACvB;SACF,CAAC;QAQA,uBAAA,IAAI,8BAAW;YACb,GAAG,MAAM;YACT,SAAS,EAAE;gBACT,GAAG,MAAM,CAAC,SAAS;gBACnB,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,IAAI,IAAI;aAC1C;SACF,MAAA,CAAC;QACF,uBAAA,IAAI,6BAAU,KAAK,IAAI,yBAAa,MAAA,CAAC;IACvC,CAAC;IAED,mBAAmB,CAAC,OAAsC;QACxD,OAAO,CACL,OAAO,CAAC,IAAI,KAAK,4BAAc,CAAC,GAAG;YACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAM,iCAAY,CAAC,EAAa,CAC9D,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,kBAAkB,CAAC,IAAI,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CACzC,gDAAgD,EAChD,oBAAoB,CACrB,CAAC;QACF,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CACtC,wCAAwC,EACxC,eAAe,CAChB,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IA2CD;;;;;OAKG;IACH,KAAK,CAAC,cAAc,CAClB,OAA6B;QAE7B,IAAA,kDAAoC,EAAC,OAAO,EAAE;YAC5C,GAAG,iCAAmB,CAAC,gBAAgB,EAAE;YACzC,GAAG,iCAAmB,CAAC,qBAAqB,EAAE;SAC/C,CAAC,CAAC;QAEH,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;QAElC,IAAI,OAAO,CAAC,IAAI,KAAK,iCAAmB,CAAC,qBAAqB,EAAE,CAAC;YAC/D,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;YAE1B,sDAAsD;YACtD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CACzC,EAAE,EAAE,EAAE,aAAa,EAAE,EACrB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACpB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;gBAE7C,+EAA+E;gBAC/E,IAAI,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACjC,MAAM,IAAI,KAAK,CACb,sEAAsE,KAAK,CAAC,IAAI,aAAa,QAAQ,CAAC,MAAM,0BAA0B,CACvI,CAAC;gBACJ,CAAC;gBAED,MAAM,MAAM,GAAgB,EAAE,CAAC;gBAE/B,8CAA8C;gBAC9C,KACE,IAAI,UAAU,GAAG,KAAK,CAAC,IAAI,EAC3B,UAAU,IAAI,KAAK,CAAC,EAAE,EACtB,UAAU,EAAE,EACZ,CAAC;oBACD,IAAI,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;wBACjC,0BAA0B;wBAC1B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;oBACvC,CAAC;gBACH,CAAC;gBAED,iEAAiE;gBACjE,qDAAqD;gBACrD,KACE,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EACtD,UAAU,IAAI,KAAK,CAAC,EAAE,EACtB,UAAU,EAAE,EACZ,CAAC;oBACD,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC;wBAC7C,IAAI,EAAE,iCAAmB,CAAC,gBAAgB;wBAC1C,aAAa;wBACb,UAAU;qBACX,CAAC,CAAC;oBACH,IAAA,cAAM,EAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;oBAC3C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC1B,CAAC;gBAED,OAAO,MAAM,CAAC;YAChB,CAAC,CACF,CAAC;YAEF,MAAM,QAAQ,GAAsB,EAAE,CAAC;YACvC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CACvC,gCAAgC,EAChC,UAAU,CACX,EAAE,CAAC;gBACF,2BAA2B,CAAC,OAAO,CAAC,CAAC;gBACrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC9B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;YAED,IAAA,iDAAsB,EAAC,QAAQ,CAAC,CAAC;YACjC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,qDAAqD;QACrD,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;QAE/B,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,uBAAA,IAAI,wEAAe,MAAnB,IAAI,EAAgB;YAC1C,aAAa;YACb,UAAU;YACV,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,IAAA,cAAM,EAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;QAE3C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CACjC,+BAA+B,EAC/B,OAAO,CAAC,EAAE,CACX,CAAC;QAEF,gDAAgD;QAChD,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,IAAA,iDAAsB,EAAC,aAAa,CAAC,CAAC;QAEtC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9B,OAAO,aAAa,CAAC;IACvB,CAAC;IAwFD;;;;;;;OAOG;IACH,KAAK,CAAC,gBAAgB,CAAC,IAGtB;QACC,OAAO,uBAAA,IAAI,iCAAO,MAAX,IAAI,EACT;YACE,IAAI,EAAE,kBAAS,CAAC,mBAAmB;YACnC,IAAI,EAAE;gBACJ,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;aACzB;SACF,EACD,KAAK,IAAI,EAAE;YACT,IAAI,CAAC,uBAAA,IAAI,kCAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBACpC,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YACvC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;YAE3C,MAAM,qBAAqB,GAAG,MAAM,uBAAA,IAAI,mFAA0B,MAA9B,IAAI,EAA2B;gBACjE,aAAa;gBACb,UAAU;aACX,CAAC,CAAC;YAEH,MAAM,KAAK,GAAG,MAAM,uBAAA,IAAI,8EAAqB,MAAzB,IAAI,EACtB,QAAQ,EACR,qBAAqB,CACtB,CAAC;YACF,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,uEAAuE;YACvE,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,uBAAA,IAAI,wEAAe,MAAnB,IAAI,EAAgB;gBAC1C,aAAa;gBACb,UAAU;gBACV,UAAU,EAAE,KAAK;aAClB,CAAC,CAAC;YAEH,IAAA,cAAM,EAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;YAC3C,IAAA,cAAM,EACJ,qBAAqB,KAAK,OAAO,CAAC,OAAO,EACzC,0DAA0D,CAC3D,CAAC;YAEF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CACjC,+BAA+B,EAC/B,OAAO,CAAC,EAAE,CACX,CAAC;YACF,2BAA2B,CAAC,OAAO,CAAC,CAAC;YACrC,IAAA,+CAAoB,EAAC,OAAO,CAAC,CAAC;YAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC9B,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB,CAAC,CACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,4EAA4E;QAC5E,qBAAqB;IACvB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,aAAa,CAAC,EAAsC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAEjD,MAAM,IAAI,CAAC,aAAa,CACtB,EAAE,EAAE,EAAE,aAAa,EAAE,EACrB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YACpB,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;;AAjYH,gDAkYC;;AAvUC;;;;;;;;;GASG;AACH,KAAK,4CAAgB,EACnB,aAAa,EACb,UAAU,EACV,UAAU,GAKX;IACC,OAAO,MAAM,IAAI,CAAC,aAAa,CAC7B,EAAE,EAAE,EAAE,aAAa,EAAE,EACrB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAChC,CAAC;QAED,0EAA0E;QAC1E,IAAI,UAAU,IAAI,UAAU,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,MAAM,OAAO,CAAC,cAAc,CAAC;YAClC,IAAI,EAAE,iCAAmB,CAAC,gBAAgB;YAC1C,aAAa;YACb,UAAU;SACX,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC;AA4GD;;;;;;;;;;;;GAYG;AACH,KAAK,uDAA2B,EAC9B,aAAa,EACb,UAAU,GAIX;IACC,4FAA4F;IAC5F,mCAAmC;IACnC,OAAO,MAAM,IAAI,CAAC,aAAa,CAC7B,EAAE,EAAE,EAAE,aAAa,EAAE,EACrB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,+EAA+E;QAC/E,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YACjC,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAc,CAAC;QAC7C,CAAC;QAED,8EAA8E;QAC9E,IAAA,cAAM,EAAC,OAAO,CAAC,IAAI,EAAE,oCAAoC,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACnD,IAAA,cAAM,EAAC,KAAK,CAAC,SAAS,EAAE,+BAA+B,CAAC,CAAC;QAEzD,OAAO,IAAA,aAAK,EACV,IAAA,kBAAU,EAAC,IAAA,sBAAe,EAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CACjE,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,kDACH,QAAkB,EAClB,OAAe;IAEf,MAAM,MAAM,GAAG,yBAAyB,CAAC;IAEzC,MAAM,QAAQ,GAAG,MAAM,IAAA,iBAAS,EAC9B,GAAG,EAAE,CACH,IAAA,mBAAW,EACT,GAAG,EAAE,CACH,QAAQ,CAAC,OAAO,CAAC;QACf,MAAM;QACN,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;KAC5B,CAAC,EACJ,uBAAA,IAAI,kCAAQ,CAAC,SAAS,CAAC,SAAS,CACjC,EACH;QACE,WAAW,EAAE,uBAAA,IAAI,kCAAQ,CAAC,SAAS,CAAC,WAAW;QAC/C,SAAS,EAAE,uBAAA,IAAI,kCAAQ,CAAC,SAAS,CAAC,SAAS;KAC5C,CACF,CAAC;IAEF,gHAAgH;IAChH,IAAI,CAAC,IAAA,yBAAiB,EAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,uCAAuC,MAAM,cAAc,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAEtG,IAAA,sBAAG,EAAC,GAAG,uBAAc,IAAI,OAAO,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEtB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAjSM,uBAAI,GAAG,iCAAyB,AAA5B,CAA6B","sourcesContent":["import { publicToAddress } from '@ethereumjs/util';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { HdKeyring } from '@metamask/eth-hd-keyring/v2';\nimport type {\n  CreateAccountOptions,\n  EntropySourceId,\n  KeyringAccount,\n} from '@metamask/keyring-api';\nimport {\n  AccountCreationType,\n  assertCreateAccountOptionIsSupported,\n  EthAccountType,\n  EthScope,\n} from '@metamask/keyring-api';\nimport type { KeyringCapabilities, Keyring } from '@metamask/keyring-api/v2';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { AccountId } from '@metamask/keyring-utils';\nimport type { Provider } from '@metamask/network-controller';\nimport { add0x, assert, bytesToHex, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { traceFallback } from '../analytics';\nimport { TraceName } from '../analytics/traces';\nimport { projectLogger as log, WARNING_PREFIX } from '../logger';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport {\n  assertAreBip44Accounts,\n  assertIsBip44Account,\n  BaseBip44AccountProvider,\n} from './BaseBip44AccountProvider';\nimport { withRetry, withTimeout } from './utils';\n\nconst ETH_MAINNET_CHAIN_ID = '0x1';\n\n/**\n * Asserts an internal account exists.\n *\n * @param account - The internal account to check.\n * @throws An error if the internal account does not exist.\n */\nfunction assertInternalAccountExists(\n  account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n  if (!account) {\n    throw new Error('Internal account does not exist');\n  }\n}\n\nexport type EvmAccountProviderConfig = {\n  discovery: {\n    enabled?: boolean;\n    maxAttempts: number;\n    timeoutMs: number;\n    backOffMs: number;\n  };\n};\n\nexport const EVM_ACCOUNT_PROVIDER_NAME = 'EVM';\n\nexport const EVM_ACCOUNT_PROVIDER_DEFAULT_CONFIG = {\n  discovery: {\n    maxAttempts: 3,\n    timeoutMs: 500,\n    backOffMs: 500,\n  },\n};\n\nexport class EvmAccountProvider extends BaseBip44AccountProvider {\n  static NAME = EVM_ACCOUNT_PROVIDER_NAME;\n\n  readonly #config: EvmAccountProviderConfig;\n\n  readonly #trace: TraceCallback;\n\n  readonly capabilities: KeyringCapabilities = {\n    scopes: [EthScope.Eoa],\n    bip44: {\n      deriveIndex: true,\n      deriveIndexRange: true,\n    },\n  };\n\n  constructor(\n    messenger: MultichainAccountServiceMessenger,\n    config: EvmAccountProviderConfig = EVM_ACCOUNT_PROVIDER_DEFAULT_CONFIG,\n    trace?: TraceCallback,\n  ) {\n    super(messenger);\n    this.#config = {\n      ...config,\n      discovery: {\n        ...config.discovery,\n        enabled: config.discovery.enabled ?? true,\n      },\n    };\n    this.#trace = trace ?? traceFallback;\n  }\n\n  isAccountCompatible(account: Bip44Account<InternalAccount>): boolean {\n    return (\n      account.type === EthAccountType.Eoa &&\n      account.metadata.keyring.type === (KeyringTypes.hd as string)\n    );\n  }\n\n  getName(): string {\n    return EvmAccountProvider.NAME;\n  }\n\n  /**\n   * Get the EVM provider.\n   *\n   * @returns The EVM provider.\n   */\n  getEvmProvider(): Provider {\n    const networkClientId = this.messenger.call(\n      'NetworkController:findNetworkClientIdByChainId',\n      ETH_MAINNET_CHAIN_ID,\n    );\n    const { provider } = this.messenger.call(\n      'NetworkController:getNetworkClientById',\n      networkClientId,\n    );\n    return provider;\n  }\n\n  /**\n   * Create an EVM account.\n   *\n   * @param opts - The options for the creation of the account.\n   * @param opts.entropySource - The entropy source to use for the creation of the account.\n   * @param opts.groupIndex - The index of the group to create the account for.\n   * @param opts.throwOnGap - Whether to throw an error if the account index is not contiguous.\n   * @returns The created or existing keyring account(s) at the requested group\n   * index. Returns an empty array if the keyring did not create an account.\n   */\n  async #createAccount({\n    entropySource,\n    groupIndex,\n    throwOnGap,\n  }: {\n    entropySource: EntropySourceId;\n    groupIndex: number;\n    throwOnGap: boolean;\n  }): Promise<KeyringAccount[]> {\n    return await this.withKeyringV2<Keyring, KeyringAccount[]>(\n      { id: entropySource },\n      async ({ keyring }) => {\n        const existing = await keyring.getAccounts();\n        if (groupIndex < existing.length) {\n          return [existing[groupIndex]];\n        }\n\n        // If the throwOnGap flag is set, we throw an error to prevent index gaps.\n        if (throwOnGap && groupIndex !== existing.length) {\n          throw new Error('Trying to create too many accounts');\n        }\n\n        return await keyring.createAccounts({\n          type: AccountCreationType.Bip44DeriveIndex,\n          entropySource,\n          groupIndex,\n        });\n      },\n    );\n  }\n\n  /**\n   * Create accounts for the EVM provider.\n   *\n   * @param options - The options for the creation of the accounts.\n   * @returns The accounts for the EVM provider.\n   */\n  async createAccounts(\n    options: CreateAccountOptions,\n  ): Promise<Bip44Account<KeyringAccount>[]> {\n    assertCreateAccountOptionIsSupported(options, [\n      `${AccountCreationType.Bip44DeriveIndex}`,\n      `${AccountCreationType.Bip44DeriveIndexRange}`,\n    ]);\n\n    const { entropySource } = options;\n\n    if (options.type === AccountCreationType.Bip44DeriveIndexRange) {\n      const { range } = options;\n\n      // Use a single withKeyring call for the entire range.\n      const accountIds = await this.withKeyringV2<Keyring, AccountId[]>(\n        { id: entropySource },\n        async ({ keyring }) => {\n          const existing = await keyring.getAccounts();\n\n          // Validate no gaps: we can only create accounts starting from existing.length.\n          if (range.from > existing.length) {\n            throw new Error(\n              `Bad account creation request, group index range would create gaps (${range.from} (from) > ${existing.length} (next available index))`,\n            );\n          }\n\n          const result: AccountId[] = [];\n\n          // Collect existing accounts within the range.\n          for (\n            let groupIndex = range.from;\n            groupIndex <= range.to;\n            groupIndex++\n          ) {\n            if (groupIndex < existing.length) {\n              // Account already exists.\n              result.push(existing[groupIndex].id);\n            }\n          }\n\n          // Create new accounts one-by-one since HdKeyringV2 only supports\n          // bip44:derive-index (not bip44:derive-index-range).\n          for (\n            let groupIndex = Math.max(range.from, existing.length);\n            groupIndex <= range.to;\n            groupIndex++\n          ) {\n            const [created] = await keyring.createAccounts({\n              type: AccountCreationType.Bip44DeriveIndex,\n              entropySource,\n              groupIndex,\n            });\n            assert(created, 'Account creation failed');\n            result.push(created.id);\n          }\n\n          return result;\n        },\n      );\n\n      const accounts: InternalAccount[] = [];\n      for (const account of this.messenger.call(\n        'AccountsController:getAccounts',\n        accountIds,\n      )) {\n        assertInternalAccountExists(account);\n        this.accounts.add(account.id);\n        accounts.push(account);\n      }\n\n      assertAreBip44Accounts(accounts);\n      return accounts;\n    }\n\n    // Handle Bip44DeriveIndex (single account creation).\n    const { groupIndex } = options;\n\n    const [created] = await this.#createAccount({\n      entropySource,\n      groupIndex,\n      throwOnGap: true,\n    });\n\n    assert(created, 'Account creation failed');\n\n    const account = this.messenger.call(\n      'AccountsController:getAccount',\n      created.id,\n    );\n\n    // We MUST have the associated internal account.\n    assertInternalAccountExists(account);\n\n    const accountsArray = [account];\n    assertAreBip44Accounts(accountsArray);\n\n    this.accounts.add(account.id);\n    return accountsArray;\n  }\n\n  /**\n   * Get the address that would be derived for a given group index without\n   * persisting an account in the keyring.\n   *\n   * Peeks at the next address via the HD `root` so discovery can short-circuit\n   * (and skip the vault write + `stateChange` event) when there is no on-chain\n   * activity at this index.\n   *\n   * @param opts - The options for the address derivation.\n   * @param opts.entropySource - The entropy source to derive from.\n   * @param opts.groupIndex - The group index to derive at.\n   * @returns The derived address for the given group index.\n   */\n  async #getAddressFromGroupIndex({\n    entropySource,\n    groupIndex,\n  }: {\n    entropySource: EntropySourceId;\n    groupIndex: number;\n  }): Promise<Hex> {\n    // NOTE: To avoid exposing this function at keyring level, we just re-use its internal state\n    // and compute the derivation here.\n    return await this.withKeyringV2<HdKeyring, Hex>(\n      { id: entropySource },\n      async ({ keyring }) => {\n        // If the account already exist, do not re-derive and just re-use that account.\n        const existing = await keyring.getAccounts();\n        if (groupIndex < existing.length) {\n          return existing[groupIndex].address as Hex;\n        }\n\n        // If not, then we just \"peek\" the next address to avoid creating the account.\n        assert(keyring.root, 'Expected HD keyring.root to be set');\n        const hdKey = keyring.root.deriveChild(groupIndex);\n        assert(hdKey.publicKey, 'Expected public key to be set');\n\n        return add0x(\n          bytesToHex(publicToAddress(hdKey.publicKey, true)).toLowerCase(),\n        );\n      },\n    );\n  }\n\n  /**\n   * Get the transaction count for an EVM account.\n   * This method uses a retry and timeout mechanism to handle transient failures.\n   *\n   * @param provider - The provider to use for the transaction count.\n   * @param address - The address of the account.\n   * @returns The transaction count.\n   */\n  async #getTransactionCount(\n    provider: Provider,\n    address: string,\n  ): Promise<number> {\n    const method = 'eth_getTransactionCount';\n\n    const response = await withRetry(\n      () =>\n        withTimeout(\n          () =>\n            provider.request({\n              method,\n              params: [address, 'latest'],\n            }),\n          this.#config.discovery.timeoutMs,\n        ),\n      {\n        maxAttempts: this.#config.discovery.maxAttempts,\n        backOffMs: this.#config.discovery.backOffMs,\n      },\n    );\n\n    // Make sure we got the right response format, if not, we fallback to \"0x0\", to avoid having to deal with `NaN`.\n    if (!isStrictHexString(response)) {\n      const message = `Received invalid hex response from \"${method}\" request: ${JSON.stringify(response)}`;\n\n      log(`${WARNING_PREFIX} ${message}`);\n      console.warn(message);\n\n      return 0;\n    }\n\n    return parseInt(response, 16);\n  }\n\n  /**\n   * Discover and create accounts for the EVM provider.\n   *\n   * @param opts - The options for the discovery and creation of accounts.\n   * @param opts.entropySource - The entropy source to use for the discovery and creation of accounts.\n   * @param opts.groupIndex - The index of the group to create the accounts for.\n   * @returns The accounts for the EVM provider.\n   */\n  async discoverAccounts(opts: {\n    entropySource: EntropySourceId;\n    groupIndex: number;\n  }): Promise<Bip44Account<KeyringAccount>[]> {\n    return this.#trace(\n      {\n        name: TraceName.EvmDiscoverAccounts,\n        data: {\n          provider: this.getName(),\n        },\n      },\n      async () => {\n        if (!this.#config.discovery.enabled) {\n          return [];\n        }\n\n        const provider = this.getEvmProvider();\n        const { entropySource, groupIndex } = opts;\n\n        const addressFromGroupIndex = await this.#getAddressFromGroupIndex({\n          entropySource,\n          groupIndex,\n        });\n\n        const count = await this.#getTransactionCount(\n          provider,\n          addressFromGroupIndex,\n        );\n        if (count === 0) {\n          return [];\n        }\n\n        // We have some activity on this address, we try to create the account.\n        const [created] = await this.#createAccount({\n          entropySource,\n          groupIndex,\n          throwOnGap: false,\n        });\n\n        assert(created, 'Account creation failed');\n        assert(\n          addressFromGroupIndex === created.address,\n          'Created account does not match address from group index.',\n        );\n\n        const account = this.messenger.call(\n          'AccountsController:getAccount',\n          created.id,\n        );\n        assertInternalAccountExists(account);\n        assertIsBip44Account(account);\n        this.accounts.add(account.id);\n        return [account];\n      },\n    );\n  }\n\n  async resyncAccounts(): Promise<void> {\n    // No-op for the EVM account provider, since keyring accounts are already on\n    // the MetaMask side.\n  }\n\n  /**\n   * Delete an EVM account by id.\n   *\n   * Resolves the account's entropy source from the tracked account, then\n   * forwards to the v2 HD keyring's `deleteAccount(id)`. When this is the\n   * last account on a non-primary HD keyring, the keyring controller will\n   * automatically prune the empty keyring (see\n   * `KeyringController.#cleanUpEmptiedKeyringsAfter`).\n   *\n   * @param id - The id of the account to delete.\n   */\n  async deleteAccount(id: Bip44Account<KeyringAccount>['id']): Promise<void> {\n    const account = this.getAccount(id);\n    const entropySource = account.options.entropy.id;\n\n    await this.withKeyringV2<Keyring>(\n      { id: entropySource },\n      async ({ keyring }) => {\n        await keyring.deleteAccount(id);\n      },\n    );\n\n    this.accounts.delete(id);\n  }\n}\n"]}