Skip to main content

scope/display/
format.rs

1//! Shared formatting utilities for consistent presentation across all chains.
2
3/// Formats a USD value with K, M, B suffixes.
4///
5/// # Examples
6///
7/// ```
8/// use scope::display::format::format_usd;
9///
10/// assert_eq!(format_usd(1_500_000_000.0), "$1.50B");
11/// assert_eq!(format_usd(1_500_000.0), "$1.50M");
12/// assert_eq!(format_usd(1_500.0), "$1.50K");
13/// assert_eq!(format_usd(15.50), "$15.50");
14/// ```
15pub fn format_usd(value: f64) -> String {
16    if value >= 1_000_000_000.0 {
17        format!("${:.2}B", value / 1_000_000_000.0)
18    } else if value >= 1_000_000.0 {
19        format!("${:.2}M", value / 1_000_000.0)
20    } else if value >= 1_000.0 {
21        format!("${:.2}K", value / 1_000.0)
22    } else {
23        format!("${:.2}", value)
24    }
25}
26
27/// Formats a large number with K, M, B suffixes (no currency prefix).
28///
29/// # Examples
30///
31/// ```
32/// use scope::display::format::format_large_number;
33///
34/// assert_eq!(format_large_number(1_500_000_000.0), "1.50B");
35/// assert_eq!(format_large_number(1_500_000.0), "1.50M");
36/// assert_eq!(format_large_number(1_500.0), "1.50K");
37/// assert_eq!(format_large_number(500.0), "500.00");
38/// ```
39pub fn format_large_number(value: f64) -> String {
40    if value >= 1_000_000_000.0 {
41        format!("{:.2}B", value / 1_000_000_000.0)
42    } else if value >= 1_000_000.0 {
43        format!("{:.2}M", value / 1_000_000.0)
44    } else if value >= 1_000.0 {
45        format!("{:.2}K", value / 1_000.0)
46    } else {
47        format!("{:.2}", value)
48    }
49}
50
51/// Formats a raw token balance string with proper decimals and K/M/B suffixes.
52///
53/// # Arguments
54///
55/// * `balance` - Raw balance in smallest units (e.g., wei, lamports)
56/// * `decimals` - Token decimal places
57///
58/// # Examples
59///
60/// ```
61/// use scope::display::format::format_token_balance;
62///
63/// assert!(format_token_balance("1000000000000000000", 18).starts_with("1.00"));
64/// assert!(format_token_balance("5000000000000000000000000", 18).contains("M"));
65/// ```
66pub fn format_token_balance(balance: &str, decimals: u8) -> String {
67    let balance_f64: f64 = balance.parse().unwrap_or(0.0);
68    let divisor = 10_f64.powi(decimals as i32);
69    let formatted = balance_f64 / divisor;
70
71    if formatted >= 1_000_000_000.0 {
72        format!("{:.2}B", formatted / 1_000_000_000.0)
73    } else if formatted >= 1_000_000.0 {
74        format!("{:.2}M", formatted / 1_000_000.0)
75    } else if formatted >= 1_000.0 {
76        format!("{:.2}K", formatted / 1_000.0)
77    } else {
78        format!("{:.4}", formatted)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_format_usd() {
88        assert_eq!(format_usd(1_500_000_000.0), "$1.50B");
89        assert_eq!(format_usd(1_500_000.0), "$1.50M");
90        assert_eq!(format_usd(1_500.0), "$1.50K");
91        assert_eq!(format_usd(15.50), "$15.50");
92        assert_eq!(format_usd(0.0), "$0.00");
93    }
94
95    #[test]
96    fn test_format_large_number() {
97        assert_eq!(format_large_number(500.0), "500.00");
98        assert_eq!(format_large_number(1_500.0), "1.50K");
99        assert_eq!(format_large_number(1_500_000.0), "1.50M");
100        assert_eq!(format_large_number(1_500_000_000.0), "1.50B");
101    }
102
103    #[test]
104    fn test_format_token_balance() {
105        assert!(format_token_balance("1000000000000000000", 18).starts_with("1.00"));
106        assert!(format_token_balance("5000000000000000000", 18).contains("5.00"));
107        assert!(format_token_balance("0", 18).starts_with("0.00"));
108    }
109}