@metamask/eth-ledger-bridge-keyring 11.4.0 → 12.0.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [12.0.0]
11
+
12
+ ### Added
13
+
14
+ - Add `./v2` subpath export for keyring v2 implementation ([#513](https://github.com/MetaMask/accounts/pull/513))
15
+ - `LedgerKeyring` and `LedgerKeyringOptions` are now available from `@metamask/eth-ledger-bridge-keyring/v2`.
16
+
17
+ ### Changed
18
+
19
+ - **BREAKING:** Move and rename `LedgerKeyringV2` and `LedgerKeyringV2Options` to the new `./v2` subpath export ([#513](https://github.com/MetaMask/accounts/pull/513))
20
+ - `LedgerKeyringV2` is now `LedgerKeyring` from `@metamask/eth-ledger-bridge-keyring/v2`.
21
+ - `LedgerKeyringV2Options` is now `LedgerKeyringOptions` from `@metamask/eth-ledger-bridge-keyring/v2`.
22
+ - Bump `@metamask/utils` from `^11.10.0` to `^11.11.0` ([#483](https://github.com/MetaMask/accounts/pull/483))
23
+ - Bump `@metamask/account-api` from `^1.0.1` to `^1.0.2` ([#515](https://github.com/MetaMask/accounts/pull/515))
24
+ - Bump `@metamask/keyring-api` from `^22.0.0` to `^23.0.0` ([#515](https://github.com/MetaMask/accounts/pull/515))
25
+ - Bump `@metamask/keyring-sdk` from `^1.2.0` to `^2.0.0` ([#515](https://github.com/MetaMask/accounts/pull/515))
26
+
27
+ ### Fixed
28
+
29
+ - Add dynamic NFT and ERC-20 check ([#506](https://github.com/MetaMask/accounts/pull/506))
30
+
10
31
  ## [11.4.0]
11
32
 
12
33
  ### Added
@@ -384,7 +405,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
384
405
 
385
406
  - Support new versions of ethereumjs/tx ([#68](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/68))
386
407
 
387
- [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.4.0...HEAD
408
+ [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@12.0.0...HEAD
409
+ [12.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.4.0...@metamask/eth-ledger-bridge-keyring@12.0.0
388
410
  [11.4.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-ledger-bridge-keyring@11.3.1...@metamask/eth-ledger-bridge-keyring@11.4.0
389
411
  [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
390
412
  [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
package/README.md CHANGED
@@ -19,6 +19,14 @@ The iframe is allowed to interact with the Ledger device (since U2F requires SSL
19
19
 
20
20
  The iframe code it's hosted in the same repo under the branch [gh-pages](https://github.com/MetaMask/eth-ledger-bridge-keyring/tree/gh-pages) and it's being served via github pages. In the future we might move it under the metamask.io domain.
21
21
 
22
+ ## Installation
23
+
24
+ `yarn add @metamask/eth-ledger-bridge-keyring`
25
+
26
+ or
27
+
28
+ `npm install @metamask/eth-ledger-bridge-keyring`
29
+
22
30
  ## Usage
23
31
 
24
32
  In addition to all the known methods from the [Keyring class protocol](https://github.com/MetaMask/eth-simple-keyring#the-keyring-class-protocol),
package/dist/index.cjs CHANGED
@@ -15,7 +15,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./ledger-keyring.cjs"), exports);
18
- __exportStar(require("./ledger-keyring-v2.cjs"), exports);
19
18
  __exportStar(require("./ledger-iframe-bridge.cjs"), exports);
20
19
  __exportStar(require("./ledger-mobile-bridge.cjs"), exports);
21
20
  __exportStar(require("./ledger-transport-middleware.cjs"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAiC;AACjC,0DAAoC;AACpC,6DAAuC;AACvC,6DAAuC;AAEvC,oEAA8C;AAE9C,sDAAgC;AAChC,+CAAyB;AACzB,6DAAuC;AACvC,kDAA4B;AAC5B,8CAAwB","sourcesContent":["export * from './ledger-keyring';\nexport * from './ledger-keyring-v2';\nexport * from './ledger-iframe-bridge';\nexport * from './ledger-mobile-bridge';\nexport type * from './ledger-bridge';\nexport * from './ledger-transport-middleware';\nexport type * from './type';\nexport * from './ledger-hw-app';\nexport * from './errors';\nexport * from './ledger-error-handler';\nexport * from './constants';\nexport * from './utils';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAiC;AACjC,6DAAuC;AACvC,6DAAuC;AAEvC,oEAA8C;AAE9C,sDAAgC;AAChC,+CAAyB;AACzB,6DAAuC;AACvC,kDAA4B;AAC5B,8CAAwB","sourcesContent":["export * from './ledger-keyring';\nexport * from './ledger-iframe-bridge';\nexport * from './ledger-mobile-bridge';\nexport type * from './ledger-bridge';\nexport * from './ledger-transport-middleware';\nexport type * from './type';\nexport * from './ledger-hw-app';\nexport * from './errors';\nexport * from './ledger-error-handler';\nexport * from './constants';\nexport * from './utils';\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./ledger-keyring.cjs";
2
- export * from "./ledger-keyring-v2.cjs";
3
2
  export * from "./ledger-iframe-bridge.cjs";
4
3
  export * from "./ledger-mobile-bridge.cjs";
5
4
  export type * from "./ledger-bridge.cjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,wCAAoC;AACpC,2CAAuC;AACvC,2CAAuC;AACvC,yCAAqC;AACrC,kDAA8C;AAC9C,gCAA4B;AAC5B,oCAAgC;AAChC,6BAAyB;AACzB,2CAAuC;AACvC,gCAA4B;AAC5B,4BAAwB"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,2CAAuC;AACvC,2CAAuC;AACvC,yCAAqC;AACrC,kDAA8C;AAC9C,gCAA4B;AAC5B,oCAAgC;AAChC,6BAAyB;AACzB,2CAAuC;AACvC,gCAA4B;AAC5B,4BAAwB"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./ledger-keyring.mjs";
2
- export * from "./ledger-keyring-v2.mjs";
3
2
  export * from "./ledger-iframe-bridge.mjs";
4
3
  export * from "./ledger-mobile-bridge.mjs";
5
4
  export type * from "./ledger-bridge.mjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,wCAAoC;AACpC,2CAAuC;AACvC,2CAAuC;AACvC,yCAAqC;AACrC,kDAA8C;AAC9C,gCAA4B;AAC5B,oCAAgC;AAChC,6BAAyB;AACzB,2CAAuC;AACvC,gCAA4B;AAC5B,4BAAwB"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,2CAAuC;AACvC,2CAAuC;AACvC,yCAAqC;AACrC,kDAA8C;AAC9C,gCAA4B;AAC5B,oCAAgC;AAChC,6BAAyB;AACzB,2CAAuC;AACvC,gCAA4B;AAC5B,4BAAwB"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./ledger-keyring.mjs";
2
- export * from "./ledger-keyring-v2.mjs";
3
2
  export * from "./ledger-iframe-bridge.mjs";
4
3
  export * from "./ledger-mobile-bridge.mjs";
5
4
  export * from "./ledger-transport-middleware.mjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,wCAAoC;AACpC,2CAAuC;AACvC,2CAAuC;AAEvC,kDAA8C;AAE9C,oCAAgC;AAChC,6BAAyB;AACzB,2CAAuC;AACvC,gCAA4B;AAC5B,4BAAwB","sourcesContent":["export * from './ledger-keyring';\nexport * from './ledger-keyring-v2';\nexport * from './ledger-iframe-bridge';\nexport * from './ledger-mobile-bridge';\nexport type * from './ledger-bridge';\nexport * from './ledger-transport-middleware';\nexport type * from './type';\nexport * from './ledger-hw-app';\nexport * from './errors';\nexport * from './ledger-error-handler';\nexport * from './constants';\nexport * from './utils';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAiC;AACjC,2CAAuC;AACvC,2CAAuC;AAEvC,kDAA8C;AAE9C,oCAAgC;AAChC,6BAAyB;AACzB,2CAAuC;AACvC,gCAA4B;AAC5B,4BAAwB","sourcesContent":["export * from './ledger-keyring';\nexport * from './ledger-iframe-bridge';\nexport * from './ledger-mobile-bridge';\nexport type * from './ledger-bridge';\nexport * from './ledger-transport-middleware';\nexport type * from './type';\nexport * from './ledger-hw-app';\nexport * from './errors';\nexport * from './ledger-error-handler';\nexport * from './constants';\nexport * from './utils';\n"]}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ledger-keyring.cjs"), exports);
18
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/v2/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAiC","sourcesContent":["export * from './ledger-keyring';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from "./ledger-keyring.cjs";
2
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/v2/index.ts"],"names":[],"mappings":"AAAA,qCAAiC"}
@@ -0,0 +1,2 @@
1
+ export * from "./ledger-keyring.mjs";
2
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/v2/index.ts"],"names":[],"mappings":"AAAA,qCAAiC"}
@@ -0,0 +1,2 @@
1
+ export * from "./ledger-keyring.mjs";
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/v2/index.ts"],"names":[],"mappings":"AAAA,qCAAiC","sourcesContent":["export * from './ledger-keyring';\n"]}
@@ -4,11 +4,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
5
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
6
  };
7
- var _LedgerKeyringV2_instances, _LedgerKeyringV2_getChecksumHexAddress, _LedgerKeyringV2_parseDerivationPath, _LedgerKeyringV2_getIndexForAddress, _LedgerKeyringV2_createKeyringAccount;
7
+ var _LedgerKeyring_instances, _LedgerKeyring_getChecksumHexAddress, _LedgerKeyring_parseDerivationPath, _LedgerKeyring_getIndexForAddress, _LedgerKeyring_createKeyringAccount;
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.LedgerKeyringV2 = void 0;
9
+ exports.LedgerKeyring = void 0;
10
10
  const keyring_api_1 = require("@metamask/keyring-api");
11
- const keyring_sdk_1 = require("@metamask/keyring-sdk");
11
+ const v2_1 = require("@metamask/keyring-api/v2");
12
+ const v2_2 = require("@metamask/keyring-sdk/v2");
12
13
  const utils_1 = require("@metamask/utils");
13
14
  /**
14
15
  * Methods supported by Ledger keyring EOA accounts.
@@ -19,7 +20,7 @@ const LEDGER_KEYRING_METHODS = [
19
20
  keyring_api_1.EthMethod.PersonalSign,
20
21
  keyring_api_1.EthMethod.SignTypedDataV4,
21
22
  ];
22
- const ledgerKeyringV2Capabilities = {
23
+ const ledgerKeyringCapabilities = {
23
24
  scopes: [keyring_api_1.EthScope.Eoa],
24
25
  bip44: {
25
26
  deriveIndex: true,
@@ -45,14 +46,14 @@ const LEDGER_LIVE_PATH_PATTERN = /^m\/44'\/60'\/(\d+)'\/0\/0$/u;
45
46
  * and custom paths that follow the m/44'/60'/... pattern.
46
47
  */
47
48
  const INDEX_AT_END_PATH_PATTERN = /^(m\/44'\/60'(?:\/\d+'?)*)\/(\d+)$/u;
48
- class LedgerKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
49
+ class LedgerKeyring extends v2_2.EthKeyringWrapper {
49
50
  constructor(options) {
50
51
  super({
51
- type: keyring_api_1.KeyringType.Ledger,
52
+ type: v2_1.KeyringType.Ledger,
52
53
  inner: options.legacyKeyring,
53
- capabilities: ledgerKeyringV2Capabilities,
54
+ capabilities: ledgerKeyringCapabilities,
54
55
  });
55
- _LedgerKeyringV2_instances.add(this);
56
+ _LedgerKeyring_instances.add(this);
56
57
  this.entropySource = options.entropySource;
57
58
  }
58
59
  async getAccounts() {
@@ -69,8 +70,8 @@ class LedgerKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
69
70
  return cached;
70
71
  }
71
72
  }
72
- const addressIndex = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_getIndexForAddress).call(this, address);
73
- return __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_createKeyringAccount).call(this, address, addressIndex);
73
+ const addressIndex = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_getIndexForAddress).call(this, address);
74
+ return __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_createKeyringAccount).call(this, address, addressIndex);
74
75
  });
75
76
  }
76
77
  async createAccounts(options) {
@@ -92,7 +93,7 @@ class LedgerKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
92
93
  let derivationPath;
93
94
  if (options.type === 'bip44:derive-path') {
94
95
  // Parse the derivation path to extract base path and index
95
- const parsed = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_parseDerivationPath).call(this, options.derivationPath);
96
+ const parsed = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_parseDerivationPath).call(this, options.derivationPath);
96
97
  targetIndex = parsed.index;
97
98
  basePath = parsed.basePath;
98
99
  derivationPath = options.derivationPath;
@@ -117,7 +118,7 @@ class LedgerKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
117
118
  if (!newAddress) {
118
119
  throw new Error('Failed to create new account');
119
120
  }
120
- const newAccount = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_createKeyringAccount).call(this, newAddress, targetIndex);
121
+ const newAccount = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_createKeyringAccount).call(this, newAddress, targetIndex);
121
122
  return [newAccount];
122
123
  });
123
124
  }
@@ -137,10 +138,10 @@ class LedgerKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
137
138
  });
138
139
  }
139
140
  }
140
- exports.LedgerKeyringV2 = LedgerKeyringV2;
141
- _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddress = function _LedgerKeyringV2_getChecksumHexAddress(address) {
141
+ exports.LedgerKeyring = LedgerKeyring;
142
+ _LedgerKeyring_instances = new WeakSet(), _LedgerKeyring_getChecksumHexAddress = function _LedgerKeyring_getChecksumHexAddress(address) {
142
143
  return (0, utils_1.getChecksumAddress)((0, utils_1.add0x)(address));
143
- }, _LedgerKeyringV2_parseDerivationPath = function _LedgerKeyringV2_parseDerivationPath(derivationPath) {
144
+ }, _LedgerKeyring_parseDerivationPath = function _LedgerKeyring_parseDerivationPath(derivationPath) {
144
145
  // Try Ledger Live format first: m/44'/60'/{index}'/0/0
145
146
  const ledgerLiveMatch = derivationPath.match(LEDGER_LIVE_PATH_PATTERN);
146
147
  if (ledgerLiveMatch?.[1]) {
@@ -166,8 +167,8 @@ _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddre
166
167
  }
167
168
  throw new Error(`Invalid derivation path format: ${derivationPath}. ` +
168
169
  `Expected Ledger Live (m/44'/60'/{index}'/0/0) or index-at-end (m/44'/60'/.../{index}) format.`);
169
- }, _LedgerKeyringV2_getIndexForAddress = function _LedgerKeyringV2_getIndexForAddress(address) {
170
- const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_getChecksumHexAddress).call(this, address);
170
+ }, _LedgerKeyring_getIndexForAddress = function _LedgerKeyring_getIndexForAddress(address) {
171
+ const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_getChecksumHexAddress).call(this, address);
171
172
  const details = this.inner.accountDetails[checksummedAddress];
172
173
  if (!details) {
173
174
  throw new Error(`Address ${checksummedAddress} not found in account details`);
@@ -200,9 +201,9 @@ _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddre
200
201
  }
201
202
  }
202
203
  throw new Error(`Could not extract index from HD path: ${hdPath}`);
203
- }, _LedgerKeyringV2_createKeyringAccount = function _LedgerKeyringV2_createKeyringAccount(address, addressIndex) {
204
+ }, _LedgerKeyring_createKeyringAccount = function _LedgerKeyring_createKeyringAccount(address, addressIndex) {
204
205
  const id = this.registry.register(address);
205
- const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_getChecksumHexAddress).call(this, address);
206
+ const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_getChecksumHexAddress).call(this, address);
206
207
  const details = this.inner.accountDetails[checksummedAddress];
207
208
  if (!details?.hdPath) {
208
209
  throw new Error(`No HD path found for address ${checksummedAddress}. Cannot create account.`);
@@ -225,4 +226,4 @@ _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddre
225
226
  this.registry.set(account);
226
227
  return account;
227
228
  };
228
- //# sourceMappingURL=ledger-keyring-v2.cjs.map
229
+ //# sourceMappingURL=ledger-keyring.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-keyring.cjs","sourceRoot":"","sources":["../../src/v2/ledger-keyring.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n EthAccountType,\n EthMethod,\n EthScope,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport {\n type CreateAccountOptions,\n type KeyringCapabilities,\n type Keyring,\n KeyringType,\n} from '@metamask/keyring-api/v2';\nimport { EthKeyringWrapper } from '@metamask/keyring-sdk/v2';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress, 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,25 +1,26 @@
1
1
  import type { Bip44Account } from "@metamask/account-api";
2
- import { type CreateAccountOptions, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
3
- import { EthKeyringWrapper } from "@metamask/keyring-sdk";
2
+ import { type KeyringAccount, type EntropySourceId } from "@metamask/keyring-api";
3
+ import { type CreateAccountOptions, type Keyring } from "@metamask/keyring-api/v2";
4
+ import { EthKeyringWrapper } from "@metamask/keyring-sdk/v2";
4
5
  import type { AccountId, EthKeyring } from "@metamask/keyring-utils";
5
- import type { LedgerKeyring } from "./ledger-keyring.mjs";
6
+ import type { LedgerKeyring as LegacyLedgerKeyring } from "../ledger-keyring.cjs";
6
7
  /**
7
- * Concrete {@link KeyringV2} adapter for {@link LedgerKeyring}.
8
+ * Concrete {@link Keyring} adapter for {@link LedgerKeyring}.
8
9
  *
9
10
  * This wrapper exposes the accounts and signing capabilities of the legacy
10
11
  * Ledger keyring via the unified V2 interface.
11
12
  *
12
13
  * All Ledger keyring accounts are BIP-44 derived from the device.
13
14
  */
14
- export type LedgerKeyringV2Options = {
15
- legacyKeyring: LedgerKeyring;
15
+ export type LedgerKeyringOptions = {
16
+ legacyKeyring: LegacyLedgerKeyring;
16
17
  entropySource: EntropySourceId;
17
18
  };
18
- type LedgerKeyringAsEthKeyring = LedgerKeyring & EthKeyring;
19
- export declare class LedgerKeyringV2 extends EthKeyringWrapper<LedgerKeyringAsEthKeyring, Bip44Account<KeyringAccount>> implements KeyringV2 {
19
+ type LedgerKeyringAsEthKeyring = LegacyLedgerKeyring & EthKeyring;
20
+ export declare class LedgerKeyring extends EthKeyringWrapper<LedgerKeyringAsEthKeyring, Bip44Account<KeyringAccount>> implements Keyring {
20
21
  #private;
21
22
  readonly entropySource: EntropySourceId;
22
- constructor(options: LedgerKeyringV2Options);
23
+ constructor(options: LedgerKeyringOptions);
23
24
  getAccounts(): Promise<Bip44Account<KeyringAccount>[]>;
24
25
  createAccounts(options: CreateAccountOptions): Promise<Bip44Account<KeyringAccount>[]>;
25
26
  /**
@@ -30,4 +31,4 @@ export declare class LedgerKeyringV2 extends EthKeyringWrapper<LedgerKeyringAsEt
30
31
  deleteAccount(accountId: AccountId): Promise<void>;
31
32
  }
32
33
  export {};
33
- //# sourceMappingURL=ledger-keyring-v2.d.mts.map
34
+ //# sourceMappingURL=ledger-keyring.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-keyring.d.cts","sourceRoot":"","sources":["../../src/v2/ledger-keyring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EAIL,KAAK,cAAc,EAEnB,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,OAAO,EAEb,iCAAiC;AAClC,OAAO,EAAE,iBAAiB,EAAE,iCAAiC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AAGrE,OAAO,KAAK,EAAE,aAAa,IAAI,mBAAmB,EAAE,8BAA0B;AA2C9E;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAKF,KAAK,yBAAyB,GAAG,mBAAmB,GAAG,UAAU,CAAC;AAElE,qBAAa,aACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,OAAO;;IAElB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,oBAAoB;IA2JnC,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,25 +1,26 @@
1
1
  import type { Bip44Account } from "@metamask/account-api";
2
- import { type CreateAccountOptions, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
3
- import { EthKeyringWrapper } from "@metamask/keyring-sdk";
2
+ import { type KeyringAccount, type EntropySourceId } from "@metamask/keyring-api";
3
+ import { type CreateAccountOptions, type Keyring } from "@metamask/keyring-api/v2";
4
+ import { EthKeyringWrapper } from "@metamask/keyring-sdk/v2";
4
5
  import type { AccountId, EthKeyring } from "@metamask/keyring-utils";
5
- import type { LedgerKeyring } from "./ledger-keyring.cjs";
6
+ import type { LedgerKeyring as LegacyLedgerKeyring } from "../ledger-keyring.mjs";
6
7
  /**
7
- * Concrete {@link KeyringV2} adapter for {@link LedgerKeyring}.
8
+ * Concrete {@link Keyring} adapter for {@link LedgerKeyring}.
8
9
  *
9
10
  * This wrapper exposes the accounts and signing capabilities of the legacy
10
11
  * Ledger keyring via the unified V2 interface.
11
12
  *
12
13
  * All Ledger keyring accounts are BIP-44 derived from the device.
13
14
  */
14
- export type LedgerKeyringV2Options = {
15
- legacyKeyring: LedgerKeyring;
15
+ export type LedgerKeyringOptions = {
16
+ legacyKeyring: LegacyLedgerKeyring;
16
17
  entropySource: EntropySourceId;
17
18
  };
18
- type LedgerKeyringAsEthKeyring = LedgerKeyring & EthKeyring;
19
- export declare class LedgerKeyringV2 extends EthKeyringWrapper<LedgerKeyringAsEthKeyring, Bip44Account<KeyringAccount>> implements KeyringV2 {
19
+ type LedgerKeyringAsEthKeyring = LegacyLedgerKeyring & EthKeyring;
20
+ export declare class LedgerKeyring extends EthKeyringWrapper<LedgerKeyringAsEthKeyring, Bip44Account<KeyringAccount>> implements Keyring {
20
21
  #private;
21
22
  readonly entropySource: EntropySourceId;
22
- constructor(options: LedgerKeyringV2Options);
23
+ constructor(options: LedgerKeyringOptions);
23
24
  getAccounts(): Promise<Bip44Account<KeyringAccount>[]>;
24
25
  createAccounts(options: CreateAccountOptions): Promise<Bip44Account<KeyringAccount>[]>;
25
26
  /**
@@ -30,4 +31,4 @@ export declare class LedgerKeyringV2 extends EthKeyringWrapper<LedgerKeyringAsEt
30
31
  deleteAccount(accountId: AccountId): Promise<void>;
31
32
  }
32
33
  export {};
33
- //# sourceMappingURL=ledger-keyring-v2.d.cts.map
34
+ //# sourceMappingURL=ledger-keyring.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-keyring.d.mts","sourceRoot":"","sources":["../../src/v2/ledger-keyring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EAIL,KAAK,cAAc,EAEnB,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,OAAO,EAEb,iCAAiC;AAClC,OAAO,EAAE,iBAAiB,EAAE,iCAAiC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gCAAgC;AAGrE,OAAO,KAAK,EAAE,aAAa,IAAI,mBAAmB,EAAE,8BAA0B;AA2C9E;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAKF,KAAK,yBAAyB,GAAG,mBAAmB,GAAG,UAAU,CAAC;AAElE,qBAAa,aACX,SAAQ,iBAAiB,CACvB,yBAAyB,EACzB,YAAY,CAAC,cAAc,CAAC,CAE9B,YAAW,OAAO;;IAElB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAE5B,OAAO,EAAE,oBAAoB;IA2JnC,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"}
@@ -3,9 +3,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _LedgerKeyringV2_instances, _LedgerKeyringV2_getChecksumHexAddress, _LedgerKeyringV2_parseDerivationPath, _LedgerKeyringV2_getIndexForAddress, _LedgerKeyringV2_createKeyringAccount;
7
- import { EthAccountType, EthMethod, EthScope, KeyringAccountEntropyTypeOption, KeyringType } from "@metamask/keyring-api";
8
- import { EthKeyringWrapper } from "@metamask/keyring-sdk";
6
+ var _LedgerKeyring_instances, _LedgerKeyring_getChecksumHexAddress, _LedgerKeyring_parseDerivationPath, _LedgerKeyring_getIndexForAddress, _LedgerKeyring_createKeyringAccount;
7
+ import { EthAccountType, EthMethod, EthScope, KeyringAccountEntropyTypeOption } from "@metamask/keyring-api";
8
+ import { KeyringType } from "@metamask/keyring-api/v2";
9
+ import { EthKeyringWrapper } from "@metamask/keyring-sdk/v2";
9
10
  import { add0x, getChecksumAddress } from "@metamask/utils";
10
11
  /**
11
12
  * Methods supported by Ledger keyring EOA accounts.
@@ -16,7 +17,7 @@ const LEDGER_KEYRING_METHODS = [
16
17
  EthMethod.PersonalSign,
17
18
  EthMethod.SignTypedDataV4,
18
19
  ];
19
- const ledgerKeyringV2Capabilities = {
20
+ const ledgerKeyringCapabilities = {
20
21
  scopes: [EthScope.Eoa],
21
22
  bip44: {
22
23
  deriveIndex: true,
@@ -42,14 +43,14 @@ const LEDGER_LIVE_PATH_PATTERN = /^m\/44'\/60'\/(\d+)'\/0\/0$/u;
42
43
  * and custom paths that follow the m/44'/60'/... pattern.
43
44
  */
44
45
  const INDEX_AT_END_PATH_PATTERN = /^(m\/44'\/60'(?:\/\d+'?)*)\/(\d+)$/u;
45
- export class LedgerKeyringV2 extends EthKeyringWrapper {
46
+ export class LedgerKeyring extends EthKeyringWrapper {
46
47
  constructor(options) {
47
48
  super({
48
49
  type: KeyringType.Ledger,
49
50
  inner: options.legacyKeyring,
50
- capabilities: ledgerKeyringV2Capabilities,
51
+ capabilities: ledgerKeyringCapabilities,
51
52
  });
52
- _LedgerKeyringV2_instances.add(this);
53
+ _LedgerKeyring_instances.add(this);
53
54
  this.entropySource = options.entropySource;
54
55
  }
55
56
  async getAccounts() {
@@ -66,8 +67,8 @@ export class LedgerKeyringV2 extends EthKeyringWrapper {
66
67
  return cached;
67
68
  }
68
69
  }
69
- const addressIndex = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_getIndexForAddress).call(this, address);
70
- return __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_createKeyringAccount).call(this, address, addressIndex);
70
+ const addressIndex = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_getIndexForAddress).call(this, address);
71
+ return __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_createKeyringAccount).call(this, address, addressIndex);
71
72
  });
72
73
  }
73
74
  async createAccounts(options) {
@@ -89,7 +90,7 @@ export class LedgerKeyringV2 extends EthKeyringWrapper {
89
90
  let derivationPath;
90
91
  if (options.type === 'bip44:derive-path') {
91
92
  // Parse the derivation path to extract base path and index
92
- const parsed = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_parseDerivationPath).call(this, options.derivationPath);
93
+ const parsed = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_parseDerivationPath).call(this, options.derivationPath);
93
94
  targetIndex = parsed.index;
94
95
  basePath = parsed.basePath;
95
96
  derivationPath = options.derivationPath;
@@ -114,7 +115,7 @@ export class LedgerKeyringV2 extends EthKeyringWrapper {
114
115
  if (!newAddress) {
115
116
  throw new Error('Failed to create new account');
116
117
  }
117
- const newAccount = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_createKeyringAccount).call(this, newAddress, targetIndex);
118
+ const newAccount = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_createKeyringAccount).call(this, newAddress, targetIndex);
118
119
  return [newAccount];
119
120
  });
120
121
  }
@@ -134,9 +135,9 @@ export class LedgerKeyringV2 extends EthKeyringWrapper {
134
135
  });
135
136
  }
136
137
  }
137
- _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddress = function _LedgerKeyringV2_getChecksumHexAddress(address) {
138
+ _LedgerKeyring_instances = new WeakSet(), _LedgerKeyring_getChecksumHexAddress = function _LedgerKeyring_getChecksumHexAddress(address) {
138
139
  return getChecksumAddress(add0x(address));
139
- }, _LedgerKeyringV2_parseDerivationPath = function _LedgerKeyringV2_parseDerivationPath(derivationPath) {
140
+ }, _LedgerKeyring_parseDerivationPath = function _LedgerKeyring_parseDerivationPath(derivationPath) {
140
141
  // Try Ledger Live format first: m/44'/60'/{index}'/0/0
141
142
  const ledgerLiveMatch = derivationPath.match(LEDGER_LIVE_PATH_PATTERN);
142
143
  if (ledgerLiveMatch?.[1]) {
@@ -162,8 +163,8 @@ _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddre
162
163
  }
163
164
  throw new Error(`Invalid derivation path format: ${derivationPath}. ` +
164
165
  `Expected Ledger Live (m/44'/60'/{index}'/0/0) or index-at-end (m/44'/60'/.../{index}) format.`);
165
- }, _LedgerKeyringV2_getIndexForAddress = function _LedgerKeyringV2_getIndexForAddress(address) {
166
- const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_getChecksumHexAddress).call(this, address);
166
+ }, _LedgerKeyring_getIndexForAddress = function _LedgerKeyring_getIndexForAddress(address) {
167
+ const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_getChecksumHexAddress).call(this, address);
167
168
  const details = this.inner.accountDetails[checksummedAddress];
168
169
  if (!details) {
169
170
  throw new Error(`Address ${checksummedAddress} not found in account details`);
@@ -196,9 +197,9 @@ _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddre
196
197
  }
197
198
  }
198
199
  throw new Error(`Could not extract index from HD path: ${hdPath}`);
199
- }, _LedgerKeyringV2_createKeyringAccount = function _LedgerKeyringV2_createKeyringAccount(address, addressIndex) {
200
+ }, _LedgerKeyring_createKeyringAccount = function _LedgerKeyring_createKeyringAccount(address, addressIndex) {
200
201
  const id = this.registry.register(address);
201
- const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyringV2_instances, "m", _LedgerKeyringV2_getChecksumHexAddress).call(this, address);
202
+ const checksummedAddress = __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_getChecksumHexAddress).call(this, address);
202
203
  const details = this.inner.accountDetails[checksummedAddress];
203
204
  if (!details?.hdPath) {
204
205
  throw new Error(`No HD path found for address ${checksummedAddress}. Cannot create account.`);
@@ -221,4 +222,4 @@ _LedgerKeyringV2_instances = new WeakSet(), _LedgerKeyringV2_getChecksumHexAddre
221
222
  this.registry.set(account);
222
223
  return account;
223
224
  };
224
- //# sourceMappingURL=ledger-keyring-v2.mjs.map
225
+ //# sourceMappingURL=ledger-keyring.mjs.map
@@ -0,0 +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 type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport {\n type CreateAccountOptions,\n type KeyringCapabilities,\n type Keyring,\n KeyringType,\n} from '@metamask/keyring-api/v2';\nimport { EthKeyringWrapper } from '@metamask/keyring-sdk/v2';\nimport type { AccountId, EthKeyring } from '@metamask/keyring-utils';\nimport { add0x, getChecksumAddress, 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/eth-ledger-bridge-keyring",
3
- "version": "11.4.0",
3
+ "version": "12.0.0",
4
4
  "description": "A MetaMask compatible keyring, for ledger hardware wallets",
5
5
  "keywords": [
6
6
  "ethereum",
@@ -8,15 +8,16 @@
8
8
  "ledger",
9
9
  "metamask"
10
10
  ],
11
- "homepage": "https://github.com/MetaMask/eth-ledger-bridge-keyring#readme",
11
+ "homepage": "https://github.com/MetaMask/accounts/tree/main/packages/keyring-eth-ledger-bridge#readme",
12
12
  "bugs": {
13
- "url": "https://github.com/MetaMask/eth-ledger-bridge-keyring/issues"
13
+ "url": "https://github.com/MetaMask/accounts/issues"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/MetaMask/eth-ledger-bridge-keyring.git"
17
+ "url": "https://github.com/MetaMask/accounts.git"
18
18
  },
19
19
  "license": "ISC",
20
+ "sideEffects": false,
20
21
  "exports": {
21
22
  ".": {
22
23
  "import": {
@@ -27,7 +28,18 @@
27
28
  "types": "./dist/index.d.cts",
28
29
  "default": "./dist/index.cjs"
29
30
  }
30
- }
31
+ },
32
+ "./v2": {
33
+ "import": {
34
+ "types": "./dist/v2/index.d.mts",
35
+ "default": "./dist/v2/index.mjs"
36
+ },
37
+ "require": {
38
+ "types": "./dist/v2/index.d.cts",
39
+ "default": "./dist/v2/index.cjs"
40
+ }
41
+ },
42
+ "./package.json": "./package.json"
31
43
  },
32
44
  "main": "./dist/index.cjs",
33
45
  "types": "./dist/index.d.cts",
@@ -35,15 +47,20 @@
35
47
  "dist/"
36
48
  ],
37
49
  "scripts": {
38
- "build": "ts-bridge --project tsconfig.build.json --no-references",
50
+ "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references",
51
+ "build:all": "ts-bridge --project tsconfig.build.json --verbose --clean",
39
52
  "build:clean": "yarn build --clean",
40
53
  "build:docs": "typedoc",
41
54
  "changelog:update": "../../scripts/update-changelog.sh @metamask/eth-ledger-bridge-keyring",
42
55
  "changelog:validate": "../../scripts/validate-changelog.sh @metamask/eth-ledger-bridge-keyring",
43
56
  "publish:preview": "yarn npm publish --tag preview",
44
- "test": "jest && jest-it-up",
45
- "test:clean": "jest --clearCache",
46
- "test:watch": "jest --watch"
57
+ "since-latest-release": "../../scripts/since-latest-release.sh",
58
+ "test": "yarn test:source && yarn test:types",
59
+ "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache",
60
+ "test:source": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",
61
+ "test:types": "../../scripts/tsd-test.sh ./src",
62
+ "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
63
+ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
47
64
  },
48
65
  "dependencies": {
49
66
  "@ethereumjs/rlp": "^5.0.2",
@@ -52,9 +69,8 @@
52
69
  "@ledgerhq/hw-app-eth": "^6.42.0",
53
70
  "@metamask/eth-sig-util": "^8.2.0",
54
71
  "@metamask/hw-wallet-sdk": "^0.8.0",
55
- "@metamask/keyring-api": "^22.0.0",
56
- "@metamask/keyring-sdk": "^1.2.0",
57
- "@metamask/keyring-utils": "^3.2.0",
72
+ "@metamask/keyring-api": "^23.0.0",
73
+ "@metamask/keyring-sdk": "^2.0.0",
58
74
  "hdkey": "^2.1.0"
59
75
  },
60
76
  "devDependencies": {
@@ -65,10 +81,10 @@
65
81
  "@ledgerhq/types-cryptoassets": "^7.15.1",
66
82
  "@ledgerhq/types-devices": "^6.25.3",
67
83
  "@ledgerhq/types-live": "^6.52.0",
68
- "@metamask/account-api": "^1.0.1",
84
+ "@metamask/account-api": "^1.0.2",
69
85
  "@metamask/auto-changelog": "^3.4.4",
70
86
  "@metamask/keyring-utils": "^3.2.0",
71
- "@metamask/utils": "^11.10.0",
87
+ "@metamask/utils": "^11.11.0",
72
88
  "@ts-bridge/cli": "^0.6.3",
73
89
  "@types/ethereumjs-tx": "^1.0.1",
74
90
  "@types/hdkey": "^2.0.1",
@@ -1 +0,0 @@
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 +0,0 @@
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 +0,0 @@
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"}
@@ -1 +0,0 @@
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"]}