OpenZeppelin / OpenZeppelin/Event-Scanner

feat: Support Multiple Event Filters for a Single Event Stream

Open
#169 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: feature
Dominant language
Rust
Stars
19
Forks
7
Avg merge
2h 15m
Merged PRs (30d)
4

Description

Currently it is possible to create only a single event filter per an event stream, and if one wants multiple event filters, they need to create multiple event streams:

let mut scanner = EventScannerBuilder::live()
    .block_confirmations(confirmations)
    .connect(provider.clone())
    .await?;

// track `CountIncreased` events from contract `a`
let a_filter = EventFilter::new()
    .contract_address(*a.address())
    .event(TestCounter::CountIncreased::SIGNATURE.to_owned());
// track `CountDecreased` events from contract `b`
let b_filter = EventFilter::new()
    .contract_address(*b.address())
    .event(TestCounter::CountDecreased::SIGNATURE.to_owned());

let a_stream = scanner.subscribe(a_filter);
let b_stream = scanner.subscribe(b_filter);

In the above example, merging the filters (and streams) would would result in different filter behavior:

// track `CountIncreased` and `CountDecreased` events from from both contracts `a` and `b`
let filter = EventFilter::new()
    .contract_address(*a.address())
    .contract_address(*b.address())
    .event(TestCounter::CountIncreased::SIGNATURE.to_owned())
    .event(TestCounter::CountDecreased::SIGNATURE.to_owned());

The difference is subtle, but important: in the first example the scanner would filter for CountIncreased events emitted only from contract a and for CountDecreased events emitted only from contract b, whereas in the second example the scanner would filter for both CountIncreased and CountDecreased events emitted from both contracts a and b; this means that CountIncreased emitted from b and CountDecreased emitted from a would also be tracked, which differs from the first example's behavior.

There are use cases when a user might want the scanner to filter events in the former way, but return them in a single stream, and not multiple ones.

This would probably look something like:

let mut scanner = EventScannerBuilder::live()
    .block_confirmations(confirmations)
    .connect(provider.clone())
    .await?;

// track `CountIncreased` events from contract `a`
let a_filter = EventFilter::new()
    .contract_address(*a.address())
    .event(TestCounter::CountIncreased::SIGNATURE.to_owned());
// track `CountDecreased` events from contract `b`
let b_filter = EventFilter::new()
    .contract_address(*b.address())
    .event(TestCounter::CountDecreased::SIGNATURE.to_owned());

// pass multiple filters as a slice/vector
// 
let stream = scanner.subscribe(&[a_filter, b_filter]);

To give an example of the expected behavior:

  • event listeners: A and B
  • block ranges being processed: 1-10, 11-20, 21-30
  • scanner processing block range 1-10
    • collects all events A and B in the range
    • sorts the events in chronological order (if not already sorted)
    • streams the sorted batch of A and B events
  • scanner processing block range 11-20
    ...

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at EventScannerBuilder::subscribe and the EventFilter usage shown in the issue, then trace how the scanner processes each block range and emits streams. Verify how multiple filters should preserve each filter's contract/event pairing while producing one chronologically sorted stream. Done means a slice or vector of filters can be subscribed to and batches from all matching filters are emitted as described.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
blockchain
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.