tokens.rs (6020B)
1 #![allow(dead_code)] 2 #![allow(unused_variables)] 3 #![allow(unused_imports)] 4 #![allow(unused_mut)] 5 6 use std::{ 7 collections::BTreeMap, 8 fs::OpenOptions, 9 path::Path, 10 str::FromStr 11 }; 12 use alloy::{ 13 primitives::Address, 14 providers::RootProvider, 15 transports::{http::{Client, Http}, BoxTransport}, 16 }; 17 use indicatif::{ProgressBar, ProgressStyle}; 18 use anyhow::{anyhow, Result}; 19 use csv::StringRecord; 20 use log::info; 21 22 use crate::{interfaces::IERC20, pools::Pool}; 23 24 25 #[derive(Debug, Clone)] 26 pub struct Token { 27 pub id: i64, 28 pub address: Address, 29 pub name: String, 30 pub symbol: String, 31 pub decimals: u8 32 } 33 34 impl From<StringRecord> for Token { 35 fn from(record: StringRecord) -> Self { 36 Self { 37 id: record.get(0).unwrap().parse().unwrap(), 38 address: Address::from_str(record.get(1).unwrap()).unwrap(), 39 name: String::from(record.get(2).unwrap()), 40 symbol: String::from(record.get(3).unwrap()), 41 decimals: record.get(4).unwrap().parse().unwrap(), 42 } 43 } 44 } 45 46 impl Token { 47 pub fn cache_row(&self) -> (i64, String, String, String, u8) { 48 ( 49 self.id, 50 format!("{:?}", self.address), 51 self.name.clone(), 52 self.symbol.clone(), 53 self.decimals, 54 ) 55 } 56 } 57 58 pub async fn load_tokens( 59 provider: RootProvider<BoxTransport>, 60 path: &Path, 61 pools: &BTreeMap<Address, Pool>, 62 parallel: u64, 63 last_pool_id: i64, 64 ) -> Result<BTreeMap<Address, Token>> { 65 66 info!("Loading tokens..."); 67 68 let mut tokens = BTreeMap::new(); 69 70 let file = OpenOptions::new() 71 .write(true) 72 .append(true) 73 .create(true) 74 .open(path) 75 .unwrap(); 76 77 let mut writer = csv::Writer::from_writer(file); 78 79 let mut token_id = 0; 80 if path.exists() { 81 let mut reader = csv::Reader::from_path(path)?; 82 for row in reader.records() { 83 let row = row.unwrap(); 84 let token = Token::from(row); 85 tokens.insert(token.address, token); 86 token_id += 1; 87 } 88 } else { 89 writer.write_record(&[ 90 "id", 91 "address", 92 "name", 93 "symbol", 94 "decimals", 95 ])?; 96 } 97 98 let pb = ProgressBar::new(pools.len() as u64); 99 pb.set_style( 100 ProgressStyle::with_template( 101 "[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", 102 ) 103 .unwrap() 104 .progress_chars("##-"), 105 ); 106 107 let new_token_id = token_id; 108 109 let mut count = 0; 110 let mut requests = Vec::new(); 111 112 for (_, pool) in pools.into_iter() { 113 let pool_id = pool.id; 114 if pool_id <= last_pool_id { 115 continue; 116 } 117 let token0 = pool.token0; 118 let token1 = pool.token1; 119 for token in [token0, token1] { 120 if !tokens.contains_key(&token) { 121 requests.push( 122 tokio::task::spawn( 123 get_token_data( 124 provider.clone(), 125 token, 126 ) 127 ) 128 ); 129 count += 1 ; 130 } 131 if count == parallel { 132 let results = futures::future::join_all(requests).await; 133 for result in results { 134 match result { 135 Ok(r) => match r { 136 Ok(t) => { 137 tokens.insert( 138 t.address, 139 Token { 140 id: token_id, 141 address: t.address, 142 name: t.name, 143 symbol: t.symbol, 144 decimals: t.decimals 145 } 146 ); 147 token_id += 1 148 } 149 Err(e) => { info!("Something wrong 0 {:?}", e) } 150 } 151 Err(e) => { info!("Something wrong 1 {:?}", e) } 152 } 153 } 154 requests = Vec::new(); 155 count = 0; 156 pb.inc(parallel); 157 } 158 } 159 } 160 161 let mut added = 0; 162 for token in tokens.values().collect::<Vec<&Token>>().iter() { 163 if token.id >= new_token_id { 164 writer.serialize(token.cache_row())?; 165 added += 1 166 } 167 } 168 writer.flush()?; 169 170 Ok(tokens) 171 } 172 173 async fn get_token_data( 174 provider: RootProvider<BoxTransport>, 175 token: Address, 176 ) -> Result<Token> { 177 178 let interface = IERC20::new(token, provider); 179 180 let decimals = match interface.decimals().call().await { 181 Ok(r) => r.decimals, 182 Err(e) => { return Err(anyhow!("Decimals of token failed {:?}", e )) } 183 }; 184 185 let name = match interface.name().call().await { 186 Ok(r) => r.name, 187 Err(e) => { 188 info!("Name of token {:?} failed {:?}", token, e); 189 String::from("PlaceHolderName") 190 } 191 }; 192 let symbol = match interface.symbol().call().await{ 193 Ok(r) => r.symbol, 194 Err(e) => { 195 info!("Symbol of token failed {:?}", e ); 196 String::from("PlaceHolderSymbol") 197 } 198 }; 199 200 Ok(Token { 201 id: -1, 202 address: token, 203 name, 204 symbol, 205 decimals, 206 }) 207 } 208 209 pub fn load_tokens_from_file( 210 path: &Path, 211 ) -> Result<BTreeMap<Address, Token>> { 212 let mut tokens = BTreeMap::new(); 213 214 if path.exists() { 215 let mut reader = csv::Reader::from_path(path)?; 216 for row in reader.records() { 217 let row = row.unwrap(); 218 let token = Token::from(row); 219 tokens.insert(token.address, token); 220 } 221 } else { 222 return Err(anyhow!("File path does not exist")); 223 } 224 225 Ok(tokens) 226 }