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