use crate::error::HyperliquidError::InvalidRequestParameter;
use crate::error::{HyperliquidError, Result};
use once_cell::sync::Lazy;
use serde::de::DeserializeOwned;
use std::collections::HashSet;
use tracing;
pub static SUPPORTED_INTERVALS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
[
"1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "8h", "12h", "1d", "3d", "1w", "1M",
]
.into_iter()
.collect()
});
#[inline]
pub(crate) const fn err_request_invalid_hyperliquid_address(
method: String,
parameter: String,
reason: String,
) -> HyperliquidError {
InvalidRequestParameter {
method,
parameter,
reason,
}
}
pub(crate) async fn post_json<T>(
client: &reqwest::Client,
url: &str,
body: serde_json::Value,
) -> Result<T>
where
T: DeserializeOwned,
{
tracing::trace!("Executing POST request with payload {:?}", body);
let res = client
.post(url)
.json(&body)
.send()
.await?
.error_for_status()
.map_err(|e| {
if let Some(status) = e.status() {
HyperliquidError::Api {
status: status.as_u16(),
body: e.to_string(),
}
} else {
HyperliquidError::from(e)
}
})?;
let text = res.text().await?;
tracing::debug!("Server response: {}", text);
let json: T = serde_json::from_str(&text)?;
Ok(json)
}
pub fn normalize_decimal(s: &str) -> String {
s.parse::<f64>()
.ok()
.map(|f| {
let formatted = format!("{:.8}", f);
let trimmed = formatted.trim_end_matches('0').trim_end_matches('.');
if trimmed.is_empty() {
"0".to_string()
} else {
trimmed.to_string()
}
})
.unwrap_or_else(|| s.to_string())
}
#[cfg(test)]
mod tests {
use super::normalize_decimal;
#[test]
fn test_removes_trailing_zeros() {
assert_eq!(normalize_decimal("1.50000000"), "1.5");
assert_eq!(normalize_decimal("100.00"), "100");
assert_eq!(normalize_decimal("25.86750000"), "25.8675");
}
#[test]
fn test_preserves_significant_decimals() {
assert_eq!(normalize_decimal("1.23456789"), "1.23456789");
assert_eq!(normalize_decimal("0.001"), "0.001");
}
#[test]
fn test_whole_numbers() {
assert_eq!(normalize_decimal("100"), "100");
assert_eq!(normalize_decimal("0"), "0");
assert_eq!(normalize_decimal("0.0"), "0");
}
#[test]
fn test_small_decimals() {
assert_eq!(normalize_decimal("0.00001"), "0.00001");
assert_eq!(normalize_decimal("0.10000"), "0.1");
}
#[test]
fn test_invalid_input() {
assert_eq!(normalize_decimal("not_a_number"), "not_a_number");
assert_eq!(normalize_decimal(""), "");
}
}