diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index fb8c4e39fe28..6ca23d4191ee 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -230,7 +230,12 @@ pub enum CastSubcommand { unit: String, }, - /// Convert a number into a uint. + /// Convert a number into a uint with arbitrary decimals. + /// + /// Examples: + /// - 1.0 6 (for USDC, result: 1000000) + /// - 2.5 12 (for 12 decimals token, result: 2500000000000) + /// - 1.23 3 (for 3 decimals token, result: 1230) #[command(visible_aliases = &["--parse-uints", "pu"])] ParseUints { /// The value to convert. @@ -240,7 +245,12 @@ pub enum CastSubcommand { unit: u8, }, - /// Format a number into a unit. + /// Format a number from smallest unit to decimal with arbitrary decimals. + /// + /// Examples: + /// - 1000000 6 (for USDC, result: 1.0) + /// - 2500000000000 12 (for 12 decimals, result: 2.5) + /// - 1230 3 (for 3 decimals, result: 1.23) #[command(visible_aliases = &["--format-units", "fu"])] FormatUnits { /// The value to format. diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 773218ba2ca1..6b225754f754 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -1364,16 +1364,56 @@ impl SimpleCast { Ok(formatted) } + /// Convert a number into a uint with arbitrary decimals. + /// + /// # Example + /// + /// ``` + /// use cast::SimpleCast as Cast; + /// + /// # fn main() -> eyre::Result<()> { + /// assert_eq!(Cast::parse_units("1.0", 6)?, "1000000"); // USDC (6 decimals) + /// assert_eq!(Cast::parse_units("2.5", 6)?, "2500000"); + /// assert_eq!(Cast::parse_units("1.0", 12)?, "1000000000000"); // 12 decimals + /// assert_eq!(Cast::parse_units("1.23", 3)?, "1230"); // 3 decimals + /// # Ok(()) + /// # } + /// ``` pub fn parse_units(value: &str, unit: u8) -> Result { let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!("invalid unit"))?; Ok(ParseUnits::parse_units(value, unit)?.to_string()) } + /// Format a number from smallest unit to decimal with arbitrary decimals. + /// + /// # Example + /// + /// ``` + /// use cast::SimpleCast as Cast; + /// + /// # fn main() -> eyre::Result<()> { + /// assert_eq!(Cast::format_units("1000000", 6)?, "1"); // USDC (6 decimals) + /// assert_eq!(Cast::format_units("2500000", 6)?, "2.500000"); + /// assert_eq!(Cast::format_units("1000000000000", 12)?, "1"); // 12 decimals + /// assert_eq!(Cast::format_units("1230", 3)?, "1.230"); // 3 decimals + /// # Ok(()) + /// # } + /// ``` pub fn format_units(value: &str, unit: u8) -> Result { let value = NumberWithBase::parse_int(value, None)?.number(); let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!("invalid unit"))?; - Ok(ParseUnits::U256(value).format_units(unit)) + let mut formatted = ParseUnits::U256(value).format_units(unit); + + // Trim empty fractional part. + if let Some(dot) = formatted.find('.') { + let fractional = &formatted[dot + 1..]; + if fractional.chars().all(|c: char| c == '0') { + formatted = formatted[..dot].to_string(); + } + } + + Ok(formatted) } /// Converts wei into an eth amount