Skip to content

fix: preserve eip-7702 authorization yParity in serializeAuthorizationList - #5304

Merged
jxom merged 1 commit into
mainfrom
jxom/fervent-bell-gu92e6
Oct 26, 2026
Merged

jxom merged 1 commit into
mainfrom
jxom/fervent-bell-gu92e6

Conversation

@jxom

@jxom jxom commented Oct 26, 2026

Copy link
Copy Markdown
Member

Fixes #5297

serializeAuthorizationList passed each authorization's signature through toYParitySignatureArray, which normalizes any nonzero yParity to 1. EIP-7702 permits any y_parity below 2**8 in an authorization tuple. A tuple that fails recovery is skipped and does not invalidate the transaction, so such transactions land on chain. Re-serializing one (for example, mainnet 0xaec84209…cb09, whose authorization holds yParity: 28) produced a different hash.

A numeric authorization yParity is now encoded as is. Everything else is unchanged: yParity 0 and 1, the v-only fallback, unsigned tuples, and the transaction-level signature.

serializeAuthorizationList([{ ...authorization, yParity: 28 }])
// before: [..., '0x1', r, s]
// after:  [..., '0x1c', r, s]

Tests: a new serializeTransaction case rebuilds the mainnet transaction from the issue and matches the raw bytes from eth_getRawTransactionByHash and the on-chain hash. A new serializeAuthorizationList case covers yParity: 28. Both fail without the change.

For reviewers: parseTransaction still throws InvalidYParityError for authorization yParity values other than 0 or 1, as the existing invalid authorization list yParity test asserts. Parsing this transaction's raw bytes therefore still throws. This PR leaves that as is. Changing it would mean accepting values below 2**8 and choosing what v is for them.


Generated by Claude Code

…tionList`

`serializeAuthorizationList` normalized every nonzero authorization
`yParity` to 1. EIP-7702 permits any `y_parity` below 2**8 in an
authorization tuple, so mainnet transactions with such tuples serialized
to a different hash. A numeric `yParity` is now encoded as is.

Fixes #5297

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018xsBq1f9h7D6pGXhaZ2aJv
@vercel

vercel Bot commented Oct 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
viem Building Building Preview Oct 26, 2026 5:34am UTC

Request Review

@changeset-bot

changeset-bot Bot commented Oct 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e98d1f5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
viem Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T05:36:54.379649Z e98d1f5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@jxom
jxom merged commit 918955e into main Oct 26, 2026
32 of 34 checks passed
@jxom
jxom deleted the jxom/fervent-bell-gu92e6 branch October 26, 2026 05:35
@github-actions github-actions Bot mentioned this pull request Oct 26, 2026
jxom added a commit to wevm/ox that referenced this pull request Oct 26, 2026
* fix: accept punycode top-level domains in `Siwe.createMessage`

Ports wevm/viem#5299.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: preserve EIP-7702 authorization `yParity` above 1 in `Authorization`

Ports wevm/viem#5304. EIP-7702 permits any `y_parity` below 2**8 in an
authorization tuple. `Authorization.fromRpc`, `Authorization.fromTuple`,
and `Authorization.toTuple` now read and encode it as is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: bound authorization `yParity` to one byte and keep it in `Authorization.toRpc`

`Authorization.fromRpc` and `Authorization.fromTuple` reject a `yParity`
of 2**8 or more, which EIP-7702 forbids, with the same
`Hex.IntegerOutOfRangeError` as `Authorization.toTuple`.
`Authorization.toRpc` encodes `yParity` as is instead of through
`Signature.toRpc`, which writes 0 or 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: keep the port in group 3 of `Siwe.domainRegex`

The top-level domain alternation is non-capturing, so the capture
groups of the exported regex stay as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: use a line comment for the private `assertYParity` helper

`check:tsdoc` requires an `@example` in every JSDoc block, and the helper
is not part of the public API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* docs: name `Authorization.toRpc` in the authorization `yParity` changeset

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: bound authorization `yParity` to one byte in `Authorization.toRpc`

`Authorization.toRpc` now rejects a `yParity` of 2**8 or more with the
same `Hex.IntegerOutOfRangeError` as the other `Authorization` codecs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: check authorization `yParity` in `Authorization.toTuple`

`Authorization.toTuple` encoded a `NaN` `yParity` as the zero parity.
It now rejects any `yParity` that is not an integer from 0 to 255, like
the other `Authorization` codecs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

---------

Co-authored-by: Claude <noreply@anthropic.com>
jxom added a commit to wevm/ox that referenced this pull request Oct 26, 2026
* fix: accept punycode top-level domains in `Siwe.createMessage`

Ports wevm/viem#5299.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: preserve EIP-7702 authorization `yParity` above 1 in `Authorization`

Ports wevm/viem#5304. EIP-7702 permits any `y_parity` below 2**8 in an
authorization tuple. `Authorization.fromRpc`, `Authorization.fromTuple`,
and `Authorization.toTuple` now read and encode it as is, and the zod
`Authorization` schemas accept an 8-bit `yParity`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: bound authorization `yParity` to one byte in `Authorization.fromRpc` and `Authorization.fromTuple`

Both now reject a `yParity` of 2**8 or more, which EIP-7702 forbids, with
the same `Hex.IntegerOutOfRangeError` as `Authorization.toTuple`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: keep the port in group 3 of `Siwe.domainRegex`

The top-level domain alternation is non-capturing, so the capture
groups of the exported regex stay as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: bound authorization `yParity` to one byte in `Authorization.toRpc`

`Authorization.toRpc` now rejects a `yParity` of 2**8 or more with the
same `Hex.IntegerOutOfRangeError` as the other `Authorization` codecs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

* fix: check authorization `yParity` in `Authorization.toTuple`

`Authorization.toTuple` encoded a `NaN` `yParity` as the zero parity.
It now rejects any `yParity` that is not an integer from 0 to 255, like
the other `Authorization` codecs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLjvB9RWejr3jdFDh3WjiM

---------

Co-authored-by: Claude <noreply@anthropic.com>
jxom added a commit that referenced this pull request Nov 1, 2026
…in recovery (#5371)

* fix: accept an EIP-7702 authorization `yParity` above 1 in `parseTransaction`

`parseAuthorizationList` parsed each authorization signature with
`parseEIP155Signature`, which throws `InvalidYParityError` for any
`yParity` other than 0 or 1. EIP-7702 permits any `y_parity` below 2**8
in an authorization tuple, and #5304 made `serializeTransaction` keep
such a value, so a transaction viem serializes, for example mainnet
0xaec84209...cb09 whose authorization has a `y_parity` of 28, could not
be parsed back, and `recoverTransactionAddress` threw on it.

An authorization `yParity` from 2 to 255 is now kept as is, with `r`
and `s` padded as before. 0 and 1 parse as before, and 256 or more
still throws.

* fix: reject an EIP-7702 authorization `yParity` other than 0 or 1 in recovery

With `parseTransaction` now keeping an authorization `yParity` from 2 to
255, a parsed `yParity` of 27 or 28 reached `recoverPublicKey`, which
maps them to recovery bits 0 and 1 as legacy `v` values. A tuple the
protocol skips therefore recovered a signer, and `verifyAuthorization`
returned `true` for it.

EIP-7702 recovers the authority with `y_parity` as the raw recovery id,
so `recoverAuthorizationAddress` now throws `InvalidYParityError` for a
`yParity` other than 0 or 1, and `verifyAuthorization` returns `false`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3nmWhB4o7Zekbowt3QdXf

---------

Co-authored-by: ecamli <107792368+erkancamli@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — e98d1f57 Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

serializeTransaction changes EIP-7702 authorization yParity, breaking transaction round-trips

2 participants