Skip to main content

df_hyperliquid_core/markets/
dex.rs

1//! Which perp dex a read or a coin is about: a request without `dex` is the main dex's, one with
2//! `"dex":"xyz"` that HIP-3 dex's ([`Dex::field`]). A HIP-3 coin is `dex:SYMBOL`; its asset id is
3//! [`Asset::hip3`](crate::utils::asset::Asset::hip3).
4
5use crate::utils::Json;
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
8pub enum Dex<'a> {
9    /// The main dex, the first in `perpDexs`.
10    #[default]
11    Main,
12    /// A HIP-3 dex by its name: `xyz`, the `xyz:` of its coins.
13    Hip3(&'a str),
14}
15
16impl<'a> Dex<'a> {
17    /// The dex a coin trades on: `xyz:TSLA` on `xyz`, `BTC` on the main dex.
18    #[must_use]
19    pub fn of_coin(coin: &'a str) -> Dex<'a> {
20        match coin.split_once(':') {
21            Some((dex, _)) => Dex::Hip3(dex),
22            None => Dex::Main,
23        }
24    }
25
26    /// The `dex` a request names; `None` for the main dex.
27    #[must_use]
28    pub const fn name(self) -> Option<&'a str> {
29        match self {
30            Dex::Main => None,
31            Dex::Hip3(name) => Some(name),
32        }
33    }
34
35    /// The `dex` field of a request body; `None` for the main dex, which a request leaves unnamed.
36    #[must_use]
37    pub fn field(self) -> Option<(&'static str, Json)> {
38        self.name().map(|name| ("dex", Json::String(name.to_owned())))
39    }
40}
41
42/// `xyz:TSLA` as `("xyz", "TSLA")`. `None` for a main-dex coin or an empty part.
43#[must_use]
44pub fn split_coin(coin: &str) -> Option<(&str, &str)> {
45    let (dex, symbol) = coin.split_once(':')?;
46    (!dex.is_empty() && !symbol.is_empty()).then_some((dex, symbol))
47}
48
49/// `xyz` and `TSLA` as `xyz:TSLA`.
50#[must_use]
51pub fn coin(dex: &str, symbol: &str) -> String {
52    format!("{dex}:{symbol}")
53}
54
55#[cfg(test)]
56#[path = "tests/dex.rs"]
57mod tests;