Skip to content

fix: decode anonymous event logs in AbiEvent.decodeLog and extractLogs - #564

Merged
jxom merged 1 commit into
mainfrom
jxom/anonymous-event-logs
Nov 2, 2026
Merged

jxom merged 1 commit into
mainfrom
jxom/anonymous-event-logs

Conversation

@jxom

@jxom jxom commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Port of wevm/viem#5375. AbiEvent.decode and encode already handle anonymous events, but decodeLog and extractLogs match logs only by selector topic, so anonymous logs were never decoded.

An anonymous log has no selector topic, so nothing in it identifies the event: any log with the same topic count fits. Matching anonymous events unconditionally would label logs from other contracts in a receipt as the anonymous event. So anonymous events are matched only when they are requested:

  • decodeLog: when every event in the ABI is anonymous. For a mixed ABI, decode with the event itself through AbiEvent.decode.
  • extractLogs: when eventName names the event, or every event in the ABI is anonymous.

A selector match still wins. A log that fits several anonymous events isn't guessed, because dynamic data can decode as a static type without throwing: decodeLog throws the new AbiEvent.AnonymousEventAmbiguityError, and extractLogs skips the log. The non-strict fallback in extractLogs applies only to a selector match.

const abi = [transfer, anonymousPing] // mixed ABI

AbiEvent.extractLogs(abi, logs) // Transfer logs only
AbiEvent.extractLogs(abi, logs, { eventName: ['Ping', 'Transfer'] }) // both

Also adds src/core/_test/AbiEvent.fuzz.ts, with properties over random events (anonymous or not, any ABI type, named, unnamed, or mixed inputs) and random logs:

  • decode and extractLogs decode the arguments a log was encoded from.
  • encode produces the topics a contract emits.
  • decode returns or throws an ox error for any log.
  • decodeLog decodes a selector match the same way whatever else the ABI holds.
  • extractLogs matches a model of its matching rules, with and without eventName, and doesn't throw in non-strict mode.

Against unmodified main, the 4 anonymous-event properties fail and the 6 compatibility properties pass. Unit tests cover the same cases deterministically.

Validation: FC_NUM_RUNS=2000 pnpm test:fuzz src/core/_test/AbiEvent.fuzz.ts passes (about 17 s). The AbiEvent unit tests pass except the 2 network tests, which need anvil (not available locally). pnpm check:types and vp check pass. zile examples:check couldn't run locally, because zile dev fails in this environment, so CI will check the new TSDoc examples.

Backport of decode/encode anonymous support to 0.x: #565.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh

`decodeLog` and `extractLogs` only matched logs by their selector topic, so
anonymous event logs were never decoded. An anonymous log carries nothing
that identifies its event, so anonymous events are now matched only when
requested: every event in the ABI is anonymous, or (for `extractLogs`)
`eventName` names the event. A selector match still wins, and a log that fits
several anonymous events is not guessed: `decodeLog` throws
`AbiEvent.AnonymousEventAmbiguityError` and `extractLogs` skips it.

Also add `AbiEvent.fuzz.ts`, with properties over random events (anonymous or
not, any ABI type, named, unnamed, or mixed inputs) and random logs: `decode`
and `extractLogs` round-trip, `encode` produces the topics a contract emits,
`decode` returns or throws an ox error for any log, `decodeLog` decodes a
selector match the same way in any ABI, and `extractLogs` matches a model of
its matching rules with and without `eventName`.

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

vercel Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
ox Error Error Nov 2, 2026 2:24am UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 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-11-02T02:26:44.459996Z da652b2 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da652b2780

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/AbiEvent.ts
if (!event && !strict) {
// An anonymous event that fails to decode is not identified, so the
// non-strict fallback only applies to a signature match.
if (!event && !strict && items[0]!.anonymous !== true) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor non-strict decoding for selected anonymous events

When eventName explicitly selects a single anonymous event, a log with the expected topic count but missing or truncated data is rejected by the initial strict decode, and this condition then suppresses the non-strict fallback solely because the event is anonymous. Consequently, extractLogs(..., { eventName: 'Ping', strict: false }) returns [] instead of the partial arguments that the same strict: false option provides for named events; once the caller has selected an unambiguous anonymous candidate, it should proceed through the existing non-strict path.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Published ox@0.0.0-pr-564-da652b2 under the pr-564 dist-tag, which follows this pull request until it closes.

pnpm add ox@pr-564
pnpm add ox@0.0.0-pr-564-da652b2

@jxom
jxom merged commit b03705a into main Nov 2, 2026
15 of 16 checks passed
@jxom
jxom deleted the jxom/anonymous-event-logs branch November 2, 2026 02:48
@github-actions github-actions Bot mentioned this pull request Nov 2, 2026

This branch had an error being deployed

1 failed deployment
Preview — da652b27 Deployed Nov 2, 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.

2 participants