From af83e7b3a62b7bf3306f7d7307b07508148c0f22 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Fri, 6 Feb 2026 16:33:52 +0100 Subject: [PATCH 1/7] fix: fix re-use string for user-ops sender/to --- packages/keyring-api/src/eth/erc4337/types.ts | 14 +++++++++++--- packages/keyring-api/src/eth/types.ts | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/keyring-api/src/eth/erc4337/types.ts b/packages/keyring-api/src/eth/erc4337/types.ts index c9fd8aab5..f1ea6be4e 100644 --- a/packages/keyring-api/src/eth/erc4337/types.ts +++ b/packages/keyring-api/src/eth/erc4337/types.ts @@ -1,7 +1,11 @@ import { exactOptional, object, UrlStruct } from '@metamask/keyring-utils'; import { type Infer } from '@metamask/superstruct'; -import { EthAddressStruct, EthBytesStruct, EthUint256Struct } from '../types'; +import { + EthAddressAsStringStruct, + EthBytesStruct, + EthUint256Struct, +} from '../types'; /** * Struct of a UserOperation as defined by ERC-4337. @@ -9,7 +13,9 @@ import { EthAddressStruct, EthBytesStruct, EthUint256Struct } from '../types'; * @see https://eips.ethereum.org/EIPS/eip-4337#definitions */ export const EthUserOperationStruct = object({ - sender: EthAddressStruct, + // FIXME: We use a `string` here instead of a `Hex` as this quickly bubbles up + // to other controllers/components. + sender: EthAddressAsStringStruct, nonce: EthUint256Struct, initCode: EthBytesStruct, callData: EthBytesStruct, @@ -32,7 +38,9 @@ export const EthBaseTransactionStruct = object({ /** * Address of the transaction recipient. */ - to: EthAddressStruct, + // FIXME: We use a `string` here instead of a `Hex` as this quickly bubbles up + // to other controllers/components. + to: EthAddressAsStringStruct, /** * Amount of wei to transfer to the recipient. diff --git a/packages/keyring-api/src/eth/types.ts b/packages/keyring-api/src/eth/types.ts index 12c586631..ed598ec92 100644 --- a/packages/keyring-api/src/eth/types.ts +++ b/packages/keyring-api/src/eth/types.ts @@ -17,6 +17,11 @@ export const EthAddressStruct = definePattern( /^0x[0-9a-f]{40}$/iu, ); +export const EthAddressAsStringStruct = definePattern( + 'EthAddress', + /^0x[0-9a-f]{40}$/iu, +); + export const EthUint256Struct = definePattern( 'EthUint256', /^0x([1-9a-f][0-9a-f]*|0)$/iu, From 689db1666c71d68c6150876cb003309663ddb65a Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Mon, 9 Feb 2026 09:16:45 +0100 Subject: [PATCH 2/7] chore: update changelog --- packages/keyring-api/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/keyring-api/CHANGELOG.md b/packages/keyring-api/CHANGELOG.md index d5a27d9c6..5a6db1739 100644 --- a/packages/keyring-api/CHANGELOG.md +++ b/packages/keyring-api/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING:** Refine `EthAddressStruct` in order to make it compatible with the `Hex` type from `@metamask/utils` ([#405](https://github.com/MetaMask/accounts/pull/405)) + - This change was not properly reported as breaking on the `21.4.0`. +- Re-use `string` for ERC4337 address-like types ([#465](https://github.com/MetaMask/accounts/pull/465)) + - This change reverts that and keeps using `string` for all address-like types + - #405 changed the associated type for `EthAddressStruct` from `string` to `Hex`, this was actually a small breaking change that went unnoticed and that would require some effort to adapt in upstream clients/controllers. + ## [21.4.0] ### Added From 0af7a1edd5a8aa9193e3f39817969d029eee3b78 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Mon, 9 Feb 2026 09:37:58 +0100 Subject: [PATCH 3/7] chore: update changelog + add EthAddressStrictStruct --- packages/keyring-api/CHANGELOG.md | 10 +++++++--- packages/keyring-api/src/eth/erc4337/types.ts | 10 +++------- packages/keyring-api/src/eth/rpc/params.ts | 8 ++++++-- packages/keyring-api/src/eth/types.ts | 12 +++++------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/keyring-api/CHANGELOG.md b/packages/keyring-api/CHANGELOG.md index 5a6db1739..5595ca19e 100644 --- a/packages/keyring-api/CHANGELOG.md +++ b/packages/keyring-api/CHANGELOG.md @@ -7,13 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `EthAddressStrictStruct` ([#465](https://github.com/MetaMask/accounts/pull/465)) + - This is a stricter variant of `EthAddressStruct` which uses `Hex` instead of `string` for its inferred type. + ### Changed -- **BREAKING:** Refine `EthAddressStruct` in order to make it compatible with the `Hex` type from `@metamask/utils` ([#405](https://github.com/MetaMask/accounts/pull/405)) - - This change was not properly reported as breaking on the `21.4.0`. - Re-use `string` for ERC4337 address-like types ([#465](https://github.com/MetaMask/accounts/pull/465)) - - This change reverts that and keeps using `string` for all address-like types + - This change reverts that and keeps using `string` for all address-like types. - #405 changed the associated type for `EthAddressStruct` from `string` to `Hex`, this was actually a small breaking change that went unnoticed and that would require some effort to adapt in upstream clients/controllers. + - Version 21.4.0 will be marked as **YANKED**, consumers are expected to use this new version that reverts this breaking change. ## [21.4.0] diff --git a/packages/keyring-api/src/eth/erc4337/types.ts b/packages/keyring-api/src/eth/erc4337/types.ts index f1ea6be4e..6e22abae8 100644 --- a/packages/keyring-api/src/eth/erc4337/types.ts +++ b/packages/keyring-api/src/eth/erc4337/types.ts @@ -1,11 +1,7 @@ import { exactOptional, object, UrlStruct } from '@metamask/keyring-utils'; import { type Infer } from '@metamask/superstruct'; -import { - EthAddressAsStringStruct, - EthBytesStruct, - EthUint256Struct, -} from '../types'; +import { EthAddressStruct, EthBytesStruct, EthUint256Struct } from '../types'; /** * Struct of a UserOperation as defined by ERC-4337. @@ -15,7 +11,7 @@ import { export const EthUserOperationStruct = object({ // FIXME: We use a `string` here instead of a `Hex` as this quickly bubbles up // to other controllers/components. - sender: EthAddressAsStringStruct, + sender: EthAddressStruct, nonce: EthUint256Struct, initCode: EthBytesStruct, callData: EthBytesStruct, @@ -40,7 +36,7 @@ export const EthBaseTransactionStruct = object({ */ // FIXME: We use a `string` here instead of a `Hex` as this quickly bubbles up // to other controllers/components. - to: EthAddressAsStringStruct, + to: EthAddressStruct, /** * Amount of wei to transfer to the recipient. diff --git a/packages/keyring-api/src/eth/rpc/params.ts b/packages/keyring-api/src/eth/rpc/params.ts index 2331f3818..697fc3d65 100644 --- a/packages/keyring-api/src/eth/rpc/params.ts +++ b/packages/keyring-api/src/eth/rpc/params.ts @@ -23,7 +23,11 @@ import { unknown, } from '@metamask/superstruct'; -import { EthAddressStruct, EthBytesStruct } from '../types'; +import { + EthAddressStrictStruct, + EthAddressStruct, + EthBytesStruct, +} from '../types'; /** * A struct for validating Ethereum transaction data. @@ -118,7 +122,7 @@ export type EthEncryptedData = Infer; */ export const EthEip7702AuthorizationStruct = tuple([ number(), // chainId - EthAddressStruct, // address (contract to delegate to) + EthAddressStrictStruct, // address (contract to delegate to) number(), // nonce ]); diff --git a/packages/keyring-api/src/eth/types.ts b/packages/keyring-api/src/eth/types.ts index ed598ec92..290650783 100644 --- a/packages/keyring-api/src/eth/types.ts +++ b/packages/keyring-api/src/eth/types.ts @@ -12,14 +12,12 @@ import { export const EthBytesStruct = definePattern('EthBytes', /^0x[0-9a-f]*$/iu); -export const EthAddressStruct = definePattern( +const ETH_ADDRESS_REGEX = /^0x[0-9a-f]{40}$/iu; +export const EthAddressStruct = definePattern('EthAddress', ETH_ADDRESS_REGEX); +// Stricter struct that uses `Hex` as final type. +export const EthAddressStrictStruct = definePattern( 'EthAddress', - /^0x[0-9a-f]{40}$/iu, -); - -export const EthAddressAsStringStruct = definePattern( - 'EthAddress', - /^0x[0-9a-f]{40}$/iu, + ETH_ADDRESS_REGEX, ); export const EthUint256Struct = definePattern( From d6f08eabf8ade1867de83b63598a403df3a7d6db Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Mon, 9 Feb 2026 10:53:07 +0100 Subject: [PATCH 4/7] chore: revert --- packages/keyring-api/src/eth/erc4337/types.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/keyring-api/src/eth/erc4337/types.ts b/packages/keyring-api/src/eth/erc4337/types.ts index 6e22abae8..c9fd8aab5 100644 --- a/packages/keyring-api/src/eth/erc4337/types.ts +++ b/packages/keyring-api/src/eth/erc4337/types.ts @@ -9,8 +9,6 @@ import { EthAddressStruct, EthBytesStruct, EthUint256Struct } from '../types'; * @see https://eips.ethereum.org/EIPS/eip-4337#definitions */ export const EthUserOperationStruct = object({ - // FIXME: We use a `string` here instead of a `Hex` as this quickly bubbles up - // to other controllers/components. sender: EthAddressStruct, nonce: EthUint256Struct, initCode: EthBytesStruct, @@ -34,8 +32,6 @@ export const EthBaseTransactionStruct = object({ /** * Address of the transaction recipient. */ - // FIXME: We use a `string` here instead of a `Hex` as this quickly bubbles up - // to other controllers/components. to: EthAddressStruct, /** From d40557557938763f4a94a78be2014183e14281df Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Mon, 9 Feb 2026 10:54:35 +0100 Subject: [PATCH 5/7] chore: better changelog --- packages/keyring-api/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/keyring-api/CHANGELOG.md b/packages/keyring-api/CHANGELOG.md index 5595ca19e..f3bccf7d1 100644 --- a/packages/keyring-api/CHANGELOG.md +++ b/packages/keyring-api/CHANGELOG.md @@ -9,15 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `EthAddressStrictStruct` ([#465](https://github.com/MetaMask/accounts/pull/465)) +- Add `EthAddressStrictStruct` struct and `EthAddressStrict` types ([#465](https://github.com/MetaMask/accounts/pull/465)) - This is a stricter variant of `EthAddressStruct` which uses `Hex` instead of `string` for its inferred type. ### Changed -- Re-use `string` for ERC4337 address-like types ([#465](https://github.com/MetaMask/accounts/pull/465)) +- Re-use `string` for ERC4337 address-like fields ([#465](https://github.com/MetaMask/accounts/pull/465)) - This change reverts that and keeps using `string` for all address-like types. - - #405 changed the associated type for `EthAddressStruct` from `string` to `Hex`, this was actually a small breaking change that went unnoticed and that would require some effort to adapt in upstream clients/controllers. - - Version 21.4.0 will be marked as **YANKED**, consumers are expected to use this new version that reverts this breaking change. + - [#405] changed the associated type for `EthAddressStruct` from `string` to `Hex`, this was actually a small breaking change that went unnoticed and that would require some effort to adapt in upstream clients/controllers. + - Version [21.4.0] will be marked as **YANKED**, consumers are expected to use this new version that reverts this breaking change. ## [21.4.0] From 2b1eb2418506f62334ffc4d94c9652c694ab4b46 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Mon, 9 Feb 2026 10:56:28 +0100 Subject: [PATCH 6/7] chore: better changelog --- packages/keyring-api/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/keyring-api/CHANGELOG.md b/packages/keyring-api/CHANGELOG.md index f3bccf7d1..bb2aaf599 100644 --- a/packages/keyring-api/CHANGELOG.md +++ b/packages/keyring-api/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Re-use `string` for ERC4337 address-like fields ([#465](https://github.com/MetaMask/accounts/pull/465)) - This change reverts that and keeps using `string` for all address-like types. - - [#405] changed the associated type for `EthAddressStruct` from `string` to `Hex`, this was actually a small breaking change that went unnoticed and that would require some effort to adapt in upstream clients/controllers. + - Changes in [#405](https://github.com/MetaMask/accounts/pull/405) updated the associated type for `EthAddressStruct` from `string` to `Hex`, this was actually a small breaking change that went unnoticed and that would require some effort to adapt in upstream clients/controllers, for this reason, we are undoing this change for now. - Version [21.4.0] will be marked as **YANKED**, consumers are expected to use this new version that reverts this breaking change. ## [21.4.0] From 67374c96233149e17a992baf6e32617b3fca3921 Mon Sep 17 00:00:00 2001 From: Charly Chevalier Date: Mon, 9 Feb 2026 11:11:40 +0100 Subject: [PATCH 7/7] chore: rename struct --- packages/keyring-api/src/eth/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/keyring-api/src/eth/types.ts b/packages/keyring-api/src/eth/types.ts index 290650783..02f6e39ed 100644 --- a/packages/keyring-api/src/eth/types.ts +++ b/packages/keyring-api/src/eth/types.ts @@ -16,7 +16,7 @@ const ETH_ADDRESS_REGEX = /^0x[0-9a-f]{40}$/iu; export const EthAddressStruct = definePattern('EthAddress', ETH_ADDRESS_REGEX); // Stricter struct that uses `Hex` as final type. export const EthAddressStrictStruct = definePattern( - 'EthAddress', + 'EthAddressStrict', ETH_ADDRESS_REGEX, );