From cfc72a6fc23050a5d95000714cb52f3e73d878bd Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Fri, 21 Feb 2025 15:07:08 +0100 Subject: [PATCH 01/14] fix: `Keyring.signTypedData` accepts types for V1 --- .../src/ledger-keyring.ts | 12 +++++++---- .../keyring-eth-simple/src/simple-keyring.ts | 21 +++++++++++++------ .../keyring-eth-trezor/src/trezor-keyring.ts | 10 ++++++--- packages/keyring-utils/src/keyring.ts | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts index 4155a384..ed5d6208 100644 --- a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts +++ b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts @@ -484,12 +484,16 @@ export class LedgerKeyring implements Keyring { return hdPath; } - async signTypedData<T extends MessageTypes>( + async signTypedData< + Version extends SignTypedDataVersion.V4, + Types extends MessageTypes, + Options extends { version?: Version }, + >( withAccount: Hex, - data: TypedMessage<T>, - options: { version?: string } = {}, + data: TypedMessage<Types>, + options: Options, ): Promise<string> { - const isV4 = options.version === 'V4'; + const isV4 = options?.version === 'V4'; if (!isV4) { throw new Error( 'Ledger: Only version 4 of typed data signing is supported', diff --git a/packages/keyring-eth-simple/src/simple-keyring.ts b/packages/keyring-eth-simple/src/simple-keyring.ts index 8b7410bd..dc46e9ad 100644 --- a/packages/keyring-eth-simple/src/simple-keyring.ts +++ b/packages/keyring-eth-simple/src/simple-keyring.ts @@ -10,6 +10,9 @@ import { toBuffer, } from '@ethereumjs/util'; import { + type TypedDataV1, + type MessageTypes, + type TypedMessage, concatSig, decrypt, EIP7702Authorization, @@ -147,17 +150,23 @@ export default class SimpleKeyring implements Keyring { return decrypt({ privateKey, encryptedData }); } - // personal_signTypedData, signs data along with the schema - async signTypedData( + async signTypedData< + Version extends SignTypedDataVersion, + Types extends MessageTypes, + Options extends { version: Version } & KeyringOpt, + >( address: Hex, - typedData: any, - opts: KeyringOpt = { version: SignTypedDataVersion.V1 }, + typedData: Version extends SignTypedDataVersion.V1 + ? TypedDataV1 + : TypedMessage<Types>, + opts?: Options, ): Promise<string> { + const options = opts ?? { version: SignTypedDataVersion.V1 }; // Treat invalid versions as "V1" let version = SignTypedDataVersion.V1; - if (opts.version && isSignTypedDataVersion(opts.version)) { - version = SignTypedDataVersion[opts.version]; + if (options.version && isSignTypedDataVersion(options.version)) { + version = SignTypedDataVersion[options.version]; } const privateKey = this.#getPrivateKeyFor(address, opts); diff --git a/packages/keyring-eth-trezor/src/trezor-keyring.ts b/packages/keyring-eth-trezor/src/trezor-keyring.ts index 203864c1..ca3d7111 100644 --- a/packages/keyring-eth-trezor/src/trezor-keyring.ts +++ b/packages/keyring-eth-trezor/src/trezor-keyring.ts @@ -453,10 +453,14 @@ export class TrezorKeyring implements Keyring { } // EIP-712 Sign Typed Data - async signTypedData<T extends MessageTypes>( + async signTypedData< + Version extends SignTypedDataVersion.V3 | SignTypedDataVersion.V4, + Types extends MessageTypes, + Options extends { version?: Version }, + >( address: Hex, - data: TypedMessage<T>, - { version }: { version: SignTypedDataVersion }, + data: TypedMessage<Types>, + { version }: Options, ): Promise<string> { const dataWithHashes = transformTypedData( data, diff --git a/packages/keyring-utils/src/keyring.ts b/packages/keyring-utils/src/keyring.ts index a523e3ce..9859d128 100644 --- a/packages/keyring-utils/src/keyring.ts +++ b/packages/keyring-utils/src/keyring.ts @@ -229,7 +229,7 @@ export type Keyring = { */ signTypedData?( address: Hex, - typedData: Record<string, unknown>, + typedData: unknown[] | Record<string, unknown>, options?: Record<string, unknown>, ): Promise<string>; From affd252f1f75f48910850caf30f2df2710c10819 Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Fri, 21 Feb 2025 15:16:27 +0100 Subject: [PATCH 02/14] refactor: change hdkeyring type --- packages/keyring-eth-hd/src/index.ts | 17 ++++++++++------- .../keyring-eth-simple/src/simple-keyring.ts | 4 +--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/keyring-eth-hd/src/index.ts b/packages/keyring-eth-hd/src/index.ts index f340593d..3febef5e 100644 --- a/packages/keyring-eth-hd/src/index.ts +++ b/packages/keyring-eth-hd/src/index.ts @@ -349,16 +349,19 @@ class HdKeyring { * @param opts - The options for signing the message. * @returns The signature of the message. */ - async signTypedData<Types extends MessageTypes>( + async signTypedData< + Version extends SignTypedDataVersion, + Types extends MessageTypes, + Options extends { version: Version }, + >( withAccount: Hex, - typedData: TypedDataV1 | TypedMessage<Types>, - opts: HDKeyringAccountSelectionOptions & { - version: SignTypedDataVersion; - } = { version: SignTypedDataVersion.V1 }, + typedData: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, + opts?: HDKeyringAccountSelectionOptions & Options, ): Promise<string> { + const options = opts ?? { version: SignTypedDataVersion.V1 }; // Treat invalid versions as "V1" - const version = Object.keys(SignTypedDataVersion).includes(opts.version) - ? opts.version + const version = Object.keys(SignTypedDataVersion).includes(options.version) + ? options.version : SignTypedDataVersion.V1; const privateKey = this.#getPrivateKeyFor(withAccount, opts); diff --git a/packages/keyring-eth-simple/src/simple-keyring.ts b/packages/keyring-eth-simple/src/simple-keyring.ts index dc46e9ad..87ea28a0 100644 --- a/packages/keyring-eth-simple/src/simple-keyring.ts +++ b/packages/keyring-eth-simple/src/simple-keyring.ts @@ -156,9 +156,7 @@ export default class SimpleKeyring implements Keyring { Options extends { version: Version } & KeyringOpt, >( address: Hex, - typedData: Version extends SignTypedDataVersion.V1 - ? TypedDataV1 - : TypedMessage<Types>, + typedData: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, opts?: Options, ): Promise<string> { const options = opts ?? { version: SignTypedDataVersion.V1 }; From a20af8580e731d10a9893e56e62cfd305d3c28ca Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Fri, 21 Feb 2025 15:28:32 +0100 Subject: [PATCH 03/14] test: fix ledger tests --- .../keyring-eth-ledger-bridge/src/ledger-keyring.test.ts | 4 ++-- packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts index 0297a89b..81425428 100644 --- a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts +++ b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts @@ -968,7 +968,7 @@ describe('LedgerKeyring', function () { ], }, }; - const options = { version: 'V4' }; + const options = { version: sigUtil.SignTypedDataVersion.V4 }; beforeEach(async function () { jest @@ -1043,7 +1043,7 @@ describe('LedgerKeyring', function () { it('throws an error if the signTypedData version is not v4', async function () { await expect( keyring.signTypedData(fakeAccounts[0], fixtureData, { - version: 'V3', + version: sigUtil.SignTypedDataVersion.V3, }), ).rejects.toThrow( 'Ledger: Only version 4 of typed data signing is supported', diff --git a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts index ed5d6208..7d030b75 100644 --- a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts +++ b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts @@ -485,15 +485,16 @@ export class LedgerKeyring implements Keyring { } async signTypedData< - Version extends SignTypedDataVersion.V4, + Version extends SignTypedDataVersion, Types extends MessageTypes, Options extends { version?: Version }, >( withAccount: Hex, data: TypedMessage<Types>, - options: Options, + options?: Options, ): Promise<string> { - const isV4 = options?.version === 'V4'; + const { version } = options ?? {}; + const isV4 = version === 'V4'; if (!isV4) { throw new Error( 'Ledger: Only version 4 of typed data signing is supported', From fc6bec1bfc2ba9c167878eb073590025a1ef5fcb Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Fri, 21 Feb 2025 15:47:53 +0100 Subject: [PATCH 04/14] test: fix simple keyring tests --- .../keyring-eth-simple/src/simple-keyring.test.ts | 11 ++++++----- packages/keyring-eth-simple/src/simple-keyring.ts | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/keyring-eth-simple/src/simple-keyring.test.ts b/packages/keyring-eth-simple/src/simple-keyring.test.ts index 6a35b429..1fe6a51d 100644 --- a/packages/keyring-eth-simple/src/simple-keyring.test.ts +++ b/packages/keyring-eth-simple/src/simple-keyring.test.ts @@ -360,6 +360,7 @@ describe('simple-keyring', function () { it('returns the expected value if invalid version is given', async function () { await keyring.deserialize([privKeyHex]); const signature = await keyring.signTypedData(address, typedData, { + // @ts-expect-error: intentionally passing invalid version version: 'FOO', }); expect(signature).toBe(expectedSignature); @@ -390,7 +391,7 @@ describe('simple-keyring', function () { it('works via `V1` string', async function () { await keyring.deserialize([privKeyHex]); const signature = await keyring.signTypedData(address, typedData, { - version: 'V1', + version: SignTypedDataVersion.V1, }); expect(signature).toBe(expectedSignature); const restored = recoverTypedSignature({ @@ -446,7 +447,7 @@ describe('simple-keyring', function () { await keyring.deserialize([privKeyHex]); const signature = await keyring.signTypedData(address, typedData, { - version: 'V3', + version: SignTypedDataVersion.V3, }); const restored = recoverTypedSignature({ data: typedData, @@ -506,7 +507,7 @@ describe('simple-keyring', function () { const address = (await keyring.getAccounts())[0]; assert(address, 'address is undefined'); const signature = await keyring.signTypedData(address, typedData, { - version: 'V3', + version: SignTypedDataVersion.V3, }); expect(signature).toBe(expectedSignature); const restored = recoverTypedSignature({ @@ -535,7 +536,7 @@ describe('simple-keyring', function () { await keyring.deserialize([privKeyHex]); const signature = await keyring.signTypedData(address, typedData, { - version: 'V4', + version: SignTypedDataVersion.V4, }); const restored = recoverTypedSignature({ data: typedData, @@ -734,7 +735,7 @@ describe('simple-keyring', function () { const address = (await keyring.getAccounts())[0]; assert(address, 'address is undefined'); const signature = await keyring.signTypedData(address, typedData, { - version: 'V4', + version: SignTypedDataVersion.V4, }); expect(signature).toBe(expectedSignature); const restored = recoverTypedSignature({ diff --git a/packages/keyring-eth-simple/src/simple-keyring.ts b/packages/keyring-eth-simple/src/simple-keyring.ts index 87ea28a0..e34d5233 100644 --- a/packages/keyring-eth-simple/src/simple-keyring.ts +++ b/packages/keyring-eth-simple/src/simple-keyring.ts @@ -153,7 +153,7 @@ export default class SimpleKeyring implements Keyring { async signTypedData< Version extends SignTypedDataVersion, Types extends MessageTypes, - Options extends { version: Version } & KeyringOpt, + Options extends { version?: Version } & KeyringOpt, >( address: Hex, typedData: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, From 5f859426a80bfe6871e5025beae02d3c33a4e3fa Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Fri, 21 Feb 2025 15:53:39 +0100 Subject: [PATCH 05/14] bump coverage threshold --- packages/keyring-eth-ledger-bridge/jest.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/keyring-eth-ledger-bridge/jest.config.js b/packages/keyring-eth-ledger-bridge/jest.config.js index 8e17553d..5fb1fcc0 100644 --- a/packages/keyring-eth-ledger-bridge/jest.config.js +++ b/packages/keyring-eth-ledger-bridge/jest.config.js @@ -23,10 +23,10 @@ module.exports = merge(baseConfig, { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 90.78, + branches: 90.97, functions: 96, - lines: 95.02, - statements: 95.07, + lines: 95.03, + statements: 95.09, }, }, }); From e4436a779198b85956baa8b74b1eca3ebda18003 Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Fri, 21 Feb 2025 18:43:34 +0100 Subject: [PATCH 06/14] update changelogs --- packages/keyring-eth-hd/CHANGELOG.md | 3 +++ packages/keyring-eth-ledger-bridge/CHANGELOG.md | 1 + packages/keyring-eth-simple/CHANGELOG.md | 2 ++ packages/keyring-eth-trezor/CHANGELOG.md | 1 + 4 files changed, 7 insertions(+) diff --git a/packages/keyring-eth-hd/CHANGELOG.md b/packages/keyring-eth-hd/CHANGELOG.md index b73b7243..874d9494 100644 --- a/packages/keyring-eth-hd/CHANGELOG.md +++ b/packages/keyring-eth-hd/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) + - The method now accepts a `TypedDataV1` object when `SigntypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested + ## [10.0.1] ### Changed diff --git a/packages/keyring-eth-ledger-bridge/CHANGELOG.md b/packages/keyring-eth-ledger-bridge/CHANGELOG.md index 80aeaa4a..81442e24 100644 --- a/packages/keyring-eth-ledger-bridge/CHANGELOG.md +++ b/packages/keyring-eth-ledger-bridge/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `signPersonalMessage` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `signTypedData` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `unlockAccountByAddress` method now accepts an `Hex` typed value as the `address` parameter. +- **BREAKING:** The `signTypedData` method now requires `SignTypedDataVersion` as version for the `options` argument ([#224](https://github.com/MetaMask/accounts/pull/224)). ### Removed diff --git a/packages/keyring-eth-simple/CHANGELOG.md b/packages/keyring-eth-simple/CHANGELOG.md index c7647f65..5cad5bc2 100644 --- a/packages/keyring-eth-simple/CHANGELOG.md +++ b/packages/keyring-eth-simple/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING:** The `SimpleKeyring` class now implements `Keyring` from `@metamask/keyring-utils` ([#217](https://github.com/MetaMask/accounts/pull/217)) - The `deserialize` method now requires a `string[]` argument. +- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) + - The method now accepts a `TypedDataV1` object when `SigntypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested ## [8.1.1] diff --git a/packages/keyring-eth-trezor/CHANGELOG.md b/packages/keyring-eth-trezor/CHANGELOG.md index bb61c365..5748f25d 100644 --- a/packages/keyring-eth-trezor/CHANGELOG.md +++ b/packages/keyring-eth-trezor/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `signPersonalMessage` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `signTypedData` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `unlockAccountByAddress` method now accepts an `Hex` typed value as the `address` parameter. +- **BREAKING:** The `signTypedData` `options.version` argument type has been restricted to accept `SignTypedDataVersion.V3 | SignTypedDataVersion.V4` ([#224](https://github.com/MetaMask/accounts/pull/224)) ### Removed From a761af18f7741dfa0e944f168786828e5386d8d7 Mon Sep 17 00:00:00 2001 From: Michele Esposito <34438276+mikesposito@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:49:22 +0100 Subject: [PATCH 07/14] Update packages/keyring-eth-hd/CHANGELOG.md --- packages/keyring-eth-hd/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/keyring-eth-hd/CHANGELOG.md b/packages/keyring-eth-hd/CHANGELOG.md index 874d9494..02b6228d 100644 --- a/packages/keyring-eth-hd/CHANGELOG.md +++ b/packages/keyring-eth-hd/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + - **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) - The method now accepts a `TypedDataV1` object when `SigntypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested From 467a5765d7c46207aaa59ea21fcc33a3221a8f1d Mon Sep 17 00:00:00 2001 From: Michele Esposito <34438276+mikesposito@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:56:17 +0100 Subject: [PATCH 08/14] Update packages/keyring-eth-hd/CHANGELOG.md Co-authored-by: Charly Chevalier <charly.chevalier@consensys.net> --- packages/keyring-eth-hd/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/keyring-eth-hd/CHANGELOG.md b/packages/keyring-eth-hd/CHANGELOG.md index dc9fa5f8..ccc1774e 100644 --- a/packages/keyring-eth-hd/CHANGELOG.md +++ b/packages/keyring-eth-hd/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING:** The `HdKeyring` is not exported as default anymore ([#161](https://github.com/MetaMask/accounts/pull/161)) - **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) - - The method now accepts a `TypedDataV1` object when `SigntypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested + - The method now accepts a `TypedDataV1` object when `SignTypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested. ## [10.0.1] From 463d850ceba7053083d4fce120f1eac1b4b16ad5 Mon Sep 17 00:00:00 2001 From: Michele Esposito <34438276+mikesposito@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:56:36 +0100 Subject: [PATCH 09/14] Update packages/keyring-eth-simple/CHANGELOG.md Co-authored-by: Charly Chevalier <charly.chevalier@consensys.net> --- packages/keyring-eth-simple/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/keyring-eth-simple/CHANGELOG.md b/packages/keyring-eth-simple/CHANGELOG.md index 5cad5bc2..02f7cd52 100644 --- a/packages/keyring-eth-simple/CHANGELOG.md +++ b/packages/keyring-eth-simple/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING:** The `SimpleKeyring` class now implements `Keyring` from `@metamask/keyring-utils` ([#217](https://github.com/MetaMask/accounts/pull/217)) - The `deserialize` method now requires a `string[]` argument. - **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) - - The method now accepts a `TypedDataV1` object when `SigntypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested + - The method now accepts a `TypedDataV1` object when `SignTypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested. ## [8.1.1] From 94360d0325d6846d4d98b13cbeae4155e54cc8d6 Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Wed, 19 Mar 2025 10:17:44 +0100 Subject: [PATCH 10/14] refactor: align options type --- .github/workflows/security-code-scanner.yml | 9 +- packages/keyring-eth-hd/CHANGELOG.md | 7 +- .../keyring-eth-hd/src/hd-keyring.test.ts | 15 + packages/keyring-eth-hd/src/hd-keyring.ts | 30 +- .../keyring-eth-ledger-bridge/CHANGELOG.md | 5 +- .../src/ledger-keyring.ts | 4 +- packages/keyring-eth-simple/CHANGELOG.md | 8 +- .../keyring-eth-simple/src/simple-keyring.ts | 19 +- packages/keyring-eth-trezor/CHANGELOG.md | 7 +- .../keyring-eth-trezor/src/trezor-keyring.ts | 6 +- yarn.lock | 297 +++++++++--------- 11 files changed, 215 insertions(+), 192 deletions(-) diff --git a/.github/workflows/security-code-scanner.yml b/.github/workflows/security-code-scanner.yml index ced04497..6bb460d2 100644 --- a/.github/workflows/security-code-scanner.yml +++ b/.github/workflows/security-code-scanner.yml @@ -1,10 +1,13 @@ -name: 'MetaMask Security Code Scanner' +name: MetaMask Security Code Scanner on: push: - branches: ['main'] + branches: + - main pull_request: - branches: ['main'] + branches: + - main + workflow_dispatch: jobs: run-security-scan: diff --git a/packages/keyring-eth-hd/CHANGELOG.md b/packages/keyring-eth-hd/CHANGELOG.md index 17c2adab..a9672035 100644 --- a/packages/keyring-eth-hd/CHANGELOG.md +++ b/packages/keyring-eth-hd/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) + - The method now accepts a `TypedDataV1` object when `SignTypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested. + ## [12.0.0] ### Changed @@ -22,8 +27,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **BREAKING:** The `HdKeyring` is not exported as default anymore ([#161](https://github.com/MetaMask/accounts/pull/161)) -- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) - - The method now accepts a `TypedDataV1` object when `SignTypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested. ## [10.0.1] diff --git a/packages/keyring-eth-hd/src/hd-keyring.test.ts b/packages/keyring-eth-hd/src/hd-keyring.test.ts index dc3d185b..76c9e3dc 100644 --- a/packages/keyring-eth-hd/src/hd-keyring.test.ts +++ b/packages/keyring-eth-hd/src/hd-keyring.test.ts @@ -19,9 +19,12 @@ import { type MessageTypes, type EIP7702Authorization, } from '@metamask/eth-sig-util'; +import { mnemonicPhraseToBytes } from '@metamask/key-tree'; import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; import { assert, bytesToHex, hexToBytes, type Hex } from '@metamask/utils'; import { webcrypto } from 'crypto'; +// eslint-disable-next-line n/no-sync +import { mnemonicToSeedSync } from 'ethereum-cryptography/bip39'; import { keccak256 } from 'ethereum-cryptography/keccak'; // eslint-disable-next-line @typescript-eslint/naming-convention import OldHdKeyring from 'old-hd-keyring'; @@ -37,6 +40,10 @@ const sampleMnemonic = const firstAcct = '0x1c96099350f13d558464ec79b9be4445aa0ef579'; const secondAcct = '0x1b00aed43a693f3a957f9feb5cc08afa031e37a0'; +const sampleMnemonicBytes = mnemonicPhraseToBytes(sampleMnemonic); +// eslint-disable-next-line n/no-sync +const sampleMnemonicSeed = mnemonicToSeedSync(sampleMnemonic); + const notKeyringAddress = '0xbD20F6F5F1616947a39E11926E78ec94817B3931'; const getAddressAtIndex = (keyring: HdKeyring, index: number): Hex => { @@ -175,6 +182,8 @@ describe('hd-keyring', () => { const accounts = keyring.getAccounts(); expect(accounts[0]).toStrictEqual(firstAcct); expect(accounts[1]).toStrictEqual(secondAcct); + expect(keyring.mnemonic).toStrictEqual(sampleMnemonicBytes); + expect(keyring.seed).toStrictEqual(sampleMnemonicSeed); }); it('deserializes with a typeof buffer mnemonic', async () => { @@ -188,6 +197,8 @@ describe('hd-keyring', () => { const accounts = keyring.getAccounts(); expect(accounts[0]).toStrictEqual(firstAcct); expect(accounts[1]).toStrictEqual(secondAcct); + expect(keyring.mnemonic).toStrictEqual(sampleMnemonicBytes); + expect(keyring.seed).toStrictEqual(sampleMnemonicSeed); }); it('deserializes with a typeof Uint8Array mnemonic', async () => { @@ -207,6 +218,8 @@ describe('hd-keyring', () => { const accounts = keyring.getAccounts(); expect(accounts[0]).toStrictEqual(firstAcct); expect(accounts[1]).toStrictEqual(secondAcct); + expect(keyring.mnemonic).toStrictEqual(sampleMnemonicBytes); + expect(keyring.seed).toStrictEqual(sampleMnemonicSeed); }); it('deserializes using custom cryptography', async () => { @@ -251,6 +264,8 @@ describe('hd-keyring', () => { const accounts = keyring.getAccounts(); expect(accounts[0]).toStrictEqual(firstAcct); expect(accounts[1]).toStrictEqual(secondAcct); + expect(keyring.mnemonic).toStrictEqual(sampleMnemonicBytes); + expect(keyring.seed).toStrictEqual(sampleMnemonicSeed); expect(cryptographicFunctions.pbkdf2Sha512).toHaveBeenCalledTimes(1); }); diff --git a/packages/keyring-eth-hd/src/hd-keyring.ts b/packages/keyring-eth-hd/src/hd-keyring.ts index 4585da03..6b2acf13 100644 --- a/packages/keyring-eth-hd/src/hd-keyring.ts +++ b/packages/keyring-eth-hd/src/hd-keyring.ts @@ -90,6 +90,8 @@ export class HdKeyring { mnemonic?: Uint8Array | null; + seed?: Uint8Array | null; + root?: HDKey | null; hdWallet?: HDKey; @@ -154,6 +156,7 @@ export class HdKeyring { } this.#wallets = []; this.mnemonic = null; + this.seed = null; this.root = null; this.hdPath = opts.hdPath ?? hdPathString; @@ -338,9 +341,9 @@ export class HdKeyring { * Sign a typed message using the private key of the specified account. * This method is compatible with the `eth_signTypedData` RPC method. * - * @param withAccount - The address of the account. - * @param typedData - The typed data to sign. - * @param opts - The options for signing the message. + * @param address - The address of the account. + * @param data - The typed data to sign. + * @param options - The options for signing the message. * @returns The signature of the message. */ async signTypedData< @@ -348,20 +351,21 @@ export class HdKeyring { Types extends MessageTypes, Options extends { version: Version }, >( - withAccount: Hex, - typedData: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, - opts?: HDKeyringAccountSelectionOptions & Options, + address: Hex, + data: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, + options?: HDKeyringAccountSelectionOptions & Options, ): Promise<string> { - const options = opts ?? { version: SignTypedDataVersion.V1 }; + let { version } = options ?? { version: SignTypedDataVersion.V1 }; + // Treat invalid versions as "V1" - const version = Object.keys(SignTypedDataVersion).includes(options.version) - ? options.version + version = Object.keys(SignTypedDataVersion).includes(version) + ? version : SignTypedDataVersion.V1; - const privateKey = this.#getPrivateKeyFor(withAccount, opts); + const privateKey = this.#getPrivateKeyFor(address, options); return signTypedData({ privateKey: Buffer.from(privateKey), - data: typedData, + data, version, }); } @@ -591,12 +595,12 @@ export class HdKeyring { this.mnemonic = this.#mnemonicToUint8Array(mnemonic); - const seed = await mnemonicToSeed( + this.seed = await mnemonicToSeed( this.mnemonic, '', // No passphrase this.#cryptographicFunctions, ); - this.hdWallet = HDKey.fromMasterSeed(seed); + this.hdWallet = HDKey.fromMasterSeed(this.seed); this.root = this.hdWallet.derive(this.hdPath); } diff --git a/packages/keyring-eth-ledger-bridge/CHANGELOG.md b/packages/keyring-eth-ledger-bridge/CHANGELOG.md index 790fdda6..e55227ba 100644 --- a/packages/keyring-eth-ledger-bridge/CHANGELOG.md +++ b/packages/keyring-eth-ledger-bridge/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** The `signTypedData` method now requires `SignTypedDataVersion.V4` as version for the `options` argument ([#224](https://github.com/MetaMask/accounts/pull/224)). + ## [10.0.0] ### Changed @@ -35,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `signPersonalMessage` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `signTypedData` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `unlockAccountByAddress` method now accepts an `Hex` typed value as the `address` parameter. -- **BREAKING:** The `signTypedData` method now requires `SignTypedDataVersion` as version for the `options` argument ([#224](https://github.com/MetaMask/accounts/pull/224)). ### Removed diff --git a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts index 3156c82a..b9f4e53d 100644 --- a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts +++ b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts @@ -494,9 +494,9 @@ export class LedgerKeyring implements Keyring { } async signTypedData< - Version extends SignTypedDataVersion, + Version extends SignTypedDataVersion.V4, Types extends MessageTypes, - Options extends { version?: Version }, + Options extends { version: Version }, >( withAccount: Hex, data: TypedMessage<Types>, diff --git a/packages/keyring-eth-simple/CHANGELOG.md b/packages/keyring-eth-simple/CHANGELOG.md index 80cdd75c..70b367cb 100644 --- a/packages/keyring-eth-simple/CHANGELOG.md +++ b/packages/keyring-eth-simple/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) + - The method now accepts a `TypedDataV1` object when `SignTypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested. + - The `options` argument type has been changed to `{ version: SignTypedDataVersion } | undefined`. + ## [10.0.0] ### Changed @@ -23,8 +29,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING:** The `SimpleKeyring` class now implements `Keyring` from `@metamask/keyring-utils` ([#217](https://github.com/MetaMask/accounts/pull/217)) - The `deserialize` method now requires a `string[]` argument. -- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) - - The method now accepts a `TypedDataV1` object when `SignTypedDataVersion.V1` is passed in the options, and `TypedMessage<Types>` when other versions are requested. ## [8.1.1] diff --git a/packages/keyring-eth-simple/src/simple-keyring.ts b/packages/keyring-eth-simple/src/simple-keyring.ts index 85cae4ce..35718f1d 100644 --- a/packages/keyring-eth-simple/src/simple-keyring.ts +++ b/packages/keyring-eth-simple/src/simple-keyring.ts @@ -160,22 +160,21 @@ export default class SimpleKeyring implements Keyring { async signTypedData< Version extends SignTypedDataVersion, Types extends MessageTypes, - Options extends { version?: Version } & KeyringOpt, + Options extends { version: Version } & KeyringOpt, >( address: Hex, - typedData: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, - opts?: Options, + data: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, + options?: Options, ): Promise<string> { - const options = opts ?? { version: SignTypedDataVersion.V1 }; - // Treat invalid versions as "V1" - let version = SignTypedDataVersion.V1; + let { version } = options ?? { version: SignTypedDataVersion.V1 }; - if (options.version && isSignTypedDataVersion(options.version)) { - version = SignTypedDataVersion[options.version]; + // Treat invalid versions as "V1" + if (!isSignTypedDataVersion(version)) { + version = SignTypedDataVersion.V1; } - const privateKey = this.#getPrivateKeyFor(address, opts); - return signTypedData({ privateKey, data: typedData, version }); + const privateKey = this.#getPrivateKeyFor(address, options); + return signTypedData({ privateKey, data, version }); } // get public key for nacl diff --git a/packages/keyring-eth-trezor/CHANGELOG.md b/packages/keyring-eth-trezor/CHANGELOG.md index d379078e..a55fe1d2 100644 --- a/packages/keyring-eth-trezor/CHANGELOG.md +++ b/packages/keyring-eth-trezor/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** The method signature for `signTypedData` has been changed ([#224](https://github.com/MetaMask/accounts/pull/224)) + - The `options` argument type has been changed to `{ version: SignTypedDataVersion.V3 | SignTypedDataVersion.V4 } | undefined`. + - The `options.version` argument type has been restricted to accept `SignTypedDataVersion.V3 | SignTypedDataVersion.V4` ([#224](https://github.com/MetaMask/accounts/pull/224)) + ## [8.0.0] ### Changed @@ -35,7 +41,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `signPersonalMessage` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `signTypedData` method now accepts an `Hex` typed value as the `withAccount` parameter. - The `unlockAccountByAddress` method now accepts an `Hex` typed value as the `address` parameter. -- **BREAKING:** The `signTypedData` `options.version` argument type has been restricted to accept `SignTypedDataVersion.V3 | SignTypedDataVersion.V4` ([#224](https://github.com/MetaMask/accounts/pull/224)) ### Removed diff --git a/packages/keyring-eth-trezor/src/trezor-keyring.ts b/packages/keyring-eth-trezor/src/trezor-keyring.ts index 339a4832..b2bf197e 100644 --- a/packages/keyring-eth-trezor/src/trezor-keyring.ts +++ b/packages/keyring-eth-trezor/src/trezor-keyring.ts @@ -462,12 +462,14 @@ export class TrezorKeyring implements Keyring { async signTypedData< Version extends SignTypedDataVersion.V3 | SignTypedDataVersion.V4, Types extends MessageTypes, - Options extends { version?: Version }, + Options extends { version: Version }, >( address: Hex, data: TypedMessage<Types>, - { version }: Options, + options?: Options, ): Promise<string> { + const { version } = options ?? { version: SignTypedDataVersion.V4 }; + const dataWithHashes = transformTypedData( data, version === SignTypedDataVersion.V4, diff --git a/yarn.lock b/yarn.lock index ba9a48aa..2390c891 100644 --- a/yarn.lock +++ b/yarn.lock @@ -677,215 +677,215 @@ __metadata: linkType: hard "@ethersproject/abi@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/abi@npm:5.7.0" + version: 5.8.0 + resolution: "@ethersproject/abi@npm:5.8.0" dependencies: - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/constants": "npm:^5.7.0" - "@ethersproject/hash": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - checksum: 10/6ed002cbc61a7e21bc0182702345659c1984f6f8e6bad166e43aee76ea8f74766dd0f6236574a868e1b4600af27972bf25b973fae7877ae8da3afa90d3965cac + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/hash": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10/a63ebc2c8ea795ceca5289abaf817bb402c83c330cffd0ae2d355be70c54050a21ddd408abd4fd0dce4c3fd5c5f091707be2095011c233022a52f2110e7012d6 languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/abstract-provider@npm:5.7.0" +"@ethersproject/abstract-provider@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/abstract-provider@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/networks": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/transactions": "npm:^5.7.0" - "@ethersproject/web": "npm:^5.7.0" - checksum: 10/c03e413a812486002525f4036bf2cb90e77a19b98fa3d16279e28e0a05520a1085690fac2ee9f94b7931b9a803249ff8a8bbb26ff8dee52196a6ef7a3fc5edc5 + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/networks": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/transactions": "npm:^5.8.0" + "@ethersproject/web": "npm:^5.8.0" + checksum: 10/2066aa717c7ecf0b6defe47f4f0af21943ee76e47f6fdc461d89b15d8af76c37d25355b4f5d635ed30e7378eafb0599b283df8ef9133cef389d938946874200d languageName: node linkType: hard -"@ethersproject/abstract-signer@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/abstract-signer@npm:5.7.0" +"@ethersproject/abstract-signer@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/abstract-signer@npm:5.8.0" dependencies: - "@ethersproject/abstract-provider": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - checksum: 10/0a6ffade0a947c9ba617048334e1346838f394d1d0a5307ac435a0c63ed1033b247e25ffb0cd6880d7dcf5459581f52f67e3804ebba42ff462050f1e4321ba0c + "@ethersproject/abstract-provider": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + checksum: 10/10986eb1520dd94efb34bc19de4f53a49bea023493a0df686711872eb2cb446f3cca3c98c1ecec7831497004822e16ead756d6c7d6977971eaa780f4d41db327 languageName: node linkType: hard -"@ethersproject/address@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/address@npm:5.7.0" +"@ethersproject/address@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/address@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/rlp": "npm:^5.7.0" - checksum: 10/1ac4f3693622ed9fbbd7e966a941ec1eba0d9445e6e8154b1daf8e93b8f62ad91853d1de5facf4c27b41e6f1e47b94a317a2492ba595bee1841fd3030c3e9a27 + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/rlp": "npm:^5.8.0" + checksum: 10/4b8ef5b3001f065fae571d86f113395d0dd081a2f411c99e354da912d4138e14a1fbe206265725daeb55c4e735ddb761891b58779208c5e2acec03f3219ce6ef languageName: node linkType: hard -"@ethersproject/base64@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/base64@npm:5.7.0" +"@ethersproject/base64@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/base64@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - checksum: 10/7105105f401e1c681e61db1e9da1b5960d8c5fbd262bbcacc99d61dbb9674a9db1181bb31903d98609f10e8a0eb64c850475f3b040d67dea953e2b0ac6380e96 + "@ethersproject/bytes": "npm:^5.8.0" + checksum: 10/c83e4ee01a1e69d874277d05c0e3fbc2afcdb9c80507be6963d31c77e505e355191cbba2d8fecf1c922b68c1ff072ede7914981fd965f1d8771c5b0706beb911 languageName: node linkType: hard -"@ethersproject/bignumber@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/bignumber@npm:5.7.0" +"@ethersproject/bignumber@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/bignumber@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" bn.js: "npm:^5.2.1" - checksum: 10/09cffa18a9f0730856b57c14c345bd68ba451159417e5aff684a8808011cd03b27b7c465d423370333a7d1c9a621392fc74f064a3b02c9edc49ebe497da6d45d + checksum: 10/15538ba9eef8475bc14a2a2bb5f0d7ae8775cf690283cb4c7edc836761a4310f83d67afe33f6d0b8befd896b10f878d8ca79b89de6e6ebd41a9e68375ec77123 languageName: node linkType: hard -"@ethersproject/bytes@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/bytes@npm:5.7.0" +"@ethersproject/bytes@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/bytes@npm:5.8.0" dependencies: - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/8b3ffedb68c1a82cfb875e9738361409cc33e2dcb1286b6ccfdc4dd8dd0317f7eacc8937b736c467d213dffc44b469690fe1a951e901953d5a90c5af2b675ae4 + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10/b8956aa4f607d326107cec522a881effed62585d5b5c5ad66ada4f7f83b42fd6c6acb76f355ec7a57e4cadea62a0194e923f4b5142d50129fe03d2fe7fc664f8 languageName: node linkType: hard -"@ethersproject/constants@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/constants@npm:5.7.0" +"@ethersproject/constants@npm:^5.7.0, @ethersproject/constants@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/constants@npm:5.8.0" dependencies: - "@ethersproject/bignumber": "npm:^5.7.0" - checksum: 10/6d4b1355747cce837b3e76ec3bde70e4732736f23b04f196f706ebfa5d4d9c2be50904a390d4d40ce77803b98d03d16a9b6898418e04ba63491933ce08c4ba8a + "@ethersproject/bignumber": "npm:^5.8.0" + checksum: 10/74830c44f4315a1058b905c73be7a9bb92850e45213cb28a957447b8a100f22a514f4500b0ea5ac7a995427cecef9918af39ae4e0e0ecf77aa4835b1ea5c3432 languageName: node linkType: hard -"@ethersproject/hash@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/hash@npm:5.7.0" +"@ethersproject/hash@npm:^5.7.0, @ethersproject/hash@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/hash@npm:5.8.0" dependencies: - "@ethersproject/abstract-signer": "npm:^5.7.0" - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/base64": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - checksum: 10/d83de3f3a1b99b404a2e7bb503f5cdd90c66a97a32cce1d36b09bb8e3fb7205b96e30ad28e2b9f30083beea6269b157d0c6e3425052bb17c0a35fddfdd1c72a3 + "@ethersproject/abstract-signer": "npm:^5.8.0" + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/base64": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10/a355cc1120b51c5912d960c66e2d1e2fb9cceca7d02e48c3812abd32ac2480035d8345885f129d2ed1cde9fb044adad1f98e4ea39652fa96c5de9c2720e83d28 languageName: node linkType: hard -"@ethersproject/keccak256@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/keccak256@npm:5.7.0" +"@ethersproject/keccak256@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/keccak256@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.8.0" js-sha3: "npm:0.8.0" - checksum: 10/ff70950d82203aab29ccda2553422cbac2e7a0c15c986bd20a69b13606ed8bb6e4fdd7b67b8d3b27d4f841e8222cbaccd33ed34be29f866fec7308f96ed244c6 + checksum: 10/af3621d2b18af6c8f5181dacad91e1f6da4e8a6065668b20e4c24684bdb130b31e45e0d4dbaed86d4f1314d01358aa119f05be541b696e455424c47849d81913 languageName: node linkType: hard -"@ethersproject/logger@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/logger@npm:5.7.0" - checksum: 10/683a939f467ae7510deedc23d7611d0932c3046137f5ffb92ba1e3c8cd9cf2fbbaa676b660c248441a0fa9143783137c46d6e6d17d676188dd5a6ef0b72dd091 +"@ethersproject/logger@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/logger@npm:5.8.0" + checksum: 10/dab862d6cc3a4312f4c49d62b4a603f4b60707da8b8ff0fee6bdfee3cbed48b34ec8f23fedfef04dd3d24f2fa2d7ad2be753c775aa00fe24dcd400631d65004a languageName: node linkType: hard -"@ethersproject/networks@npm:^5.7.0": - version: 5.7.1 - resolution: "@ethersproject/networks@npm:5.7.1" +"@ethersproject/networks@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/networks@npm:5.8.0" dependencies: - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/5265d0b4b72ef91af57be804b44507f4943038d609699764d8a69157ed381e30fe22ebf63630ed8e530ceb220f15d69dae8cda2e5023ccd793285c9d5882e599 + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10/8e2f4c3fd3a701ebd3d767a5f3217f8ced45a9f8ebf830c73b2dd87107dd50777f4869c3c9cc946698e2c597d3fe53eadeec55d19af7769c7d6bdb4a1493fb6f languageName: node linkType: hard -"@ethersproject/properties@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/properties@npm:5.7.0" +"@ethersproject/properties@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/properties@npm:5.8.0" dependencies: - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/f8401a161940aa1c32695115a20c65357877002a6f7dc13ab1600064bf54d7b825b4db49de8dc8da69efcbb0c9f34f8813e1540427e63e262ab841c1bf6c1c1e + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10/3bc1af678c1cf7c87f39aec24b1d86cfaa5da1f9f54e426558701fff1c088c1dcc9ec3e1f395e138bdfcda94a0161e7192f0596e11c8ff25d31735e6b33edc59 languageName: node linkType: hard -"@ethersproject/rlp@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/rlp@npm:5.7.0" +"@ethersproject/rlp@npm:^5.7.0, @ethersproject/rlp@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/rlp@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/3b8c5279f7654794d5874569f5598ae6a880e19e6616013a31e26c35c5f586851593a6e85c05ed7b391fbc74a1ea8612dd4d867daefe701bf4e8fcf2ab2f29b9 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10/353f04618f44c822d20da607b055286b3374fc6ab9fc50b416140f21e410f6d6e89ff9d951bef667b8baf1314e2d5f0b47c5615c3f994a2c8b2d6c01c6329bb4 languageName: node linkType: hard -"@ethersproject/signing-key@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/signing-key@npm:5.7.0" +"@ethersproject/signing-key@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/signing-key@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" bn.js: "npm:^5.2.1" - elliptic: "npm:6.5.4" + elliptic: "npm:6.6.1" hash.js: "npm:1.1.7" - checksum: 10/ff2f79ded86232b139e7538e4aaa294c6022a7aaa8c95a6379dd7b7c10a6d363685c6967c816f98f609581cf01f0a5943c667af89a154a00bcfe093a8c7f3ce7 + checksum: 10/07e5893bf9841e1d608c52b58aa240ed10c7aa01613ff45b15c312c1403887baa8ed543871721052d7b7dd75d80b1fa90945377b231d18ccb6986c6677c8315d languageName: node linkType: hard -"@ethersproject/strings@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/strings@npm:5.7.0" +"@ethersproject/strings@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/strings@npm:5.8.0" dependencies: - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/constants": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - checksum: 10/24191bf30e98d434a9fba2f522784f65162d6712bc3e1ccc98ed85c5da5884cfdb5a1376b7695374655a7b95ec1f5fdbeef5afc7d0ea77ffeb78047e9b791fa5 + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + checksum: 10/536264dad4b9ad42d8287be7b7a9f3e243d0172fafa459e22af2d416eb6fe6a46ff623ca5456457f841dec4b080939da03ed02ab9774dcd1f2391df9ef5a96bb languageName: node linkType: hard -"@ethersproject/transactions@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/transactions@npm:5.7.0" +"@ethersproject/transactions@npm:^5.7.0, @ethersproject/transactions@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/transactions@npm:5.8.0" dependencies: - "@ethersproject/address": "npm:^5.7.0" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/constants": "npm:^5.7.0" - "@ethersproject/keccak256": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/rlp": "npm:^5.7.0" - "@ethersproject/signing-key": "npm:^5.7.0" - checksum: 10/d809e9d40020004b7de9e34bf39c50377dce8ed417cdf001bfabc81ecb1b7d1e0c808fdca0a339ea05e1b380648eaf336fe70f137904df2d3c3135a38190a5af + "@ethersproject/address": "npm:^5.8.0" + "@ethersproject/bignumber": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/constants": "npm:^5.8.0" + "@ethersproject/keccak256": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/rlp": "npm:^5.8.0" + "@ethersproject/signing-key": "npm:^5.8.0" + checksum: 10/b43fd97ee359154c9162037c7aedc23abafae3cedf78d8fd2e641e820a0443120d22c473ec9bb79e8301f179f61a6120d61b0b757560e3aad8ae2110127018ba languageName: node linkType: hard -"@ethersproject/web@npm:^5.7.0": - version: 5.7.1 - resolution: "@ethersproject/web@npm:5.7.1" +"@ethersproject/web@npm:^5.8.0": + version: 5.8.0 + resolution: "@ethersproject/web@npm:5.8.0" dependencies: - "@ethersproject/base64": "npm:^5.7.0" - "@ethersproject/bytes": "npm:^5.7.0" - "@ethersproject/logger": "npm:^5.7.0" - "@ethersproject/properties": "npm:^5.7.0" - "@ethersproject/strings": "npm:^5.7.0" - checksum: 10/c83b6b3ac40573ddb67b1750bb4cf21ded7d8555be5e53a97c0f34964622fd88de9220a90a118434bae164a2bff3acbdc5ecb990517b5f6dc32bdad7adf604c2 + "@ethersproject/base64": "npm:^5.8.0" + "@ethersproject/bytes": "npm:^5.8.0" + "@ethersproject/logger": "npm:^5.8.0" + "@ethersproject/properties": "npm:^5.8.0" + "@ethersproject/strings": "npm:^5.8.0" + checksum: 10/93aad7041ffae7a4f881cc8df3356a297d736b50e6e48952b3b76e547b83e4d9189bbf2f417543031e91e74568c54395d1bb43c3252c3adf4f7e1c0187012912 languageName: node linkType: hard @@ -5437,24 +5437,9 @@ __metadata: languageName: node linkType: hard -"elliptic@npm:6.5.4": - version: 6.5.4 - resolution: "elliptic@npm:6.5.4" - dependencies: - bn.js: "npm:^4.11.9" - brorand: "npm:^1.1.0" - hash.js: "npm:^1.0.0" - hmac-drbg: "npm:^1.0.1" - inherits: "npm:^2.0.4" - minimalistic-assert: "npm:^1.0.1" - minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10/2cd7ff4b69720dbb2ca1ca650b2cf889d1df60c96d4a99d331931e4fe21e45a7f3b8074e86618ca7e56366c4b6258007f234f9d61d9b0c87bbbc8ea990b99e94 - languageName: node - linkType: hard - -"elliptic@npm:^6.4.0, elliptic@npm:^6.5.2, elliptic@npm:^6.5.4, elliptic@npm:^6.5.7": - version: 6.5.7 - resolution: "elliptic@npm:6.5.7" +"elliptic@npm:6.6.1, elliptic@npm:^6.4.0, elliptic@npm:^6.5.2, elliptic@npm:^6.5.4, elliptic@npm:^6.5.7": + version: 6.6.1 + resolution: "elliptic@npm:6.6.1" dependencies: bn.js: "npm:^4.11.9" brorand: "npm:^1.1.0" @@ -5463,7 +5448,7 @@ __metadata: inherits: "npm:^2.0.4" minimalistic-assert: "npm:^1.0.1" minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10/fbad1fad0a5cc07df83f80cc1f7a784247ef59075194d3e340eaeb2f4dd594825ee24c7e9b0cf279c9f1982efe610503bb3139737926428c4821d4fca1bcf348 + checksum: 10/dc678c9febd89a219c4008ba3a9abb82237be853d9fd171cd602c8fb5ec39927e65c6b5e7a1b2a4ea82ee8e0ded72275e7932bb2da04a5790c2638b818e4e1c5 languageName: node linkType: hard From c0fe40504932bc2186bed70967849ec78a35fd5c Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Wed, 19 Mar 2025 10:29:32 +0100 Subject: [PATCH 11/14] update trezor coverage threshold --- packages/keyring-eth-trezor/jest.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/keyring-eth-trezor/jest.config.js b/packages/keyring-eth-trezor/jest.config.js index 34ecf687..0bb9dd48 100644 --- a/packages/keyring-eth-trezor/jest.config.js +++ b/packages/keyring-eth-trezor/jest.config.js @@ -23,10 +23,10 @@ module.exports = merge(baseConfig, { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 51.63, + branches: 52.38, functions: 91.22, - lines: 90.1, - statements: 90.3, + lines: 90.15, + statements: 90.35, }, }, }); From 0851d8508e38e26d129386a3e852327af9252684 Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Wed, 19 Mar 2025 10:46:35 +0100 Subject: [PATCH 12/14] refactor: options.version is optional --- packages/keyring-eth-hd/src/hd-keyring.ts | 8 +++--- .../src/ledger-keyring.test.ts | 26 +++++++++++++------ .../src/ledger-keyring.ts | 2 +- .../keyring-eth-simple/src/simple-keyring.ts | 4 +-- .../keyring-eth-trezor/src/trezor-keyring.ts | 2 +- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/keyring-eth-hd/src/hd-keyring.ts b/packages/keyring-eth-hd/src/hd-keyring.ts index 6b2acf13..a97475b7 100644 --- a/packages/keyring-eth-hd/src/hd-keyring.ts +++ b/packages/keyring-eth-hd/src/hd-keyring.ts @@ -349,7 +349,7 @@ export class HdKeyring { async signTypedData< Version extends SignTypedDataVersion, Types extends MessageTypes, - Options extends { version: Version }, + Options extends { version?: Version }, >( address: Hex, data: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, @@ -358,9 +358,9 @@ export class HdKeyring { let { version } = options ?? { version: SignTypedDataVersion.V1 }; // Treat invalid versions as "V1" - version = Object.keys(SignTypedDataVersion).includes(version) - ? version - : SignTypedDataVersion.V1; + if (!version || !Object.keys(SignTypedDataVersion).includes(version)) { + version = SignTypedDataVersion.V1; + } const privateKey = this.#getPrivateKeyFor(address, options); return signTypedData({ diff --git a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts index 66ed70b2..446d3d46 100644 --- a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts +++ b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.test.ts @@ -968,7 +968,6 @@ describe('LedgerKeyring', function () { ], }, }; - const options = { version: sigUtil.SignTypedDataVersion.V4 }; beforeEach(async function () { jest @@ -989,7 +988,7 @@ describe('LedgerKeyring', function () { const result = await keyring.signTypedData( fakeAccounts[15], fixtureData, - options, + { version: sigUtil.SignTypedDataVersion.V4 }, ); expect(result).toBe( '0x72d4e38a0e582e09a620fd38e236fe687a1ec782206b56d576f579c026a7e5b946759735981cd0c3efb02d36df28bb2feedfec3d90e408efc93f45b894946e321b', @@ -1016,7 +1015,7 @@ describe('LedgerKeyring', function () { const result = await keyring.signTypedData( fakeAccounts[15], fixtureDataWithoutSalt, - options, + { version: sigUtil.SignTypedDataVersion.V4 }, ); expect(result).toBe( '0x72d4e38a0e582e09a620fd38e236fe687a1ec782206b56d576f579c026a7e5b946759735981cd0c3efb02d36df28bb2feedfec3d90e408efc93f45b894946e321b', @@ -1034,7 +1033,9 @@ describe('LedgerKeyring', function () { })); await expect( - keyring.signTypedData(fakeAccounts[15], fixtureData, options), + keyring.signTypedData(fakeAccounts[15], fixtureData, { + version: sigUtil.SignTypedDataVersion.V4, + }), ).rejects.toThrow( 'Ledger: The signature doesnt match the right address', ); @@ -1043,6 +1044,7 @@ describe('LedgerKeyring', function () { it('throws an error if the signTypedData version is not v4', async function () { await expect( keyring.signTypedData(fakeAccounts[0], fixtureData, { + // @ts-expect-error we want to test an invalid version version: sigUtil.SignTypedDataVersion.V3, }), ).rejects.toThrow( @@ -1063,7 +1065,9 @@ describe('LedgerKeyring', function () { .spyOn(keyring, 'unlockAccountByAddress') .mockResolvedValue(undefined); await expect( - keyring.signTypedData(fakeAccounts[0], fixtureData, options), + keyring.signTypedData(fakeAccounts[0], fixtureData, { + version: sigUtil.SignTypedDataVersion.V4, + }), ).rejects.toThrow('Ledger: Unknown error while signing message'); }); @@ -1073,7 +1077,9 @@ describe('LedgerKeyring', function () { .mockRejectedValue(new Error('some error')); await expect( - keyring.signTypedData(fakeAccounts[15], fixtureData, options), + keyring.signTypedData(fakeAccounts[15], fixtureData, { + version: sigUtil.SignTypedDataVersion.V4, + }), ).rejects.toThrow('some error'); }); @@ -1083,7 +1089,9 @@ describe('LedgerKeyring', function () { .mockRejectedValue('some error'); await expect( - keyring.signTypedData(fakeAccounts[15], fixtureData, options), + keyring.signTypedData(fakeAccounts[15], fixtureData, { + version: sigUtil.SignTypedDataVersion.V4, + }), ).rejects.toThrow('Ledger: Unknown error while signing message'); }); @@ -1096,7 +1104,9 @@ describe('LedgerKeyring', function () { const result = await keyring.signTypedData( fakeAccounts[15], fixtureData, - options, + { + version: sigUtil.SignTypedDataVersion.V4, + }, ); expect(result).toBe( '0x72d4e38a0e582e09a620fd38e236fe687a1ec782206b56d576f579c026a7e5b946759735981cd0c3efb02d36df28bb2feedfec3d90e408efc93f45b894946e3200', diff --git a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts index b9f4e53d..da285a27 100644 --- a/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts +++ b/packages/keyring-eth-ledger-bridge/src/ledger-keyring.ts @@ -496,7 +496,7 @@ export class LedgerKeyring implements Keyring { async signTypedData< Version extends SignTypedDataVersion.V4, Types extends MessageTypes, - Options extends { version: Version }, + Options extends { version?: Version }, >( withAccount: Hex, data: TypedMessage<Types>, diff --git a/packages/keyring-eth-simple/src/simple-keyring.ts b/packages/keyring-eth-simple/src/simple-keyring.ts index 35718f1d..85ba37e8 100644 --- a/packages/keyring-eth-simple/src/simple-keyring.ts +++ b/packages/keyring-eth-simple/src/simple-keyring.ts @@ -160,7 +160,7 @@ export default class SimpleKeyring implements Keyring { async signTypedData< Version extends SignTypedDataVersion, Types extends MessageTypes, - Options extends { version: Version } & KeyringOpt, + Options extends { version?: Version } & KeyringOpt, >( address: Hex, data: Version extends 'V1' ? TypedDataV1 : TypedMessage<Types>, @@ -169,7 +169,7 @@ export default class SimpleKeyring implements Keyring { let { version } = options ?? { version: SignTypedDataVersion.V1 }; // Treat invalid versions as "V1" - if (!isSignTypedDataVersion(version)) { + if (!version || !isSignTypedDataVersion(version)) { version = SignTypedDataVersion.V1; } diff --git a/packages/keyring-eth-trezor/src/trezor-keyring.ts b/packages/keyring-eth-trezor/src/trezor-keyring.ts index b2bf197e..fcf33aaf 100644 --- a/packages/keyring-eth-trezor/src/trezor-keyring.ts +++ b/packages/keyring-eth-trezor/src/trezor-keyring.ts @@ -462,7 +462,7 @@ export class TrezorKeyring implements Keyring { async signTypedData< Version extends SignTypedDataVersion.V3 | SignTypedDataVersion.V4, Types extends MessageTypes, - Options extends { version: Version }, + Options extends { version?: Version }, >( address: Hex, data: TypedMessage<Types>, From 2fb23c30d2f44248999696e84067276251c1eda4 Mon Sep 17 00:00:00 2001 From: Michele Esposito <michele@esposito.codes> Date: Wed, 19 Mar 2025 10:52:24 +0100 Subject: [PATCH 13/14] adjust hdkeyring coverage threshold --- packages/keyring-eth-hd/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/keyring-eth-hd/jest.config.js b/packages/keyring-eth-hd/jest.config.js index e5d1182c..46378eee 100644 --- a/packages/keyring-eth-hd/jest.config.js +++ b/packages/keyring-eth-hd/jest.config.js @@ -26,7 +26,7 @@ module.exports = merge(baseConfig, { branches: 83.87, functions: 100, lines: 95, - statements: 97.91, + statements: 97.27, }, }, }); From 8b332a6f0e4b6be4cd6e16dd9aebb2ac19c1ab89 Mon Sep 17 00:00:00 2001 From: Michele Esposito <34438276+mikesposito@users.noreply.github.com> Date: Wed, 19 Mar 2025 11:39:10 +0100 Subject: [PATCH 14/14] Update packages/keyring-eth-ledger-bridge/CHANGELOG.md Co-authored-by: Charly Chevalier <charly.chevalier@consensys.net> --- packages/keyring-eth-ledger-bridge/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/keyring-eth-ledger-bridge/CHANGELOG.md b/packages/keyring-eth-ledger-bridge/CHANGELOG.md index e55227ba..874032bf 100644 --- a/packages/keyring-eth-ledger-bridge/CHANGELOG.md +++ b/packages/keyring-eth-ledger-bridge/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- **BREAKING:** The `signTypedData` method now requires `SignTypedDataVersion.V4` as version for the `options` argument ([#224](https://github.com/MetaMask/accounts/pull/224)). +- **BREAKING:** The `signTypedData` method now requires `SignTypedDataVersion.V4` as version for the `options` argument ([#224](https://github.com/MetaMask/accounts/pull/224)) ## [10.0.0]