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}