Skip to main content

df_hyperliquid_core/client/evm/precompiles/
read.rs

1//! A typed [`Read`]: where the call goes, its calldata and how its answer reads,
2//! and the [`Rpc`] method that makes one.
3
4use crate::client::Http;
5use crate::client::evm::abi::AbiError;
6use crate::client::evm::precompiles::table::address;
7use crate::client::evm::rpc::{BlockTag, CallRequest, Rpc, RpcError};
8use crate::client::evm::u256::{B256, U256};
9use crate::utils::Address;
10
11/// A typed read: where the call goes, its calldata, and how its answer reads.
12#[derive(Debug, Clone)]
13pub struct Read<T> {
14    pub at: Address,
15    pub data: Vec<u8>,
16    decode: fn(&[u8]) -> Result<T, AbiError>,
17}
18
19impl<T> Read<T> {
20    /// The `eth_call` that makes the read.
21    #[must_use]
22    pub fn request(&self) -> CallRequest {
23        CallRequest::to(self.at, self.data.clone())
24    }
25
26    /// The answer's bytes, read against the declared struct.
27    pub fn decode(&self, answer: &[u8]) -> Result<T, AbiError> {
28        (self.decode)(answer)
29    }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
33pub enum ReadError {
34    #[error(transparent)]
35    Rpc(#[from] RpcError),
36    #[error("the precompile's answer does not fit its struct: {0}")]
37    Abi(#[from] AbiError),
38}
39
40impl<H: Http> Rpc<H> {
41    /// One read precompile, at the latest block: the only one HyperEVM serves.
42    pub async fn read<T>(&self, read: &Read<T>) -> Result<T, ReadError> {
43        let answer = self.call(&read.request(), BlockTag::Latest).await?;
44        Ok(read.decode(&answer)?)
45    }
46}
47
48/// One argument word: every precompile argument is a static type, so the
49/// calldata is the words one after another, as `abi.encode` writes them.
50pub(super) enum Arg {
51    Address(Address),
52    Uint(u64),
53}
54
55pub(super) fn read<T>(at: u16, args: &[Arg], decode: fn(&[u8]) -> Result<T, AbiError>) -> Read<T> {
56    let mut data = Vec::with_capacity(args.len() * 32);
57    for arg in args {
58        let word = match arg {
59            Arg::Address(address) => B256::from_address(*address).0,
60            Arg::Uint(value) => U256::from_u64(*value).to_be_bytes(),
61        };
62        data.extend_from_slice(&word);
63    }
64    Read { at: address(at), data, decode }
65}