use crate::provider::Erc20Contract;
use alloy::{
contract::Error,
network::Network,
primitives::{Address, U256},
providers::Provider,
};
use async_once_cell::OnceCell;
use bigdecimal::{
num_bigint::{BigInt, Sign},
BigDecimal,
};
use futures::TryFutureExt;
use std::{
fmt::Debug,
future::{ready, IntoFuture},
};
#[derive(Debug)]
pub struct LazyToken<P, N> {
name: OnceCell<String>,
symbol: OnceCell<String>,
decimals: OnceCell<u8>,
pub instance: Erc20Contract::Erc20ContractInstance<P, N>,
}
impl<P, N> LazyToken<P, N>
where
P: Provider<N>,
N: Network,
{
pub const fn new(address: Address, provider: P) -> Self {
Self {
name: OnceCell::new(),
symbol: OnceCell::new(),
decimals: OnceCell::new(),
instance: Erc20Contract::new(address, provider),
}
}
pub const fn address(&self) -> &Address {
self.instance.address()
}
pub async fn name(&self) -> Result<&String, Error> {
self.name
.get_or_try_init(
self.instance
.name()
.call()
.into_future()
.and_then(|r| ready(Ok(r))),
)
.await
}
pub async fn symbol(&self) -> Result<&String, Error> {
self.symbol
.get_or_try_init(
self.instance
.symbol()
.call()
.into_future()
.and_then(|r| ready(Ok(r))),
)
.await
}
pub async fn decimals(&self) -> Result<&u8, Error> {
self.decimals
.get_or_try_init(
self.instance
.decimals()
.call()
.into_future()
.and_then(|r| ready(Ok(r))),
)
.await
}
pub async fn total_supply(&self) -> Result<U256, Error> {
self.instance
.totalSupply()
.call()
.into_future()
.and_then(|r| ready(Ok(r)))
.await
}
pub async fn balance_of(&self, account: Address) -> Result<U256, Error> {
self.instance
.balanceOf(account)
.call()
.into_future()
.and_then(|r| ready(Ok(r)))
.await
}
pub async fn allowance(&self, owner: Address, spender: Address) -> Result<U256, Error> {
self.instance
.allowance(owner, spender)
.call()
.into_future()
.and_then(|r| ready(Ok(r)))
.await
}
pub async fn get_balance(&self, amount: U256) -> Result<BigDecimal, Error> {
let decimals = self.decimals().await?;
let balance = BigDecimal::from((
BigInt::from_bytes_be(Sign::Plus, &amount.to_be_bytes::<{ U256::BYTES }>()),
*decimals as i64,
));
Ok(balance)
}
}