{"version":3,"file":"ledger-keyring.cjs","sourceRoot":"","sources":["../../src/v2/ledger-keyring.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n  EthAccountType,\n  EthMethod,\n  EthScope,\n  KeyringAccountEntropyTypeOption,\n} from '@metamask/keyring-api';\nimport type { KeyringAccount, EntropySourceId } from '@metamask/keyring-api';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type {\n  CreateAccountOptions,\n  KeyringCapabilities,\n  Keyring,\n} from '@metamask/keyring-api/v2';\nimport { EthKeyringMethod, EthKeyringWrapper } from '@metamask/keyring-sdk/v2';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type {\n  GetAppNameAndVersionResponse,\n  LedgerBridge,\n  LedgerBridgeOptions,\n} from '../ledger-bridge';\nimport type {\n  AccountPage,\n  LedgerKeyring as LegacyLedgerKeyring,\n} from '../ledger-keyring';\n\n/**\n * Methods supported by Ledger keyring EOA accounts.\n * Ledger keyrings support a subset of signing methods (no encryption or app keys).\n */\nconst LEDGER_KEYRING_METHODS = [\n  EthMethod.SignTransaction,\n  EthMethod.PersonalSign,\n  EthMethod.SignTypedDataV4,\n  EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst ledgerKeyringCapabilities: KeyringCapabilities = {\n  scopes: [EthScope.Eoa],\n  bip44: {\n    deriveIndex: true,\n    derivePath: true,\n  },\n};\n\n/**\n * Ledger Live HD path constant.\n */\nconst LEDGER_LIVE_HD_PATH = `m/44'/60'/0'/0/0`;\n\n/**\n * BIP-44 standard HD path prefix constant for Ethereum.\n */\nconst BIP44_HD_PATH_PREFIX = `m/44'/60'/0'/0`;\n\n/**\n * Regex pattern for validating and parsing Ledger Live derivation paths.\n * Format: m/44'/60'/{index}'/0/0\n */\nconst LEDGER_LIVE_PATH_PATTERN = /^m\\/44'\\/60'\\/(\\d+)'\\/0\\/0$/u;\n\n/**\n * Regex pattern for validating and parsing non-Ledger-Live derivation paths.\n * Supports Legacy (m/44'/60'/0'/{index}), BIP44 (m/44'/60'/0'/0/{index}),\n * and custom paths that follow the m/44'/60'/... pattern.\n */\nconst INDEX_AT_END_PATH_PATTERN = /^(m\\/44'\\/60'(?:\\/\\d+'?)*)\\/(\\d+)$/u;\n\n/**\n * Concrete {@link Keyring} adapter for {@link LedgerKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * Ledger keyring via the unified V2 interface.\n *\n * All Ledger keyring accounts are BIP-44 derived from the device.\n */\nexport type LedgerKeyringOptions = {\n  legacyKeyring: LegacyLedgerKeyring;\n  entropySource: EntropySourceId;\n};\n\n// LegacyLedgerKeyring.signTransaction returns `TypedTransaction | OldEthJsTransaction` for\n// backwards compatibility with old ethereumjs-tx, but EthKeyring expects `TypedTxData`.\n// The runtime behavior is correct - we cast the type to satisfy the constraint.\ntype LedgerKeyringAsEthKeyring = LegacyLedgerKeyring & EthKeyring;\n\nexport class LedgerKeyring\n  extends EthKeyringWrapper<\n    LedgerKeyringAsEthKeyring,\n    Bip44Account<KeyringAccount>\n  >\n  implements Keyring\n{\n  readonly entropySource: EntropySourceId;\n\n  constructor(options: LedgerKeyringOptions) {\n    super({\n      type: KeyringType.Ledger,\n      inner: options.legacyKeyring as LedgerKeyringAsEthKeyring,\n      capabilities: ledgerKeyringCapabilities,\n    });\n    this.entropySource = options.entropySource;\n  }\n\n  /**\n   * Normalizes an address to a checksummed hex address.\n   *\n   * @param address - The address to normalize.\n   * @returns The checksummed hex address.\n   */\n  #getChecksumHexAddress(address: string): Hex {\n    return getChecksumAddress(add0x(address));\n  }\n\n  /**\n   * Parses a derivation path to extract the base HD path and account index.\n   *\n   * Supports two path formats:\n   * - Ledger Live: m/44'/60'/{index}'/0/0 → base: m/44'/60'/0'/0/0, index from position 3\n   * - Index at end: m/44'/60'/.../{index} → base: m/44'/60'/..., index from last segment\n   *\n   * @param derivationPath - The full derivation path.\n   * @returns The base HD path and account index.\n   * @throws If the path format is invalid.\n   */\n  #parseDerivationPath(derivationPath: string): {\n    basePath: string;\n    index: number;\n  } {\n    // Try Ledger Live format first: m/44'/60'/{index}'/0/0\n    const ledgerLiveMatch = derivationPath.match(LEDGER_LIVE_PATH_PATTERN);\n    if (ledgerLiveMatch?.[1]) {\n      return {\n        // This constant is used by `inner.setHdPath` to determine which derivation\n        // mode we should use (Ledger Live derivation mode here).\n        basePath: LEDGER_LIVE_HD_PATH,\n        index: parseInt(ledgerLiveMatch[1], 10),\n      };\n    }\n\n    // Try index-at-end format: m/44'/60'/.../{index}\n    const indexAtEndMatch = derivationPath.match(INDEX_AT_END_PATH_PATTERN);\n    if (indexAtEndMatch) {\n      // If the condition is true, indexAtEndMatch[1] and indexAtEndMatch[2] are defined, so\n      // we can safely cast them to string.\n      // This is necessary to get 100% code coverage.\n      return {\n        // Here, we use a derivation path prefix for `inner.setHdPath`\n        // (prefix + index derivation mode).\n        basePath: indexAtEndMatch[1] as string,\n        index: parseInt(indexAtEndMatch[2] as string, 10),\n      };\n    }\n\n    throw new Error(\n      `Invalid derivation path format: ${derivationPath}. ` +\n        `Expected Ledger Live (m/44'/60'/{index}'/0/0) or index-at-end (m/44'/60'/.../{index}) format.`,\n    );\n  }\n\n  /**\n   * Gets the index for an address from the account details.\n   *\n   * @param address - The address to get the index for.\n   * @returns The index for the address.\n   * @throws If the address is not found in account details.\n   */\n  #getIndexForAddress(address: Hex): number {\n    const checksummedAddress = this.#getChecksumHexAddress(address);\n    const details = this.inner.accountDetails[checksummedAddress];\n\n    if (!details) {\n      throw new Error(\n        `Address ${checksummedAddress} not found in account details`,\n      );\n    }\n\n    // Extract index from hdPath\n    const { hdPath } = details;\n    if (!hdPath) {\n      throw new Error(`No HD path found for address ${checksummedAddress}`);\n    }\n\n    // Ledger supports multiple derivation path formats:\n    // - Ledger Live (bip44: true): m/44'/60'/{index}'/0/0 - index at position 3\n    // - Other paths (bip44: false): {hdPath}/{index} - index at end\n    //   - BIP44: m/44'/60'/0'/0/{index}\n    //   - Legacy: m/44'/60'/0'/{index}\n    //   - Custom paths via setHdPath\n    //\n    // We use the `bip44` flag to determine which extraction pattern to use.\n    if (details.bip44) {\n      // Ledger Live format: m/44'/60'/{index}'/0/0\n      const match = hdPath.match(LEDGER_LIVE_PATH_PATTERN);\n      if (match?.[1]) {\n        return parseInt(match[1], 10);\n      }\n    } else {\n      // Index-at-end format: m/44'/60'/.../{index}\n      const match = hdPath.match(INDEX_AT_END_PATH_PATTERN);\n      if (match?.[2]) {\n        return parseInt(match[2], 10);\n      }\n    }\n\n    throw new Error(`Could not extract index from HD path: ${hdPath}`);\n  }\n\n  /**\n   * Creates a Bip44Account object for the given address.\n   *\n   * @param address - The account address.\n   * @param addressIndex - The account index in the derivation path.\n   * @returns The created Bip44Account.\n   */\n  #createKeyringAccount(\n    address: Hex,\n    addressIndex: number,\n  ): Bip44Account<KeyringAccount> {\n    const id = this.registry.register(address);\n\n    const checksummedAddress = this.#getChecksumHexAddress(address);\n    const details = this.inner.accountDetails[checksummedAddress];\n\n    if (!details?.hdPath) {\n      throw new Error(\n        `No HD path found for address ${checksummedAddress}. Cannot create account.`,\n      );\n    }\n\n    const account: Bip44Account<KeyringAccount> = {\n      id,\n      type: EthAccountType.Eoa,\n      address,\n      scopes: [...this.capabilities.scopes],\n      methods: [...LEDGER_KEYRING_METHODS],\n      options: {\n        entropy: {\n          type: KeyringAccountEntropyTypeOption.Mnemonic,\n          id: this.entropySource,\n          groupIndex: addressIndex,\n          derivationPath: details.hdPath,\n        },\n      },\n    };\n\n    this.registry.set(account);\n    return account;\n  }\n\n  async getAccounts(): Promise<Bip44Account<KeyringAccount>[]> {\n    const addresses = await this.inner.getAccounts();\n\n    if (addresses.length === 0) {\n      return [];\n    }\n\n    return addresses.map((address) => {\n      // Check if we already have this account in the registry\n      const existingId = this.registry.getAccountId(address);\n      if (existingId) {\n        const cached = this.registry.get(existingId);\n        if (cached) {\n          return cached;\n        }\n      }\n\n      const addressIndex = this.#getIndexForAddress(address);\n      return this.#createKeyringAccount(address, addressIndex);\n    });\n  }\n\n  async createAccounts(\n    options: CreateAccountOptions,\n  ): Promise<Bip44Account<KeyringAccount>[]> {\n    return this.withLock(async () => {\n      if (\n        options.type === 'bip44:derive-path' ||\n        options.type === 'bip44:derive-index'\n      ) {\n        // Validate that the entropy source matches this keyring's entropy source\n        if (options.entropySource !== this.entropySource) {\n          throw new Error(\n            `Entropy source mismatch: expected '${this.entropySource}', got '${options.entropySource}'`,\n          );\n        }\n      } else {\n        throw new Error(\n          `Unsupported account creation type for LedgerKeyring: ${String(\n            options.type,\n          )}`,\n        );\n      }\n\n      // Check if an account at this index already exists with the same derivation path\n      const currentAccounts = await this.getAccounts();\n\n      let targetIndex: number;\n      let basePath: string;\n      let derivationPath: string;\n\n      if (options.type === 'bip44:derive-path') {\n        // Parse the derivation path to extract base path and index\n        const parsed = this.#parseDerivationPath(options.derivationPath);\n        targetIndex = parsed.index;\n        basePath = parsed.basePath;\n\n        derivationPath = options.derivationPath;\n      } else {\n        // derive-index uses BIP-44 standard path by default\n        targetIndex = options.groupIndex;\n        basePath = BIP44_HD_PATH_PREFIX;\n        derivationPath = `${basePath}/${targetIndex}`;\n      }\n\n      const existingAccount = currentAccounts.find((account) => {\n        return (\n          account.options.entropy.groupIndex === targetIndex &&\n          account.options.entropy.derivationPath === derivationPath\n        );\n      });\n\n      if (existingAccount) {\n        return [existingAccount];\n      }\n\n      // Derive the account at the specified index\n      this.inner.setHdPath(basePath);\n      this.inner.setAccountToUnlock(targetIndex);\n      const [newAddress] = await this.inner.addAccounts(1);\n\n      if (!newAddress) {\n        throw new Error('Failed to create new account');\n      }\n\n      const newAccount = this.#createKeyringAccount(newAddress, targetIndex);\n\n      return [newAccount];\n    });\n  }\n\n  /**\n   * Delete an account from the keyring.\n   *\n   * @param accountId - The account ID to delete.\n   */\n  async deleteAccount(accountId: AccountId): Promise<void> {\n    await this.withLock(async () => {\n      const { address } = await this.getAccount(accountId);\n      const hexAddress = this.toHexAddress(address);\n\n      // Remove from the legacy keyring\n      this.inner.removeAccount(hexAddress);\n\n      // Remove from the registry\n      this.registry.delete(accountId);\n    });\n  }\n\n  /**\n   * @returns The current derivation path used by the inner keyring.\n   */\n  get hdPath(): string {\n    return this.inner.hdPath;\n  }\n\n  /**\n   * @returns The bridge instance used by the inner keyring to communicate\n   * with the device.\n   */\n  get bridge(): LedgerBridge<LedgerBridgeOptions> {\n    return this.inner.bridge;\n  }\n\n  /**\n   * @returns The device ID for the paired Ledger device.\n   */\n  getDeviceId(): string {\n    return this.inner.getDeviceId();\n  }\n\n  /**\n   * Set the device ID for the paired Ledger device.\n   *\n   * @param deviceId - The device ID to set.\n   */\n  setDeviceId(deviceId: string): void {\n    this.inner.setDeviceId(deviceId);\n  }\n\n  /**\n   * Set the derivation path on the inner keyring.\n   *\n   * @param hdPath - The derivation path to set.\n   */\n  setHdPath(hdPath: string): void {\n    this.inner.setHdPath(hdPath);\n  }\n\n  /**\n   * Fetch the first page of candidate addresses from the device.\n   *\n   * @returns The first page of accounts.\n   */\n  async getFirstPage(): Promise<AccountPage> {\n    return this.inner.getFirstPage();\n  }\n\n  /**\n   * Fetch the next page of candidate addresses from the device.\n   *\n   * @returns The next page of accounts.\n   */\n  async getNextPage(): Promise<AccountPage> {\n    return this.inner.getNextPage();\n  }\n\n  /**\n   * Fetch the previous page of candidate addresses from the device.\n   *\n   * @returns The previous page of accounts.\n   */\n  async getPreviousPage(): Promise<AccountPage> {\n    return this.inner.getPreviousPage();\n  }\n\n  /**\n   * Clear the inner keyring's device-pairing state and accounts, and reset\n   * the V2 account registry to keep them in sync.\n   */\n  async forgetDevice(): Promise<void> {\n    await this.withLock(async () => {\n      this.inner.forgetDevice();\n      this.registry.clear();\n    });\n  }\n\n  /**\n   * @returns Whether the inner keyring has an unlocked HD key.\n   */\n  isUnlocked(): boolean {\n    return this.inner.isUnlocked();\n  }\n\n  /**\n   * Attempt to open the Ethereum app on the connected Ledger device.\n   *\n   * @returns Whether the app was opened.\n   */\n  async attemptMakeApp(): Promise<boolean> {\n    return this.inner.attemptMakeApp();\n  }\n\n  /**\n   * @returns The app name and version currently running on the connected\n   * Ledger device.\n   */\n  async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n    return this.inner.getAppNameAndVersion();\n  }\n}\n"]}