forge_script/
providers.rs1use alloy_network::Ethereum;
2use alloy_primitives::map::{HashMap, hash_map::Entry};
3use alloy_provider::{Provider, RootProvider, utils::Eip1559Estimation};
4use eyre::{Result, WrapErr};
5use foundry_common::provider::ProviderBuilder;
6use foundry_config::Chain;
7use std::{ops::Deref, sync::Arc};
8
9#[derive(Default)]
11pub struct ProvidersManager {
12 pub inner: HashMap<String, ProviderInfo>,
13}
14
15impl ProvidersManager {
16 pub async fn get_or_init_provider(
18 &mut self,
19 rpc: &str,
20 is_legacy: bool,
21 ) -> Result<&ProviderInfo> {
22 Ok(match self.inner.entry(rpc.to_string()) {
23 Entry::Occupied(entry) => entry.into_mut(),
24 Entry::Vacant(entry) => {
25 let info = ProviderInfo::new(rpc, is_legacy).await?;
26 entry.insert(info)
27 }
28 })
29 }
30}
31
32impl Deref for ProvidersManager {
33 type Target = HashMap<String, ProviderInfo>;
34
35 fn deref(&self) -> &Self::Target {
36 &self.inner
37 }
38}
39
40#[derive(Debug)]
42pub struct ProviderInfo {
43 pub provider: Arc<RootProvider<Ethereum>>,
44 pub chain: u64,
45 pub gas_price: GasPrice,
46}
47
48#[derive(Debug)]
50pub enum GasPrice {
51 Legacy(Result<u128>),
52 EIP1559(Result<Eip1559Estimation>),
53}
54
55impl ProviderInfo {
56 pub async fn new(rpc: &str, mut is_legacy: bool) -> Result<Self> {
57 let provider = Arc::new(ProviderBuilder::new(rpc).build()?);
58 let chain = provider.get_chain_id().await?;
59
60 if let Some(chain) = Chain::from(chain).named() {
61 is_legacy |= chain.is_legacy();
62 };
63
64 let gas_price = if is_legacy {
65 GasPrice::Legacy(
66 provider.get_gas_price().await.wrap_err("Failed to get legacy gas price"),
67 )
68 } else {
69 GasPrice::EIP1559(
70 provider.estimate_eip1559_fees().await.wrap_err("Failed to get EIP-1559 fees"),
71 )
72 };
73
74 Ok(Self { provider, chain, gas_price })
75 }
76
77 pub fn gas_price(&self) -> Result<u128> {
79 let res = match &self.gas_price {
80 GasPrice::Legacy(res) => res.as_ref(),
81 GasPrice::EIP1559(res) => res.as_ref().map(|res| &res.max_fee_per_gas),
82 };
83 match res {
84 Ok(val) => Ok(*val),
85 Err(err) => Err(eyre::eyre!("{}", err)),
86 }
87 }
88}