use crate::types::{PairCreated, PairInfo, TokenInfo};
use ethers::utils::hex;
use eyre::{eyre, ErrReport, Result};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::time::Duration;
use tokio::time::sleep;
const MAX_RETRIES: u32 = 15;
const BASE_DELAY_MS: u64 = 100;
const MAX_DELAY_MS: u64 = 2000;
impl Error for JsonRpcError {}
impl fmt::Display for JsonRpcError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "JSON-RPC error: {} (code {})", self.message, self.code)
}
}
#[derive(Serialize, Deserialize, Debug)]
struct JsonRpcRequest {
jsonrpc: String,
method: String,
params: Vec<serde_json::Value>,
id: u64,
}
#[derive(Serialize, Deserialize, Debug)]
struct JsonRpcResponse<T> {
id: u64,
jsonrpc: String,
result: Option<T>,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<JsonRpcError>,
}
#[derive(Serialize, Deserialize, Debug)]
struct JsonRpcError {
code: i32,
message: String,
}
pub async fn get_tokens_for_pairs_with_retry(
url: &str,
pairs: Vec<(PairCreated, [String; 2])>,
) -> Result<Vec<(PairInfo, TokenInfo, TokenInfo)>> {
let mut retries = 0;
let mut delay = Duration::from_millis(BASE_DELAY_MS);
loop {
match get_tokens_for_pairs(url, pairs.clone()).await {
Ok(result) => return Ok(result),
Err(err) => {
println!("Error parent: {:?}", err);
println!("Retrying... (attempt {}/{})", retries + 1, MAX_RETRIES);
if retries >= MAX_RETRIES {
return Err(eyre!("Error: {:?}", err));
}
retries += 1;
sleep(delay).await;
delay = Duration::from_millis(std::cmp::min(
(delay.as_millis() * 2).try_into().unwrap_or(MAX_DELAY_MS),
MAX_DELAY_MS,
));
continue;
}
}
}
}
pub async fn get_tokens_for_pairs(
url: &str,
pairs: Vec<(PairCreated, [String; 2])>,
) -> Result<Vec<(PairInfo, TokenInfo, TokenInfo)>> {
let client = Client::new();
let methods = [
("eth_call", "0x313ce567"), ("eth_call", "0x8da5cb5b"), ("eth_call", "0x18160ddd"), ("eth_call", "0x06fdde03"), ("eth_call", "0x95d89b41"), ];
println!("Getting tokens for {} pairs", pairs.len());
let mut requests = Vec::new();
let mut id = 1u64;
for (pair_address, token_addresses) in pairs.clone() {
for address in token_addresses {
for &(method, data) in &methods {
requests.push(JsonRpcRequest {
jsonrpc: "2.0".to_string(),
method: method.to_string(),
params: vec![
serde_json::json!({
"to": address,
"data": data
}),
"latest".into(),
],
id: id,
});
id += 1;
}
}
for &(method, data) in &methods[3..5] {
println!("Pair address: {:?}", pair_address.pair);
requests.push(JsonRpcRequest {
jsonrpc: "2.0".to_string(),
method: method.to_string(),
params: vec![
serde_json::json!({
"to": pair_address.pair,
"data": data
}),
"latest".into(),
],
id: id,
});
id += 1;
}
}
let response = client.post(url).json(&requests).send().await?;
let raw_response = response.text().await?;
println!("Raw JSON response: {}", raw_response);
let results: Vec<JsonRpcResponse<Value>> = serde_json::from_str(&raw_response)?;
let mut parsed_results: Vec<(PairInfo, TokenInfo, TokenInfo)> = Vec::new();
let mut result_map: HashMap<u64, &JsonRpcResponse<Value>> = HashMap::new();
for result in results.iter() {
result_map.insert(result.id, result);
}
for pair_idx_usize in 0..pairs.len() {
let pair_idx = pair_idx_usize as u64;
println!("Result map: {:?}", result_map);
println!("Result map id 2: {:?}", result_map.get(&2).unwrap());
println!(
"Result map id 2 unwrap: {:?}",
parse_result_number(result_map.get(&2).unwrap())
);
let pair = PairInfo {
address: pairs[pair_idx_usize].0.pair.to_lowercase().to_string(),
name: match parse_result_text(result_map.get(&((pair_idx * 12) + 11)).unwrap()){
Ok(name) => name,
Err(err) => return Err(err),
},
symbol: match parse_result_text(result_map.get(&((pair_idx * 12) + 12)).unwrap()){
Ok(symbol) => symbol,
Err(err) => return Err(err),
},
v3: pairs[pair_idx_usize].0.v3,
factory: pairs[pair_idx_usize].0.factory.to_lowercase().to_string(),
tickSpacing: pairs[pair_idx_usize].0.tickSpacing,
fee: pairs[pair_idx_usize].0.fee,
};
let token0 = TokenInfo {
decimals: match parse_result_number(result_map.get(&((pair_idx * 12) + 1)).unwrap()) {
Ok(decimals) => decimals,
Err(err) => return Err(err),
},
owner: match parse_address_hex(result_map.get(&((pair_idx * 12) + 2)).unwrap()).as_str()
{
"0" => "None".to_string(),
other => other.to_string(),
},
address: pairs[pair_idx_usize].1[0].to_lowercase().to_string(),
total_supply: parse_result_number(result_map.get(&((pair_idx * 12) + 3)).unwrap())
.unwrap(),
name: match parse_result_text(result_map.get(&((pair_idx * 12) + 4)).unwrap()){
Ok(name) => name,
Err(err) => return Err(err),
},
symbol: match parse_result_text(result_map.get(&((pair_idx * 12) + 5)).unwrap()){
Ok(symbol) => symbol,
Err(err) => return Err(err),
},
};
let token1 = TokenInfo {
decimals: match parse_result_number(result_map.get(&((pair_idx * 12) + 6)).unwrap()) {
Ok(decimals) => decimals,
Err(err) => return Err(err),
},
owner: match parse_address_hex(result_map.get(&((pair_idx * 12) + 7)).unwrap()).as_str()
{
"0" => "None".to_string(),
other => other.to_string(),
},
address: pairs[pair_idx_usize].1[1].to_lowercase().to_string(),
total_supply: match parse_result_number(result_map.get(&((pair_idx * 12) + 8)).unwrap())
{
Ok(total_supply) => total_supply,
Err(err) => return Err(err),
},
name: match parse_result_text(result_map.get(&((pair_idx * 12) + 9)).unwrap()){
Ok(name) => name,
Err(err) => return Err(err),
},
symbol: match parse_result_text(result_map.get(&((pair_idx * 12) + 10)).unwrap()){
Ok(symbol) => symbol,
Err(err) => return Err(err),
},
};
parsed_results.push((pair, token0, token1));
}
Ok(parsed_results)
}
fn parse_result_text(result: &JsonRpcResponse<Value>) -> Result<String> {
if let Some(serde_json::Value::String(hex_data)) = &result.result {
let data = &hex_data[2..]; if let Ok(bytes) = hex::decode(data) {
if let Ok(text) = std::str::from_utf8(&bytes) {
let text = text.trim_matches('\0').trim();
let trimmed =
text.trim_matches(|c: char| c.is_whitespace() || c == '\0' || c.is_control());
return Ok(trimmed.to_string());
} else {
println!("Failed to decode UTF-8 text for result {}", result.id);
Ok("None".to_string())
}
} else {
println!("Failed to decode hex for result {}", result.id);
Ok("None".to_string())
}
} else if let Some(err) = &result.error {
println!(
"Error for ID {}: {} (Code {})",
result.id, err.message, err.code
);
if err.code == -32005 {
Err(eyre!("Rate limit exceeded"))
} else if err.code == -32000{
Ok("None".to_string())
} else {
Err(eyre!(
"Error for ID {}: {} (Code {})",
result.id,
err.message,
err.code
)) }
} else {
Err(eyre!("No result or error for ID {}", result.id))
}
}
fn parse_address_hex(result: &JsonRpcResponse<Value>) -> String {
if let Some(serde_json::Value::String(hex_data)) = &result.result {
if hex_data.len() > 26 {
let stripped_data = &hex_data[26..]; let address = format!("0x{}", stripped_data);
return address.to_string();
} else {
println!("Invalid hex_data length: {}", hex_data.len());
}
} else if let Some(err) = &result.error {
println!(
"Error for ID {}: {} (Code {})",
result.id, err.message, err.code
);
} else {
println!("No result or error for ID {}", result.id);
}
"None".to_string()
}
fn parse_result_number(result: &JsonRpcResponse<Value>) -> Result<String> {
if let Some(serde_json::Value::String(hex_data)) = &result.result {
let data = &hex_data[2..]; println!("INSIDE DATA: {:?}", data);
let number = u128::from_str_radix(data, 16).unwrap_or_default();
println!("INSIDE DATA: {:?}", data);
println!("Result {}: {}", result.id, number);
return Ok(number.to_string());
} else if let Some(err) = &result.error {
println!(
"Error for ID {}: {} (Code {})",
result.id, err.message, err.code
);
if err.code == -32005 {
Err(eyre!("Rate limit exceeded"))
}else if err.code == -32000{
Ok("None".to_string())
} else {
Err(eyre!(
"Error for ID {}: {} (Code {})",
result.id,
err.message,
err.code
))
}
} else {
Err(eyre!("No result or error for ID {}", result.id))
}
}