use std::fmt::Display;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct HyperliquidAssetId(pub u32);
impl HyperliquidAssetId {
pub fn perp(index: u32) -> Self {
Self(index)
}
pub fn spot(index: u32) -> Self {
Self(10_000 + index)
}
pub fn builder_perp(dex_index: u32, meta_index: u32) -> Self {
Self(100_000 + dex_index * 10_000 + meta_index)
}
pub fn is_spot(self) -> bool {
self.0 >= 10_000 && self.0 < 100_000
}
pub fn is_builder_perp(self) -> bool {
self.0 >= 100_000
}
pub fn base_index(self) -> u32 {
if self.is_spot() {
self.0 - 10_000
} else if self.is_builder_perp() {
(self.0 - 100_000) % 10_000
} else {
self.0
}
}
pub fn to_raw(self) -> u32 {
self.0
}
}
impl Display for HyperliquidAssetId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
fn test_asset_id_perp() {
let asset_id = HyperliquidAssetId::perp(7);
assert_eq!(asset_id.to_raw(), 7);
assert!(!asset_id.is_spot());
assert!(!asset_id.is_builder_perp());
assert_eq!(asset_id.base_index(), 7);
}
#[rstest]
fn test_asset_id_spot() {
let asset_id = HyperliquidAssetId::spot(7);
assert_eq!(asset_id.to_raw(), 10_007);
assert!(asset_id.is_spot());
assert!(!asset_id.is_builder_perp());
assert_eq!(asset_id.base_index(), 7);
}
#[rstest]
fn test_asset_id_builder_perp() {
let asset_id = HyperliquidAssetId::builder_perp(1, 7);
assert_eq!(asset_id.to_raw(), 110_007);
assert!(!asset_id.is_spot());
assert!(asset_id.is_builder_perp());
assert_eq!(asset_id.base_index(), 7);
}
}