Repository navigation
fix: decode anonymous event logs when requested - #5375
Conversation
`decodeEventLog` and `parseEventLogs` matched an anonymous event to any log with an unknown signature topic and the same topic count. Since a log carries nothing that identifies an anonymous event, an ABI that holds one (such as DSNote's `LogNote`) claimed unrelated logs from other contracts in a receipt. Anonymous events are now only matched when `eventName` names them, or when every event in `abi` is anonymous (as with `getLogs` and `watchEvent` given a single anonymous `event`). A mixed ABI without `eventName` throws `AbiEventSignatureNotFoundError` for an unknown signature again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 6ceab0e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76e0600643
ℹ️ 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".
Move `AbiEventAmbiguityError` from `errors/abi.ts` to the bottom of `decodeEventLog.ts` and export it from there. For overloads that share a name, the error now recommends an `abi` narrowed to one event, since `eventName` cannot choose between them. Also shorten the changeset to one sentence, split the anonymous-event paragraphs in the `decodeEventLog` and `parseEventLogs` docs, and assert the anonymous-event decoder results with inline snapshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
|
Published pnpm add viem@pr-5375
pnpm add viem@0.0.0-pr-5375-6481114 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6a15de8d1
ℹ️ 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".
| if (!event && !strict) { | ||
| abiItem = abiItems[0] | ||
| const fallback = abiItems[0] | ||
| if (!fallback || fallback.abi.anonymous) return null |
There was a problem hiding this comment.
Retry unique anonymous candidates in non-strict mode
When strict: false is used with a uniquely selected anonymous event whose topics have the expected arity but whose data is missing or nonconforming, the initial strict probe fails and this return drops the log outright. parseEventLogs documents non-strict mode as partially decoding nonconforming logs, and the candidate is already uniquely identified by eventName or an all-anonymous ABI, so it should receive the same strict: false retry as a signature match.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Leaving this as is for now. A non-anonymous log is identified by its signature topic before non-strict decoding runs. An anonymous log has nothing identifying it, so a strict decode is the only check left that it came from the event. getLogs defaults to strict: false, so a non-strict retry here would label any same-arity log from the watched address as the anonymous event, with partial args. This is the false positive this PR removes. I've asked the maintainer to make the call.
Generated by Claude Code
TypeScript 7 rejects `encodeEventTopics` parameters without `eventName` for this ABI literal, which failed `Verify / Types (latest)`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a40dbe156
ℹ️ 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".
| return requested.filter( | ||
| (item) => item.anonymous && indexedCount(item) === topicCount, |
There was a problem hiding this comment.
Preserve partial decoding for selected anonymous events
When strict: false is used with a uniquely selected anonymous event whose indexed topics are missing, this exact arity filter rejects the event before decodeMatchedEventLog can apply its existing non-strict handling for missing indexed inputs. For example, an explicit eventName plus one topic for an anonymous event with two indexed parameters now throws AbiEventSignatureNotFoundError instead of returning the partially decoded argument set, unlike the same mismatch on a non-anonymous event. Allow the uniquely identified candidate to reach the non-strict decoder.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Same reasoning as #5375 (comment). For an anonymous event the topic count is the only structural check left, since there's no signature topic. If a log with fewer topics could reach the non-strict decoder, any shorter log from the address would decode as the event, with the missing inputs read from data. A non-anonymous mismatch differs because its signature topic already identifies the event. I've asked the maintainer to make the call.
Generated by Claude Code
`getFilterChanges` and `getFilterLogs` now pass `filter.eventName` to `parseEventLogs`, and the `watchContractEvent` subscription passes `eventName` to `decodeEventLog`, so an anonymous event selected from a mixed ABI decodes. In strict mode, `watchEvent` and `watchContractEvent` subscriptions skip logs that match no requested event, which a topic filter cannot exclude for anonymous events. Also add TSDoc to `AbiEventAmbiguityError`, import public helpers from `viem` in the `decodeEventLog` tests, and raise the `viem` (esm and cjs) and `viem/actions` size limits by 1 kB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
Property tests over random ABIs (named and anonymous events, overloads, integer, bytes, string, tuple, and array inputs, named and unnamed) and random logs: - `decodeEventLog` decodes the arguments a log was encoded from. - `decodeEventLog` matches ox for named non-anonymous events. - A signature match decodes the same way whatever else the ABI holds. - `decodeEventLog` returns or throws a Viem error for any log. - `parseEventLogs` matches a model of its documented matching rules, with and without `eventName`, keeps a log whose own indexed values are passed as `args`, and does not throw in non-strict mode. `FUZZ_RUNS` and `FUZZ_SEED` control the runs, as for the Tempo fuzz tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6481114dba
ℹ️ 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".
Move the `decodeEventLog` properties to `decodeEventLog.fuzz.test.ts` and the `parseEventLogs` properties to `parseEventLogs.fuzz.test.ts`, beside their modules. The shared ABI and log generators move to `test/src/abi/eventLogs.ts`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
`watchEvent` (with `event` or `events`) and `watchContractEvent` (with `eventName`) subscriptions now skip logs that match no requested event in non-strict mode too, as their polling paths do. A topic filter cannot select an anonymous event, so the subscription can deliver other logs from the same address. Watches that name no event still emit every log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
`abitype` does not resolve from `test/src` in CI, which failed `Verify / Types (latest)`. `src/index.ts` re-exports `AbiEvent` and `AbiParameter`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3nmWga38V3yjkJET3UZeh
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6ceab0ea0a
ℹ️ 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".
|
|
||
| return decodeMatchedEventLog({ | ||
| abiItem, | ||
| argTopics: abiItem.anonymous ? topics : topics.slice(1), |
There was a problem hiding this comment.
Account for anonymous topics in return-type inference
For an anonymous event, this branch correctly treats every topic as indexed data at runtime, but DecodeEventLogParameters still models the first element as a signature and infers the topics generic from only the remaining elements. Consequently, an anonymous event with one indexed argument infers topics as [], making the return type report args?: undefined (or optional when data is supplied) even though this call returns the decoded argument object; consumers therefore cannot safely access the primary result of the new feature. Update the parameter/return inference for anonymous events and cover it in decodeEventLog.test-d.ts.
AGENTS.md reference: AGENTS.md:L70-L76
Useful? React with 👍 / 👎.
| const decoded = decodeEventLog({ | ||
| abi: abi, | ||
| data: log.data, | ||
| eventName, |
There was a problem hiding this comment.
Filter signature matches from anonymous subscriptions
When a non-polling watchContractEvent selects an anonymous event from a mixed ABI with no selective indexed arguments, its subscription has no signature topic and therefore also receives ordinary named events. Passing eventName here does not scope signature matches because decodeEventLog deliberately checks non-anonymous selectors first, so a received named event is successfully decoded and emitted instead of being skipped; the polling path filters that same result through parseEventLogs. Verify that decoded.eventName matches the requested name before emitting, or decode against only the selected ABI event.
Useful? React with 👍 / 👎.
|
|
||
| A log matches an anonymous event when its topic count equals the event's indexed argument count, and its first topic is not another event's signature. | ||
|
|
||
| A log that fits several anonymous events is left out. Pass `eventName` to choose one. |
There was a problem hiding this comment.
Document narrowing for same-name anonymous overloads
When several anonymous overloads share both a name and indexed-topic count, passing that eventName still leaves multiple candidates, so parseEventLogs continues to omit the log even after the reader follows this instruction. As the adjacent decodeEventLog documentation already explains, this case requires narrowing abi to the desired overload; include that qualification here so the documented remedy actually resolves every stated ambiguity.
Useful? React with 👍 / 👎.
Supersedes #5374 and keeps @mortezashojaei's two commits, with one follow-up commit on top.
encodeEventTopicsalready leaves out the signature topic for anonymous events.decodeEventLogandparseEventLogsstill readtopics[0]as the signature, sogetLogsandwatchEventdropped anonymous logs. #5374 fixed that.It also let an anonymous event claim any log whose signature topic is unknown and whose topic count matches. A log carries nothing that identifies an anonymous event. Decoding is a weak check: address and uint topics decode from any 32 bytes, and extra data is ignored. So an ABI that already holds an anonymous event, such as DSNote's
LogNotein Maker ABIs, would quietly mislabel unrelated logs from other contracts in a receipt.This PR matches anonymous events only when they are requested:
eventNamenames the event, orabiis anonymous. This coversgetLogsandwatchEventwith a single anonymousevent, so they need no changes.The rest of #5374 is unchanged: a signature match wins, the topic count must match, events with the same number of indexed inputs are never guessed (
AbiEventAmbiguityErroror the log is dropped), and the non-strict fallback never invents an anonymous event. The follow-up also removes an unreachableif (!abiItem)branch and replaces a nested ternary inparseEventLogs.Not covered:
getLogs({ events: [...] })with a mix of anonymous and non-anonymous events still can't fetch the anonymous logs. The topic filter only ORs the selectors. That predates this PR, and the changeset now states the single-eventscope.Validation:
decodeEventLog,parseEventLogs,encodeEventTopics, andindextests pass (97), except the 3 existingparseEventLogstests that need anvil, which weren't available locally.tsc -p src/tsconfig.jsonand Biome are clean.Generated by Claude Code