df_hyperliquid_core/utils/
units.rs1use crate::utils::dec::{Dec, Round};
6
7#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
8pub enum BadUnits {
9 #[error("{0} is not a positive amount")]
10 NotPositive(Dec),
11 #[error("{value} has more than {places} decimal places")]
12 TooFine { value: Dec, places: u32 },
13 #[error("{0} is too large")]
14 TooLarge(Dec),
15}
16
17pub fn exact_units(value: Dec, places: u32) -> Result<u64, BadUnits> {
20 if value.places() > places {
21 return Err(BadUnits::TooFine { value, places });
22 }
23 cut_units(value, places)
24}
25
26pub fn cut_units(value: Dec, places: u32) -> Result<u64, BadUnits> {
29 if !value.is_positive() {
30 return Err(BadUnits::NotPositive(value));
31 }
32 let units = value.units_at(places, Round::Down).ok_or(BadUnits::TooLarge(value))?;
33 match u64::try_from(units) {
34 Ok(0) => Err(BadUnits::NotPositive(value)),
35 Ok(units) => Ok(units),
36 Err(_) => Err(BadUnits::TooLarge(value)),
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 fn dec(text: &str) -> Dec {
45 Dec::parse(text).unwrap()
46 }
47
48 #[test]
49 fn an_exact_amount_is_counted_and_a_finer_one_refused() {
50 assert_eq!(exact_units(dec("10"), 6), Ok(10_000_000));
51 assert_eq!(exact_units(dec("2.5"), 6), Ok(2_500_000));
52 assert_eq!(exact_units(dec("100"), 8), Ok(10_000_000_000));
53 assert_eq!(exact_units(dec("0.00000001"), 8), Ok(1));
54 assert_eq!(exact_units(dec("1.0000001"), 6), Err(BadUnits::TooFine { value: dec("1.0000001"), places: 6 }));
55 assert_eq!(exact_units(Dec::ZERO, 6), Err(BadUnits::NotPositive(Dec::ZERO)));
56 assert_eq!(exact_units(dec("-1"), 6), Err(BadUnits::NotPositive(dec("-1"))));
57 assert_eq!(exact_units(dec("18446744073709.551616"), 6), Err(BadUnits::TooLarge(dec("18446744073709.551616"))));
58 }
59
60 #[test]
61 fn a_computed_amount_is_cut_toward_zero() {
62 assert_eq!(cut_units(dec("604931.6453119999"), 6), Ok(604_931_645_311));
63 assert_eq!(
64 cut_units(dec("0.0000009"), 6),
65 Err(BadUnits::NotPositive(dec("0.0000009"))),
66 "dust cuts to nothing"
67 );
68 }
69}