ethers-rs/examples/transactions/examples/gas_price_usd.rs

75 lines
2.2 KiB
Rust

use std::{
error::Error,
ops::{Div, Mul},
sync::Arc,
};
use ethers::{
contract::abigen,
core::{
types::{Address, I256, U256},
utils::format_units,
},
providers::{Http, Middleware, Provider},
};
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://eth.llamarpc.com";
/// 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<dyn Error>> {
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::<f64>()?;
// 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
---------------
{gwei:>10.2} gwei
{usd_per_gas:>10.8} usd
"#
);
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<f64, Box<dyn Error>> {
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::<f64>()?)
}
fn get_client() -> Arc<Provider<Http>> {
let provider: Provider<Http> = Provider::<Http>::try_from(RPC_URI).expect("Valid URL");
Arc::new(provider)
}
fn get_oracle(client: &Arc<Provider<Http>>) -> AggregatorInterface<Provider<Http>> {
let address: Address = ETH_USD_FEED.parse().expect("Valid address");
AggregatorInterface::new(address, Arc::clone(client))
}