use crate::PoolInfo;
use alloy::dyn_abi::DynSolType;
use alloy::network::Network;
use alloy::primitives::{address, Address};
use alloy::providers::Provider;
use alloy::transports::Transport;
use anyhow::Result;
use rand::Rng;
use std::sync::Arc;
use std::time::Duration;
use super::gen::{
BalancerV2DataSync, MaverickDataSync, SlipStreamDataSync, TriCurveDataSync, TwoCurveDataSync,
V2DataSync, V3DataSync,
};
use crate::pools::gen::ERC20;
use crate::pools::gen::{AerodromePool, AerodromeV2Factory};
use crate::pools::{Pool, PoolType, Chain};
pub const INITIAL_BACKOFF: u64 = 1000; pub const MAX_RETRIES: u32 = 5;
pub async fn build_pools<P, T, N>(
provider: &Arc<P>,
addresses: Vec<Address>,
pool_type: PoolType,
data: DynSolType,
chain: Chain,
) -> Result<Vec<Pool>>
where
P: Provider<T, N> + Sync + 'static,
T: Transport + Sync + Clone,
N: Network,
{
let mut retry_count = 0;
let mut backoff = INITIAL_BACKOFF;
loop {
match populate_pool_data(provider, addresses.clone(), pool_type, data.clone(), chain).await
{
Ok(pools) => {
return Ok(pools);
}
Err(e) => {
if retry_count >= MAX_RETRIES {
eprintln!("Max retries reached. Error: {:?} {:?}", e, addresses);
return Ok(Vec::new());
}
let jitter = rand::thread_rng().gen_range(0..=100);
let sleep_duration = Duration::from_millis(backoff + jitter);
tokio::time::sleep(sleep_duration).await;
retry_count += 1;
backoff *= 2; }
}
}
}
async fn populate_pool_data<P, T, N>(
provider: &Arc<P>,
pool_addresses: Vec<Address>,
pool_type: PoolType,
data: DynSolType,
chain: Chain
) -> Result<Vec<Pool>>
where
P: Provider<T, N> + Sync + 'static,
T: Transport + Sync + Clone,
N: Network,
{
let pool_data = match pool_type {
PoolType::UniswapV2
| PoolType::SushiSwapV2
| PoolType::PancakeSwapV2
| PoolType::BaseSwapV2
| PoolType::Aerodrome
| PoolType::AlienBaseV2
| PoolType::SwapBasedV2
| PoolType::DackieSwapV2 => {
V2DataSync::deploy_builder(provider.clone(), pool_addresses.to_vec()).await?
}
PoolType::MaverickV1 | PoolType::MaverickV2 => {
MaverickDataSync::deploy_builder(provider.clone(), pool_addresses.to_vec()).await?
}
PoolType::UniswapV3
| PoolType::SushiSwapV3
| PoolType::BaseSwapV3
| PoolType::AlienBaseV3
| PoolType::PancakeSwapV3
| PoolType::SwapBasedV3
| PoolType::DackieSwapV3 => {
V3DataSync::deploy_builder(provider.clone(), pool_addresses.to_vec()).await?
}
PoolType::Slipstream => {
SlipStreamDataSync::deploy_builder(provider.clone(), pool_addresses.to_vec()).await?
}
PoolType::BalancerV2 => {
BalancerV2DataSync::deploy_builder(provider.clone(), pool_addresses.to_vec()).await?
}
PoolType::CurveTwoCrypto => {
let factory_addr = if chain == Chain::Ethereum {
address!("98EE851a00abeE0d95D08cF4CA2BdCE32aeaAF7F")
} else {
address!("c9Fe0C63Af9A39402e8a5514f9c43Af0322b665F")
};
TwoCurveDataSync::deploy_builder(provider.clone(), factory_addr, pool_addresses.to_vec()).await?
}
PoolType::CurveTriCrypto => {
let factory_addr = if chain == Chain::Ethereum {
address!("0c0e5f2fF0ff18a3be9b835635039256dC4B4963")
} else {
address!("A5961898870943c68037F6848d2D866Ed2016bcB")
};
TriCurveDataSync::deploy_builder(provider.clone(), factory_addr, pool_addresses.to_vec()).await?
}
};
let decoded_data = data.abi_decode_sequence(&pool_data)?;
let mut pools = Vec::new();
if let Some(pool_data_arr) = decoded_data.as_array() {
for pool_data_tuple in pool_data_arr {
if let Some(pool_data) = pool_data_tuple.as_tuple() {
let pool = pool_type.build_pool(pool_data);
if pool.is_valid() {
pools.push(pool);
}
}
}
}
for pool in &mut pools {
let token0_contract = ERC20::new(pool.token0_address(), &provider);
if let Ok(ERC20::symbolReturn { _0: name }) = token0_contract.symbol().call().await {
Pool::update_token0_name(pool, name);
}
let token1_contract = ERC20::new(pool.token1_address(), &provider);
if let Ok(ERC20::symbolReturn { _0: name }) = token1_contract.symbol().call().await {
Pool::update_token1_name(pool, name);
}
if pool_type == PoolType::BalancerV2 {
let pool = pool.get_balancer_mut().unwrap();
for token in &pool.additional_tokens {
let token_contract = ERC20::new(*token, &provider);
if let Ok(ERC20::symbolReturn { _0: name }) = token_contract.symbol().call().await {
pool.additional_token_names.push(name);
}
}
}
if pool_type == PoolType::CurveTriCrypto {
let pool = pool.get_curve_tri_mut().unwrap();
let token_contract = ERC20::new(pool.token2, &provider);
if let Ok(ERC20::symbolReturn { _0: name }) = token_contract.symbol().call().await {
pool.token2_name = name;
}
}
if pool_type == PoolType::Aerodrome {
let factory = address!("420DD381b31aEf6683db6B902084cB0FFECe40Da");
let pool = pool.get_v2_mut().unwrap();
let pool_contract = AerodromePool::new(pool.address, &provider);
let AerodromePool::stableReturn { _0: stable } =
pool_contract.stable().call().await.unwrap();
pool.stable = Some(stable);
let factory_contract = AerodromeV2Factory::new(factory, &provider);
let AerodromeV2Factory::getFeeReturn { _0: fee } = factory_contract
.getFee(pool.address, stable)
.call()
.await
.unwrap();
pool.fee = Some(fee);
}
}
Ok(pools)
}