substreams_ethereum_core/event.rs
1use std::marker::PhantomData;
2
3use crate::pb::eth::v2::Log;
4
5pub trait Event: Sized {
6 const NAME: &'static str;
7
8 fn match_log(log: &Log) -> bool;
9 fn decode(log: &Log) -> Result<Self, String>;
10
11 /// Attempts to match and decode the log.
12 /// If `Self::match_log(log)` is `false`, returns `None`.
13 /// If it matches, but decoding fails, logs the decoding error and returns `None`.
14 fn match_and_decode(log: impl AsRef<Log>) -> Option<Self> {
15 let log = log.as_ref();
16 if !Self::match_log(log) {
17 return None;
18 }
19
20 match Self::decode(&log) {
21 Ok(event) => Some(event),
22 Err(err) => {
23 substreams::log::info!(
24 "Log for event `{}` at index {} matched but failed to decode with error: {}",
25 Self::NAME,
26 log.block_index,
27 err
28 );
29 None
30 }
31 }
32 }
33}
34
35impl AsRef<Log> for Log {
36 fn as_ref(&self) -> &Self {
37 self
38 }
39}
40
41/// Ethereum events with indexed parameters that are of dynamic types like a 'string',
42/// 'bytes' or array of value do not contain the actual value in the log. Instead, they
43/// contain a hash of the value. This struct is used to represent such values in the
44/// decoded event.
45///
46/// The hash value read can be retrieved from the `hash` field, the original value
47/// cannot be retrieved (unless you know it already, in which case you can validate
48/// it fits the current hash).
49///
50/// You can access the hash (also equivalent to the topic in this case) directly
51/// on the struct:
52///
53/// ```ignore
54/// # use substreams_ethereum::IndexedDynamicValue;
55/// let value = IndexedDynamicValue::<String>::new("0x1234".into());
56/// assert_eq!(value.hash, "0x1234".into());
57/// ```
58#[derive(Debug, Clone, PartialEq)]
59pub struct IndexedDynamicValue<T> {
60 phantom: PhantomData<T>,
61
62 /// The hash of the value that was indexed, **not** the real value
63 /// that was actually indexed. The original real value cannot be
64 /// retrieved.
65 pub hash: Vec<u8>,
66}
67
68impl<T> IndexedDynamicValue<T> {
69 pub fn new(topic: Vec<u8>) -> Self {
70 Self {
71 phantom: PhantomData,
72 hash: topic,
73 }
74 }
75}
76
77impl<T> From<Vec<u8>> for IndexedDynamicValue<T> {
78 fn from(topic: Vec<u8>) -> Self {
79 Self::new(topic)
80 }
81}