forge_script/
providers.rs1use alloy_network::Network;
2use alloy_primitives::map::{HashMap, hash_map::Entry};
3use alloy_provider::{Provider, RootProvider};
4use eyre::{Result, WrapErr};
5use foundry_common::provider::{
6 ProviderBuilder,
7 fee::{ResolvedEip1559Fees, estimate_eip1559_fees},
8};
9use foundry_config::{Chain, Eip1559FeeEstimatePreset};
10use std::{ops::Deref, sync::Arc};
11
12pub struct ProvidersManager<N: Network> {
14 pub inner: HashMap<String, ProviderInfo<N>>,
15}
16
17impl<N: Network> Default for ProvidersManager<N> {
18 fn default() -> Self {
19 Self { inner: Default::default() }
20 }
21}
22
23impl<N: Network> ProvidersManager<N> {
24 pub async fn get_or_init_provider(
26 &mut self,
27 rpc: &str,
28 chain: Option<u64>,
29 is_legacy: bool,
30 fee_estimate: Eip1559FeeEstimatePreset,
31 ) -> Result<&ProviderInfo<N>> {
32 Ok(match self.inner.entry(rpc.to_string()) {
33 Entry::Occupied(entry) => entry.into_mut(),
34 Entry::Vacant(entry) => {
35 let info = ProviderInfo::new(rpc, chain, is_legacy, fee_estimate).await?;
36 entry.insert(info)
37 }
38 })
39 }
40}
41
42impl<N: Network> Deref for ProvidersManager<N> {
43 type Target = HashMap<String, ProviderInfo<N>>;
44
45 fn deref(&self) -> &Self::Target {
46 &self.inner
47 }
48}
49
50#[derive(Debug)]
52pub struct ProviderInfo<N: Network> {
53 pub provider: Arc<RootProvider<N>>,
54 pub chain: u64,
55 pub gas_price: GasPrice,
56}
57
58#[derive(Debug)]
60pub enum GasPrice {
61 Legacy(Result<u128>),
62 EIP1559(Result<ResolvedEip1559Fees>),
63}
64
65impl<N: Network> ProviderInfo<N> {
66 pub async fn new(
67 rpc: &str,
68 chain: Option<u64>,
69 mut is_legacy: bool,
70 fee_estimate: Eip1559FeeEstimatePreset,
71 ) -> Result<Self> {
72 let provider = Arc::new(ProviderBuilder::new(rpc).build()?);
73 let chain = match chain {
74 Some(chain) => chain,
75 None => provider.get_chain_id().await?,
76 };
77
78 if let Some(chain) = Chain::from(chain).named() {
79 is_legacy |= chain.is_legacy();
80 };
81
82 let gas_price = if is_legacy {
83 GasPrice::Legacy(
84 provider.get_gas_price().await.wrap_err("Failed to get legacy gas price"),
85 )
86 } else {
87 GasPrice::EIP1559(
88 estimate_eip1559_fees(&provider, fee_estimate)
89 .await
90 .wrap_err("Failed to get EIP-1559 fees"),
91 )
92 };
93
94 Ok(Self { provider, chain, gas_price })
95 }
96
97 pub fn gas_price(&self) -> Result<u128> {
101 match &self.gas_price {
102 GasPrice::Legacy(res) => match res {
103 Ok(val) => Ok(*val),
104 Err(err) => Err(eyre::eyre!("{}", err)),
105 },
106 GasPrice::EIP1559(res) => match res {
107 Ok(fees) => Ok(fees.max_fee_per_gas),
108 Err(err) => Err(eyre::eyre!("{}", err)),
109 },
110 }
111 }
112
113 pub const fn eip1559_fees(&self) -> Option<&ResolvedEip1559Fees> {
115 match &self.gas_price {
116 GasPrice::EIP1559(Ok(fees)) => Some(fees),
117 _ => None,
118 }
119 }
120}