Skip to main content

eth_prices/config/
mod.rs

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