use crate::client::Http;
use crate::client::evm::abi::AbiError;
use crate::client::evm::precompiles::table::address;
use crate::client::evm::rpc::{BlockTag, CallRequest, Rpc, RpcError};
use crate::client::evm::u256::{B256, U256};
use crate::utils::Address;
#[derive(Debug, Clone)]
pub struct Read<T> {
pub at: Address,
pub data: Vec<u8>,
decode: fn(&[u8]) -> Result<T, AbiError>,
}
impl<T> Read<T> {
#[must_use]
pub fn request(&self) -> CallRequest {
CallRequest::to(self.at, self.data.clone())
}
pub fn decode(&self, answer: &[u8]) -> Result<T, AbiError> {
(self.decode)(answer)
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ReadError {
#[error(transparent)]
Rpc(#[from] RpcError),
#[error("the precompile's answer does not fit its struct: {0}")]
Abi(#[from] AbiError),
}
impl<H: Http> Rpc<H> {
pub async fn read<T>(&self, read: &Read<T>) -> Result<T, ReadError> {
let answer = self.call(&read.request(), BlockTag::Latest).await?;
Ok(read.decode(&answer)?)
}
}
pub(super) enum Arg {
Address(Address),
Uint(u64),
}
pub(super) fn read<T>(at: u16, args: &[Arg], decode: fn(&[u8]) -> Result<T, AbiError>) -> Read<T> {
let mut data = Vec::with_capacity(args.len() * 32);
for arg in args {
let word = match arg {
Arg::Address(address) => B256::from_address(*address).0,
Arg::Uint(value) => U256::from_u64(*value).to_be_bytes(),
};
data.extend_from_slice(&word);
}
Read { at: address(at), data, decode }
}