ethers_middleware/gas_oracle/
middleware.rs1use 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#[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 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}