chaindexing/events/
event.rs

1use std::collections::HashMap;
2use std::hash::{Hash, Hasher};
3
4use crate::diesel::schema::chaindexing_events;
5use diesel::{Insertable, Queryable};
6use ethers::abi::{LogParam, Token};
7use ethers::types::{Address, Log, I256, U256, U64};
8use ethers::utils::format_ether;
9
10use crate::{ChainId, ContractEvent};
11use uuid::Uuid;
12
13use serde::Deserialize;
14
15/// Events, aka. provider logs, are emitted from smart contracts
16/// to help infer their states.
17#[derive(Debug, Deserialize, Clone, Eq, Queryable, Insertable)]
18#[diesel(table_name = chaindexing_events)]
19pub struct Event {
20    pub id: Uuid,
21    pub(crate) chain_id: i64,
22    pub contract_address: String,
23    pub contract_name: String,
24    pub abi: String,
25    parameters: serde_json::Value,
26    topics: serde_json::Value,
27    pub block_hash: String,
28    pub(crate) block_number: i64,
29    block_timestamp: i64,
30    pub transaction_hash: String,
31    pub(crate) transaction_index: i32,
32    pub(crate) log_index: i32,
33    removed: bool,
34}
35
36/// Introduced to allow computing with a subset of Event struct
37#[derive(Debug, Deserialize, Clone, Eq, PartialEq)]
38pub struct PartialEvent {
39    pub id: Uuid,
40    pub chain_id: i64,
41    pub contract_address: String,
42    pub contract_name: String,
43    pub block_hash: String,
44    pub block_number: i64,
45    pub block_timestamp: i64,
46    pub transaction_hash: String,
47    pub transaction_index: i64,
48    pub log_index: i64,
49}
50
51impl PartialEq for Event {
52    fn eq(&self, other: &Self) -> bool {
53        self.chain_id == other.chain_id
54            && self.contract_address == other.contract_address
55            && self.abi == other.abi
56            && self.block_hash == other.block_hash
57    }
58}
59
60impl Hash for Event {
61    fn hash<H: Hasher>(&self, state: &mut H) {
62        self.chain_id.hash(state);
63        self.contract_address.hash(state);
64        self.abi.hash(state);
65        self.block_hash.hash(state);
66    }
67}
68
69impl Event {
70    pub fn new(
71        log: &Log,
72        event: &ContractEvent,
73        chain_id: &ChainId,
74        contract_name: &str,
75        block_timestamp: i64,
76    ) -> Self {
77        let log_params = event.value.parse_log(log.clone().into()).unwrap().params;
78        let parameters = Self::log_params_to_parameters(&log_params);
79
80        Self {
81            id: uuid::Uuid::new_v4(),
82            chain_id: *chain_id as i64,
83            contract_address: utils::address_to_string(&log.address).to_lowercase(),
84            contract_name: contract_name.to_owned(),
85            abi: event.abi.clone(),
86            parameters: serde_json::to_value(parameters).unwrap(),
87            topics: serde_json::to_value(&log.topics).unwrap(),
88            block_hash: hashes::h256_to_string(&log.block_hash.unwrap()).to_lowercase(),
89            block_number: log.block_number.unwrap().as_u64() as i64,
90            block_timestamp,
91            transaction_hash: hashes::h256_to_string(&log.transaction_hash.unwrap()).to_lowercase(),
92            transaction_index: log.transaction_index.unwrap().as_u32() as i32,
93            log_index: log.log_index.unwrap().as_u32() as i32,
94            removed: log.removed.unwrap(),
95        }
96    }
97
98    pub(crate) fn get_abi(&self) -> &str {
99        self.abi.as_str()
100    }
101
102    /// Returns the event's block number
103    pub fn get_block_number(&self) -> u64 {
104        self.block_number as u64
105    }
106    /// Returns the event's block timestamp
107    pub fn get_block_timestamp(&self) -> u64 {
108        self.block_timestamp as u64
109    }
110    /// Returns the event's transaction index
111    pub fn get_transaction_index(&self) -> u32 {
112        self.transaction_index as u32
113    }
114    /// Returns the event's log index
115    pub fn get_log_index(&self) -> u32 {
116        self.log_index as u32
117    }
118
119    /// Returns the event's parameters
120    pub fn get_params(&self) -> EventParam {
121        EventParam::new(&self.parameters)
122    }
123
124    /// Returns the event's chain id
125    pub fn get_chain_id(&self) -> ChainId {
126        U64::from(self.chain_id).try_into().unwrap()
127    }
128
129    fn log_params_to_parameters(log_params: &[LogParam]) -> HashMap<String, Token> {
130        log_params.iter().fold(HashMap::new(), |mut parameters, log_param| {
131            parameters.insert(log_param.name.to_string(), log_param.value.clone());
132
133            parameters
134        })
135    }
136}
137
138/// Represents the parameters parsed from an event/log.
139/// Contains convenient parsers to convert or transform into useful primitives
140/// as needed.
141pub struct EventParam {
142    value: HashMap<String, Token>,
143}
144
145impl EventParam {
146    pub(crate) fn new(parameters: &serde_json::Value) -> EventParam {
147        EventParam {
148            value: serde_json::from_value(parameters.clone()).unwrap(),
149        }
150    }
151
152    /// N/B: This function is UNSAFE.
153    /// Ensure source contract can be trusted before using it or
154    /// preprocess the string before indexing.
155    /// A potential attacker could inject SQL string statements from  here.
156    pub fn get_string_unsafely(&self, key: &str) -> String {
157        self.value.get(key).unwrap().to_string()
158    }
159
160    /// Returns `bytes` or bytes1, bytes2. bytes3...bytes32
161    pub fn get_bytes(&self, key: &str) -> Vec<u8> {
162        let token = self.get_token(key);
163
164        token.clone().into_fixed_bytes().or(token.into_bytes()).unwrap()
165    }
166
167    pub fn get_i8_array(&self, key: &str) -> Vec<i8> {
168        self.get_array_and_transform(key, |token| token_to_int(token).as_i8())
169    }
170    pub fn get_i32_array(&self, key: &str) -> Vec<i32> {
171        self.get_array_and_transform(key, |token| token_to_int(token).as_i32())
172    }
173    pub fn get_i64_array(&self, key: &str) -> Vec<i64> {
174        self.get_array_and_transform(key, |token| token_to_int(token).as_i64())
175    }
176    pub fn get_i128_array(&self, key: &str) -> Vec<i128> {
177        self.get_array_and_transform(key, |token| token_to_int(token).as_i128())
178    }
179
180    pub fn get_u8_array(&self, key: &str) -> Vec<u8> {
181        self.get_array_and_transform(key, |token| token_to_uint(token).as_usize() as u8)
182    }
183    pub fn get_u32_array(&self, key: &str) -> Vec<u32> {
184        self.get_array_and_transform(key, |token| token_to_uint(token).as_u32())
185    }
186    pub fn get_u64_array(&self, key: &str) -> Vec<u64> {
187        self.get_array_and_transform(key, |token| token_to_uint(token).as_u64())
188    }
189    pub fn get_u128_array(&self, key: &str) -> Vec<u128> {
190        self.get_array_and_transform(key, |token| token_to_uint(token).as_u128())
191    }
192    pub fn get_uint_array(&self, key: &str) -> Vec<U256> {
193        self.get_array_and_transform(key, token_to_uint)
194    }
195    pub fn get_int_array(&self, key: &str) -> Vec<I256> {
196        self.get_array_and_transform(key, |token| I256::from_raw(token.into_int().unwrap()))
197    }
198
199    pub fn get_address_array(&self, key: &str) -> Vec<Address> {
200        self.get_array_and_transform(key, token_to_address)
201    }
202    pub fn get_address_string_array(&self, key: &str) -> Vec<String> {
203        self.get_array_and_transform(key, |token| token_to_address_string(token).to_lowercase())
204    }
205
206    fn get_array_and_transform<TokenTransformer, Output>(
207        &self,
208        key: &str,
209        token_transformer: TokenTransformer,
210    ) -> Vec<Output>
211    where
212        TokenTransformer: Fn(Token) -> Output,
213    {
214        self.get_array(key).into_iter().map(token_transformer).collect()
215    }
216    fn get_array(&self, key: &str) -> Vec<Token> {
217        let token = self.get_token(key);
218
219        token.clone().into_fixed_array().or(token.into_array()).unwrap()
220    }
221
222    pub fn get_int_gwei(&self, key: &str) -> f64 {
223        self.get_int_ether(key) * GWEI
224    }
225    pub fn get_int_ether(&self, key: &str) -> f64 {
226        format_ether(self.get_int(key)).parse().unwrap()
227    }
228
229    pub fn get_uint_gwei(&self, key: &str) -> f64 {
230        self.get_uint_ether(key) * GWEI
231    }
232    pub fn get_uint_ether(&self, key: &str) -> f64 {
233        format_ether(self.get_uint(key)).parse().unwrap()
234    }
235
236    pub fn get_i8(&self, key: &str) -> i8 {
237        self.get_int(key).as_i8()
238    }
239    pub fn get_i32(&self, key: &str) -> i32 {
240        self.get_int(key).as_i32()
241    }
242    pub fn get_i64(&self, key: &str) -> i64 {
243        self.get_int(key).as_i64()
244    }
245    pub fn get_i128(&self, key: &str) -> i128 {
246        self.get_int(key).as_i128()
247    }
248
249    pub fn get_u8(&self, key: &str) -> u8 {
250        self.get_usize(key) as u8
251    }
252    pub fn get_usize(&self, key: &str) -> usize {
253        self.get_uint(key).as_usize()
254    }
255    pub fn get_u32(&self, key: &str) -> u32 {
256        self.get_uint(key).as_u32()
257    }
258    pub fn get_u64(&self, key: &str) -> u64 {
259        self.get_uint(key).as_u64()
260    }
261    pub fn get_u128(&self, key: &str) -> u128 {
262        self.get_uint(key).as_u128()
263    }
264    /// Same as get_u256
265    pub fn get_uint(&self, key: &str) -> U256 {
266        token_to_uint(self.get_token(key))
267    }
268    pub fn get_int(&self, key: &str) -> I256 {
269        token_to_int(self.get_token(key))
270    }
271    pub fn get_address_string(&self, key: &str) -> String {
272        token_to_address_string(self.get_token(key))
273    }
274    pub fn get_address(&self, key: &str) -> Address {
275        token_to_address(self.get_token(key))
276    }
277
278    fn get_token(&self, key: &str) -> Token {
279        self.value.get(key).unwrap().clone()
280    }
281}
282
283fn token_to_address_string(token: Token) -> String {
284    utils::address_to_string(&token_to_address(token)).to_lowercase()
285}
286
287fn token_to_address(token: Token) -> Address {
288    token.into_address().unwrap()
289}
290
291fn token_to_uint(token: Token) -> U256 {
292    token.into_uint().unwrap()
293}
294fn token_to_int(token: Token) -> I256 {
295    I256::from_raw(token.into_int().unwrap())
296}
297
298const GWEI: f64 = 1_000_000_000.0;
299
300mod hashes {
301    use ethers::types::{H160, H256};
302
303    pub fn h160_to_string(h160: &H160) -> String {
304        serde_json::to_value(h160).unwrap().as_str().unwrap().to_string()
305    }
306
307    pub fn h256_to_string(h256: &H256) -> String {
308        serde_json::to_value(h256).unwrap().as_str().unwrap().to_string()
309    }
310}
311
312mod utils {
313    use ethers::types::H160;
314
315    use super::hashes;
316
317    pub fn address_to_string(address: &H160) -> String {
318        hashes::h160_to_string(address)
319    }
320}
321
322#[cfg(test)]
323mod event_param_tests {
324    use ethers::types::I256;
325    use serde_json::json;
326
327    use super::*;
328
329    #[test]
330    fn returns_uint_values() {
331        let event_param =
332            EventParam::new(&json!({"sqrtPriceX96":{"Uint":"0x1ca2dce57b617d43d62181e8"}}));
333        assert_eq!(
334            event_param.get_uint("sqrtPriceX96"),
335            U256::from_dec_str("8862469411596380921745474024").unwrap()
336        );
337    }
338
339    #[test]
340    fn returns_int_values() {
341        let event_param = EventParam::new(
342            &json!({"amount0":{"Int":"0xfffffffffffffffffffffffffffffffffffffffffffffffe92da20f7358d10e9"}}),
343        );
344        assert_eq!(
345            event_param.get_int("amount0"),
346            I256::from_dec_str("-26311681626831253271").unwrap()
347        );
348    }
349}