etop_core/datasets/
erc20_transfers_by_erc20.rs1use crate::{AddressQueryArgument, DataSpec, DataWarehouse, EtopError, InputDataset};
2use etop_format::ColumnFormatShorthand;
3use polars::prelude::*;
4use std::collections::HashMap;
5
6#[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}