balance.rs•2.07 kB
//! Balance-related operations for Ethereum service
use crate::abis::ERC20;
use crate::ethereum::utils;
use crate::types::BalanceQuery;
use alloy::primitives::Address;
use anyhow::{Context, Result};
/// Get token decimals from ERC20 contract
pub async fn get_token_decimals<P: alloy::providers::Provider>(
token_address: Address,
provider: &P,
) -> Result<u8> {
let erc20 = ERC20::new(token_address, provider);
let decimals_result = erc20.decimals().call().await
.context("Failed to call decimals()")?;
Ok(decimals_result)
}
/// Query ETH balance for an address
pub async fn get_eth_balance<P: alloy::providers::Provider>(
address: &str,
provider: &P,
) -> Result<String> {
let addr: Address = address.parse().context("Invalid address")?;
let balance = provider.get_balance(addr).await?;
Ok(format!("{} ETH", utils::wei_to_eth(&balance)))
}
/// Query ERC-20 token balance using Alloy's ABI system
pub async fn get_token_balance<P: alloy::providers::Provider>(
token_address: &str,
holder_address: &str,
provider: &P,
) -> Result<String> {
// Parse and validate addresses
let token_addr: Address = token_address.parse()
.context("Invalid token address")?;
let holder_addr: Address = holder_address.parse()
.context("Invalid holder address")?;
// Instantiate the contract
let erc20 = ERC20::new(token_addr, provider);
// Fetch the balance using the type-safe contract interface
let balance_result = erc20.balanceOf(holder_addr).call().await
.context("Failed to call balanceOf")?;
Ok(format!("{} tokens", balance_result))
}
/// Query balance based on parameters
pub async fn query_balance<P: alloy::providers::Provider>(
params: &BalanceQuery,
provider: &P,
) -> Result<String> {
match ¶ms.token_address {
Some(token) => Ok(format!("ERC-20 balance: {}",
get_token_balance(token, ¶ms.address, provider).await?)),
None => get_eth_balance(¶ms.address, provider).await,
}
}