ethers_middleware/gas_oracle/
etherscan.rs

1use super::{GasCategory, GasOracle, GasOracleError, Result};
2use async_trait::async_trait;
3use ethers_core::types::U256;
4use ethers_etherscan::Client;
5use std::ops::{Deref, DerefMut};
6
7/// A client over HTTP for the [Etherscan](https://api.etherscan.io/api?module=gastracker&action=gasoracle) gas tracker API
8/// that implements the `GasOracle` trait
9#[derive(Clone, Debug)]
10#[must_use]
11pub struct Etherscan {
12    client: Client,
13    gas_category: GasCategory,
14}
15
16impl Deref for Etherscan {
17    type Target = Client;
18
19    fn deref(&self) -> &Self::Target {
20        &self.client
21    }
22}
23
24impl DerefMut for Etherscan {
25    fn deref_mut(&mut self) -> &mut Self::Target {
26        &mut self.client
27    }
28}
29
30#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
31#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
32impl GasOracle for Etherscan {
33    async fn fetch(&self) -> Result<U256> {
34        // handle unsupported gas categories before making the request
35        match self.gas_category {
36            GasCategory::SafeLow | GasCategory::Standard | GasCategory::Fast => {}
37            GasCategory::Fastest => return Err(GasOracleError::GasCategoryNotSupported),
38        }
39
40        let result = self.query().await?;
41        let gas_price = match self.gas_category {
42            GasCategory::SafeLow => result.safe_gas_price,
43            GasCategory::Standard => result.propose_gas_price,
44            GasCategory::Fast => result.fast_gas_price,
45            _ => unreachable!(),
46        };
47        Ok(gas_price)
48    }
49
50    async fn estimate_eip1559_fees(&self) -> Result<(U256, U256)> {
51        Err(GasOracleError::Eip1559EstimationNotSupported)
52    }
53}
54
55impl Etherscan {
56    /// Creates a new [Etherscan](https://etherscan.io/gastracker) gas price oracle.
57    pub fn new(client: Client) -> Self {
58        Etherscan { client, gas_category: GasCategory::Standard }
59    }
60
61    /// Sets the gas price category to be used when fetching the gas price.
62    pub fn category(mut self, gas_category: GasCategory) -> Self {
63        self.gas_category = gas_category;
64        self
65    }
66
67    /// Perform a request to the gas price API and deserialize the response.
68    pub async fn query(&self) -> Result<ethers_etherscan::gas::GasOracle> {
69        Ok(self.client.gas_oracle().await?)
70    }
71}