@metamask/eth-hd-keyring 13.1.0 → 13.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/dist/hd-keyring-v2.cjs +6 -5
- package/dist/hd-keyring-v2.cjs.map +1 -1
- package/dist/hd-keyring-v2.d.cts +2 -1
- package/dist/hd-keyring-v2.d.cts.map +1 -1
- package/dist/hd-keyring-v2.d.mts +2 -1
- package/dist/hd-keyring-v2.d.mts.map +1 -1
- package/dist/hd-keyring-v2.mjs +2 -1
- package/dist/hd-keyring-v2.mjs.map +1 -1
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [13.1.1]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Add new dependency `@metamask/keyring-sdk@1.2.0` ([#478](https://github.com/MetaMask/accounts/pull/478)), ([#482](https://github.com/MetaMask/accounts/pull/482)), ([#496](https://github.com/MetaMask/accounts/pull/496)), ([#509](https://github.com/MetaMask/accounts/pull/509))
|
|
15
|
+
- This package now contains the keyring v2 wrapper helpers (`EthKeyringWrapper`, `EthKeyringMethod`).
|
|
16
|
+
- The account ID (generated by `KeyringAccountRegistry`) are now deterministic for EVM addresses.
|
|
17
|
+
- Bump `@metamask/keyring-api` from `^21.6.0` to `^22.0.0` ([#482](https://github.com/MetaMask/accounts/pull/482))
|
|
18
|
+
- Bump `@metamask/account-api` from `^1.0.0` to `^1.0.1` ([#487](https://github.com/MetaMask/accounts/pull/487))
|
|
19
|
+
- Bump `@metamask/utils` from `^11.1.0` to `^11.10.0` ([#489](https://github.com/MetaMask/accounts/pull/489))
|
|
20
|
+
|
|
10
21
|
## [13.1.0]
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -235,7 +246,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
235
246
|
- Deserialize method (and `HdKeyring` constructor by extension) can no longer be passed an options object containing a value for `numberOfAccounts` if it is not also containing a value for `mnemonic`.
|
|
236
247
|
- Package name changed from `eth-hd-keyring` to `@metamask/eth-hd-keyring`.
|
|
237
248
|
|
|
238
|
-
[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-hd-keyring@13.1.
|
|
249
|
+
[Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-hd-keyring@13.1.1...HEAD
|
|
250
|
+
[13.1.1]: https://github.com/MetaMask/accounts/compare/@metamask/eth-hd-keyring@13.1.0...@metamask/eth-hd-keyring@13.1.1
|
|
239
251
|
[13.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-hd-keyring@13.0.0...@metamask/eth-hd-keyring@13.1.0
|
|
240
252
|
[13.0.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-hd-keyring@12.1.0...@metamask/eth-hd-keyring@13.0.0
|
|
241
253
|
[12.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-hd-keyring@12.0.0...@metamask/eth-hd-keyring@12.1.0
|
package/dist/hd-keyring-v2.cjs
CHANGED
|
@@ -8,6 +8,7 @@ var _HdKeyringV2_instances, _HdKeyringV2_isLastAccount, _HdKeyringV2_createKeyri
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.HdKeyringV2 = void 0;
|
|
10
10
|
const keyring_api_1 = require("@metamask/keyring-api");
|
|
11
|
+
const keyring_sdk_1 = require("@metamask/keyring-sdk");
|
|
11
12
|
const utils_1 = require("@metamask/utils");
|
|
12
13
|
/**
|
|
13
14
|
* Methods supported by HD keyring EOA accounts.
|
|
@@ -20,10 +21,10 @@ const HD_KEYRING_METHODS = [
|
|
|
20
21
|
keyring_api_1.EthMethod.SignTypedDataV1,
|
|
21
22
|
keyring_api_1.EthMethod.SignTypedDataV3,
|
|
22
23
|
keyring_api_1.EthMethod.SignTypedDataV4,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
keyring_sdk_1.EthKeyringMethod.Decrypt,
|
|
25
|
+
keyring_sdk_1.EthKeyringMethod.GetEncryptionPublicKey,
|
|
26
|
+
keyring_sdk_1.EthKeyringMethod.GetAppKeyAddress,
|
|
27
|
+
keyring_sdk_1.EthKeyringMethod.SignEip7702Authorization,
|
|
27
28
|
];
|
|
28
29
|
const hdKeyringV2Capabilities = {
|
|
29
30
|
scopes: [keyring_api_1.EthScope.Eoa],
|
|
@@ -34,7 +35,7 @@ const hdKeyringV2Capabilities = {
|
|
|
34
35
|
exportFormats: [{ encoding: keyring_api_1.PrivateKeyEncoding.Hexadecimal }],
|
|
35
36
|
},
|
|
36
37
|
};
|
|
37
|
-
class HdKeyringV2 extends
|
|
38
|
+
class HdKeyringV2 extends keyring_sdk_1.EthKeyringWrapper {
|
|
38
39
|
constructor(options) {
|
|
39
40
|
super({
|
|
40
41
|
type: keyring_api_1.KeyringType.Hd,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hd-keyring-v2.cjs","sourceRoot":"","sources":["../src/hd-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringMethod,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type ExportAccountOptions,\n type ExportedAccount,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n PrivateKeyEncoding,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport { add0x, type Hex } from '@metamask/utils';\n\nimport type { HdKeyring } from './hd-keyring';\n\n/**\n * Methods supported by HD keyring EOA accounts.\n * HD keyrings support all standard signing methods plus encryption and app keys.\n */\nconst HD_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.Sign,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n EthKeyringMethod.Decrypt,\n EthKeyringMethod.GetEncryptionPublicKey,\n EthKeyringMethod.GetAppKeyAddress,\n EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst hdKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n bip44: {\n deriveIndex: true,\n },\n privateKey: {\n exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],\n },\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link HdKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * HD keyring via the unified V2 interface.\n */\nexport type HdKeyringV2Options = {\n legacyKeyring: HdKeyring;\n entropySource: EntropySourceId;\n};\n\nexport class HdKeyringV2\n extends EthKeyringWrapper<HdKeyring, Bip44Account<KeyringAccount>>\n implements KeyringV2\n{\n protected readonly entropySource: EntropySourceId;\n\n constructor(options: HdKeyringV2Options) {\n super({\n type: KeyringType.Hd,\n inner: options.legacyKeyring,\n capabilities: hdKeyringV2Capabilities,\n });\n this.entropySource = options.entropySource;\n }\n\n /**\n * Checks if the given address is the last account in the inner keyring.\n * This compares against the actual inner keyring state, not the registry,\n * to avoid issues with stale registry entries.\n *\n * @param address - The address to check.\n * @returns True if this is the last account in the inner keyring.\n */\n async #isLastAccount(address: string): Promise<boolean> {\n const innerAddresses = await this.inner.getAccounts();\n const lastAddress = innerAddresses[innerAddresses.length - 1];\n return address === lastAddress;\n }\n\n /**\n * Creates a KeyringAccount object for the given address and index.\n *\n * @param address - The account address.\n * @param addressIndex - The account index in the HD path.\n * @returns The created KeyringAccount.\n */\n #createKeyringAccount(\n address: Hex,\n addressIndex: number,\n ): Bip44Account<KeyringAccount> {\n const id = this.registry.register(address);\n\n const account: Bip44Account<KeyringAccount> = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...HD_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.Mnemonic,\n id: this.entropySource,\n groupIndex: addressIndex,\n derivationPath: `${this.inner.hdPath}/${addressIndex}`,\n },\n exportable: true,\n },\n };\n\n // Add the account to the registry\n this.registry.set(account);\n\n return account;\n }\n\n async getAccounts(): Promise<Bip44Account<KeyringAccount>[]> {\n const addresses = await this.inner.getAccounts();\n\n return addresses.map((address, addressIndex) => {\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 // Create and register the account if not already cached\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 // For HD keyring, we only support BIP-44 derive index\n if (options.type !== 'bip44:derive-index') {\n throw new Error(\n `Unsupported account creation type for HdKeyring: ${options.type}`,\n );\n }\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\n // Sync with the inner keyring state in case it was modified externally\n // This ensures our cache is up-to-date before we make changes\n const currentAccounts = await this.getAccounts();\n const currentCount = currentAccounts.length;\n const targetIndex = options.groupIndex;\n\n // Check if an account at this index already exists\n // Since only the last account can be deleted, array position always equals groupIndex\n const existingAccount = currentAccounts[targetIndex];\n if (existingAccount) {\n return [existingAccount];\n }\n\n // Only allow derivation of the next account in sequence\n if (targetIndex !== currentCount) {\n throw new Error(\n `Can only create the next account in sequence. ` +\n `Expected groupIndex ${currentCount}, got ${targetIndex}.`,\n );\n }\n\n // Add the next account\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 * ⚠️ Warning: Only deleting the last account is possible.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n // Get the account first, before any registry operations\n const { address } = await this.getAccount(accountId);\n const hexAddress = this.toHexAddress(address);\n\n // Assert that the account to delete is the last one in the inner keyring\n // We check against the inner keyring directly to avoid stale registry issues\n if (!(await this.#isLastAccount(address))) {\n throw new Error(\n 'Can only delete the last account in the HD keyring due to derivation index constraints.',\n );\n }\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 * Export the private key for an account in hexadecimal format.\n *\n * @param accountId - The ID of the account to export.\n * @param options - Export options (only hexadecimal encoding is supported).\n * @returns The exported account with private key.\n */\n async exportAccount(\n accountId: AccountId,\n options?: ExportAccountOptions,\n ): Promise<ExportedAccount> {\n const account = await this.getAccount(accountId);\n\n // Validate encoding - we only support hexadecimal for Ethereum keys\n const requestedEncoding =\n options?.encoding ?? PrivateKeyEncoding.Hexadecimal;\n\n if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for Ethereum HD keyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n // The legacy HdKeyring returns a hex string without 0x prefix.\n const privateKeyWithout0x = await this.inner.exportAccount(\n this.toHexAddress(account.address),\n );\n const privateKey = add0x(privateKeyWithout0x);\n\n return {\n type: 'private-key',\n privateKey,\n encoding: PrivateKeyEncoding.Hexadecimal,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hd-keyring-v2.cjs","sourceRoot":"","sources":["../src/hd-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 ExportAccountOptions,\n type ExportedAccount,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n PrivateKeyEncoding,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport { EthKeyringMethod, EthKeyringWrapper } from '@metamask/keyring-sdk';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport { add0x, type Hex } from '@metamask/utils';\n\nimport type { HdKeyring } from './hd-keyring';\n\n/**\n * Methods supported by HD keyring EOA accounts.\n * HD keyrings support all standard signing methods plus encryption and app keys.\n */\nconst HD_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.Sign,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n EthKeyringMethod.Decrypt,\n EthKeyringMethod.GetEncryptionPublicKey,\n EthKeyringMethod.GetAppKeyAddress,\n EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst hdKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n bip44: {\n deriveIndex: true,\n },\n privateKey: {\n exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],\n },\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link HdKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * HD keyring via the unified V2 interface.\n */\nexport type HdKeyringV2Options = {\n legacyKeyring: HdKeyring;\n entropySource: EntropySourceId;\n};\n\nexport class HdKeyringV2\n extends EthKeyringWrapper<HdKeyring, Bip44Account<KeyringAccount>>\n implements KeyringV2\n{\n protected readonly entropySource: EntropySourceId;\n\n constructor(options: HdKeyringV2Options) {\n super({\n type: KeyringType.Hd,\n inner: options.legacyKeyring,\n capabilities: hdKeyringV2Capabilities,\n });\n this.entropySource = options.entropySource;\n }\n\n /**\n * Checks if the given address is the last account in the inner keyring.\n * This compares against the actual inner keyring state, not the registry,\n * to avoid issues with stale registry entries.\n *\n * @param address - The address to check.\n * @returns True if this is the last account in the inner keyring.\n */\n async #isLastAccount(address: string): Promise<boolean> {\n const innerAddresses = await this.inner.getAccounts();\n const lastAddress = innerAddresses[innerAddresses.length - 1];\n return address === lastAddress;\n }\n\n /**\n * Creates a KeyringAccount object for the given address and index.\n *\n * @param address - The account address.\n * @param addressIndex - The account index in the HD path.\n * @returns The created KeyringAccount.\n */\n #createKeyringAccount(\n address: Hex,\n addressIndex: number,\n ): Bip44Account<KeyringAccount> {\n const id = this.registry.register(address);\n\n const account: Bip44Account<KeyringAccount> = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...HD_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.Mnemonic,\n id: this.entropySource,\n groupIndex: addressIndex,\n derivationPath: `${this.inner.hdPath}/${addressIndex}`,\n },\n exportable: true,\n },\n };\n\n // Add the account to the registry\n this.registry.set(account);\n\n return account;\n }\n\n async getAccounts(): Promise<Bip44Account<KeyringAccount>[]> {\n const addresses = await this.inner.getAccounts();\n\n return addresses.map((address, addressIndex) => {\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 // Create and register the account if not already cached\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 // For HD keyring, we only support BIP-44 derive index\n if (options.type !== 'bip44:derive-index') {\n throw new Error(\n `Unsupported account creation type for HdKeyring: ${options.type}`,\n );\n }\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\n // Sync with the inner keyring state in case it was modified externally\n // This ensures our cache is up-to-date before we make changes\n const currentAccounts = await this.getAccounts();\n const currentCount = currentAccounts.length;\n const targetIndex = options.groupIndex;\n\n // Check if an account at this index already exists\n // Since only the last account can be deleted, array position always equals groupIndex\n const existingAccount = currentAccounts[targetIndex];\n if (existingAccount) {\n return [existingAccount];\n }\n\n // Only allow derivation of the next account in sequence\n if (targetIndex !== currentCount) {\n throw new Error(\n `Can only create the next account in sequence. ` +\n `Expected groupIndex ${currentCount}, got ${targetIndex}.`,\n );\n }\n\n // Add the next account\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 * ⚠️ Warning: Only deleting the last account is possible.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n // Get the account first, before any registry operations\n const { address } = await this.getAccount(accountId);\n const hexAddress = this.toHexAddress(address);\n\n // Assert that the account to delete is the last one in the inner keyring\n // We check against the inner keyring directly to avoid stale registry issues\n if (!(await this.#isLastAccount(address))) {\n throw new Error(\n 'Can only delete the last account in the HD keyring due to derivation index constraints.',\n );\n }\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 * Export the private key for an account in hexadecimal format.\n *\n * @param accountId - The ID of the account to export.\n * @param options - Export options (only hexadecimal encoding is supported).\n * @returns The exported account with private key.\n */\n async exportAccount(\n accountId: AccountId,\n options?: ExportAccountOptions,\n ): Promise<ExportedAccount> {\n const account = await this.getAccount(accountId);\n\n // Validate encoding - we only support hexadecimal for Ethereum keys\n const requestedEncoding =\n options?.encoding ?? PrivateKeyEncoding.Hexadecimal;\n\n if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for Ethereum HD keyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n // The legacy HdKeyring returns a hex string without 0x prefix.\n const privateKeyWithout0x = await this.inner.exportAccount(\n this.toHexAddress(account.address),\n );\n const privateKey = add0x(privateKeyWithout0x);\n\n return {\n type: 'private-key',\n privateKey,\n encoding: PrivateKeyEncoding.Hexadecimal,\n };\n }\n}\n"]}
|
package/dist/hd-keyring-v2.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Bip44Account } from "@metamask/account-api";
|
|
2
|
-
import { type CreateAccountOptions,
|
|
2
|
+
import { type CreateAccountOptions, type ExportAccountOptions, type ExportedAccount, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
|
|
3
|
+
import { EthKeyringWrapper } from "@metamask/keyring-sdk";
|
|
3
4
|
import type { AccountId } from "@metamask/keyring-utils";
|
|
4
5
|
import type { HdKeyring } from "./hd-keyring.cjs";
|
|
5
6
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hd-keyring-v2.d.cts","sourceRoot":"","sources":["../src/hd-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"hd-keyring-v2.d.cts","sourceRoot":"","sources":["../src/hd-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAIzB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAGd,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,EAAoB,iBAAiB,EAAE,8BAA8B;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,gCAAgC;AAGzD,OAAO,KAAK,EAAE,SAAS,EAAE,yBAAqB;AA6B9C;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF,qBAAa,WACX,SAAQ,iBAAiB,CAAC,SAAS,EAAE,YAAY,CAAC,cAAc,CAAC,CACjE,YAAW,SAAS;;IAEpB,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAEtC,OAAO,EAAE,kBAAkB;IA2DjC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAkBtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAkD1C;;;;;;OAMG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBxD;;;;;;OAMG;IACG,aAAa,CACjB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,eAAe,CAAC;CAyB5B"}
|
package/dist/hd-keyring-v2.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Bip44Account } from "@metamask/account-api";
|
|
2
|
-
import { type CreateAccountOptions,
|
|
2
|
+
import { type CreateAccountOptions, type ExportAccountOptions, type ExportedAccount, type KeyringAccount, type KeyringV2, type EntropySourceId } from "@metamask/keyring-api";
|
|
3
|
+
import { EthKeyringWrapper } from "@metamask/keyring-sdk";
|
|
3
4
|
import type { AccountId } from "@metamask/keyring-utils";
|
|
4
5
|
import type { HdKeyring } from "./hd-keyring.mjs";
|
|
5
6
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hd-keyring-v2.d.mts","sourceRoot":"","sources":["../src/hd-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"hd-keyring-v2.d.mts","sourceRoot":"","sources":["../src/hd-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,EACL,KAAK,oBAAoB,EAIzB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAGd,KAAK,eAAe,EACrB,8BAA8B;AAC/B,OAAO,EAAoB,iBAAiB,EAAE,8BAA8B;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,gCAAgC;AAGzD,OAAO,KAAK,EAAE,SAAS,EAAE,yBAAqB;AA6B9C;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,aAAa,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF,qBAAa,WACX,SAAQ,iBAAiB,CAAC,SAAS,EAAE,YAAY,CAAC,cAAc,CAAC,CACjE,YAAW,SAAS;;IAEpB,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;gBAEtC,OAAO,EAAE,kBAAkB;IA2DjC,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAkBtD,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAkD1C;;;;;;OAMG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBxD;;;;;;OAMG;IACG,aAAa,CACjB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,eAAe,CAAC;CAyB5B"}
|
package/dist/hd-keyring-v2.mjs
CHANGED
|
@@ -4,7 +4,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
5
|
};
|
|
6
6
|
var _HdKeyringV2_instances, _HdKeyringV2_isLastAccount, _HdKeyringV2_createKeyringAccount;
|
|
7
|
-
import { EthAccountType,
|
|
7
|
+
import { EthAccountType, EthMethod, EthScope, KeyringAccountEntropyTypeOption, KeyringType, PrivateKeyEncoding } from "@metamask/keyring-api";
|
|
8
|
+
import { EthKeyringMethod, EthKeyringWrapper } from "@metamask/keyring-sdk";
|
|
8
9
|
import { add0x } from "@metamask/utils";
|
|
9
10
|
/**
|
|
10
11
|
* Methods supported by HD keyring EOA accounts.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hd-keyring-v2.mjs","sourceRoot":"","sources":["../src/hd-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringMethod,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type ExportAccountOptions,\n type ExportedAccount,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n PrivateKeyEncoding,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport { add0x, type Hex } from '@metamask/utils';\n\nimport type { HdKeyring } from './hd-keyring';\n\n/**\n * Methods supported by HD keyring EOA accounts.\n * HD keyrings support all standard signing methods plus encryption and app keys.\n */\nconst HD_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.Sign,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n EthKeyringMethod.Decrypt,\n EthKeyringMethod.GetEncryptionPublicKey,\n EthKeyringMethod.GetAppKeyAddress,\n EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst hdKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n bip44: {\n deriveIndex: true,\n },\n privateKey: {\n exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],\n },\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link HdKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * HD keyring via the unified V2 interface.\n */\nexport type HdKeyringV2Options = {\n legacyKeyring: HdKeyring;\n entropySource: EntropySourceId;\n};\n\nexport class HdKeyringV2\n extends EthKeyringWrapper<HdKeyring, Bip44Account<KeyringAccount>>\n implements KeyringV2\n{\n protected readonly entropySource: EntropySourceId;\n\n constructor(options: HdKeyringV2Options) {\n super({\n type: KeyringType.Hd,\n inner: options.legacyKeyring,\n capabilities: hdKeyringV2Capabilities,\n });\n this.entropySource = options.entropySource;\n }\n\n /**\n * Checks if the given address is the last account in the inner keyring.\n * This compares against the actual inner keyring state, not the registry,\n * to avoid issues with stale registry entries.\n *\n * @param address - The address to check.\n * @returns True if this is the last account in the inner keyring.\n */\n async #isLastAccount(address: string): Promise<boolean> {\n const innerAddresses = await this.inner.getAccounts();\n const lastAddress = innerAddresses[innerAddresses.length - 1];\n return address === lastAddress;\n }\n\n /**\n * Creates a KeyringAccount object for the given address and index.\n *\n * @param address - The account address.\n * @param addressIndex - The account index in the HD path.\n * @returns The created KeyringAccount.\n */\n #createKeyringAccount(\n address: Hex,\n addressIndex: number,\n ): Bip44Account<KeyringAccount> {\n const id = this.registry.register(address);\n\n const account: Bip44Account<KeyringAccount> = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...HD_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.Mnemonic,\n id: this.entropySource,\n groupIndex: addressIndex,\n derivationPath: `${this.inner.hdPath}/${addressIndex}`,\n },\n exportable: true,\n },\n };\n\n // Add the account to the registry\n this.registry.set(account);\n\n return account;\n }\n\n async getAccounts(): Promise<Bip44Account<KeyringAccount>[]> {\n const addresses = await this.inner.getAccounts();\n\n return addresses.map((address, addressIndex) => {\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 // Create and register the account if not already cached\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 // For HD keyring, we only support BIP-44 derive index\n if (options.type !== 'bip44:derive-index') {\n throw new Error(\n `Unsupported account creation type for HdKeyring: ${options.type}`,\n );\n }\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\n // Sync with the inner keyring state in case it was modified externally\n // This ensures our cache is up-to-date before we make changes\n const currentAccounts = await this.getAccounts();\n const currentCount = currentAccounts.length;\n const targetIndex = options.groupIndex;\n\n // Check if an account at this index already exists\n // Since only the last account can be deleted, array position always equals groupIndex\n const existingAccount = currentAccounts[targetIndex];\n if (existingAccount) {\n return [existingAccount];\n }\n\n // Only allow derivation of the next account in sequence\n if (targetIndex !== currentCount) {\n throw new Error(\n `Can only create the next account in sequence. ` +\n `Expected groupIndex ${currentCount}, got ${targetIndex}.`,\n );\n }\n\n // Add the next account\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 * ⚠️ Warning: Only deleting the last account is possible.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n // Get the account first, before any registry operations\n const { address } = await this.getAccount(accountId);\n const hexAddress = this.toHexAddress(address);\n\n // Assert that the account to delete is the last one in the inner keyring\n // We check against the inner keyring directly to avoid stale registry issues\n if (!(await this.#isLastAccount(address))) {\n throw new Error(\n 'Can only delete the last account in the HD keyring due to derivation index constraints.',\n );\n }\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 * Export the private key for an account in hexadecimal format.\n *\n * @param accountId - The ID of the account to export.\n * @param options - Export options (only hexadecimal encoding is supported).\n * @returns The exported account with private key.\n */\n async exportAccount(\n accountId: AccountId,\n options?: ExportAccountOptions,\n ): Promise<ExportedAccount> {\n const account = await this.getAccount(accountId);\n\n // Validate encoding - we only support hexadecimal for Ethereum keys\n const requestedEncoding =\n options?.encoding ?? PrivateKeyEncoding.Hexadecimal;\n\n if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for Ethereum HD keyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n // The legacy HdKeyring returns a hex string without 0x prefix.\n const privateKeyWithout0x = await this.inner.exportAccount(\n this.toHexAddress(account.address),\n );\n const privateKey = add0x(privateKeyWithout0x);\n\n return {\n type: 'private-key',\n privateKey,\n encoding: PrivateKeyEncoding.Hexadecimal,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hd-keyring-v2.mjs","sourceRoot":"","sources":["../src/hd-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 ExportAccountOptions,\n type ExportedAccount,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n PrivateKeyEncoding,\n type EntropySourceId,\n} from '@metamask/keyring-api';\nimport { EthKeyringMethod, EthKeyringWrapper } from '@metamask/keyring-sdk';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport { add0x, type Hex } from '@metamask/utils';\n\nimport type { HdKeyring } from './hd-keyring';\n\n/**\n * Methods supported by HD keyring EOA accounts.\n * HD keyrings support all standard signing methods plus encryption and app keys.\n */\nconst HD_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.Sign,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n EthKeyringMethod.Decrypt,\n EthKeyringMethod.GetEncryptionPublicKey,\n EthKeyringMethod.GetAppKeyAddress,\n EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst hdKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n bip44: {\n deriveIndex: true,\n },\n privateKey: {\n exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],\n },\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link HdKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * HD keyring via the unified V2 interface.\n */\nexport type HdKeyringV2Options = {\n legacyKeyring: HdKeyring;\n entropySource: EntropySourceId;\n};\n\nexport class HdKeyringV2\n extends EthKeyringWrapper<HdKeyring, Bip44Account<KeyringAccount>>\n implements KeyringV2\n{\n protected readonly entropySource: EntropySourceId;\n\n constructor(options: HdKeyringV2Options) {\n super({\n type: KeyringType.Hd,\n inner: options.legacyKeyring,\n capabilities: hdKeyringV2Capabilities,\n });\n this.entropySource = options.entropySource;\n }\n\n /**\n * Checks if the given address is the last account in the inner keyring.\n * This compares against the actual inner keyring state, not the registry,\n * to avoid issues with stale registry entries.\n *\n * @param address - The address to check.\n * @returns True if this is the last account in the inner keyring.\n */\n async #isLastAccount(address: string): Promise<boolean> {\n const innerAddresses = await this.inner.getAccounts();\n const lastAddress = innerAddresses[innerAddresses.length - 1];\n return address === lastAddress;\n }\n\n /**\n * Creates a KeyringAccount object for the given address and index.\n *\n * @param address - The account address.\n * @param addressIndex - The account index in the HD path.\n * @returns The created KeyringAccount.\n */\n #createKeyringAccount(\n address: Hex,\n addressIndex: number,\n ): Bip44Account<KeyringAccount> {\n const id = this.registry.register(address);\n\n const account: Bip44Account<KeyringAccount> = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...HD_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.Mnemonic,\n id: this.entropySource,\n groupIndex: addressIndex,\n derivationPath: `${this.inner.hdPath}/${addressIndex}`,\n },\n exportable: true,\n },\n };\n\n // Add the account to the registry\n this.registry.set(account);\n\n return account;\n }\n\n async getAccounts(): Promise<Bip44Account<KeyringAccount>[]> {\n const addresses = await this.inner.getAccounts();\n\n return addresses.map((address, addressIndex) => {\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 // Create and register the account if not already cached\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 // For HD keyring, we only support BIP-44 derive index\n if (options.type !== 'bip44:derive-index') {\n throw new Error(\n `Unsupported account creation type for HdKeyring: ${options.type}`,\n );\n }\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\n // Sync with the inner keyring state in case it was modified externally\n // This ensures our cache is up-to-date before we make changes\n const currentAccounts = await this.getAccounts();\n const currentCount = currentAccounts.length;\n const targetIndex = options.groupIndex;\n\n // Check if an account at this index already exists\n // Since only the last account can be deleted, array position always equals groupIndex\n const existingAccount = currentAccounts[targetIndex];\n if (existingAccount) {\n return [existingAccount];\n }\n\n // Only allow derivation of the next account in sequence\n if (targetIndex !== currentCount) {\n throw new Error(\n `Can only create the next account in sequence. ` +\n `Expected groupIndex ${currentCount}, got ${targetIndex}.`,\n );\n }\n\n // Add the next account\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 * ⚠️ Warning: Only deleting the last account is possible.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n // Get the account first, before any registry operations\n const { address } = await this.getAccount(accountId);\n const hexAddress = this.toHexAddress(address);\n\n // Assert that the account to delete is the last one in the inner keyring\n // We check against the inner keyring directly to avoid stale registry issues\n if (!(await this.#isLastAccount(address))) {\n throw new Error(\n 'Can only delete the last account in the HD keyring due to derivation index constraints.',\n );\n }\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 * Export the private key for an account in hexadecimal format.\n *\n * @param accountId - The ID of the account to export.\n * @param options - Export options (only hexadecimal encoding is supported).\n * @returns The exported account with private key.\n */\n async exportAccount(\n accountId: AccountId,\n options?: ExportAccountOptions,\n ): Promise<ExportedAccount> {\n const account = await this.getAccount(accountId);\n\n // Validate encoding - we only support hexadecimal for Ethereum keys\n const requestedEncoding =\n options?.encoding ?? PrivateKeyEncoding.Hexadecimal;\n\n if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for Ethereum HD keyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n // The legacy HdKeyring returns a hex string without 0x prefix.\n const privateKeyWithout0x = await this.inner.exportAccount(\n this.toHexAddress(account.address),\n );\n const privateKey = add0x(privateKeyWithout0x);\n\n return {\n type: 'private-key',\n privateKey,\n encoding: PrivateKeyEncoding.Hexadecimal,\n };\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/eth-hd-keyring",
|
|
3
|
-
"version": "13.1.
|
|
3
|
+
"version": "13.1.1",
|
|
4
4
|
"description": "A simple standard interface for a seed phrase generated set of Ethereum accounts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ethereum",
|
|
@@ -47,17 +47,18 @@
|
|
|
47
47
|
"@ethereumjs/util": "^9.1.0",
|
|
48
48
|
"@metamask/eth-sig-util": "^8.2.0",
|
|
49
49
|
"@metamask/key-tree": "^10.0.2",
|
|
50
|
-
"@metamask/keyring-api": "^
|
|
51
|
-
"@metamask/keyring-
|
|
50
|
+
"@metamask/keyring-api": "^22.0.0",
|
|
51
|
+
"@metamask/keyring-sdk": "^1.2.0",
|
|
52
|
+
"@metamask/keyring-utils": "^3.2.0",
|
|
52
53
|
"@metamask/scure-bip39": "^2.1.1",
|
|
53
54
|
"@metamask/superstruct": "^3.1.0",
|
|
54
|
-
"@metamask/utils": "^11.
|
|
55
|
+
"@metamask/utils": "^11.10.0",
|
|
55
56
|
"ethereum-cryptography": "^2.1.2"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@lavamoat/allow-scripts": "^3.2.1",
|
|
59
60
|
"@lavamoat/preinstall-always-fail": "^2.1.0",
|
|
60
|
-
"@metamask/account-api": "^0.
|
|
61
|
+
"@metamask/account-api": "^1.0.1",
|
|
61
62
|
"@metamask/auto-changelog": "^3.4.4",
|
|
62
63
|
"@metamask/bip39": "^4.0.0",
|
|
63
64
|
"@ts-bridge/cli": "^0.6.3",
|