use crate::error::{
ApiError, ConnectivityError, UnindexedApiError, UnindexedClientError, UnindexedOrderError,
};
use rustrade_instrument::instrument::name::InstrumentNameExchange;
pub fn map_sdk_error(error: hyperliquid_rust_sdk::Error) -> UnindexedClientError {
let msg = error.to_string();
let msg_lower = msg.to_lowercase();
if msg_lower.contains("rate limit")
|| msg_lower.contains("too many requests")
|| msg_lower.contains("429")
{
return UnindexedClientError::Api(UnindexedApiError::RateLimit);
}
if msg_lower.contains("connection")
|| msg_lower.contains("timeout")
|| msg_lower.contains("network")
|| msg_lower.contains("dns")
|| msg_lower.contains("tls")
|| msg_lower.contains("ssl")
|| msg_lower.contains(" 500")
|| msg_lower.contains(" 502")
|| msg_lower.contains(" 503")
|| msg_lower.contains(" 504")
|| msg_lower.contains("bad gateway")
|| msg_lower.contains("service unavailable")
|| msg_lower.contains("gateway timeout")
{
return UnindexedClientError::Connectivity(ConnectivityError::Socket(msg));
}
if msg_lower.contains("signature")
|| msg_lower.contains("unauthorized")
|| msg_lower.contains("invalid key")
|| msg_lower.contains("authentication")
|| msg_lower.contains("eip712")
{
return UnindexedClientError::Api(UnindexedApiError::Unauthenticated(msg));
}
UnindexedClientError::Internal(msg)
}
pub fn map_order_error(
error: hyperliquid_rust_sdk::Error,
instrument: &InstrumentNameExchange,
) -> UnindexedOrderError {
let msg = error.to_string();
let msg_lower = msg.to_lowercase();
if msg_lower.contains("unknown")
|| msg_lower.contains("not found")
|| msg_lower.contains("invalid symbol")
{
return UnindexedOrderError::Rejected(ApiError::InstrumentInvalid(instrument.clone(), msg));
}
UnindexedOrderError::Rejected(ApiError::OrderRejected(msg))
}
#[cfg(test)]
mod tests {
use super::*;
use hyperliquid_rust_sdk::Error;
fn make_sdk_error(msg: &str) -> Error {
Error::GenericReader(msg.to_string())
}
#[test]
fn test_map_sdk_error_connectivity() {
let err = map_sdk_error(make_sdk_error("connection refused"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
let err = map_sdk_error(make_sdk_error("request timeout occurred"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
let err = map_sdk_error(make_sdk_error("DNS lookup failed"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
let err = map_sdk_error(make_sdk_error("TLS handshake error"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
}
#[test]
fn test_map_sdk_error_5xx_transient() {
let err = map_sdk_error(make_sdk_error("HTTP 500 Internal Server Error"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
let err = map_sdk_error(make_sdk_error("502 Bad Gateway"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
let err = map_sdk_error(make_sdk_error("503 Service Unavailable"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
let err = map_sdk_error(make_sdk_error("504 Gateway Timeout"));
assert!(matches!(err, UnindexedClientError::Connectivity(_)));
}
#[test]
fn test_map_sdk_error_rate_limit() {
let err = map_sdk_error(make_sdk_error("rate limit exceeded"));
assert!(matches!(
err,
UnindexedClientError::Api(UnindexedApiError::RateLimit)
));
let err = map_sdk_error(make_sdk_error("too many requests"));
assert!(matches!(
err,
UnindexedClientError::Api(UnindexedApiError::RateLimit)
));
let err = map_sdk_error(make_sdk_error("HTTP 429"));
assert!(matches!(
err,
UnindexedClientError::Api(UnindexedApiError::RateLimit)
));
}
#[test]
fn test_map_sdk_error_auth() {
let err = map_sdk_error(make_sdk_error("invalid signature"));
assert!(matches!(
err,
UnindexedClientError::Api(UnindexedApiError::Unauthenticated(_))
));
let err = map_sdk_error(make_sdk_error("unauthorized access"));
assert!(matches!(
err,
UnindexedClientError::Api(UnindexedApiError::Unauthenticated(_))
));
let err = map_sdk_error(make_sdk_error("Error from Eip712 struct: invalid key"));
assert!(matches!(
err,
UnindexedClientError::Api(UnindexedApiError::Unauthenticated(_))
));
}
#[test]
fn test_map_sdk_error_internal() {
let err = map_sdk_error(make_sdk_error("some unknown error"));
assert!(matches!(err, UnindexedClientError::Internal(_)));
}
#[test]
fn test_map_order_error_instrument_invalid() {
let instrument = InstrumentNameExchange::from("INVALID-USD-PERP");
let err = map_order_error(make_sdk_error("unknown asset"), &instrument);
assert!(matches!(
err,
UnindexedOrderError::Rejected(ApiError::InstrumentInvalid(_, _))
));
let err = map_order_error(make_sdk_error("Asset not found"), &instrument);
assert!(matches!(
err,
UnindexedOrderError::Rejected(ApiError::InstrumentInvalid(_, _))
));
}
#[test]
fn test_map_order_error_rejected() {
let instrument = InstrumentNameExchange::from("BTC-USD-PERP");
let err = map_order_error(make_sdk_error("insufficient margin"), &instrument);
assert!(matches!(
err,
UnindexedOrderError::Rejected(ApiError::OrderRejected(_))
));
let err = map_order_error(make_sdk_error("price precision too high"), &instrument);
assert!(matches!(
err,
UnindexedOrderError::Rejected(ApiError::OrderRejected(_))
));
}
}