df_papertrade_core/client/
chain.rs1use df_hyperliquid_core::client::Http;
7use df_hyperliquid_core::client::evm::{AbiError, BlockTag, CallRequest, Function, Rpc, RpcError, Token};
8use df_hyperliquid_core::utils::Address;
9
10use crate::client::deployment::{DEPOSIT_PROXY_FACTORY, EXCHANGE, PAPER_STAKING};
11
12pub struct Read<T> {
14 pub to: Address,
15 pub data: Vec<u8>,
16 decode: fn(&[Token]) -> Option<T>,
17 function: Function,
18}
19
20impl<T> std::fmt::Debug for Read<T> {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.debug_struct("Read").field("to", &self.to).field("function", &self.function.signature()).finish()
23 }
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
28pub enum ReadError {
29 #[error(transparent)]
30 Rpc(#[from] RpcError),
31 #[error("the answer does not fit the function's outputs: {0}")]
32 Abi(#[from] AbiError),
33 #[error("the answer is not the value the function returns")]
34 Shape,
35}
36
37impl<T> Read<T> {
38 fn new(to: Address, signature: &str, args: &[Token], decode: fn(&[Token]) -> Option<T>) -> Result<Self, AbiError> {
39 let function = Function::parse(signature)?;
40 Ok(Read { to, data: function.encode(args)?, decode, function })
41 }
42
43 #[must_use]
45 pub fn request(&self) -> CallRequest {
46 CallRequest::to(self.to, self.data.clone())
47 }
48
49 pub fn decode(&self, answer: &[u8]) -> Result<T, ReadError> {
51 let tokens = self.function.decode_output(answer)?;
52 (self.decode)(&tokens).ok_or(ReadError::Shape)
53 }
54
55 pub async fn run<H: Http>(&self, rpc: &Rpc<H>) -> Result<T, ReadError> {
57 let answer = rpc.call(&self.request(), BlockTag::Latest).await?;
58 self.decode(&answer)
59 }
60}
61
62pub fn deposit_address(wallet: Address) -> Result<Read<Address>, AbiError> {
65 Read::new(
66 DEPOSIT_PROXY_FACTORY,
67 "computeProxyAddress(address user) view returns (address)",
68 &[Token::address(wallet)],
69 |tokens| tokens.first()?.as_address(),
70 )
71}
72
73pub fn win_fee_rate() -> Result<Read<u128>, AbiError> {
75 Read::new(EXCHANGE, "winFeeRate() view returns (uint256)", &[], |tokens| tokens.first()?.as_u128())
76}
77
78pub fn pending_reward(wallet: Address) -> Result<Read<u128>, AbiError> {
80 Read::new(
81 PAPER_STAKING,
82 "pendingReward(address user) view returns (uint256)",
83 &[Token::address(wallet)],
84 |tokens| tokens.first()?.as_u128(),
85 )
86}
87
88#[cfg(test)]
89#[path = "tests/chain.rs"]
90mod tests;