Skip to content

Commit 244f5fb

Browse files
committed
docs: move latest events docs out of readme to appropriate builder fn
1 parent d8a0e29 commit 244f5fb

File tree

2 files changed

+102
-53
lines changed

2 files changed

+102
-53
lines changed

README.md

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ Event Scanner is a Rust library for streaming EVM-based smart contract events. I
2121
- [Building a Scanner](#building-a-scanner)
2222
- [Defining Event Filters](#defining-event-filters)
2323
- [Scanning Modes](#scanning-modes)
24-
- [Scanning Latest Events](#scanning-latest-events)
2524
- [Examples](#examples)
2625
- [Testing](#testing)
2726

@@ -200,58 +199,6 @@ let multi_sigs = EventFilter::new()
200199

201200
See the integration tests under `tests/` for concrete examples.
202201

203-
### Scanning Latest Events
204-
205-
Scanner mode that collects a specified number of the most recent matching events for each registered stream.
206-
207-
- It does not enter live mode; it scans a block range and then returns.
208-
- Each registered stream receives at most `count` logs in a single message, chronologically ordered.
209-
210-
Basic usage:
211-
212-
```rust
213-
use alloy::{network::Ethereum, primitives::Address, transports::http::reqwest::Url};
214-
use event_scanner::{EventFilter, EventScanner, Message};
215-
use tokio_stream::StreamExt;
216-
217-
async fn latest_events(ws_url: Url, addr: Address) -> anyhow::Result<()> {
218-
let mut scanner = EventScanner::latest().count(10).connect_ws::<Ethereum>(ws_url).await?;
219-
220-
let filter = EventFilter::new().contract_address(addr);
221-
222-
let mut stream = scanner.subscribe(filter);
223-
224-
// Collect the latest 10 events across Earliest..=Latest
225-
scanner.start().await?;
226-
227-
// Expect a single message with up to 10 logs, then the stream ends
228-
while let Some(Message::Data(logs)) = stream.next().await {
229-
println!("Latest logs: {}", logs.len());
230-
}
231-
232-
Ok(())
233-
}
234-
```
235-
236-
Restricting to a specific block range:
237-
238-
```rust
239-
// Collect the latest 5 events between blocks [1_000_000, 1_100_000]
240-
let mut scanner = EventScanner::latest()
241-
.count(5)
242-
.from_block(1_000_000)
243-
.to_block(1_100_000)
244-
.connect_ws::<Ethereum>(ws_url).await?;
245-
.await?;
246-
```
247-
248-
The scanner periodically checks the tip to detect reorgs. On reorg, the scanner emits `ScannerStatus::ReorgDetected`, resets to the updated tip, and restarts the scan. Final delivery to log listeners is in chronological order.
249-
250-
Notes:
251-
252-
- Ensure you create streams via `subscribe()` before calling `start` so listeners are registered.
253-
- The function returns after delivering the messages; to continuously stream new blocks, use `EventScanner::sync().from_latest(count)`.
254-
255202
---
256203

257204
## Examples

src/event_scanner/modes/mod.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,108 @@ impl EventScanner {
3131
SyncScannerBuilder::new()
3232
}
3333

34+
/// Streams the latest `count` matching events per registered listener.
35+
///
36+
/// # Example
37+
///
38+
/// ```no_run
39+
/// # use alloy::{network::Ethereum, primitives::Address};
40+
/// # use event_scanner::{EventFilter, EventScanner, Message};
41+
/// # use tokio_stream::StreamExt;
42+
/// #
43+
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
44+
/// # let ws_url = "ws://localhost:8545".parse()?;
45+
/// # let contract_address = alloy::primitives::address!("0xd8dA6BF26964af9d7eed9e03e53415d37aa96045");
46+
/// // Collect the latest 10 events across Earliest..=Latest
47+
/// let mut scanner = EventScanner::latest()
48+
/// .count(10)
49+
/// .connect_ws::<Ethereum>(ws_url)
50+
/// .await?;
51+
///
52+
/// let filter = EventFilter::new().contract_address(contract_address);
53+
/// let mut stream = scanner.subscribe(filter);
54+
///
55+
/// scanner.start().await?;
56+
///
57+
/// // Expect a single message with up to 10 logs, then the stream ends
58+
/// while let Some(Message::Data(logs)) = stream.next().await {
59+
/// println!("Latest logs: {}", logs.len());
60+
/// }
61+
/// # Ok(())
62+
/// # }
63+
/// ```
64+
///
65+
/// Restricting to a specific block range:
66+
///
67+
/// ```no_run
68+
/// # use alloy::network::Ethereum;
69+
/// # use event_scanner::EventScanner;
70+
/// #
71+
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
72+
/// # let ws_url = "ws://localhost:8545".parse()?;
73+
/// // Collect the latest 5 events between blocks [1_000_000, 1_100_000]
74+
/// let mut scanner = EventScanner::latest()
75+
/// .count(5)
76+
/// .from_block(1_000_000)
77+
/// .to_block(1_100_000)
78+
/// .connect_ws::<Ethereum>(ws_url)
79+
/// .await?;
80+
/// # Ok(())
81+
/// # }
82+
/// ```
83+
///
84+
/// # How it works
85+
///
86+
/// The scanner performs a reverse-ordered scan (newest to oldest) within the specified block
87+
/// range, collecting up to `count` events per registered listener. Once the target count is
88+
/// reached or the range is exhausted, it delivers the events in chronological order (oldest to
89+
/// newest) and completes.
90+
///
91+
/// When using a custom block range, the scanner automatically normalizes the range boundaries.
92+
/// This means you can specify `from_block` and `to_block` in any order - the scanner will
93+
/// always scan from the higher block number down to the lower one, regardless of which
94+
/// parameter holds which value.
95+
///
96+
/// # Key behaviors
97+
///
98+
/// - **Single delivery**: Each registered stream receives at most `count` logs in a single
99+
/// message, chronologically ordered
100+
/// - **One-shot operation**: The scanner completes after delivering messages; it does not
101+
/// continue streaming
102+
/// - **Flexible count**: If fewer than `count` events exist in the range, returns all available
103+
/// events
104+
/// - **Default range**: By default, scans from `Earliest` to `Latest` block
105+
/// - **Reorg handling**: Periodically checks the tip to detect reorgs during the scan
106+
///
107+
/// # Important notes
108+
///
109+
/// - Register event streams via [`scanner.subscribe(filter)`][subscribe] **before** calling
110+
/// [`scanner.start()`][start]
111+
/// - The [`scanner.start()`][start] method returns immediately; events are delivered
112+
/// asynchronously
113+
/// - For continuous streaming after collecting latest events, use
114+
/// [`EventScanner::sync().from_latest(count)`][sync_from_latest] instead
115+
///
116+
/// # Reorg behavior
117+
///
118+
/// During the scan, the scanner periodically checks the tip to detect reorgs. On reorg
119+
/// detection:
120+
/// 1. Emits [`ScannerStatus::ReorgDetected`][reorg] to all listeners
121+
/// 2. Resets to the updated tip
122+
/// 3. Restarts the scan from the new tip
123+
/// 4. Continues until `count` events are collected
124+
///
125+
/// Final delivery to log listeners preserves chronological order regardless of reorgs.
126+
///
127+
/// [count]: latest::LatestScannerBuilder::count
128+
/// [from_block]: latest::LatestScannerBuilder::from_block
129+
/// [to_block]: latest::LatestScannerBuilder::to_block
130+
/// [block_confirmations]: latest::LatestScannerBuilder::block_confirmations
131+
/// [max_block_range]: latest::LatestScannerBuilder::max_block_range
132+
/// [subscribe]: latest::LatestEventScanner::subscribe
133+
/// [start]: latest::LatestEventScanner::start
134+
/// [sync_from_latest]: SyncScannerBuilder::from_latest
135+
/// [reorg]: crate::types::ScannerStatus::ReorgDetected
34136
#[must_use]
35137
pub fn latest() -> LatestScannerBuilder {
36138
LatestScannerBuilder::new()

0 commit comments

Comments
 (0)