1use std::fmt::{Debug, Display};
2
3use alloy::{
4 primitives::{Address, keccak256},
5 rpc::types::{Filter, Topic, ValueOrArray},
6};
7
8#[derive(Clone, Default)]
26pub struct EventFilter {
27 pub(crate) contract_addresses: Vec<Address>,
30 pub(crate) events: Vec<String>,
32 pub(crate) event_signatures: Topic,
34}
35
36impl Display for EventFilter {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 let mut content = vec![];
39 if !self.contract_addresses.is_empty() {
40 let contracts = self
41 .contract_addresses
42 .iter()
43 .map(|addr| format!("{addr}"))
44 .collect::<Vec<_>>()
45 .join(", ");
46 content.push(format!("contracts: [{contracts}]",));
47 }
48 if !self.events.is_empty() {
49 content.push(format!("events: [{}]", self.events.join(", ")));
50 }
51 if !self.event_signatures.is_empty() {
52 let value_or_array = self.event_signatures.to_value_or_array().unwrap();
54 let event_signatures = match value_or_array {
55 ValueOrArray::Value(value) => format!("{value}"),
56 ValueOrArray::Array(arr) => {
57 arr.iter().map(|t| format!("{t}")).collect::<Vec<_>>().join(", ")
58 }
59 };
60 content.push(format!("event_signatures: [{event_signatures}]"));
61 }
62
63 write!(f, "EventFilter({})", content.join(", "))
64 }
65}
66
67impl Debug for EventFilter {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(f, "{self}")
70 }
71}
72
73impl EventFilter {
74 #[must_use]
76 pub fn new() -> Self {
77 EventFilter::default()
78 }
79
80 #[must_use]
83 pub fn with_contract_address(mut self, contract_address: impl Into<Address>) -> Self {
84 self.contract_addresses.push(contract_address.into());
85 self
86 }
87
88 #[must_use]
91 pub fn with_contract_addresses(
92 mut self,
93 contract_addresses: impl IntoIterator<Item = impl Into<Address>>,
94 ) -> Self {
95 self.contract_addresses.extend(contract_addresses.into_iter().map(Into::into));
96 self
97 }
98
99 #[must_use]
103 pub fn with_event(mut self, event: impl Into<String>) -> Self {
104 let event = event.into();
105 if !event.is_empty() {
106 self.events.push(event);
107 }
108 self
109 }
110
111 #[must_use]
115 pub fn with_events(mut self, events: impl IntoIterator<Item = impl Into<String>>) -> Self {
116 self.events.extend(events.into_iter().map(Into::into));
117 self
118 }
119
120 #[must_use]
124 pub fn with_event_signature(mut self, event_signature: impl Into<Topic>) -> Self {
125 self.event_signatures = self.event_signatures.extend(event_signature.into());
126 self
127 }
128
129 #[must_use]
133 pub fn with_event_signatures(
134 mut self,
135 event_signatures: impl IntoIterator<Item = impl Into<Topic>>,
136 ) -> Self {
137 for event_signature in event_signatures {
138 self.event_signatures = self.event_signatures.extend(event_signature);
139 }
140 self
141 }
142
143 #[must_use]
146 fn all_events(&self) -> Topic {
147 let events = self.events.iter().map(|e| keccak256(e.as_bytes())).collect::<Vec<_>>();
148 let sigs = self.event_signatures.clone();
149 sigs.extend(events)
150 }
151}
152
153impl From<EventFilter> for Filter {
154 fn from(value: EventFilter) -> Self {
155 let mut filter = Filter::new();
156 let events = value.all_events();
157 if !events.is_empty() {
158 filter = filter.event_signature(events);
159 }
160 if !value.contract_addresses.is_empty() {
161 filter = filter.address(value.contract_addresses);
162 }
163 filter
164 }
165}
166
167impl From<&EventFilter> for Filter {
168 fn from(value: &EventFilter) -> Self {
169 let mut filter = Filter::new();
170 let events = value.all_events();
171 if !events.is_empty() {
172 filter = filter.event_signature(events);
173 }
174 if !value.contract_addresses.is_empty() {
175 filter = filter.address(value.contract_addresses.clone());
176 }
177 filter
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::EventFilter;
184 use alloy::{
185 primitives::{Address, address},
186 rpc::types::Topic,
187 sol,
188 sol_types::SolEvent,
189 };
190
191 sol! {
192 contract SomeContract {
193 event EventOne();
194 event EventTwo();
195 }
196 }
197
198 #[test]
199 fn display_default_no_address_no_events() {
200 let filter = EventFilter::new();
201 let got = format!("{filter}");
202 let expected = "EventFilter()";
203 assert_eq!(got, expected);
204
205 assert_eq!(format!("{filter:?}"), got);
207 }
208
209 #[test]
210 fn display_with_address() {
211 let address = address!("0x000000000000000000000000000000000000dEaD");
212 let filter = EventFilter::new().with_contract_address(address);
213 let got = format!("{filter}");
214 let expected = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD])";
215 assert_eq!(got, expected);
216
217 let filter = EventFilter::new().with_contract_addresses(vec![address]);
219 let got = format!("{filter}");
220 assert_eq!(got, expected);
221
222 assert_eq!(format!("{filter:?}"), got);
224 }
225
226 #[test]
227 fn display_with_multiple_addresses() {
228 let address_1 = address!("0x000000000000000000000000000000000000dEaD");
229 let address_2 = address!("0x0000000000000000000000000000000000000001");
230 let filter =
231 EventFilter::new().with_contract_address(address_1).with_contract_address(address_2);
232
233 let got = format!("{filter}");
234 let expected = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD, 0x0000000000000000000000000000000000000001])";
235 assert_eq!(got, expected);
236
237 let filter = EventFilter::new().with_contract_addresses(vec![address_1, address_2]);
239 let got = format!("{filter}");
240 assert_eq!(got, expected);
241
242 assert_eq!(format!("{filter:?}"), got);
244 }
245
246 #[test]
247 fn display_single_event() {
248 let event = SomeContract::EventOne::SIGNATURE;
249 let filter = EventFilter::new().with_event(event);
250 let got = format!("{filter}");
251 let expected = "EventFilter(events: [EventOne()])";
252 assert_eq!(got, expected);
253
254 assert_eq!(format!("{filter:?}"), got);
256 }
257
258 #[test]
259 fn display_single_event_signature() {
260 let event_signature = SomeContract::EventOne::SIGNATURE_HASH;
261 let filter = EventFilter::new().with_event_signature(event_signature);
262 let got = format!("{filter}");
263 let expected = "EventFilter(event_signatures: [0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91])";
264 assert_eq!(got, expected);
265
266 assert_eq!(format!("{filter:?}"), got);
268 }
269
270 #[test]
271 fn display_multiple_events_with_address() {
272 let address = address!("0x000000000000000000000000000000000000dEaD");
273 let events = vec![SomeContract::EventOne::SIGNATURE, SomeContract::EventTwo::SIGNATURE];
274 let filter = EventFilter::new().with_contract_address(address).with_events(events.clone());
275
276 let got = format!("{filter}");
277 let expected = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD], events: [EventOne(), EventTwo()])";
278 assert_eq!(got, expected);
279
280 assert_eq!(format!("{filter:?}"), got);
282 }
283
284 #[test]
285 fn display_multiple_event_signatures_with_address() {
286 let address = address!("0x000000000000000000000000000000000000dEaD");
287 let event_signatures =
288 vec![SomeContract::EventOne::SIGNATURE_HASH, SomeContract::EventTwo::SIGNATURE_HASH];
289 let filter = EventFilter::new()
290 .with_contract_address(address)
291 .with_event_signatures(event_signatures.clone());
292
293 let got = format!("{filter}");
294 let expected_1 = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD], event_signatures: [0x16eb4fc7651e068f1c31303645026f82d5fced11a8d5209bbf272072be23ddff, 0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91])";
295 let expected_2 = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD], event_signatures: [0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91, 0x16eb4fc7651e068f1c31303645026f82d5fced11a8d5209bbf272072be23ddff])";
296 assert!(
297 got == expected_1 || got == expected_2,
298 "got: {got},\nexpected_1: {expected_1},\nexpected_2: {expected_2}"
299 );
300
301 assert_eq!(format!("{filter:?}"), got);
303 }
304
305 #[test]
306 fn display_multiple_events_and_event_signatures() {
307 let events = vec![SomeContract::EventOne::SIGNATURE, SomeContract::EventTwo::SIGNATURE];
308 let event_signatures =
309 vec![SomeContract::EventOne::SIGNATURE_HASH, SomeContract::EventTwo::SIGNATURE_HASH];
310 let filter = EventFilter::new()
311 .with_events(events.clone())
312 .with_event_signatures(event_signatures.clone());
313
314 let got = format!("{filter}");
315 let expected_1 = "EventFilter(events: [EventOne(), EventTwo()], event_signatures: [0x16eb4fc7651e068f1c31303645026f82d5fced11a8d5209bbf272072be23ddff, 0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91])";
316 let expected_2 = "EventFilter(events: [EventOne(), EventTwo()], event_signatures: [0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91, 0x16eb4fc7651e068f1c31303645026f82d5fced11a8d5209bbf272072be23ddff])";
317 assert!(
318 got == expected_1 || got == expected_2,
319 "got: {got},\nexpected_1: {expected_1},\nexpected_2: {expected_2}"
320 );
321
322 assert_eq!(format!("{filter:?}"), got);
324 }
325
326 #[test]
327 fn display_multiple_events_and_event_signatures_with_addresses() {
328 let addresses = vec![
329 address!("0x000000000000000000000000000000000000dEaD"),
330 address!("0x0000000000000000000000000000000000000001"),
331 ];
332 let events = vec![SomeContract::EventOne::SIGNATURE, SomeContract::EventTwo::SIGNATURE];
333 let event_signatures =
334 vec![SomeContract::EventOne::SIGNATURE_HASH, SomeContract::EventTwo::SIGNATURE_HASH];
335 let filter = EventFilter::new()
336 .with_contract_addresses(addresses)
337 .with_events(events.clone())
338 .with_event_signatures(event_signatures.clone());
339
340 let got = format!("{filter}");
341 let expected_1 = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD, 0x0000000000000000000000000000000000000001], events: [EventOne(), EventTwo()], event_signatures: [0x16eb4fc7651e068f1c31303645026f82d5fced11a8d5209bbf272072be23ddff, 0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91])";
342 let expected_2 = "EventFilter(contracts: [0x000000000000000000000000000000000000dEaD, 0x0000000000000000000000000000000000000001], events: [EventOne(), EventTwo()], event_signatures: [0xa08dd6fd0d644da5df33d075cb9256203802f6948ab81b87079960711810dc91, 0x16eb4fc7651e068f1c31303645026f82d5fced11a8d5209bbf272072be23ddff])";
343 assert!(
344 got == expected_1 || got == expected_2,
345 "got: {got},\nexpected_1: {expected_1},\nexpected_2: {expected_2}"
346 );
347
348 assert_eq!(format!("{filter:?}"), got);
350 }
351
352 #[test]
353 fn display_with_empty_address_vector_noop() {
354 let filter = EventFilter::new().with_contract_addresses(Vec::<Address>::new());
356 let got = format!("{filter}");
357 let expected = "EventFilter()";
358 assert_eq!(got, expected);
359
360 assert_eq!(format!("{filter:?}"), got);
362 }
363
364 #[test]
365 fn display_with_empty_events_vector_noop() {
366 let filter = EventFilter::new().with_events(Vec::<String>::new());
368 let got = format!("{filter}");
369 let expected = "EventFilter()";
370 assert_eq!(got, expected);
371
372 assert_eq!(format!("{filter:?}"), got);
374 }
375
376 #[test]
377 fn display_with_empty_event_signatures_vector_noop() {
378 let filter = EventFilter::new().with_event_signatures(Vec::<Topic>::new());
380 let got = format!("{filter}");
381 let expected = "EventFilter()";
382 assert_eq!(got, expected);
383
384 assert_eq!(format!("{filter:?}"), got);
386 }
387}