@metamask/eth-ledger-bridge-keyring 11.3.0 → 11.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [11.3.1]
11
+
12
+ ### Changed
13
+
14
+ - Add new dependency `@metamask/keyring-sdk@1.2.0` ([#478](https://github.com/MetaMask/accounts/pull/478)), ([#482](https://github.com/MetaMask/accounts/pull/482)), ([#496](https://github.com/MetaMask/accounts/pull/496)), ([#509](https://github.com/MetaMask/accounts/pull/509))
15
+ - This package now contains the keyring v2 wrapper helpers (`EthKeyringWrapper`).
16
+ - The account ID (generated by `KeyringAccountRegistry`) are now deterministic for EVM addresses.
17
+ - Bump `@metamask/hw-wallet-sdk` from `^0.6.0` to `^0.8.0` ([#482](https://github.com/MetaMask/accounts/pull/482)), ([#497](https://github.com/MetaMask/accounts/pull/497))
18
+ - Bump `@metamask/keyring-api` from `^21.6.0` to `^22.0.0` ([#482](https://github.com/MetaMask/accounts/pull/482))
19
+ - Bump `@metamask/account-api` from `^1.0.0` to `^1.0.1` ([#487](https://github.com/MetaMask/accounts/pull/487))
20
+
10
21
  ## [11.3.0]
11
22
 
12
23
  ### Changed
@@ -365,7 +376,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
365
376
 
366
377
  - Support new versions of ethereumjs/tx ([#68](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/68))
367
378
 
368
- [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.3.0...HEAD
379
+ [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.3.1...HEAD
380
+ [11.3.1]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.3.0...@metamask/eth-ledger-bridge-keyring@11.3.1
369
381
  [11.3.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.2.0...@metamask/eth-ledger-bridge-keyring@11.3.0
370
382
  [11.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.1.2...@metamask/eth-ledger-bridge-keyring@11.2.0
371
383
  [11.1.2]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.1.1...@metamask/eth-ledger-bridge-keyring@11.1.2
@@ -8,6 +8,7 @@ var _LedgerKeyringV2_instances, _LedgerKeyringV2_getChecksumHexAddress, _LedgerK
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.LedgerKeyringV2 = void 0;
10
10
  const keyring_api_1 = require("@metamask/keyring-api");
11
+ const keyring_sdk_1 = require("@metamask/keyring-sdk");
11
12
  const utils_1 = require("@metamask/utils");
12
13
  /**
13
14
  * Methods supported by Ledger keyring EOA accounts.
@@ -44,7 +45,7 @@ const LEDGER_LIVE_PATH_PATTERN = /^m\/44'\/60'\/(\d+)'\/0\/0$/u;
44
45
  * and custom paths that follow the m/44'/60'/... pattern.
45
46
  */
46
47
  const INDEX_AT_END_PATH_PATTERN = /^(m\/44'\/60'(?:\/\d+'?)*)\/(\d+)$/u;
47
- class LedgerKeyringV2 extends keyring_api_1.EthKeyringWrapper {
48
+ class LedgerKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
48
49
  constructor(options) {
49
50
  super({
50
51
  type: keyring_api_1.KeyringType.Ledger,
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-keyring-v2.cjs","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":";;;;;;;;;AACA,uDAY+B;AAE/B,2CAAsE;AAItE;;;GAGG;AACH,MAAM,sBAAsB,GAAG;IAC7B,uBAAS,CAAC,eAAe;IACzB,uBAAS,CAAC,YAAY;IACtB,uBAAS,CAAC,eAAe;CAC1B,CAAC;AAEF,MAAM,2BAA2B,GAAwB;IACvD,MAAM,EAAE,CAAC,sBAAQ,CAAC,GAAG,CAAC;IACtB,KAAK,EAAE;QACL,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,IAAI;KACjB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAE/C;;GAEG;AACH,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAE9C;;;GAGG;AACH,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEhE;;;;GAIG;AACH,MAAM,yBAAyB,GAAG,qCAAqC,CAAC;AAoBxE,MAAa,eACX,SAAQ,+BAGP;IAKD,YAAY,OAA+B;QACzC,KAAK,CAAC;YACJ,IAAI,EAAE,yBAAW,CAAC,MAAM;YACxB,KAAK,EAAE,OAAO,CAAC,aAA0C;YACzD,YAAY,EAAE,2BAA2B;SAC1C,CAAC,CAAC;;QACH,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC7C,CAAC;IAoJD,KAAK,CAAC,WAAW;QACf,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAEjD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YAC/B,wDAAwD;YACxD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBAC7C,IAAI,MAAM,EAAE,CAAC;oBACX,OAAO,MAAM,CAAC;gBAChB,CAAC;YACH,CAAC;YAED,MAAM,YAAY,GAAG,uBAAA,IAAI,uEAAoB,MAAxB,IAAI,EAAqB,OAAO,CAAC,CAAC;YACvD,OAAO,uBAAA,IAAI,yEAAsB,MAA1B,IAAI,EAAuB,OAAO,EAAE,YAAY,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,OAA6B;QAE7B,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE;YAC9B,IACE,OAAO,CAAC,IAAI,KAAK,mBAAmB;gBACpC,OAAO,CAAC,IAAI,KAAK,oBAAoB,EACrC,CAAC;gBACD,yEAAyE;gBACzE,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;oBACjD,MAAM,IAAI,KAAK,CACb,sCAAsC,IAAI,CAAC,aAAa,WAAW,OAAO,CAAC,aAAa,GAAG,CAC5F,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CACb,wDAAwD,MAAM,CAC5D,OAAO,CAAC,IAAI,CACb,EAAE,CACJ,CAAC;YACJ,CAAC;YAED,iFAAiF;YACjF,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAEjD,IAAI,WAAmB,CAAC;YACxB,IAAI,QAAgB,CAAC;YACrB,IAAI,cAAsB,CAAC;YAE3B,IAAI,OAAO,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;gBACzC,2DAA2D;gBAC3D,MAAM,MAAM,GAAG,uBAAA,IAAI,wEAAqB,MAAzB,IAAI,EAAsB,OAAO,CAAC,cAAc,CAAC,CAAC;gBACjE,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3B,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;gBAE3B,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,oDAAoD;gBACpD,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;gBACjC,QAAQ,GAAG,oBAAoB,CAAC;gBAChC,cAAc,GAAG,GAAG,QAAQ,IAAI,WAAW,EAAE,CAAC;YAChD,CAAC;YAED,MAAM,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBACvD,OAAO,CACL,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,KAAK,WAAW;oBAClD,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,KAAK,cAAc,CAC1D,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,CAAC,eAAe,CAAC,CAAC;YAC3B,CAAC;YAED,4CAA4C;YAC5C,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;YAC3C,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAErD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAClD,CAAC;YAED,MAAM,UAAU,GAAG,uBAAA,IAAI,yEAAsB,MAA1B,IAAI,EAAuB,UAAU,EAAE,WAAW,CAAC,CAAC;YAEvE,OAAO,CAAC,UAAU,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,aAAa,CAAC,SAAoB;QACtC,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAE9C,iCAAiC;YACjC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YAErC,2BAA2B;YAC3B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAhRD,0CAgRC;qIAxPwB,OAAe;IACpC,OAAO,IAAA,0BAAkB,EAAC,IAAA,aAAK,EAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,CAAC,uFAaoB,cAAsB;IAIzC,uDAAuD;IACvD,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IACvE,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,2EAA2E;YAC3E,yDAAyD;YACzD,QAAQ,EAAE,mBAAmB;YAC7B,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;SACxC,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACxE,IAAI,eAAe,EAAE,CAAC;QACpB,sFAAsF;QACtF,qCAAqC;QACrC,+CAA+C;QAC/C,OAAO;YACL,8DAA8D;YAC9D,oCAAoC;YACpC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAW;YACtC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAW,EAAE,EAAE,CAAC;SAClD,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CACb,mCAAmC,cAAc,IAAI;QACnD,+FAA+F,CAClG,CAAC;AACJ,CAAC,qFASmB,OAAY;IAC9B,MAAM,kBAAkB,GAAG,uBAAA,IAAI,0EAAuB,MAA3B,IAAI,EAAwB,OAAO,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;IAE9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,WAAW,kBAAkB,+BAA+B,CAC7D,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,gCAAgC,kBAAkB,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,oDAAoD;IACpD,4EAA4E;IAC5E,gEAAgE;IAChE,oCAAoC;IACpC,mCAAmC;IACnC,iCAAiC;IACjC,EAAE;IACF,wEAAwE;IACxE,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,6CAA6C;QAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACrD,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACf,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;SAAM,CAAC;QACN,6CAA6C;QAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACtD,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACf,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC;AACrE,CAAC,yFAUC,OAAY,EACZ,YAAoB;IAEpB,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE3C,MAAM,kBAAkB,GAAG,uBAAA,IAAI,0EAAuB,MAA3B,IAAI,EAAwB,OAAO,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;IAE9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,gCAAgC,kBAAkB,0BAA0B,CAC7E,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAiC;QAC5C,EAAE;QACF,IAAI,EAAE,4BAAc,CAAC,GAAG;QACxB,OAAO;QACP,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;QACrC,OAAO,EAAE,CAAC,GAAG,sBAAsB,CAAC;QACpC,OAAO,EAAE;YACP,OAAO,EAAE;gBACP,IAAI,EAAE,6CAA+B,CAAC,QAAQ;gBAC9C,EAAE,EAAE,IAAI,CAAC,aAAa;gBACtB,UAAU,EAAE,YAAY;gBACxB,cAAc,EAAE,OAAO,CAAC,MAAM;aAC/B;SACF;KACF,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress, type Hex } from '@metamask/utils';\n\nimport type { LedgerKeyring } from './ledger-keyring';\n\n/**\n * Methods supported by Ledger keyring EOA accounts.\n * Ledger keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).\n */\nconst LEDGER_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV4,\n];\n\nconst ledgerKeyringV2Capabilities: 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 KeyringV2} 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 LedgerKeyringV2Options = {\n legacyKeyring: LedgerKeyring;\n entropySource: EntropySourceId;\n};\n\n// LedgerKeyring.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 = LedgerKeyring & EthKeyring;\n\nexport class LedgerKeyringV2\n extends EthKeyringWrapper<\n LedgerKeyringAsEthKeyring,\n Bip44Account<KeyringAccount>\n >\n implements KeyringV2\n{\n readonly entropySource: EntropySourceId;\n\n constructor(options: LedgerKeyringV2Options) {\n super({\n type: KeyringType.Ledger,\n inner: options.legacyKeyring as LedgerKeyringAsEthKeyring,\n capabilities: ledgerKeyringV2Capabilities,\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"]}
1
+ {"version":3,"file":"ledger-keyring-v2.cjs","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthMethod,\n EthScope,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport { EthKeyringWrapper } from '@metamask/keyring-sdk';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress, type Hex } from '@metamask/utils';\n\nimport type { LedgerKeyring } from './ledger-keyring';\n\n/**\n * Methods supported by Ledger keyring EOA accounts.\n * Ledger keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).\n */\nconst LEDGER_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV4,\n];\n\nconst ledgerKeyringV2Capabilities: 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 KeyringV2} 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 LedgerKeyringV2Options = {\n legacyKeyring: LedgerKeyring;\n entropySource: EntropySourceId;\n};\n\n// LedgerKeyring.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 = LedgerKeyring & EthKeyring;\n\nexport class LedgerKeyringV2\n extends EthKeyringWrapper<\n LedgerKeyringAsEthKeyring,\n Bip44Account<KeyringAccount>\n >\n implements KeyringV2\n{\n readonly entropySource: EntropySourceId;\n\n constructor(options: LedgerKeyringV2Options) {\n super({\n type: KeyringType.Ledger,\n inner: options.legacyKeyring as LedgerKeyringAsEthKeyring,\n capabilities: ledgerKeyringV2Capabilities,\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"]}
@@ -1,5 +1,6 @@
1
1
  import type { Bip44Account } from "@metamask/account-api";
2
- import { type CreateAccountOptions, EthKeyringWrapper, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
2
+ import { type CreateAccountOptions, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
3
+ import { EthKeyringWrapper } from "@metamask/keyring-sdk";
3
4
  import type { AccountId, EthKeyring } from "@metamask/keyring-utils";
4
5
  import type { LedgerKeyring } from "./ledger-keyring.cjs";
5
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-keyring-v2.d.cts","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAEzB,iBAAiB,EAGjB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAEd,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AA2CtD;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAKF,KAAK,yBAAyB,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5D,qBAAa,eACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,SAAS;;IAEpB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,sBAAsB;IA2JrC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAsBtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAmE1C;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAYzD"}
1
+ {"version":3,"file":"ledger-keyring-v2.d.cts","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAIzB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAEd,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,EAAE,iBAAiB,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AA2CtD;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAKF,KAAK,yBAAyB,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5D,qBAAa,eACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,SAAS;;IAEpB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,sBAAsB;IA2JrC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAsBtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAmE1C;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAYzD"}
@@ -1,5 +1,6 @@
1
1
  import type { Bip44Account } from "@metamask/account-api";
2
- import { type CreateAccountOptions, EthKeyringWrapper, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
2
+ import { type CreateAccountOptions, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
3
+ import { EthKeyringWrapper } from "@metamask/keyring-sdk";
3
4
  import type { AccountId, EthKeyring } from "@metamask/keyring-utils";
4
5
  import type { LedgerKeyring } from "./ledger-keyring.mjs";
5
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-keyring-v2.d.mts","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAEzB,iBAAiB,EAGjB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAEd,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AA2CtD;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAKF,KAAK,yBAAyB,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5D,qBAAa,eACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,SAAS;;IAEpB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,sBAAsB;IA2JrC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAsBtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAmE1C;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAYzD"}
1
+ {"version":3,"file":"ledger-keyring-v2.d.mts","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAIzB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAEd,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,EAAE,iBAAiB,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,6BAAyB;AA2CtD;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAKF,KAAK,yBAAyB,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5D,qBAAa,eACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,SAAS;;IAEpB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,sBAAsB;IA2JrC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAsBtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAmE1C;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAYzD"}
@@ -4,7 +4,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _LedgerKeyringV2_instances, _LedgerKeyringV2_getChecksumHexAddress, _LedgerKeyringV2_parseDerivationPath, _LedgerKeyringV2_getIndexForAddress, _LedgerKeyringV2_createKeyringAccount;
7
- import { EthAccountType, EthKeyringWrapper, EthMethod, EthScope, KeyringAccountEntropyTypeOption, KeyringType } from "@metamask/keyring-api";
7
+ import { EthAccountType, EthMethod, EthScope, KeyringAccountEntropyTypeOption, KeyringType } from "@metamask/keyring-api";
8
+ import { EthKeyringWrapper } from "@metamask/keyring-sdk";
8
9
  import { add0x, getChecksumAddress } from "@metamask/utils";
9
10
  /**
10
11
  * Methods supported by Ledger keyring EOA accounts.
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-keyring-v2.mjs","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress, type Hex } from '@metamask/utils';\n\nimport type { LedgerKeyring } from './ledger-keyring';\n\n/**\n * Methods supported by Ledger keyring EOA accounts.\n * Ledger keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).\n */\nconst LEDGER_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV4,\n];\n\nconst ledgerKeyringV2Capabilities: 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 KeyringV2} 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 LedgerKeyringV2Options = {\n legacyKeyring: LedgerKeyring;\n entropySource: EntropySourceId;\n};\n\n// LedgerKeyring.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 = LedgerKeyring & EthKeyring;\n\nexport class LedgerKeyringV2\n extends EthKeyringWrapper<\n LedgerKeyringAsEthKeyring,\n Bip44Account<KeyringAccount>\n >\n implements KeyringV2\n{\n readonly entropySource: EntropySourceId;\n\n constructor(options: LedgerKeyringV2Options) {\n super({\n type: KeyringType.Ledger,\n inner: options.legacyKeyring as LedgerKeyringAsEthKeyring,\n capabilities: ledgerKeyringV2Capabilities,\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"]}
1
+ {"version":3,"file":"ledger-keyring-v2.mjs","sourceRoot":"","sources":["../src/ledger-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthMethod,\n EthScope,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport { EthKeyringWrapper } from '@metamask/keyring-sdk';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress, type Hex } from '@metamask/utils';\n\nimport type { LedgerKeyring } from './ledger-keyring';\n\n/**\n * Methods supported by Ledger keyring EOA accounts.\n * Ledger keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).\n */\nconst LEDGER_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV4,\n];\n\nconst ledgerKeyringV2Capabilities: 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 KeyringV2} 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 LedgerKeyringV2Options = {\n legacyKeyring: LedgerKeyring;\n entropySource: EntropySourceId;\n};\n\n// LedgerKeyring.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 = LedgerKeyring & EthKeyring;\n\nexport class LedgerKeyringV2\n extends EthKeyringWrapper<\n LedgerKeyringAsEthKeyring,\n Bip44Account<KeyringAccount>\n >\n implements KeyringV2\n{\n readonly entropySource: EntropySourceId;\n\n constructor(options: LedgerKeyringV2Options) {\n super({\n type: KeyringType.Ledger,\n inner: options.legacyKeyring as LedgerKeyringAsEthKeyring,\n capabilities: ledgerKeyringV2Capabilities,\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/eth-ledger-bridge-keyring",
3
- "version": "11.3.0",
3
+ "version": "11.3.1",
4
4
  "description": "A MetaMask compatible keyring, for ledger hardware wallets",
5
5
  "keywords": [
6
6
  "ethereum",
@@ -51,8 +51,9 @@
51
51
  "@ethereumjs/util": "^9.1.0",
52
52
  "@ledgerhq/hw-app-eth": "^6.42.0",
53
53
  "@metamask/eth-sig-util": "^8.2.0",
54
- "@metamask/hw-wallet-sdk": "^0.4.0",
55
- "@metamask/keyring-api": "^21.4.0",
54
+ "@metamask/hw-wallet-sdk": "^0.8.0",
55
+ "@metamask/keyring-api": "^22.0.0",
56
+ "@metamask/keyring-sdk": "^1.2.0",
56
57
  "@metamask/keyring-utils": "^3.2.0",
57
58
  "hdkey": "^2.1.0"
58
59
  },
@@ -64,10 +65,10 @@
64
65
  "@ledgerhq/types-cryptoassets": "^7.15.1",
65
66
  "@ledgerhq/types-devices": "^6.25.3",
66
67
  "@ledgerhq/types-live": "^6.52.0",
67
- "@metamask/account-api": "^0.12.0",
68
+ "@metamask/account-api": "^1.0.1",
68
69
  "@metamask/auto-changelog": "^3.4.4",
69
70
  "@metamask/keyring-utils": "^3.2.0",
70
- "@metamask/utils": "^11.1.0",
71
+ "@metamask/utils": "^11.10.0",
71
72
  "@ts-bridge/cli": "^0.6.3",
72
73
  "@types/ethereumjs-tx": "^1.0.1",
73
74
  "@types/hdkey": "^2.0.1",