Skip to content

Commit c2b09a5

Browse files
authored
feat: Type Refactor + Prepare for Release (#143)
1 parent ecd4f7e commit c2b09a5

File tree

30 files changed

+1346
-1412
lines changed

30 files changed

+1346
-1412
lines changed

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ authors = ["OpenZeppelin"]
1414
edition = "2024"
1515
license = "AGPL-3.0-only"
1616
repository = "https://github.com/OpenZeppelin/Event-Scanner"
17-
version = "0.3.0-alpha"
17+
version = "0.4.0-alpha"
1818

1919
[workspace.lints.clippy]
2020
pedantic = "warn"

README.md

Lines changed: 73 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Event Scanner is a Rust library for streaming EVM-based smart contract events. I
4141

4242
The library exposes two primary layers:
4343

44-
- `EventScanner` – the main module the application will interact with.
44+
- `EventScanner` – the main scanner type the application will interact with.
4545
- `BlockRangeScanner` – lower-level component that streams block ranges, handles reorg, batching, and provider subscriptions.
4646

4747
---
@@ -52,14 +52,14 @@ Add `event-scanner` to your `Cargo.toml`:
5252

5353
```toml
5454
[dependencies]
55-
event-scanner = "0.3.0-alpha"
55+
event-scanner = "0.4.0-alpha"
5656
```
5757

5858
Create an event stream for the given event filters registered with the `EventScanner`:
5959

6060
```rust
6161
use alloy::{network::Ethereum, sol_types::SolEvent};
62-
use event_scanner::{EventFilter, EventScanner, EventScannerMessage};
62+
use event_scanner::{EventFilter, EventScannerBuilder, Message};
6363
use tokio_stream::StreamExt;
6464

6565
use crate::MyContract;
@@ -69,21 +69,33 @@ async fn run_scanner(
6969
contract: alloy::primitives::Address,
7070
) -> Result<(), Box<dyn std::error::Error>> {
7171
// Configure scanner with custom batch size (optional)
72-
let mut scanner = EventScanner::live()
73-
.block_read_limit(500) // Process up to 500 blocks per batch
72+
let mut scanner = EventScannerBuilder::live()
73+
.max_block_range(500) // Process up to 500 blocks per batch
7474
.connect_ws::<Ethereum>(ws_url).await?;
7575

76+
// Register an event listener
7677
let filter = EventFilter::new()
7778
.contract_address(contract)
7879
.event(MyContract::SomeEvent::SIGNATURE);
7980

8081
let mut stream = scanner.subscribe(filter);
8182

8283
// Start the scanner
83-
tokio::spawn(async move { scanner.stream().await });
84-
85-
while let Some(EventScannerMessage::Data(logs)) = stream.next().await {
86-
println!("Fetched logs: {logs:?}");
84+
scanner.start().await?;
85+
86+
// Process messages from the stream
87+
while let Some(message) = stream.next().await {
88+
match message {
89+
Message::Data(logs) => {
90+
println!("Received {} logs: {logs:?}", logs.len());
91+
}
92+
Message::Status(status) => {
93+
println!("Status update: {status:?}");
94+
}
95+
Message::Error(err) => {
96+
eprintln!("Error: {err}");
97+
}
98+
}
8799
}
88100

89101
Ok(())
@@ -96,7 +108,7 @@ async fn run_scanner(
96108

97109
### Building a Scanner
98110

99-
`EventScanner` provides mode-specific constructors and a builder pattern to configure settings before connecting.
111+
`EventScannerBuilder` provides mode-specific constructors and a functions to configure settings before connecting.
100112
Once configured, connect using one of:
101113

102114
- `connect_ws::<Ethereum>(ws_url)`
@@ -107,24 +119,36 @@ This will connect the `EventScanner` and allow you to create event streams and s
107119

108120
```rust
109121
// Live streaming mode
110-
let scanner = EventScanner::live()
111-
.block_read_limit(500) // Optional: set max blocks per read (default: 1000)
122+
let scanner = EventScannerBuilder::live()
123+
.max_block_range(500) // Optional: set max blocks per read (default: 1000)
124+
.block_confirmations(12) // Optional: set block confirmations (default: 12)
125+
.connect_ws::<Ethereum>(ws_url).await?;
126+
127+
// Historical block range mode
128+
let scanner = EventScannerBuilder::historic()
129+
.from_block(1_000_000)
130+
.to_block(2_000_000)
131+
.max_block_range(500)
112132
.connect_ws::<Ethereum>(ws_url).await?;
113133

114-
// Historical scanning mode
115-
let scanner = EventScanner::historic()
116-
.block_read_limit(500)
134+
// Latest events mode
135+
let scanner = EventScannerBuilder::latest(100)
136+
// .from_block(1_000_000) // Optional: set start of search range
137+
// .to_block(2_000_000) // Optional: set end of search range
138+
.max_block_range(500)
117139
.connect_ws::<Ethereum>(ws_url).await?;
118140

119-
// Sync mode (historical + live)
120-
let scanner = EventScanner::sync()
121-
.block_read_limit(500)
141+
// Sync from block then switch to live mode
142+
let scanner = EventScannerBuilder::sync()
143+
.from_block(100)
144+
.max_block_range(500)
145+
.block_confirmations(12)
122146
.connect_ws::<Ethereum>(ws_url).await?;
123147

124-
// Latest mode (recent blocks only)
125-
let scanner = EventScanner::latest()
126-
.count(100)
127-
.block_read_limit(500)
148+
// Sync the latest 60 events then switch to live mode
149+
let scanner = EventScannerBuilder::sync()
150+
.from_latest(60)
151+
.block_confirmations(12)
128152
.connect_ws::<Ethereum>(ws_url).await?;
129153
```
130154

@@ -163,6 +187,8 @@ Register multiple filters by invoking `subscribe` repeatedly.
163187

164188
The flexibility provided by `EventFilter` allows you to build sophisticated event monitoring systems that can track events at different granularities depending on your application's needs.
165189

190+
### Event Filter Batch Builders
191+
166192
Batch builder examples:
167193

168194
```rust
@@ -182,32 +208,40 @@ let multi_sigs = EventFilter::new()
182208
]);
183209
```
184210

185-
### Scanning Modes
211+
### Message Types
186212

187-
- **Live**`EventScanner::live()` creates a scanner that streams new blocks as they arrive. On detecting a reorg, the scanner emits `ScannerStatus::ReorgDetected` and recalculates the confirmed window, streaming logs from the corrected confirmed block range.
188-
- **Historic**`EventScanner::historic()` creates a scanner for streaming events from a past block range. Currently no reorg logic has been implemented (NOTE ⚠️: still WIP).
189-
- **Latest Events**`EventScanner::latest()` creates a scanner that streams the specified number of recently emitted events. On detecting a reorg, the scanner re-fetches all of the events in the specified block range (default: Earliest..=Latest).
190-
- **Sync from Block**`EventScanner::sync().from_block(start)` creates a scanner that streams events from a given start block, and then automatically transitions to live streaming. Reorgs are handled as per the particular mode phase the scanner is in (historic or live).
191-
- **Sync from Latest** - `EventScanner::sync().from_latest(count)` creates a scanner that streams the most recent `count` events, then automatically transitions to live streaming. Reorgs are handled as per the particular mode phase the scanner is in (latest events or live).
213+
The scanner delivers three types of messages through the event stream:
214+
215+
- **`Message::Data(Vec<Log>)`** – Contains a batch of matching event logs. Each log includes the raw event data, transaction hash, block number, and other metadata.
216+
- **`Message::Status(ScannerStatus)`** – Status notifications from the scanner:
217+
- **`Message::Error(ScannerError)`** – Error notifications if the scanner encounters issues (e.g., RPC failures, connection problems)
218+
219+
Always handle all message types in your stream processing loop to ensure robust error handling and proper reorg detection.
220+
221+
222+
### Scanning Modes
192223

193-
#### Configuration Tips
224+
- **Live** – scanner that streams new blocks as they arrive.
225+
- **Historic** – scanner for streaming events from a past block range (default: genesis..=latest).
226+
- **Latest Events** – scanner that collects up to `count` most recent events per listener. Final delivery is in chronological order (oldest to newest).
227+
- **Sync from Block** – scanner that streams events from a given start block up to the current confirmed tip, then automatically transitions to live streaming.
228+
- **Sync from Latest Events** - scanner that collects the most recent `count` events, then automatically transitions to live streaming.
194229

195-
- Set `block_read_limit` based on your RPC provider's limits (e.g., Alchemy, Infura may limit queries to 2000 blocks)
196-
- For live mode, if the WebSocket subscription lags significantly (e.g., >2000 blocks), ranges are automatically capped to prevent RPC errors
197-
- Each mode has its own appropriate configuration options for start block, end block, confirmations
198-
- The modes come with sensible defaults; for example not specifying a start block for historic mode automatically sets the start block to the genesis block.
230+
#### Important Notes
199231

200-
See the integration tests under `tests/` for concrete examples.
232+
- Set `max_block_range` based on your RPC provider's limits (e.g., Alchemy, Infura may limit queries to 2000 blocks). Default is 1000 blocks.
233+
- The modes come with sensible defaults; for example, not specifying a start block for historic mode automatically sets it to the genesis block.
234+
- For live mode, if the WebSocket subscription lags significantly (e.g., >2000 blocks), ranges are automatically capped to prevent RPC errors.
201235

202236
---
203237

204238
## Examples
205239

206-
- `examples/live_scanning` – minimal live-mode scanner using `EventScanner::live()`
207-
- `examples/historical_scanning` – demonstrates replaying historical data using `EventScanner::historic()`
208-
- `examples/sync_from_block_scanning` – demonstrates replaying from genesis (block 0) before continuing to stream the latest blocks using `EventScanner::sync().from_block(block_tag_or_number)`
209-
- `examples/latest_events_scanning` – demonstrates scanning the latest events using `EventScanner::latest()`
210-
- `examples/sync_from_latest_scanning` – demonstrates scanning the latest events before switching to live mode using `EventScanner::sync().from_latest(count)`.
240+
- `examples/live_scanning` – minimal live-mode scanner using `EventScannerBuilder::live()`
241+
- `examples/historical_scanning` – demonstrates replaying historical data using `EventScannerBuilder::historic()`
242+
- `examples/sync_from_block_scanning` – demonstrates replaying from genesis (block 0) before continuing to stream the latest blocks using `EventScannerBuilder::sync().from_block(block_tag_or_number)`
243+
- `examples/latest_events_scanning` – demonstrates scanning the latest events using `EventScannerBuilder::latest()`
244+
- `examples/sync_from_latest_scanning` – demonstrates scanning the latest events before switching to live mode using `EventScannerBuilder::sync().from_latest(count)`.
211245

212246
Run an example with:
213247

examples/historical_scanning/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use alloy::{network::Ethereum, providers::ProviderBuilder, sol, sol_types::SolEvent};
22
use alloy_node_bindings::Anvil;
33

4-
use event_scanner::{EventFilter, EventScanner, Message};
4+
use event_scanner::{EventFilter, EventScannerBuilder, Message};
55
use tokio_stream::StreamExt;
66
use tracing::{error, info};
77
use tracing_subscriber::EnvFilter;
@@ -51,7 +51,7 @@ async fn main() -> anyhow::Result<()> {
5151
let _ = counter_contract.increase().send().await?.get_receipt().await?;
5252

5353
let mut scanner =
54-
EventScanner::historic().connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
54+
EventScannerBuilder::historic().connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
5555

5656
let mut stream = scanner.subscribe(increase_filter);
5757

examples/latest_events_scanning/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use alloy::{network::Ethereum, providers::ProviderBuilder, sol, sol_types::SolEvent};
22
use alloy_node_bindings::Anvil;
3-
use event_scanner::{EventFilter, EventScanner, Message};
3+
use event_scanner::{EventFilter, EventScannerBuilder, Message};
44
use tokio_stream::StreamExt;
55
use tracing::{error, info};
66
use tracing_subscriber::EnvFilter;
@@ -48,7 +48,7 @@ async fn main() -> anyhow::Result<()> {
4848
.event(Counter::CountIncreased::SIGNATURE);
4949

5050
let mut scanner =
51-
EventScanner::latest().count(5).connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
51+
EventScannerBuilder::latest(5).connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
5252

5353
let mut stream = scanner.subscribe(increase_filter);
5454

examples/live_scanning/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use alloy::{network::Ethereum, providers::ProviderBuilder, sol, sol_types::SolEvent};
22
use alloy_node_bindings::Anvil;
3-
use event_scanner::{EventFilter, EventScanner, Message};
3+
use event_scanner::{EventFilter, EventScannerBuilder, Message};
44

55
use tokio_stream::StreamExt;
66
use tracing::{error, info};
@@ -48,7 +48,8 @@ async fn main() -> anyhow::Result<()> {
4848
.contract_address(*contract_address)
4949
.event(Counter::CountIncreased::SIGNATURE);
5050

51-
let mut scanner = EventScanner::live().connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
51+
let mut scanner =
52+
EventScannerBuilder::live().connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
5253

5354
let mut stream = scanner.subscribe(increase_filter);
5455

examples/sync_from_block_scanning/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::time::Duration;
22

33
use alloy::{network::Ethereum, providers::ProviderBuilder, sol, sol_types::SolEvent};
44
use alloy_node_bindings::Anvil;
5-
use event_scanner::{EventFilter, EventScanner, Message};
5+
use event_scanner::{EventFilter, EventScannerBuilder, Message};
66
use tokio::time::sleep;
77
use tokio_stream::StreamExt;
88
use tracing::{error, info};
@@ -56,8 +56,10 @@ async fn main() -> anyhow::Result<()> {
5656
info!("Historical event {} created", i + 1);
5757
}
5858

59-
let mut scanner =
60-
EventScanner::sync().from_block(0).connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
59+
let mut scanner = EventScannerBuilder::sync()
60+
.from_block(0)
61+
.connect_ws::<Ethereum>(anvil.ws_endpoint_url())
62+
.await?;
6163

6264
let mut stream = scanner.subscribe(increase_filter);
6365

examples/sync_from_latest_scanning/main.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use alloy::{network::Ethereum, providers::ProviderBuilder, sol, sol_types::SolEvent};
22
use alloy_node_bindings::Anvil;
3-
use event_scanner::{
4-
EventFilter,
5-
event_scanner::{EventScanner, Message},
6-
};
3+
use event_scanner::{EventFilter, EventScannerBuilder, Message};
74

85
use tokio_stream::StreamExt;
96
use tracing::{error, info};
@@ -51,8 +48,10 @@ async fn main() -> anyhow::Result<()> {
5148
.contract_address(*contract_address)
5249
.event(Counter::CountIncreased::SIGNATURE);
5350

54-
let mut client =
55-
EventScanner::sync().from_latest(5).connect_ws::<Ethereum>(anvil.ws_endpoint_url()).await?;
51+
let mut client = EventScannerBuilder::sync()
52+
.from_latest(5)
53+
.connect_ws::<Ethereum>(anvil.ws_endpoint_url())
54+
.await?;
5655

5756
let mut stream = client.subscribe(increase_filter);
5857

src/event_scanner/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
pub mod error;
2-
pub mod filter;
3-
pub mod listener;
4-
pub mod message;
5-
pub mod modes;
1+
mod error;
2+
mod filter;
3+
mod listener;
4+
mod message;
5+
mod scanner;
66

77
pub use filter::EventFilter;
88
pub use message::Message;
9-
pub use modes::{
10-
EventScanner, HistoricEventScanner, LatestEventScanner, LiveEventScanner,
11-
SyncFromBlockEventScanner, SyncFromLatestEventScanner,
9+
pub use scanner::{
10+
EventScanner, EventScannerBuilder, Historic, LatestEvents, Live, SyncFromBlock,
11+
SyncFromLatestEvents,
1212
};

0 commit comments

Comments
 (0)