@metamask/eth-ledger-bridge-keyring 12.0.3 → 12.2.0

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.
Files changed (96) hide show
  1. package/CHANGELOG.md +35 -8
  2. package/dist/dmk/__testhelpers__/mock-error.cjs +24 -0
  3. package/dist/dmk/__testhelpers__/mock-error.cjs.map +1 -0
  4. package/dist/dmk/__testhelpers__/mock-error.d.cts +13 -0
  5. package/dist/dmk/__testhelpers__/mock-error.d.cts.map +1 -0
  6. package/dist/dmk/__testhelpers__/mock-error.d.mts +13 -0
  7. package/dist/dmk/__testhelpers__/mock-error.d.mts.map +1 -0
  8. package/dist/dmk/__testhelpers__/mock-error.mjs +20 -0
  9. package/dist/dmk/__testhelpers__/mock-error.mjs.map +1 -0
  10. package/dist/dmk/dmk-error-translator.cjs +35 -0
  11. package/dist/dmk/dmk-error-translator.cjs.map +1 -0
  12. package/dist/dmk/dmk-error-translator.d.cts +12 -0
  13. package/dist/dmk/dmk-error-translator.d.cts.map +1 -0
  14. package/dist/dmk/dmk-error-translator.d.mts +12 -0
  15. package/dist/dmk/dmk-error-translator.d.mts.map +1 -0
  16. package/dist/dmk/dmk-error-translator.mjs +30 -0
  17. package/dist/dmk/dmk-error-translator.mjs.map +1 -0
  18. package/dist/dmk/eth-get-app-configuration-command.cjs +155 -0
  19. package/dist/dmk/eth-get-app-configuration-command.cjs.map +1 -0
  20. package/dist/dmk/eth-get-app-configuration-command.d.cts +71 -0
  21. package/dist/dmk/eth-get-app-configuration-command.d.cts.map +1 -0
  22. package/dist/dmk/eth-get-app-configuration-command.d.mts +71 -0
  23. package/dist/dmk/eth-get-app-configuration-command.d.mts.map +1 -0
  24. package/dist/dmk/eth-get-app-configuration-command.mjs +151 -0
  25. package/dist/dmk/eth-get-app-configuration-command.mjs.map +1 -0
  26. package/dist/dmk/internal-utils.cjs +81 -0
  27. package/dist/dmk/internal-utils.cjs.map +1 -0
  28. package/dist/dmk/internal-utils.d.cts +44 -0
  29. package/dist/dmk/internal-utils.d.cts.map +1 -0
  30. package/dist/dmk/internal-utils.d.mts +44 -0
  31. package/dist/dmk/internal-utils.d.mts.map +1 -0
  32. package/dist/dmk/internal-utils.mjs +74 -0
  33. package/dist/dmk/internal-utils.mjs.map +1 -0
  34. package/dist/dmk/ledger-dmk-bridge.cjs +379 -0
  35. package/dist/dmk/ledger-dmk-bridge.cjs.map +1 -0
  36. package/dist/dmk/ledger-dmk-bridge.d.cts +157 -0
  37. package/dist/dmk/ledger-dmk-bridge.d.cts.map +1 -0
  38. package/dist/dmk/ledger-dmk-bridge.d.mts +157 -0
  39. package/dist/dmk/ledger-dmk-bridge.d.mts.map +1 -0
  40. package/dist/dmk/ledger-dmk-bridge.mjs +375 -0
  41. package/dist/dmk/ledger-dmk-bridge.mjs.map +1 -0
  42. package/dist/dmk/ledger-dmk-transport-middleware.cjs +170 -0
  43. package/dist/dmk/ledger-dmk-transport-middleware.cjs.map +1 -0
  44. package/dist/dmk/ledger-dmk-transport-middleware.d.cts +99 -0
  45. package/dist/dmk/ledger-dmk-transport-middleware.d.cts.map +1 -0
  46. package/dist/dmk/ledger-dmk-transport-middleware.d.mts +99 -0
  47. package/dist/dmk/ledger-dmk-transport-middleware.d.mts.map +1 -0
  48. package/dist/dmk/ledger-dmk-transport-middleware.mjs +166 -0
  49. package/dist/dmk/ledger-dmk-transport-middleware.mjs.map +1 -0
  50. package/dist/index.cjs +3 -0
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +3 -0
  53. package/dist/index.d.cts.map +1 -1
  54. package/dist/index.d.mts +3 -0
  55. package/dist/index.d.mts.map +1 -1
  56. package/dist/index.mjs +3 -0
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/ledger-bridge.cjs.map +1 -1
  59. package/dist/ledger-bridge.d.cts +12 -0
  60. package/dist/ledger-bridge.d.cts.map +1 -1
  61. package/dist/ledger-bridge.d.mts +12 -0
  62. package/dist/ledger-bridge.d.mts.map +1 -1
  63. package/dist/ledger-bridge.mjs.map +1 -1
  64. package/dist/ledger-iframe-bridge.cjs +3 -0
  65. package/dist/ledger-iframe-bridge.cjs.map +1 -1
  66. package/dist/ledger-iframe-bridge.d.cts +2 -1
  67. package/dist/ledger-iframe-bridge.d.cts.map +1 -1
  68. package/dist/ledger-iframe-bridge.d.mts +2 -1
  69. package/dist/ledger-iframe-bridge.d.mts.map +1 -1
  70. package/dist/ledger-iframe-bridge.mjs +3 -0
  71. package/dist/ledger-iframe-bridge.mjs.map +1 -1
  72. package/dist/ledger-keyring.cjs +59 -3
  73. package/dist/ledger-keyring.cjs.map +1 -1
  74. package/dist/ledger-keyring.d.cts +1 -0
  75. package/dist/ledger-keyring.d.cts.map +1 -1
  76. package/dist/ledger-keyring.d.mts +1 -0
  77. package/dist/ledger-keyring.d.mts.map +1 -1
  78. package/dist/ledger-keyring.mjs +61 -5
  79. package/dist/ledger-keyring.mjs.map +1 -1
  80. package/dist/ledger-mobile-bridge.cjs +3 -0
  81. package/dist/ledger-mobile-bridge.cjs.map +1 -1
  82. package/dist/ledger-mobile-bridge.d.cts +2 -1
  83. package/dist/ledger-mobile-bridge.d.cts.map +1 -1
  84. package/dist/ledger-mobile-bridge.d.mts +2 -1
  85. package/dist/ledger-mobile-bridge.d.mts.map +1 -1
  86. package/dist/ledger-mobile-bridge.mjs +3 -0
  87. package/dist/ledger-mobile-bridge.mjs.map +1 -1
  88. package/dist/v2/ledger-keyring.cjs +92 -1
  89. package/dist/v2/ledger-keyring.cjs.map +1 -1
  90. package/dist/v2/ledger-keyring.d.cts +65 -1
  91. package/dist/v2/ledger-keyring.d.cts.map +1 -1
  92. package/dist/v2/ledger-keyring.d.mts +65 -1
  93. package/dist/v2/ledger-keyring.d.mts.map +1 -1
  94. package/dist/v2/ledger-keyring.mjs +93 -2
  95. package/dist/v2/ledger-keyring.mjs.map +1 -1
  96. package/package.json +9 -5
@@ -6,16 +6,17 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
6
6
  var _LedgerKeyring_instances, _LedgerKeyring_getChecksumHexAddress, _LedgerKeyring_parseDerivationPath, _LedgerKeyring_getIndexForAddress, _LedgerKeyring_createKeyringAccount;
7
7
  import { EthAccountType, EthMethod, EthScope, KeyringAccountEntropyTypeOption } from "@metamask/keyring-api";
8
8
  import { KeyringType } from "@metamask/keyring-api/v2";
9
- import { EthKeyringWrapper } from "@metamask/keyring-sdk/v2";
9
+ import { EthKeyringMethod, EthKeyringWrapper } from "@metamask/keyring-sdk/v2";
10
10
  import { add0x, getChecksumAddress } from "@metamask/utils";
11
11
  /**
12
12
  * Methods supported by Ledger keyring EOA accounts.
13
- * Ledger keyrings support a subset of signing methods (no encryption, app keys, or EIP-7702).
13
+ * Ledger keyrings support a subset of signing methods (no encryption or app keys).
14
14
  */
15
15
  const LEDGER_KEYRING_METHODS = [
16
16
  EthMethod.SignTransaction,
17
17
  EthMethod.PersonalSign,
18
18
  EthMethod.SignTypedDataV4,
19
+ EthKeyringMethod.SignEip7702Authorization,
19
20
  ];
20
21
  const ledgerKeyringCapabilities = {
21
22
  scopes: [EthScope.Eoa],
@@ -134,6 +135,96 @@ export class LedgerKeyring extends EthKeyringWrapper {
134
135
  this.registry.delete(accountId);
135
136
  });
136
137
  }
138
+ /**
139
+ * @returns The current derivation path used by the inner keyring.
140
+ */
141
+ get hdPath() {
142
+ return this.inner.hdPath;
143
+ }
144
+ /**
145
+ * @returns The bridge instance used by the inner keyring to communicate
146
+ * with the device.
147
+ */
148
+ get bridge() {
149
+ return this.inner.bridge;
150
+ }
151
+ /**
152
+ * @returns The device ID for the paired Ledger device.
153
+ */
154
+ getDeviceId() {
155
+ return this.inner.getDeviceId();
156
+ }
157
+ /**
158
+ * Set the device ID for the paired Ledger device.
159
+ *
160
+ * @param deviceId - The device ID to set.
161
+ */
162
+ setDeviceId(deviceId) {
163
+ this.inner.setDeviceId(deviceId);
164
+ }
165
+ /**
166
+ * Set the derivation path on the inner keyring.
167
+ *
168
+ * @param hdPath - The derivation path to set.
169
+ */
170
+ setHdPath(hdPath) {
171
+ this.inner.setHdPath(hdPath);
172
+ }
173
+ /**
174
+ * Fetch the first page of candidate addresses from the device.
175
+ *
176
+ * @returns The first page of accounts.
177
+ */
178
+ async getFirstPage() {
179
+ return this.inner.getFirstPage();
180
+ }
181
+ /**
182
+ * Fetch the next page of candidate addresses from the device.
183
+ *
184
+ * @returns The next page of accounts.
185
+ */
186
+ async getNextPage() {
187
+ return this.inner.getNextPage();
188
+ }
189
+ /**
190
+ * Fetch the previous page of candidate addresses from the device.
191
+ *
192
+ * @returns The previous page of accounts.
193
+ */
194
+ async getPreviousPage() {
195
+ return this.inner.getPreviousPage();
196
+ }
197
+ /**
198
+ * Clear the inner keyring's device-pairing state and accounts, and reset
199
+ * the V2 account registry to keep them in sync.
200
+ */
201
+ async forgetDevice() {
202
+ await this.withLock(async () => {
203
+ this.inner.forgetDevice();
204
+ this.registry.clear();
205
+ });
206
+ }
207
+ /**
208
+ * @returns Whether the inner keyring has an unlocked HD key.
209
+ */
210
+ isUnlocked() {
211
+ return this.inner.isUnlocked();
212
+ }
213
+ /**
214
+ * Attempt to open the Ethereum app on the connected Ledger device.
215
+ *
216
+ * @returns Whether the app was opened.
217
+ */
218
+ async attemptMakeApp() {
219
+ return this.inner.attemptMakeApp();
220
+ }
221
+ /**
222
+ * @returns The app name and version currently running on the connected
223
+ * Ledger device.
224
+ */
225
+ async getAppNameAndVersion() {
226
+ return this.inner.getAppNameAndVersion();
227
+ }
137
228
  }
138
229
  _LedgerKeyring_instances = new WeakSet(), _LedgerKeyring_getChecksumHexAddress = function _LedgerKeyring_getChecksumHexAddress(address) {
139
230
  return getChecksumAddress(add0x(address));
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-keyring.mjs","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 { 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 { LedgerKeyring as LegacyLedgerKeyring } 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 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"]}
1
+ {"version":3,"file":"ledger-keyring.mjs","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/eth-ledger-bridge-keyring",
3
- "version": "12.0.3",
3
+ "version": "12.2.0",
4
4
  "description": "A MetaMask compatible keyring, for ledger hardware wallets",
5
5
  "keywords": [
6
6
  "ethereum",
@@ -71,13 +71,17 @@
71
71
  "@ethereumjs/rlp": "^5.0.2",
72
72
  "@ethereumjs/tx": "^5.4.0",
73
73
  "@ethereumjs/util": "^9.1.0",
74
+ "@ledgerhq/context-module": "2.1.0",
75
+ "@ledgerhq/device-management-kit": "1.5.1",
76
+ "@ledgerhq/device-signer-kit-ethereum": "1.16.0",
74
77
  "@ledgerhq/hw-app-eth": "^6.42.0",
75
78
  "@ledgerhq/hw-transport": "^6.31.3",
76
79
  "@metamask/eth-sig-util": "^8.2.0",
77
80
  "@metamask/hw-wallet-sdk": "^0.8.0",
78
- "@metamask/keyring-api": "^23.1.0",
79
- "@metamask/keyring-sdk": "^2.1.1",
80
- "hdkey": "^2.1.0"
81
+ "@metamask/keyring-api": "^23.3.0",
82
+ "@metamask/keyring-sdk": "^2.2.0",
83
+ "hdkey": "^2.1.0",
84
+ "rxjs": "^7.8.2"
81
85
  },
82
86
  "devDependencies": {
83
87
  "@ethereumjs/common": "^4.4.0",
@@ -94,8 +98,8 @@
94
98
  "@types/ethereumjs-tx": "^1.0.1",
95
99
  "@types/hdkey": "^2.0.1",
96
100
  "@types/jest": "^29.5.12",
97
- "@types/node": "^20.12.12",
98
101
  "@types/web": "^0.0.69",
102
+ "@types/ws": "^8.18.1",
99
103
  "deepmerge": "^4.2.2",
100
104
  "depcheck": "^1.4.7",
101
105
  "ethereum-cryptography": "^2.2.1",