etop_core/datasets/
erc20_transfers_by_erc20.rs

1use crate::{AddressQueryArgument, DataSpec, DataWarehouse, EtopError, InputDataset};
2use etop_format::ColumnFormatShorthand;
3use polars::prelude::*;
4use std::collections::HashMap;
5
6/// erc20 transfers by erc20
7#[derive(Clone)]
8pub struct Erc20TransfersByErc20;
9
10impl DataSpec for Erc20TransfersByErc20 {
11    fn name(&self) -> String {
12        "erc20_transfers_by_erc20".to_string()
13    }
14
15    fn row_noun(&self) -> String {
16        "erc20s".into()
17    }
18
19    fn inputs(&self) -> Vec<InputDataset> {
20        vec![
21            InputDataset::Raw("erc20_transfers".into()),
22            InputDataset::Derived {
23                dataset: "erc20_metadata".into(),
24                dataset_column: "erc20".into(),
25                derived_from: "erc20_transfers".into(),
26                derived_from_column: "erc20".to_string(),
27                arg: AddressQueryArgument::Contract,
28            },
29        ]
30    }
31
32    fn transform(
33        &self,
34        warehouse: &DataWarehouse,
35        start_block: Option<u32>,
36        end_block: Option<u32>,
37    ) -> Result<DataFrame, EtopError> {
38        let erc20_transfers = warehouse.get_dataset("erc20_transfers")?;
39        let erc20_metadata = warehouse.get_dataset("erc20_metadata")?;
40        let erc20_transfers =
41            crate::filter_by_block_number(erc20_transfers, start_block, end_block)?;
42        let df = erc20_transfers
43            .clone()
44            .lazy()
45            .group_by(["erc20"])
46            .agg([
47                count().alias("n_transfers"),
48                col("from_address").n_unique().alias("n_senders"),
49                col("to_address").n_unique().alias("n_receivers"),
50                col("transaction_hash").n_unique().alias("n_txs"),
51                col("value_f64").sum().alias("volume"),
52                col("from_address").mode().sort(true).first().alias("most_common_sender"),
53                col("to_address").mode().sort(true).first().alias("most_common_receiver"),
54            ])
55            .sort_by_exprs(vec![col("n_transfers"), col("erc20")], [true], true, true)
56            .collect();
57        let df = df.map_err(EtopError::PolarsError)?;
58        let join_args = JoinArgs {
59            how: JoinType::Left,
60            validation: JoinValidation::ManyToMany,
61            suffix: None,
62            slice: None,
63        };
64        let df = df
65            .clone()
66            .lazy()
67            .join(
68                erc20_metadata.lazy().select([col("erc20"), col("symbol"), col("decimals")]),
69                [col("erc20")],
70                [col("erc20")],
71                join_args,
72            )
73            .with_column(col("volume") / lit(10).pow(col("decimals")))
74            .collect();
75        df.map_err(EtopError::PolarsError)
76    }
77
78    fn default_columns(&self) -> Option<Vec<String>> {
79        let columns = [
80            "symbol",
81            "n_transfers",
82            "n_senders",
83            "n_receivers",
84            "n_txs",
85            "volume",
86            "erc20",
87            "most_common_sender",
88            "most_common_receiver",
89        ]
90        .into_iter()
91        .map(|column| column.to_string())
92        .collect();
93
94        Some(columns)
95    }
96
97    fn default_column_formats(&self) -> Option<HashMap<String, ColumnFormatShorthand>> {
98        let oom_float_format = etop_format::NumberFormat::new().float_oom().precision(1);
99        let formats = vec![
100            ColumnFormatShorthand::new().name("symbol").width(9),
101            ColumnFormatShorthand::new().name("n_transfers").display_name("n\ntrans\nfers"),
102            ColumnFormatShorthand::new().name("n_senders").display_name("n\nsend\ners"),
103            ColumnFormatShorthand::new().name("n_receivers").display_name("n\nrecei\nvers"),
104            ColumnFormatShorthand::new().name("n_txs"),
105            ColumnFormatShorthand::new().name("volume").set_format(oom_float_format).min_width(6),
106            ColumnFormatShorthand::new().name("erc20").display_name("erc20 address"),
107            ColumnFormatShorthand::new()
108                .name("most_common_sender")
109                .display_name("most common sender"),
110            ColumnFormatShorthand::new()
111                .name("most_common_receiver")
112                .display_name("most common receiver"),
113        ]
114        .into_iter()
115        .map(|column| (column.name.clone(), column))
116        .collect();
117
118        Some(formats)
119    }
120}