diff --git a/examples/gas_price_usd.rs b/examples/gas_price_usd.rs new file mode 100644 index 00000000..43e9bb2c --- /dev/null +++ b/examples/gas_price_usd.rs @@ -0,0 +1,67 @@ +use ethers::{prelude::*, utils::format_units}; +use std::{ + error::Error, + ops::{Div, Mul}, + sync::Arc, +}; + +abigen!( + AggregatorInterface, + r#"[ + latestAnswer() public view virtual override returns (int256 answer) + ]"#, +); + +const ETH_DECIMALS: u32 = 18; +const USD_PRICE_DECIMALS: u32 = 8; +const ETH_USD_FEED: &str = "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"; +const RPC_URI: &str = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + +/// Retrieves the USD amount per gas unit, using a Chainlink price oracle. +/// Function gets the amount of `wei` to be spent per gas unit then multiplies +/// for the ETH USD value. +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = get_client(); + let oracle = get_oracle(&client); + + let usd_per_eth: I256 = oracle.latest_answer().call().await?; + let usd_per_eth: U256 = U256::from(usd_per_eth.as_u128()); + let wei_per_gas: U256 = client.get_gas_price().await?; + + // Gas stations use to report gas price in gwei units (1 gwei = 10^9 wei) + let gwei: f64 = format_units(wei_per_gas, "gwei")?.parse::()?; + + // Let's convert the gas price to USD + let usd_per_gas: f64 = usd_value(wei_per_gas, usd_per_eth)?; + + println!( + r#" + Gas price + --------------- + {:>10.2} gwei + {:>10.8} usd + "#, + gwei, usd_per_gas + ); + Ok(()) +} + +/// `amount`: Number of wei per gas unit (18 decimals) +/// `price_usd`: USD price per ETH (8 decimals) +fn usd_value(amount: U256, price_usd: U256) -> Result> { + let base: U256 = U256::from(10).pow(ETH_DECIMALS.into()); + let value: U256 = amount.mul(price_usd).div(base); + let f: String = format_units(value, USD_PRICE_DECIMALS)?; + Ok(f.parse::()?) +} + +fn get_client() -> Arc> { + let provider: Provider = Provider::::try_from(RPC_URI).expect("Valid URL"); + Arc::new(provider) +} + +fn get_oracle(client: &Arc>) -> AggregatorInterface> { + let address: Address = ETH_USD_FEED.parse().expect("Valid address"); + AggregatorInterface::new(address, Arc::clone(client)) +}