use crate::core::types::AccountType;
#[derive(Debug, Clone)]
pub struct HyperliquidUrls {
pub rest: &'static str,
pub ws: &'static str,
}
impl HyperliquidUrls {
pub const MAINNET: Self = Self {
rest: "https://api.hyperliquid.xyz",
ws: "wss://api.hyperliquid.xyz/ws",
};
pub const TESTNET: Self = Self {
rest: "https://api.hyperliquid-testnet.xyz",
ws: "wss://api.hyperliquid-testnet.xyz/ws",
};
pub fn rest_url(&self) -> &str {
self.rest
}
pub fn ws_url(&self) -> &str {
self.ws
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HyperliquidEndpoint {
Info, Exchange, }
impl HyperliquidEndpoint {
pub fn path(&self) -> &'static str {
match self {
Self::Info => "/info",
Self::Exchange => "/exchange",
}
}
pub fn requires_auth(&self) -> bool {
match self {
Self::Info => false, Self::Exchange => true, }
}
pub fn method(&self) -> &'static str {
"POST" }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(dead_code)]
pub enum InfoType {
MetaAndAssetCtxs, Meta, SpotMeta, AllMids, L2Book, RecentTrades, CandleSnapshot, FundingHistory,
ClearinghouseState, SpotClearinghouseState, OpenOrders, OrderStatus, UserFills, UserFillsByTime, UserFees, UserRateLimit, HistoricalOrders, UserFunding, PredictedFundings, VaultDetails, SpotMetaAndAssetCtxs, UserNonFundingLedgerUpdates, }
impl InfoType {
pub fn as_str(&self) -> &'static str {
match self {
Self::MetaAndAssetCtxs => "metaAndAssetCtxs",
Self::Meta => "meta",
Self::SpotMeta => "spotMeta",
Self::AllMids => "allMids",
Self::L2Book => "l2Book",
Self::RecentTrades => "recentTrades",
Self::CandleSnapshot => "candleSnapshot",
Self::FundingHistory => "fundingHistory",
Self::ClearinghouseState => "clearinghouseState",
Self::SpotClearinghouseState => "spotClearinghouseState",
Self::OpenOrders => "openOrders",
Self::OrderStatus => "orderStatus",
Self::UserFills => "userFills",
Self::UserFillsByTime => "userFillsByTime",
Self::UserFees => "userFees",
Self::UserRateLimit => "userRateLimit",
Self::HistoricalOrders => "historicalOrders",
Self::UserFunding => "userFunding",
Self::PredictedFundings => "predictedFundings",
Self::VaultDetails => "vaultDetails",
Self::SpotMetaAndAssetCtxs => "spotMetaAndAssetCtxs",
Self::UserNonFundingLedgerUpdates => "userNonFundingLedgerUpdates",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(dead_code)]
pub enum ActionType {
Order, Cancel, CancelByCloid, Modify, BatchModify,
UpdateLeverage, UpdateIsolatedMargin,
UsdClassTransfer, UsdSend, SpotSend, Withdraw3, }
impl ActionType {
#[allow(dead_code)]
pub fn as_str(&self) -> &'static str {
match self {
Self::Order => "order",
Self::Cancel => "cancel",
Self::CancelByCloid => "cancelByCloid",
Self::Modify => "modify",
Self::BatchModify => "batchModify",
Self::UpdateLeverage => "updateLeverage",
Self::UpdateIsolatedMargin => "updateIsolatedMargin",
Self::UsdClassTransfer => "usdClassTransfer",
Self::UsdSend => "usdSend",
Self::SpotSend => "spotSend",
Self::Withdraw3 => "withdraw3",
}
}
#[allow(dead_code)]
pub fn is_l1_action(&self) -> bool {
matches!(self,
Self::Order
| Self::Cancel
| Self::CancelByCloid
| Self::Modify
| Self::BatchModify
| Self::UpdateLeverage
| Self::UpdateIsolatedMargin
| Self::UsdClassTransfer
)
}
}
#[allow(dead_code)]
pub fn format_symbol(symbol: &str, account_type: AccountType) -> String {
match account_type {
AccountType::Spot => {
if symbol.starts_with('@') {
symbol.to_string()
} else {
symbol.to_string()
}
}
AccountType::FuturesCross | AccountType::FuturesIsolated => {
symbol.to_uppercase()
}
AccountType::Margin => {
symbol.to_uppercase()
}
_ => {
symbol.to_string()
}
}
}
pub fn map_kline_interval(interval: &str) -> &'static str {
match interval {
"1m" => "1m",
"3m" => "3m",
"5m" => "5m",
"15m" => "15m",
"30m" => "30m",
"1h" => "1h",
"2h" => "2h",
"4h" => "4h",
"8h" => "8h",
"12h" => "12h",
"1d" => "1d",
"3d" => "3d",
"1w" => "1w",
"1M" => "1M",
_ => "1h", }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_symbol() {
assert_eq!(format_symbol("BTC", AccountType::FuturesCross), "BTC");
assert_eq!(format_symbol("eth", AccountType::FuturesCross), "ETH");
assert_eq!(format_symbol("@107", AccountType::Spot), "@107");
assert_eq!(format_symbol("HYPE/USDC", AccountType::Spot), "HYPE/USDC");
}
#[test]
fn test_endpoints() {
assert_eq!(HyperliquidEndpoint::Info.path(), "/info");
assert_eq!(HyperliquidEndpoint::Exchange.path(), "/exchange");
assert_eq!(HyperliquidEndpoint::Info.method(), "POST");
assert_eq!(HyperliquidEndpoint::Exchange.method(), "POST");
}
#[test]
fn test_info_types() {
assert_eq!(InfoType::Meta.as_str(), "meta");
assert_eq!(InfoType::SpotMeta.as_str(), "spotMeta");
assert_eq!(InfoType::L2Book.as_str(), "l2Book");
}
#[test]
fn test_action_types() {
assert_eq!(ActionType::Order.as_str(), "order");
assert_eq!(ActionType::Cancel.as_str(), "cancel");
assert!(ActionType::Order.is_l1_action());
assert!(!ActionType::UsdSend.is_l1_action());
}
}