From 6a45a93685722f38f0b1b6fbed7d1d6dad025f6a Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 31 May 2022 18:43:44 +0200 Subject: [PATCH] fix: use decimal crate for parsing units (#1330) --- ethers-core/Cargo.toml | 1 + ethers-core/src/utils/mod.rs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ethers-core/Cargo.toml b/ethers-core/Cargo.toml index e7ee219e..7f80634f 100644 --- a/ethers-core/Cargo.toml +++ b/ethers-core/Cargo.toml @@ -40,6 +40,7 @@ cargo_metadata = { version = "0.14.2", optional = true } convert_case = { version = "0.5.0", optional = true } syn = { version = "1.0.95", optional = true } proc-macro2 = { version = "1.0.39", optional = true } +rust_decimal = "1.23.1" [dev-dependencies] serde_json = { version = "1.0.64", default-features = false } diff --git a/ethers-core/src/utils/mod.rs b/ethers-core/src/utils/mod.rs index 000a5335..1703276f 100644 --- a/ethers-core/src/utils/mod.rs +++ b/ethers-core/src/utils/mod.rs @@ -50,6 +50,8 @@ pub enum ConversionError { InvalidFloat(#[from] std::num::ParseFloatError), #[error(transparent)] FromDecStrError(#[from] FromDecStrErr), + #[error(transparent)] + DecimalError(#[from] rust_decimal::Error), } /// 1 Ether = 1e18 Wei == 0x0de0b6b3a7640000 Wei @@ -147,9 +149,12 @@ where S: ToString, K: TryInto + Copy, { - let float_n: f64 = - amount.to_string().parse::()? * 10u64.pow(units.try_into()?.as_num()) as f64; - let u256_n: U256 = U256::from_dec_str(&float_n.round().to_string())?; + use rust_decimal::Decimal; + let num: Decimal = amount.to_string().parse()?; + let multiplier: Decimal = 10u64.pow(units.try_into()?.as_num()).into(); + let val = + num.checked_mul(multiplier).ok_or(rust_decimal::Error::ExceedsMaximumPossibleValue)?; + let u256_n: U256 = U256::from_dec_str(&val.round().to_string())?; Ok(u256_n) } /// The address for an Ethereum contract is deterministically computed from the @@ -446,6 +451,9 @@ mod tests { let eth = parse_units(1, "ether").unwrap(); assert_eq!(eth, WEI_IN_ETHER); + + let val = parse_units("2.3", "ether").unwrap(); + assert_eq!(val, U256::from_dec_str("2300000000000000000").unwrap()); } #[test]