Add a way to fetch all contract events#222
Conversation
|
@alisinabh Hey, love the library, I keep running into having to create a bunch of filters to ingest manually multiple events of the same contract, this aims to fix this, feel free to close it if you don't think it belongs here. |
Add a way to fetch all contract events
5cbd5d0 to
b5ee972
Compare
b5ee972 to
efecb06
Compare
alisinabh
left a comment
There was a problem hiding this comment.
Thanks for the addition.
Upon first look I added one comment.
Also Im not sure a function in Ethers module is the best answer here. My initial thought is to have a function (maybe in Utils) that returns all event filters of a contract then the result of that can be used with the same get_logs function.
That sounds reasonable, could adapt the get_logs function to allow for multiple event filters, something like:
Or allow a list in the same function and have Let me know what you think. |
|
Yeah I think One caveat is that we should ensure that if there are more than one event filter with a default address they must be the same. Otherwise we should require an explicit |
Keeps the Counter contract reset() event which the new tests reuse. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Introduce Ethers.CombinedEventFilter, created via Ethers.EventFilter.combine/1 or the generated EventFilters.all/0 function of contract modules. The combined topic_0 values are sent as an OR-ed list so filtering happens server side, and fetched logs are decoded with their matching event selector. Works with both Ethers.get_logs/2 and Ethers.batch/2. Combining validates that all filters use wildcard indexed arguments and have no conflicting default addresses (eth_getLogs accepts a single address). Also normalize from_block/to_block keys to fromBlock/toBlock in get_logs pre-processing, fixing batched get_logs requests with block ranges which bypassed Ethereumex's key normalization. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the generated EventFilters.all/0 function with a hidden __all__/0 (following the __events__/__default_address__ convention) to avoid colliding with contracts that define an All event. Instead, Ethers.get_logs/2, Ethers.batch/2 and Ethers.EventFilter.combine/1 now accept an EventFilters module name directly and translate it to __all__/0 internally. Also add the Ethers.Types.is_module/1 guard for module name detection. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces combined event filters so consumers can fetch and decode logs for multiple events (OR semantics) — or all events of a contract — in a single eth_getLogs call, reducing the need for multiple event-specific requests.
Changes:
- Add
Ethers.CombinedEventFilterplusEthers.EventFilter.combine/1to OR multiple event selectors into a single filter and decode results per-event. - Extend
Ethers.get_logs/2andEthers.batch/2to accept an EventFilters module (fetch all events of a contract) and handle decoding for combined filters. - Update tests and docs (README/CHANGELOG) and add a new
ResetCalledevent to the test contract to validate multi-event behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/support/contracts/counter.sol | Adds a reset function and ResetCalled() event to support multi-event log tests. |
| test/ethers/counter_contract_test.exs | Adds coverage for combining filters, module-based “all events” fetching, batching, default address behavior, and failure cases. |
| test/ethers_test.exs | Adds regression coverage for request failure handling with combined filters and default address mapping. |
| README.md | Documents combining event filters and fetching all contract events via an EventFilters module. |
| lib/ethers/types.ex | Adds an is_module/1 guard used to detect module arguments. |
| lib/ethers/event_filter.ex | Adds combine/1 delegation and supports CombinedEventFilter in to_map/2. |
| lib/ethers/contract.ex | Generates EventFilters.__all__/0 for contract modules to expose “all events” combined filter. |
| lib/ethers/combined_event_filter.ex | Implements combined filter construction, validation, mapping to RPC params, decoding, and inspect formatting. |
| lib/ethers.ex | Extends get_logs/2 + batch request normalization to accept EventFilters modules and decode combined-filter results. |
| CHANGELOG.md | Announces the combined event filter feature and module-based “all events” usage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@ddallaire I have deviated a bit from the original approach and I believe this should be better. Thank you for the initial work on this. |
Description
Using
get_logsbecomes tedious when ingesting all (or several) of a contract's events, since each event requires its own filter and request. This PR makes it possible to fetch and decode multiple events — or all events of a contract — in a singleeth_getLogsrequest.Following the review discussion, the original
get_logs_for_contractfunction was reverted in favor of combined event filters: the combination is a filter value rather than a new function, so it works everywhere a regular event filter is accepted with no API surface changes toget_logs.Details
Combining specific events
combine/1returns anEthers.CombinedEventFilterwhich sends thetopic_0values as an OR-ed list, so filtering happens server side (no client-side dropping of logs). Each fetched log is decoded with its matching event selector.Fetching all events of a contract
Passing an EventFilters module is translated internally to a combined filter of all the contract's events (via a hidden generated
__all__/0, following the__events__/__default_address__convention to avoid colliding with contracts that define anAllevent):Module names are accepted by
Ethers.get_logs/2,Ethers.batch/2({:get_logs, MyToken.EventFilters, ...}) and insideEthers.EventFilter.combine/1(mixed with regular filters).Validation (at combine time)
combine/1raisesArgumentErrorwhen:eth_getLogsaccepts a single addressBug fix
Batched
{:get_logs, filter, from_block: ...}requests were broken since batching bypasses Ethereumex'sfrom_block→fromBlockkey normalization.pre_processnow normalizes the keys itself.Checklist
Ethers.CombinedEventFilterandEthers.EventFilter.combine/1get_logs,batchandcombine(translated to the generated__all__/0)Ethers.Types.is_module/1guard