diff --git a/Cargo.lock b/Cargo.lock index 3e8b5e48aca2c..5268539380333 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,6 +1890,7 @@ dependencies = [ [[package]] name = "ethers" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "ethers-addressbook", "ethers-contract", @@ -1904,6 +1905,7 @@ dependencies = [ [[package]] name = "ethers-addressbook" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "ethers-core", "once_cell", @@ -1914,13 +1916,13 @@ dependencies = [ [[package]] name = "ethers-contract" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "const-hex", "ethers-contract-abigen", "ethers-contract-derive", "ethers-core", "ethers-providers", - "ethers-signers", "futures-util", "once_cell", "pin-project", @@ -1932,6 +1934,7 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "Inflector", "const-hex", @@ -1954,6 +1957,7 @@ dependencies = [ [[package]] name = "ethers-contract-derive" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "Inflector", "const-hex", @@ -1968,6 +1972,7 @@ dependencies = [ [[package]] name = "ethers-core" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "arrayvec", "bytes", @@ -1996,6 +2001,7 @@ dependencies = [ [[package]] name = "ethers-etherscan" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "ethers-core", "ethers-solc", @@ -2010,6 +2016,7 @@ dependencies = [ [[package]] name = "ethers-middleware" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "async-trait", "auto_impl", @@ -2035,6 +2042,7 @@ dependencies = [ [[package]] name = "ethers-providers" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "async-trait", "auto_impl", @@ -2072,6 +2080,7 @@ dependencies = [ [[package]] name = "ethers-signers" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "async-trait", "coins-bip32", @@ -2098,6 +2107,7 @@ dependencies = [ [[package]] name = "ethers-solc" version = "2.0.8" +source = "git+https://github.com/gakonst/ethers-rs#179891d45cc7b50941f2b8c30b206355ab76d94c" dependencies = [ "cfg-if", "const-hex", diff --git a/Cargo.toml b/Cargo.toml index 0df10c561add3..67c5d3fd0622c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,16 +119,16 @@ foundry-test-utils = { path = "crates/test-utils" } foundry-utils = { path = "crates/utils" } ui = { path = "crates/ui" } -#ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-addressbook = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-contract-abigen = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-providers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-signers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-middleware = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -#ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-addressbook = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-contract-abigen = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-providers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-signers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-middleware = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false } chrono = { version = "0.4", default-features = false, features = ["clock", "std"] } hex = { package = "const-hex", version = "1.6", features = ["hex"] } @@ -136,16 +136,16 @@ itertools = "0.11" solang-parser = "=0.3.1" #[patch."https://github.com/gakonst/ethers-rs"] -ethers = { path = "../ethers-rs/ethers" } -ethers-addressbook = { path = "../ethers-rs/ethers-addressbook" } -ethers-contract = { path = "../ethers-rs/ethers-contract" } -ethers-contract-abigen = { path = "../ethers-rs/ethers-contract/ethers-contract-abigen" } -ethers-core = { path = "../ethers-rs/ethers-core" } -ethers-etherscan = { path = "../ethers-rs/ethers-etherscan" } -ethers-middleware = { path = "../ethers-rs/ethers-middleware" } -ethers-providers = { path = "../ethers-rs/ethers-providers", features = ["ws", "ipc"] } -ethers-signers = { path = "../ethers-rs/ethers-signers" } -ethers-solc = { path = "../ethers-rs/ethers-solc" } +#ethers = { path = "../ethers-rs/ethers" } +#ethers-addressbook = { path = "../ethers-rs/ethers-addressbook" } +#ethers-contract = { path = "../ethers-rs/ethers-contract" } +#ethers-contract-abigen = { path = "../ethers-rs/ethers-contract/ethers-contract-abigen" } +#ethers-core = { path = "../ethers-rs/ethers-core" } +#ethers-etherscan = { path = "../ethers-rs/ethers-etherscan" } +#ethers-middleware = { path = "../ethers-rs/ethers-middleware" } +#ethers-providers = { path = "../ethers-rs/ethers-providers", features = ["ws", "ipc"] } +#ethers-signers = { path = "../ethers-rs/ethers-signers" } +#ethers-solc = { path = "../ethers-rs/ethers-solc" } [patch.crates-io] revm = { git = "https://github.com/bluealloy/revm/", branch = "release/v25" } diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index 6516765361f53..eb9d589fe3d21 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -9,12 +9,12 @@ use foundry_cli::{ opts::{EthereumOpts, TransactionOpts}, utils::{self, handle_traces, parse_ether_value, TraceResult}, }; -use foundry_common::runtime_provider::RuntimeProvider; +use foundry_common::runtime_client::RuntimeClient; use foundry_config::{find_project_root_path, Config}; use foundry_evm::{executor::opts::EvmOpts, trace::TracingExecutor}; use std::str::FromStr; -type Provider = ethers::providers::Provider; +type Provider = ethers::providers::Provider; /// CLI arguments for `cast call`. #[derive(Debug, Parser)] diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index fc9534b7fd406..bd7162e7c8dd4 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -14,7 +14,7 @@ pub mod fmt; pub mod fs; pub mod glob; pub mod provider; -pub mod runtime_provider; +pub mod runtime_client; pub mod selectors; pub mod shell; pub mod term; diff --git a/crates/common/src/provider.rs b/crates/common/src/provider.rs index 7c0bde89cf7ec..13cc1cbfa1d4e 100644 --- a/crates/common/src/provider.rs +++ b/crates/common/src/provider.rs @@ -1,6 +1,6 @@ //! Commonly used helpers to construct `Provider`s -use crate::{runtime_provider::RuntimeProvider, ALCHEMY_FREE_TIER_CUPS, REQUEST_TIMEOUT}; +use crate::{runtime_client::RuntimeClient, ALCHEMY_FREE_TIER_CUPS, REQUEST_TIMEOUT}; use ethers_core::types::{Chain, U256}; use ethers_middleware::gas_oracle::{GasCategory, GasOracle, Polygon}; use ethers_providers::{is_local_endpoint, Middleware, Provider, DEFAULT_LOCAL_POLL_INTERVAL}; @@ -10,7 +10,7 @@ use std::{borrow::Cow, time::Duration}; use url::ParseError; /// Helper type alias for a retry provider -pub type RetryProvider = Provider; +pub type RetryProvider = Provider; /// Helper type alias for a rpc url pub type RpcUrl = String; @@ -171,7 +171,7 @@ impl ProviderBuilder { } = self; let url = url?; - let mut provider = Provider::new(RuntimeProvider::new( + let mut provider = Provider::new(RuntimeClient::new( url.clone(), max_retry, timeout_retry, diff --git a/crates/common/src/runtime_client.rs b/crates/common/src/runtime_client.rs new file mode 100644 index 0000000000000..65bca0234f6d8 --- /dev/null +++ b/crates/common/src/runtime_client.rs @@ -0,0 +1,211 @@ +//! Wrap different providers + +use async_trait::async_trait; +use ethers_core::types::U256; +use ethers_providers::{ + Http, HttpRateLimitRetryPolicy, Ipc, JsonRpcClient, JsonRpcError, ProviderError, PubsubClient, + RetryClient, RetryClientBuilder, RpcError, Ws, +}; +use serde::{de::DeserializeOwned, Serialize}; +use std::{fmt::Debug, path, sync::Arc, time::Duration}; +use thiserror::Error; +use tokio::sync::RwLock; +use url::Url; + +/// Enum representing a the client types supported by the runtime provider +#[derive(Debug)] +enum InnerClient { + /// HTTP client + Http(RetryClient), + /// WebSocket client + Ws(Ws), + /// IPC client + Ipc(Ipc), +} + +/// Error type for the runtime provider +#[derive(Error, Debug)] +pub enum RuntimeClientError { + /// Internal provider error + #[error(transparent)] + ProviderError(ProviderError), + + /// Failed to lock the client + LockError, +} + +impl RpcError for RuntimeClientError { + fn as_error_response(&self) -> Option<&JsonRpcError> { + match self { + RuntimeClientError::ProviderError(err) => err.as_error_response(), + _ => None, + } + } + + fn as_serde_error(&self) -> Option<&serde_json::Error> { + match self { + RuntimeClientError::ProviderError(e) => e.as_serde_error(), + _ => None, + } + } +} + +impl std::fmt::Display for RuntimeClientError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +impl From for ProviderError { + fn from(src: RuntimeClientError) -> Self { + match src { + RuntimeClientError::ProviderError(err) => err, + RuntimeClientError::LockError => { + ProviderError::CustomError("Failed to lock the client".to_string()) + } + } + } +} + +/// A provider that connects on first request allowing handling of different provider types at +/// runtime +#[derive(Debug, Error)] +pub struct RuntimeClient { + client: Arc>>, + url: Url, + max_retry: u32, + timeout_retry: u32, + initial_backoff: u64, + timeout: Duration, + /// available CUPS + compute_units_per_second: u64, +} + +impl ::core::fmt::Display for RuntimeClient { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "RuntimeClient") + } +} + +impl RuntimeClient { + /// Creates a new dynamic provider from a URL + pub fn new( + url: Url, + max_retry: u32, + timeout_retry: u32, + initial_backoff: u64, + timeout: Duration, + compute_units_per_second: u64, + ) -> Self { + Self { + client: Arc::new(RwLock::new(None)), + url, + max_retry, + timeout_retry, + initial_backoff, + timeout, + compute_units_per_second, + } + } + + async fn connect(&self) -> Result { + match self.url.scheme() { + "http" | "https" => { + let client = reqwest::Client::builder() + .timeout(self.timeout) + .build() + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?; + let provider = Http::new_with_client(self.url.clone(), client); + + #[allow(clippy::box_default)] + let provider = RetryClientBuilder::default() + .initial_backoff(Duration::from_millis(self.initial_backoff)) + .rate_limit_retries(self.max_retry) + .timeout_retries(self.timeout_retry) + .compute_units_per_second(self.compute_units_per_second) + .build(provider, Box::new(HttpRateLimitRetryPolicy)); + Ok(InnerClient::Http(provider)) + } + "ws" | "wss" => { + let client = Ws::connect(&self.url.to_string()) + .await + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?; + + Ok(InnerClient::Ws(client)) + } + "file" => { + let client = Ipc::connect(path::Path::new(&self.url.to_string())) + .await + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?; + + Ok(InnerClient::Ipc(client)) + } + _ => Err(RuntimeClientError::ProviderError(ProviderError::UnsupportedNodeClient)), + } + } +} + +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +impl JsonRpcClient for RuntimeClient { + type Error = RuntimeClientError; + + #[allow(implied_bounds_entailment)] + async fn request(&self, method: &str, params: T) -> Result + where + T: Debug + Serialize + Send + Sync, + R: DeserializeOwned + Send, + { + if self.client.read().await.is_none() { + let mut w = self.client.write().await; + *w = Some( + self.connect().await.map_err(|e| RuntimeClientError::ProviderError(e.into()))?, + ); + } + + let res = match self.client.read().await.as_ref().unwrap() { + InnerClient::Http(http) => RetryClient::request(http, method, params) + .await + .map_err(|e| RuntimeClientError::ProviderError(e.into())), + InnerClient::Ws(ws) => JsonRpcClient::request(ws, method, params) + .await + .map_err(|e| RuntimeClientError::ProviderError(e.into())), + InnerClient::Ipc(ipc) => JsonRpcClient::request(ipc, method, params) + .await + .map_err(|e| RuntimeClientError::ProviderError(e.into())), + }?; + Ok(res) + } +} + +// We can also implement [`PubsubClient`] for our dynamic provider. +impl PubsubClient for RuntimeClient { + // Since both `Ws` and `Ipc`'s `NotificationStream` associated type is the same, + // we can simply return one of them. + type NotificationStream = ::NotificationStream; + + fn subscribe>(&self, id: T) -> Result { + match self.client.try_read().map_err(|_| RuntimeClientError::LockError)?.as_ref().unwrap() { + InnerClient::Http(_) => { + Err(RuntimeClientError::ProviderError(ProviderError::UnsupportedRPC)) + } + InnerClient::Ws(client) => Ok(PubsubClient::subscribe(client, id) + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?), + InnerClient::Ipc(client) => Ok(PubsubClient::subscribe(client, id) + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?), + } + } + + fn unsubscribe>(&self, id: T) -> Result<(), Self::Error> { + match self.client.try_read().map_err(|_| (RuntimeClientError::LockError))?.as_ref().unwrap() + { + InnerClient::Http(_) => { + Err(RuntimeClientError::ProviderError(ProviderError::UnsupportedRPC)) + } + InnerClient::Ws(client) => Ok(PubsubClient::unsubscribe(client, id) + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?), + InnerClient::Ipc(client) => Ok(PubsubClient::unsubscribe(client, id) + .map_err(|e| RuntimeClientError::ProviderError(e.into()))?), + } + } +} diff --git a/crates/common/src/runtime_provider.rs b/crates/common/src/runtime_provider.rs deleted file mode 100644 index f411776f68556..0000000000000 --- a/crates/common/src/runtime_provider.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! Wrap different providers - -use async_trait::async_trait; -use ethers_core::types::U256; -use ethers_providers::{ - Http, HttpRateLimitRetryPolicy, Ipc, JsonRpcClient, ProviderError, PubsubClient, RetryClient, - RetryClientBuilder, RetryClientError, RetryPolicy, Ws, -}; -use serde::{de::DeserializeOwned, Serialize}; -use std::{fmt::Debug, path, sync::Arc, time::Duration}; -use thiserror::Error; -use tokio::sync::RwLock; -use url::Url; - -/// Enum representing a the client types supported by the runtime provider -#[derive(Debug)] -pub enum RuntimeClient { - /// HTTP client - Http(RetryClient), - /// WebSocket client - Ws(RetryClient), - /// IPC client - Ipc(RetryClient), -} - -/// A provider that connects on first request allowing handling of different provider types at -/// runtime -#[derive(Debug, Error)] -pub struct RuntimeProvider { - client: Arc>>, - url: Url, - max_retry: u32, - timeout_retry: u32, - initial_backoff: u64, - timeout: Duration, - /// available CUPS - compute_units_per_second: u64, -} - -impl ::core::fmt::Display for RuntimeProvider { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "RuntimeProvider") - } -} - -/// Default RetryPolicy which won't retry -#[derive(Debug, Default)] -pub struct DefaultRetryPolicy; - -impl RetryPolicy for DefaultRetryPolicy { - fn should_retry(&self, _: &T) -> bool { - false - } - - fn backoff_hint(&self, _: &T) -> Option { - None - } -} - -impl RuntimeProvider { - /// Creates a new dynamic provider from a URL - pub fn new( - url: Url, - max_retry: u32, - timeout_retry: u32, - initial_backoff: u64, - timeout: Duration, - compute_units_per_second: u64, - ) -> Self { - Self { - client: Arc::new(RwLock::new(None)), - url, - max_retry, - timeout_retry, - initial_backoff, - timeout, - compute_units_per_second, - } - } - - async fn connect(&self) -> Result { - match self.url.scheme() { - "http" | "https" => { - let client = reqwest::Client::builder() - .timeout(self.timeout) - .build() - .map_err(|e| RetryClientError::ProviderError(ProviderError::HTTPError(e)))?; - let provider = Http::new_with_client(self.url.clone(), client); - - #[allow(clippy::box_default)] - let provider = RetryClientBuilder::default() - .initial_backoff(Duration::from_millis(self.initial_backoff)) - .rate_limit_retries(self.max_retry) - .timeout_retries(self.timeout_retry) - .compute_units_per_second(self.compute_units_per_second) - .build(provider, Box::new(HttpRateLimitRetryPolicy)); - Ok(RuntimeClient::Http(provider)) - } - "ws" | "wss" => { - let client = Ws::connect(&self.url.to_string()).await.map_err(|e| { - RetryClientError::ProviderError(ProviderError::JsonRpcClientError(Box::new(e))) - })?; - - #[allow(clippy::box_default)] - let provider = RetryClientBuilder::default() - .initial_backoff(Duration::from_millis(self.initial_backoff)) - .rate_limit_retries(self.max_retry) - .timeout_retries(self.timeout_retry) - .compute_units_per_second(self.compute_units_per_second) - .build(client, Box::new(DefaultRetryPolicy)); - - Ok(RuntimeClient::Ws(provider)) - } - "file" => { - let client = - Ipc::connect(path::Path::new(&self.url.to_string())).await.map_err(|e| { - RetryClientError::ProviderError(ProviderError::JsonRpcClientError( - Box::new(e), - )) - })?; - - #[allow(clippy::box_default)] - let provider = RetryClientBuilder::default() - .initial_backoff(Duration::from_millis(self.initial_backoff)) - .rate_limit_retries(self.max_retry) - .timeout_retries(self.timeout_retry) - .compute_units_per_second(self.compute_units_per_second) - .build(client, Box::new(DefaultRetryPolicy)); - - Ok(RuntimeClient::Ipc(provider)) - } - _ => Err(RetryClientError::ProviderError(ProviderError::CustomError(format!( - "Invalid provider url: {}", - self.url - )))), - } - } -} - -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl JsonRpcClient for RuntimeProvider { - type Error = RetryClientError; - - #[allow(implied_bounds_entailment)] - async fn request(&self, method: &str, params: T) -> Result - where - T: Debug + Serialize + Send + Sync, - R: DeserializeOwned + Send, - { - if self.client.read().await.is_none() { - let mut w = self.client.write().await; - *w = Some(self.connect().await?) - } - - let res = match self.client.read().await.as_ref().unwrap() { - RuntimeClient::Http(http) => RetryClient::request(http, method, params).await, - RuntimeClient::Ws(ws) => RetryClient::request(ws, method, params).await, - RuntimeClient::Ipc(ipc) => RetryClient::request(ipc, method, params).await, - }?; - Ok(res) - } -} - -// We can also implement [`PubsubClient`] for our dynamic provider. -impl PubsubClient for RuntimeProvider { - // Since both `Ws` and `Ipc`'s `NotificationStream` associated type is the same, - // we can simply return one of them. - type NotificationStream = ::NotificationStream; - - fn subscribe>(&self, id: T) -> Result { - match self - .client - .try_read() - .map_err(|_| (RetryClientError::TimeoutError))? - .as_ref() - .unwrap() - { - RuntimeClient::Http(client) => Ok(RetryClient::subscribe(client, id)?), - RuntimeClient::Ws(client) => Ok(RetryClient::subscribe(client, id)?), - RuntimeClient::Ipc(client) => Ok(RetryClient::subscribe(client, id)?), - } - } - - fn unsubscribe>(&self, id: T) -> Result<(), Self::Error> { - match self - .client - .try_read() - .map_err(|_| (RetryClientError::TimeoutError))? - .as_ref() - .unwrap() - { - RuntimeClient::Http(client) => Ok(RetryClient::unsubscribe(client, id)?), - RuntimeClient::Ws(client) => Ok(RetryClient::unsubscribe(client, id)?), - RuntimeClient::Ipc(client) => Ok(RetryClient::unsubscribe(client, id)?), - } - } -} diff --git a/crates/evm/src/executor/fork/multi.rs b/crates/evm/src/executor/fork/multi.rs index c948c2891c3c0..d8a292c19f010 100644 --- a/crates/evm/src/executor/fork/multi.rs +++ b/crates/evm/src/executor/fork/multi.rs @@ -12,7 +12,7 @@ use ethers::{ providers::Provider, types::{BlockId, BlockNumber}, }; -use foundry_common::{runtime_provider::RuntimeProvider, ProviderBuilder}; +use foundry_common::{runtime_client::RuntimeClient, ProviderBuilder}; use foundry_config::Config; use futures::{ channel::mpsc::{channel, Receiver, Sender}, @@ -168,7 +168,7 @@ impl MultiFork { } } -type Handler = BackendHandler>>; +type Handler = BackendHandler>>; type CreateFuture = Pin> + Send>>; type CreateSender = OneshotSender>; diff --git a/crates/forge/bin/cmd/script/providers.rs b/crates/forge/bin/cmd/script/providers.rs index d50da9a0f74bb..93ff19a658f88 100644 --- a/crates/forge/bin/cmd/script/providers.rs +++ b/crates/forge/bin/cmd/script/providers.rs @@ -1,6 +1,6 @@ use ethers::prelude::{Middleware, Provider, U256}; use eyre::{Result, WrapErr}; -use foundry_common::{get_http_provider, runtime_provider::RuntimeProvider, RpcUrl}; +use foundry_common::{get_http_provider, runtime_client::RuntimeClient, RpcUrl}; use foundry_config::Chain; use std::{ collections::{hash_map::Entry, HashMap}, @@ -42,7 +42,7 @@ impl Deref for ProvidersManager { /// Holds related metadata to each provider RPC. #[derive(Debug)] pub struct ProviderInfo { - pub provider: Arc>, + pub provider: Arc>, pub chain: u64, pub gas_price: GasPrice, pub is_legacy: bool,