df-hyperliquid-core 0.0.8-beta.1

Hyperliquid SDK for Rust: markets, account, trading, transfers, earn and deploy, with exact decimals and signing. Native and wasm.
Documentation
//! A recorded `userFills` row and the info endpoint docs' builder fill, beside a recorded socket
//! `userFills` row from a liquidation (mainnet, 2026-10-08): one shape either way.

use super::*;

const READ: &str = r#"{"closedPnl":"0.0","coin":"AVAX","crossed":false,"dir":"Open Long","hash":"0xa166e3fa63c25663024b03f2e0da011a00307e4017465df020210d3d432e7cb8","oid":90542681,"px":"18.435","side":"B","startPosition":"26.86","sz":"93.53","time":1681222254710,"fee":"0.01","feeToken":"USDC","builderFee":"0.01","tid":118906512037719}"#;
const LIQUIDATION: &str = r#"{"coin":"BTC","px":"80432.0","sz":"0.02603","side":"B","time":1791480388855,"startPosition":"-12.56343","dir":"Close Short","closedPnl":"16.680024","hash":"0xeba0ed56a1ceefc8ed1a04462006440000dc053c3cc20e9a8f6998a960c2c9b3","oid":569015257022,"crossed":false,"fee":"-0.062809","tid":1051492541339376,"cloid":"0xf82e29e34219a1dcc66c6960c49a6f00","liquidation":{"liquidatedUser":"0xf467f1f46cad3f1041c765765be2891245144f6e","markPx":"80429.0","method":"market"},"feeToken":"USDC","twapId":null}"#;

fn dec(text: &str) -> Dec {
    Dec::parse(text).unwrap()
}

#[test]
fn a_fill_keeps_what_only_some_fills_carry_as_options() {
    let read: Fill = serde_json::from_str(READ).unwrap();
    assert_eq!((read.builder_fee, read.cloid.as_deref(), read.liquidation.as_ref()), (Some(dec("0.01")), None, None));
    let liquidated: Fill = serde_json::from_str(LIQUIDATION).unwrap();
    assert_eq!((liquidated.builder_fee, liquidated.twap_id), (None, None));
    assert_eq!(liquidated.cloid.as_deref(), Some("0xf82e29e34219a1dcc66c6960c49a6f00"));
    assert_eq!(
        liquidated.liquidation,
        Some(FillLiquidation {
            liquidated_user: Some("0xf467f1f46cad3f1041c765765be2891245144f6e".parse().unwrap()),
            mark_px: dec("80429"),
            method: "market".to_owned(),
        })
    );
}

#[test]
fn a_fill_without_its_fee_token_or_whether_it_crossed_is_refused() {
    for gone in ["\"feeToken\":\"USDC\",", "\"crossed\":false,"] {
        let text = LIQUIDATION.replace(gone, "");
        assert!(serde_json::from_str::<Fill>(&text).is_err(), "without {gone}");
    }
}