Skip to main content

df_papertrade_core/client/
reads.rs

1//! What the [`Client`] reads: the relayer's trading state and protocol figures, the book's BBO
2//! and the contracts' values on HyperEVM, and where the account stream is.
3
4use df_hyperliquid_core::client::Http;
5use df_hyperliquid_core::client::evm::precompiles;
6use df_hyperliquid_core::utils::Address;
7
8use crate::client::{Call, Client, Error, chain};
9use crate::markets::{QueueRank, QueueSummary, Summary, Trade, TradingState, stats};
10
11/// Hyperliquid's best bid and ask for a market and their mid, raw at the market's price scale.
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct Quote {
14    pub bid: u128,
15    pub ask: u128,
16    /// `(bid + ask) / 2`, the price an open or close executes at.
17    pub mid: u128,
18}
19
20impl<H: Http + Clone> Client<H> {
21    async fn text(&self, call: &Call) -> Result<String, Error> {
22        Ok(self.relayer().send(call).await?)
23    }
24
25    /// Every market's parameters, open interest and caps, and which intents the relayer
26    /// accepts now.
27    pub async fn trading_state(&self) -> Result<TradingState, Error> {
28        Ok(TradingState::parse(&self.text(&Call::trading_state()).await?)?)
29    }
30
31    /// TVL, LP, queue, fees, and PAPER's supply and curve.
32    pub async fn summary(&self) -> Result<Summary, Error> {
33        Ok(Summary::parse(&self.text(&Call::summary()).await?)?)
34    }
35
36    /// Each market's notional over the last day, by instrument id.
37    pub async fn volumes(&self) -> Result<Vec<(u32, u128)>, Error> {
38        Ok(stats::market_volumes(&self.text(&Call::market_stats()).await?)?)
39    }
40
41    /// The payout queue: total owed to queued winners, count, and its largest and front entries.
42    pub async fn queue(&self) -> Result<QueueSummary, Error> {
43        Ok(QueueSummary::parse(&self.text(&Call::queue_summary()).await?)?)
44    }
45
46    /// The latest trades across the venue, newest first.
47    pub async fn recent_trades(&self) -> Result<Vec<Trade>, Error> {
48        Ok(stats::recent_trades(&self.text(&Call::recent_trades()).await?)?)
49    }
50
51    /// Where `owner`'s queued intents stand in the relayer's queue.
52    pub async fn queue_rank(&self, owner: Address) -> Result<QueueRank, Error> {
53        Ok(QueueRank::parse(&self.text(&Call::queue_rank(owner)).await?)?)
54    }
55
56    /// The market's BBO from the oracle's on-chain source (`asset_index` is Hyperliquid's perp
57    /// index). An intent sent now executes at its mid, give or take a block.
58    pub async fn quote(&self, asset_index: u32) -> Result<Quote, Error> {
59        let bbo = self.rpc().read(&precompiles::bbo(asset_index)).await.map_err(Error::Precompile)?;
60        let (bid, ask) = (u128::from(bbo.bid), u128::from(bbo.ask));
61        let mid = crate::utils::units::mid(bid, ask).ok_or(Error::Decode("the book is empty or crossed".into()))?;
62        Ok(Quote { bid, ask, mid })
63    }
64
65    /// `owner`'s deposit address, derived on chain. USDC sent to it on HyperCore is swept into
66    /// the venue and credited to `owner`.
67    pub async fn deposit_address(&self, owner: Address) -> Result<Address, Error> {
68        let read = chain::deposit_address(owner).map_err(|e| Error::Decode(e.to_string()))?;
69        read.run(&self.rpc()).await.map_err(Error::Chain)
70    }
71
72    /// USDC staking rewards distributed to `owner` and not yet paid, in collateral units.
73    pub async fn pending_reward(&self, owner: Address) -> Result<u128, Error> {
74        let read = chain::pending_reward(owner).map_err(|e| Error::Decode(e.to_string()))?;
75        read.run(&self.rpc()).await.map_err(Error::Chain)
76    }
77
78    /// The Exchange contract's current win fee, an 18-decimal fraction.
79    pub async fn win_fee_rate(&self) -> Result<u128, Error> {
80        let read = chain::win_fee_rate().map_err(|e| Error::Decode(e.to_string()))?;
81        read.run(&self.rpc()).await.map_err(Error::Chain)
82    }
83
84    /// URL of `owner`'s account stream (server-sent events `liveness`, `wallet`, `heartbeat`).
85    /// Each `wallet` event's data folds into the account with
86    /// [`Account::apply`](crate::account::Account::apply).
87    #[must_use]
88    pub fn stream_url(&self, owner: Address) -> String {
89        Call::account_stream(owner).request(&self.config().relayer).url
90    }
91}