1use crate::{
4 decode::{Decode, DecodeError},
5 encode::Encode,
6 fmt::Hex,
7 log::{FromTopic, Log, ToTopic, Topics},
8 primitive::Word,
9};
10use std::{
11 error::Error,
12 fmt::{self, Debug, Display, Formatter},
13 marker::PhantomData,
14};
15
16pub trait Indexed: Sized {
18 fn from_topics(topics: &Topics) -> Result<(Word, Self), FromTopicsError>;
19 fn to_topics(topic0: &Word, indices: &Self) -> Topics;
20}
21
22pub trait IndexedAnonymous: Sized {
24 fn from_topics_anonymous(topics: &Topics) -> Result<Self, FromTopicsError>;
25 fn to_topics_anonymous(&self) -> Topics;
26}
27
28pub struct EventEncoder<I, D> {
30 pub topic0: Word,
32 _marker: PhantomData<*const (I, D)>,
33}
34
35impl<I, D> EventEncoder<I, D>
36where
37 I: Indexed,
38{
39 pub const fn new(topic0: Word) -> Self {
41 Self {
42 topic0,
43 _marker: PhantomData,
44 }
45 }
46}
47
48impl<I, D> EventEncoder<I, D>
49where
50 I: Indexed,
51 D: Encode,
52{
53 pub fn encode(&self, indices: &I, data: &D) -> Log<'_> {
55 Log {
56 topics: I::to_topics(&self.topic0, indices),
57 data: crate::encode(data).into(),
58 }
59 }
60}
61
62impl<I, D> EventEncoder<I, D>
63where
64 I: Indexed,
65 D: Decode,
66{
67 pub fn decode(&self, log: &Log) -> Result<(I, D), ParseError> {
69 let (topic0, indices) = I::from_topics(&log.topics)?;
70 if topic0 != self.topic0 {
71 return Err(ParseError::SelectorMismatch(topic0));
72 }
73 let data = crate::decode(&log.data)?;
74
75 Ok((indices, data))
76 }
77}
78
79impl<I, D> Debug for EventEncoder<I, D> {
80 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
81 f.debug_struct("EventEncoder")
82 .field("topic0", &Hex(&self.topic0))
83 .finish()
84 }
85}
86
87pub struct AnonymousEventEncoder<I, D>(PhantomData<*const (I, D)>);
89
90impl<I, D> AnonymousEventEncoder<I, D>
91where
92 I: IndexedAnonymous,
93{
94 pub fn new() -> Self {
96 Self(PhantomData)
97 }
98}
99
100impl<I, D> AnonymousEventEncoder<I, D>
101where
102 I: IndexedAnonymous,
103 D: Encode,
104{
105 pub fn encode(&self, indices: &I, data: &D) -> Log<'_> {
107 Log {
108 topics: I::to_topics_anonymous(indices),
109 data: crate::encode(data).into(),
110 }
111 }
112}
113
114impl<I, D> AnonymousEventEncoder<I, D>
115where
116 I: IndexedAnonymous,
117 D: Decode,
118{
119 pub fn decode(&self, log: &Log) -> Result<(I, D), ParseError> {
121 let indices = I::from_topics_anonymous(&log.topics)?;
122 let data = crate::decode(&log.data)?;
123
124 Ok((indices, data))
125 }
126}
127
128impl<I, D> Debug for AnonymousEventEncoder<I, D>
129where
130 I: IndexedAnonymous,
131{
132 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
133 f.debug_tuple("AnonymousEventEncoder").finish()
134 }
135}
136
137impl<I, D> Default for AnonymousEventEncoder<I, D>
138where
139 I: IndexedAnonymous,
140{
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146pub enum ParseError {
148 Topics(FromTopicsError),
150 SelectorMismatch(Word),
152 Data(DecodeError),
154}
155
156impl Debug for ParseError {
157 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
158 match self {
159 Self::Topics(err) => f.debug_tuple("FromTopics").field(err).finish(),
160 Self::SelectorMismatch(topic0) => f
161 .debug_tuple("SelectorMismatch")
162 .field(&Hex(topic0))
163 .finish(),
164 Self::Data(err) => f.debug_tuple("Data").field(err).finish(),
165 }
166 }
167}
168
169impl Display for ParseError {
170 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
171 match self {
172 Self::Topics(err) => write!(f, "{err}"),
173 Self::SelectorMismatch(_) => f.write_str("event topic0 does not match log's topic0"),
174 Self::Data(err) => write!(f, "{err}"),
175 }
176 }
177}
178
179impl Error for ParseError {}
180
181impl From<FromTopicsError> for ParseError {
182 fn from(err: FromTopicsError) -> Self {
183 Self::Topics(err)
184 }
185}
186
187impl From<DecodeError> for ParseError {
188 fn from(err: DecodeError) -> Self {
189 Self::Data(err)
190 }
191}
192
193#[derive(Debug)]
195pub enum FromTopicsError {
196 WrongCount,
198 InvalidData,
200}
201
202impl Display for FromTopicsError {
203 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
204 match self {
205 Self::WrongCount => f.write_str("event indices does not match log topics"),
206 Self::InvalidData => f.write_str("log topic data is invalid for event index"),
207 }
208 }
209}
210
211impl Error for FromTopicsError {}
212
213macro_rules! impl_indexed {
214 ($($t:ident),*) => {
215 #[allow(non_snake_case, unused_variables)]
216 impl<$($t),*> Indexed for ($($t,)*)
217 where
218 $($t: ToTopic + FromTopic,)*
219 {
220 fn from_topics(topics: &Topics) -> Result<(Word, Self), FromTopicsError> {
221 let mut topics = topics.iter().copied();
222 let topic0 = topics.next().ok_or(FromTopicsError::WrongCount)?;
223 $(let $t = $t::from_topic(topics.next().ok_or(FromTopicsError::WrongCount)?)
224 .ok_or(FromTopicsError::InvalidData)?;)*
225 if topics.next().is_some() {
226 return Err(FromTopicsError::WrongCount);
227 }
228 Ok((topic0, ($($t,)*)))
229 }
230
231 fn to_topics(topic0: &Word, ($($t,)*): &Self) -> Topics {
232 Topics::from([*topic0, $($t.to_topic()),*])
233 }
234 }
235
236 impl_indexed! { anonymous: $($t),* }
237 };
238
239 (anonymous: $($t:ident),*) => {
240 #[allow(non_snake_case, unused_mut, unused_variables)]
241 impl<$($t),*> IndexedAnonymous for ($($t,)*)
242 where
243 $($t: ToTopic + FromTopic,)*
244 {
245 fn from_topics_anonymous(topics: &Topics) -> Result<Self, FromTopicsError> {
246 let mut topics = topics.iter().copied();
247 $(let $t = $t::from_topic(topics.next().ok_or(FromTopicsError::WrongCount)?)
248 .ok_or(FromTopicsError::InvalidData)?;)*
249 if topics.next().is_some() {
250 return Err(FromTopicsError::WrongCount);
251 }
252 Ok(($($t,)*))
253 }
254
255 fn to_topics_anonymous(&self) -> Topics {
256 let ($($t,)*) = self;
257 Topics::from([$($t.to_topic()),*])
258 }
259 }
260 };
261}
262
263impl_indexed! {}
264impl_indexed! { A }
265impl_indexed! { A, B }
266impl_indexed! { A, B, C }
267impl_indexed! { anonymous: A, B, C, D }
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272 use crate::bytes::Bytes;
273 use ethprim::{address, uint, Address, U256};
274 use hex_literal::hex;
275 use std::borrow::Cow;
276
277 #[test]
278 fn transfer_event_roundtrip() {
279 let transfer = EventEncoder::<(Address, Address), (U256,)>::new(hex!(
280 "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
281 ));
282
283 let from = address!("0x0101010101010101010101010101010101010101");
284 let to = address!("0x0202020202020202020202020202020202020202");
285 let value = uint!("4_200_000_000_000_000_000");
286
287 let log = Log {
288 topics: Topics::from([
289 transfer.topic0,
290 hex!("0000000000000000000000000101010101010101010101010101010101010101"),
291 hex!("0000000000000000000000000202020202020202020202020202020202020202"),
292 ]),
293 data: hex!("0000000000000000000000000000000000000000000000003a4965bf58a40000")[..]
294 .into(),
295 };
296
297 assert_eq!(transfer.decode(&log).unwrap(), ((from, to), (value,)),);
298 assert_eq!(transfer.encode(&(from, to), &(value,)), log);
299 }
300
301 #[test]
302 fn fails_to_decode_event_with_different_indices() {
303 let selector = hex!("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
304
305 let transfer = EventEncoder::<(Address, Address), (U256,)>::new(selector);
306 let log = transfer.encode(
307 &(
308 address!("0x0101010101010101010101010101010101010101"),
309 address!("0x0202020202020202020202020202020202020202"),
310 ),
311 &(uint!("4_200_000_000_000_000_000"),),
312 );
313
314 let transfer = EventEncoder::<(Address, Address, U256), ()>::new(selector);
315 assert!(matches!(
316 transfer.decode(&log),
317 Err(ParseError::Topics(FromTopicsError::WrongCount))
318 ));
319
320 let transfer = EventEncoder::<(Address,), (Address, U256)>::new(selector);
321 assert!(matches!(
322 transfer.decode(&log),
323 Err(ParseError::Topics(FromTopicsError::WrongCount))
324 ));
325 }
326
327 #[test]
328 fn empty_indices_and_data() {
329 let event = EventEncoder::<(), (U256,)>::new([1; 32]);
330 let value = uint!("42");
331 let log = Log {
332 topics: Topics::from([event.topic0]),
333 data: hex!("000000000000000000000000000000000000000000000000000000000000002a")[..]
334 .into(),
335 };
336 assert_eq!(event.decode(&log).unwrap(), ((), (value,)),);
337 assert_eq!(event.encode(&(), &(value,)), log);
338
339 let event = EventEncoder::<(U256,), ()>::new([2; 32]);
340 let value = uint!("42");
341 let log = Log {
342 topics: Topics::from([
343 event.topic0,
344 hex!("000000000000000000000000000000000000000000000000000000000000002a"),
345 ]),
346 data: hex!("")[..].into(),
347 };
348 assert_eq!(event.decode(&log).unwrap(), ((value,), ()),);
349 assert_eq!(event.encode(&(value,), &()), log);
350
351 let event = EventEncoder::<(), ()>::new([2; 32]);
352 let log = Log {
353 topics: Topics::from([event.topic0]),
354 data: hex!("")[..].into(),
355 };
356 assert_eq!(event.decode(&log).unwrap(), ((), ()),);
357 assert_eq!(event.encode(&(), &()), log);
358 }
359
360 #[test]
361 fn anonymous_event_with_indexed_dynamic_field() {
362 let anon = AnonymousEventEncoder::<
363 (Cow<str>, Cow<[(U256, (bool, Cow<Bytes<[u8]>>))]>),
364 (U256, U256),
365 >::new();
366
367 let indices = (
368 "hello world".into(),
369 vec![
370 (U256::MAX - 1, (true, Bytes::borrowed(&[1, 2, 3]))),
371 (U256::MAX - 2, (true, Bytes::borrowed(&[4, 5, 6]))),
372 ]
373 .into(),
374 );
375 let fields = (uint!("1"), uint!("2"));
376
377 let log = Log {
378 topics: Topics::from([
379 hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"),
380 hex!("6b8a0e75eceddd0e7d4d0413a720bce2cb899061e362357db170c49c5563672f"),
381 ]),
382 data: hex!(
383 "0000000000000000000000000000000000000000000000000000000000000001
384 0000000000000000000000000000000000000000000000000000000000000002"
385 )[..]
386 .into(),
387 };
388
389 assert_eq!(anon.encode(&indices, &fields), log);
390
391 assert_eq!(anon.decode(&log).unwrap(), (Default::default(), fields));
393 }
394}