More gas oracles (#1251)
* Deriver auto_impls for GasOracle * Provider as GasOracle * impl fill_transaction in GasOracleMiddleware
This commit is contained in:
parent
0707270a05
commit
49b4ac7acb
|
@ -135,6 +135,18 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto_impl"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto_impl"
|
||||
version = "1.0.1"
|
||||
|
@ -1365,6 +1377,7 @@ name = "ethers-middleware"
|
|||
version = "0.17.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"auto_impl 0.5.0",
|
||||
"ethers-contract",
|
||||
"ethers-core",
|
||||
"ethers-etherscan",
|
||||
|
@ -1393,7 +1406,7 @@ name = "ethers-providers"
|
|||
version = "0.17.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"auto_impl",
|
||||
"auto_impl 1.0.1",
|
||||
"base64 0.13.0",
|
||||
"bytes",
|
||||
"ethers-core",
|
||||
|
@ -1547,7 +1560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "089263294bb1c38ac73649a6ad563dd9a5142c8dc0482be15b8b9acb22a1611e"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.2",
|
||||
"auto_impl",
|
||||
"auto_impl 1.0.1",
|
||||
"bytes",
|
||||
"ethereum-types",
|
||||
"fastrlp-derive",
|
||||
|
|
|
@ -21,6 +21,7 @@ ethers-providers = { version = "^0.17.0", path = "../ethers-providers", default-
|
|||
ethers-signers = { version = "^0.17.0", path = "../ethers-signers", default-features = false }
|
||||
|
||||
async-trait = { version = "0.1.50", default-features = false }
|
||||
auto_impl = { version = "0.5.0", default-features = false }
|
||||
serde = { version = "1.0.124", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0", default-features = false }
|
||||
futures-util = { version = "^0.3" }
|
||||
|
|
|
@ -23,7 +23,7 @@ struct GasNowResponseWrapper {
|
|||
data: GasNowResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct GasNowResponse {
|
||||
pub rapid: u64,
|
||||
pub fast: u64,
|
||||
|
@ -41,7 +41,7 @@ impl GasNow {
|
|||
pub fn with_client(client: Client) -> Self {
|
||||
let url = Url::parse(GAS_NOW_URL).expect("invalid url");
|
||||
|
||||
Self { url, gas_category: GasCategory::Standard }
|
||||
Self { client, url, gas_category: GasCategory::Standard }
|
||||
}
|
||||
|
||||
/// Sets the gas price category to be used when fetching the gas price.
|
||||
|
@ -64,7 +64,7 @@ impl GasNow {
|
|||
|
||||
impl Default for GasNow {
|
||||
fn default() -> Self {
|
||||
Self::new(Client::new())
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,24 +56,11 @@ where
|
|||
&self.inner
|
||||
}
|
||||
|
||||
async fn get_gas_price(&self) -> Result<U256, Self::Error> {
|
||||
Ok(self.gas_oracle.fetch().await?)
|
||||
}
|
||||
|
||||
async fn estimate_eip1559_fees(
|
||||
async fn fill_transaction(
|
||||
&self,
|
||||
_: Option<fn(U256, Vec<Vec<U256>>) -> (U256, U256)>,
|
||||
) -> Result<(U256, U256), Self::Error> {
|
||||
Ok(self.gas_oracle.estimate_eip1559_fees().await?)
|
||||
}
|
||||
|
||||
async fn send_transaction<T: Into<TypedTransaction> + Send + Sync>(
|
||||
&self,
|
||||
tx: T,
|
||||
tx: &mut TypedTransaction,
|
||||
block: Option<BlockId>,
|
||||
) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
|
||||
let mut tx = tx.into();
|
||||
|
||||
) -> Result<(), Self::Error> {
|
||||
match tx {
|
||||
TypedTransaction::Legacy(ref mut tx) => {
|
||||
if tx.gas_price.is_none() {
|
||||
|
@ -98,6 +85,28 @@ where
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.inner().fill_transaction(tx, block).await.map_err(FromErr::from)
|
||||
}
|
||||
|
||||
async fn get_gas_price(&self) -> Result<U256, Self::Error> {
|
||||
Ok(self.gas_oracle.fetch().await?)
|
||||
}
|
||||
|
||||
async fn estimate_eip1559_fees(
|
||||
&self,
|
||||
_: Option<fn(U256, Vec<Vec<U256>>) -> (U256, U256)>,
|
||||
) -> Result<(U256, U256), Self::Error> {
|
||||
Ok(self.gas_oracle.estimate_eip1559_fees().await?)
|
||||
}
|
||||
|
||||
async fn send_transaction<T: Into<TypedTransaction> + Send + Sync>(
|
||||
&self,
|
||||
tx: T,
|
||||
block: Option<BlockId>,
|
||||
) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
|
||||
let mut tx = tx.into();
|
||||
self.fill_transaction(&mut tx, block).await?;
|
||||
self.inner.send_transaction(tx, block).await.map_err(MiddlewareError::MiddlewareError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,18 @@ pub use cache::Cache;
|
|||
mod polygon;
|
||||
pub use polygon::Polygon;
|
||||
|
||||
mod gas_now;
|
||||
pub use gas_now::GasNow;
|
||||
|
||||
mod provider_oracle;
|
||||
pub use provider_oracle::ProviderOracle;
|
||||
|
||||
use ethers_core::types::U256;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use auto_impl::auto_impl;
|
||||
use reqwest::Error as ReqwestError;
|
||||
use std::error::Error;
|
||||
use thiserror::Error;
|
||||
|
||||
const GWEI_TO_WEI: u64 = 1000000000;
|
||||
|
@ -73,6 +81,10 @@ pub enum GasOracleError {
|
|||
|
||||
#[error("Chain is not supported by the oracle")]
|
||||
UnsupportedChain,
|
||||
|
||||
/// Error thrown when the provider failed.
|
||||
#[error("Chain is not supported by the oracle")]
|
||||
ProviderError(#[from] Box<dyn Error + Send + Sync>),
|
||||
}
|
||||
|
||||
/// `GasOracle` is a trait that an underlying gas oracle needs to implement.
|
||||
|
@ -95,6 +107,7 @@ pub enum GasOracleError {
|
|||
/// ```
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
#[auto_impl(&, Box, Arc)]
|
||||
pub trait GasOracle: Send + Sync + std::fmt::Debug {
|
||||
/// Makes an asynchronous HTTP query to the underlying `GasOracle`
|
||||
///
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
use crate::gas_oracle::{GasOracle, GasOracleError};
|
||||
use async_trait::async_trait;
|
||||
use ethers_core::types::U256;
|
||||
use ethers_providers::Middleware;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Gas oracle from a [`Middleware`] implementation such as an
|
||||
/// Ethereum RPC provider.
|
||||
#[derive(Debug)]
|
||||
pub struct ProviderOracle<M: Middleware> {
|
||||
provider: M,
|
||||
}
|
||||
|
||||
impl<M: Middleware> ProviderOracle<M> {
|
||||
pub fn new(provider: M) -> Self {
|
||||
Self { provider }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<M: Middleware> GasOracle for ProviderOracle<M>
|
||||
where
|
||||
<M as Middleware>::Error: 'static,
|
||||
{
|
||||
async fn fetch(&self) -> Result<U256, GasOracleError> {
|
||||
self.provider
|
||||
.get_gas_price()
|
||||
.await
|
||||
.map_err(|err| GasOracleError::ProviderError(Box::new(err)))
|
||||
}
|
||||
|
||||
async fn estimate_eip1559_fees(&self) -> Result<(U256, U256), GasOracleError> {
|
||||
// TODO: Allow configuring different estimation functions.
|
||||
self.provider
|
||||
.estimate_eip1559_fees(None)
|
||||
.await
|
||||
.map_err(|err| GasOracleError::ProviderError(Box::new(err)))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue