Skip to main content

eth_prices/config/
mod.rs

1use alloy::primitives::{U256, map::HashMap};
2use figment::{
3    Figment,
4    providers::{Format, Toml},
5};
6use serde::Deserialize;
7
8use crate::{
9    Result,
10    error::EthPricesError,
11    provider::RpcProvider,
12    quoter::{
13        AnyQuoter,
14        erc4626::{ERC4626Config, ERC4626Quoter},
15        fixed::FixedQuoter,
16        uniswap_v2::{UniswapV2Config, UniswapV2Quoter},
17        uniswap_v3::{UniswapV3Quoter, factory::UniswapV3Config},
18    },
19};
20
21#[derive(Debug, Deserialize, PartialEq)]
22pub struct Config {
23    pub chains: HashMap<String, ChainConfig>,
24}
25
26#[derive(Debug, Deserialize, PartialEq)]
27pub struct ChainConfig {
28    pub chain_id: u64,
29    pub rpc_url: String,
30    pub tokens: Vec<TokenConfig>,
31    pub quoters: QuotersConfig,
32}
33
34#[derive(Debug, Deserialize, PartialEq, Clone)]
35pub struct QuotersConfig {
36    pub fixed: Vec<FixedQuoter>,
37    pub uniswap_v2: Option<UniswapV2Config>,
38    pub uniswap_v3: Option<UniswapV3Config>,
39    pub erc4626: Vec<ERC4626Config>,
40}
41
42impl QuotersConfig {
43    pub async fn all(self, provider: &RpcProvider) -> Result<Vec<AnyQuoter>> {
44        let mut quoters: Vec<AnyQuoter> = Vec::new();
45        for tracker in self.fixed {
46            if tracker.fixed_rate <= U256::from(0) {
47                return Err(EthPricesError::InvalidConfiguration(format!(
48                    "Fixed rate for {} to {} must be > 0.0",
49                    tracker.token_in, tracker.token_out
50                )));
51            }
52            quoters.push(tracker.into());
53        }
54
55        if let Some(uniswap_v2_config) = &self.uniswap_v2 {
56            for uni_quoters in uniswap_v2_config.pairs.iter() {
57                let quoter = UniswapV2Quoter::from_selector(provider, uni_quoters.clone()).await?;
58                quoters.push(quoter.into());
59            }
60        }
61
62        if let Some(uniswap_v3_config) = &self.uniswap_v3 {
63            for uni_quoters in uniswap_v3_config.pools.iter() {
64                let quoter = UniswapV3Quoter::from_selector(provider, uni_quoters.clone()).await?;
65                quoters.push(quoter.into());
66            }
67        }
68
69        for erc4626_config in &self.erc4626 {
70            let quoter = ERC4626Quoter::new(erc4626_config.vault_address, provider).await?;
71            quoters.push(quoter.into());
72        }
73
74        Ok(quoters)
75    }
76}
77
78#[derive(Debug, Deserialize, PartialEq)]
79pub struct TokenConfig {
80    pub address: String,
81    pub slug: Option<String>,
82    pub decimals: u8,
83}
84
85impl Config {
86    pub async fn load(path: &str) -> Result<Self> {
87        let figment = Figment::new().merge(Toml::file(path));
88        figment
89            .extract::<Config>()
90            .map_err(|e| EthPricesError::ConfigError(e.to_string()))
91    }
92}