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 is_legacy: bool,
29 fee_estimate: Eip1559FeeEstimatePreset,
30 ) -> Result<&ProviderInfo<N>> {
31 Ok(match self.inner.entry(rpc.to_string()) {
32 Entry::Occupied(entry) => entry.into_mut(),
33 Entry::Vacant(entry) => {
34 let info = ProviderInfo::new(rpc, is_legacy, fee_estimate).await?;
35 entry.insert(info)
36 }
37 })
38 }
39}
40
41impl<N: Network> Deref for ProvidersManager<N> {
42 type Target = HashMap<String, ProviderInfo<N>>;
43
44 fn deref(&self) -> &Self::Target {
45 &self.inner
46 }
47}
48
49#[derive(Debug)]
51pub struct ProviderInfo<N: Network> {
52 pub provider: Arc<RootProvider<N>>,
53 pub chain: u64,
54 pub gas_price: GasPrice,
55}
56
57#[derive(Debug)]
59pub enum GasPrice {
60 Legacy(Result<u128>),
61 EIP1559(Result<ResolvedEip1559Fees>),
62}
63
64impl<N: Network> ProviderInfo<N> {
65 pub async fn new(
66 rpc: &str,
67 mut is_legacy: bool,
68 fee_estimate: Eip1559FeeEstimatePreset,
69 ) -> Result<Self> {
70 let provider = Arc::new(ProviderBuilder::new(rpc).build()?);
71 let chain = provider.get_chain_id().await?;
72
73 if let Some(chain) = Chain::from(chain).named() {
74 is_legacy |= chain.is_legacy();
75 };
76
77 let gas_price = if is_legacy {
78 GasPrice::Legacy(
79 provider.get_gas_price().await.wrap_err("Failed to get legacy gas price"),
80 )
81 } else {
82 GasPrice::EIP1559(
83 estimate_eip1559_fees(&provider, fee_estimate)
84 .await
85 .wrap_err("Failed to get EIP-1559 fees"),
86 )
87 };
88
89 Ok(Self { provider, chain, gas_price })
90 }
91
92 pub fn gas_price(&self) -> Result<u128> {
96 match &self.gas_price {
97 GasPrice::Legacy(res) => match res {
98 Ok(val) => Ok(*val),
99 Err(err) => Err(eyre::eyre!("{}", err)),
100 },
101 GasPrice::EIP1559(res) => match res {
102 Ok(fees) => Ok(fees.max_fee_per_gas),
103 Err(err) => Err(eyre::eyre!("{}", err)),
104 },
105 }
106 }
107
108 pub const fn eip1559_fees(&self) -> Option<&ResolvedEip1559Fees> {
110 match &self.gas_price {
111 GasPrice::EIP1559(Ok(fees)) => Some(fees),
112 _ => None,
113 }
114 }
115}