ethers_middleware/gas_oracle/
middleware.rs

1use super::{GasOracle, GasOracleError};
2use async_trait::async_trait;
3use ethers_core::types::{transaction::eip2718::TypedTransaction, *};
4use ethers_providers::{Middleware, MiddlewareError as METrait, PendingTransaction};
5use thiserror::Error;
6
7/// Middleware used for fetching gas prices over an API instead of `eth_gasPrice`.
8#[derive(Debug)]
9pub struct GasOracleMiddleware<M, G> {
10    inner: M,
11    gas_oracle: G,
12}
13
14impl<M, G> GasOracleMiddleware<M, G>
15where
16    M: Middleware,
17    G: GasOracle,
18{
19    pub fn new(inner: M, gas_oracle: G) -> Self {
20        Self { inner, gas_oracle }
21    }
22}
23
24#[derive(Debug, Error)]
25pub enum MiddlewareError<M: Middleware> {
26    #[error(transparent)]
27    GasOracleError(#[from] GasOracleError),
28
29    #[error("{0}")]
30    MiddlewareError(M::Error),
31
32    #[error("This gas price oracle only works with Legacy and EIP2930 transactions.")]
33    UnsupportedTxType,
34}
35
36impl<M: Middleware> METrait for MiddlewareError<M> {
37    type Inner = M::Error;
38
39    fn from_err(src: M::Error) -> MiddlewareError<M> {
40        MiddlewareError::MiddlewareError(src)
41    }
42
43    fn as_inner(&self) -> Option<&Self::Inner> {
44        match self {
45            MiddlewareError::MiddlewareError(e) => Some(e),
46            _ => None,
47        }
48    }
49}
50
51#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
52#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
53impl<M, G> Middleware for GasOracleMiddleware<M, G>
54where
55    M: Middleware,
56    G: GasOracle,
57{
58    type Error = MiddlewareError<M>;
59    type Provider = M::Provider;
60    type Inner = M;
61
62    // OVERRIDEN METHODS
63
64    fn inner(&self) -> &M {
65        &self.inner
66    }
67
68    async fn fill_transaction(
69        &self,
70        tx: &mut TypedTransaction,
71        block: Option<BlockId>,
72    ) -> Result<(), Self::Error> {
73        match tx {
74            TypedTransaction::Legacy(ref mut tx) => {
75                if tx.gas_price.is_none() {
76                    tx.gas_price = Some(self.get_gas_price().await?);
77                }
78            }
79            TypedTransaction::Eip2930(ref mut inner) => {
80                if inner.tx.gas_price.is_none() {
81                    inner.tx.gas_price = Some(self.get_gas_price().await?);
82                }
83            }
84            TypedTransaction::Eip1559(ref mut inner) => {
85                if inner.max_priority_fee_per_gas.is_none() || inner.max_fee_per_gas.is_none() {
86                    let (max_fee_per_gas, max_priority_fee_per_gas) =
87                        self.estimate_eip1559_fees(None).await?;
88                    if inner.max_priority_fee_per_gas.is_none() {
89                        inner.max_priority_fee_per_gas = Some(max_priority_fee_per_gas);
90                    }
91                    if inner.max_fee_per_gas.is_none() {
92                        inner.max_fee_per_gas = Some(max_fee_per_gas);
93                    }
94                }
95            }
96            #[cfg(feature = "optimism")]
97            TypedTransaction::DepositTransaction(ref mut inner) => {
98                if inner.tx.gas_price.is_none() {
99                    inner.tx.gas_price = Some(self.get_gas_price().await?);
100                }
101            }
102        };
103
104        self.inner().fill_transaction(tx, block).await.map_err(METrait::from_err)
105    }
106
107    async fn get_gas_price(&self) -> Result<U256, Self::Error> {
108        Ok(self.gas_oracle.fetch().await?)
109    }
110
111    async fn estimate_eip1559_fees(
112        &self,
113        _: Option<fn(U256, Vec<Vec<U256>>) -> (U256, U256)>,
114    ) -> Result<(U256, U256), Self::Error> {
115        Ok(self.gas_oracle.estimate_eip1559_fees().await?)
116    }
117
118    async fn send_transaction<T: Into<TypedTransaction> + Send + Sync>(
119        &self,
120        tx: T,
121        block: Option<BlockId>,
122    ) -> Result<PendingTransaction<'_, Self::Provider>, Self::Error> {
123        let mut tx = tx.into();
124        self.fill_transaction(&mut tx, block).await?;
125        self.inner.send_transaction(tx, block).await.map_err(MiddlewareError::MiddlewareError)
126    }
127}