diff --git a/bitcoin/src/amount.rs b/bitcoin/src/amount.rs index 23f9345f..8c5dc446 100644 --- a/bitcoin/src/amount.rs +++ b/bitcoin/src/amount.rs @@ -253,7 +253,10 @@ fn parse_signed_to_satoshi( // many as the difference in precision. let last_n = unsigned_abs(precision_diff).into(); if is_too_precise(s, last_n) { - return Err(ParseAmountError::TooPrecise); + match s.parse::() { + Ok(v) if v == 0_i64 => return Ok((is_negative, 0)), + _ => return Err(ParseAmountError::TooPrecise), + } } s = &s[0..s.len() - last_n]; 0 @@ -1545,6 +1548,30 @@ mod tests { use super::*; + #[test] + fn from_str_zero() { + let denoms = vec!["BTC", "mBTC", "uBTC", "nBTC", "pBTC", "bits", "sats", "msats"]; + for denom in denoms { + for v in &["0", "000"] { + let s = format!("{} {}", v, denom); + match Amount::from_str(&s) { + Err(e) => panic!("Failed to crate amount from {}: {:?}", s, e), + Ok(amount) => assert_eq!(amount, Amount::from_sat(0)), + } + } + + let s = format!("-0 {}", denom); + match Amount::from_str(&s) { + Err(e) => assert_eq!(e, ParseAmountError::Negative), + Ok(_) => panic!("Unsigned amount from {}", s), + } + match SignedAmount::from_str(&s) { + Err(e) => panic!("Failed to crate amount from {}: {:?}", s, e), + Ok(amount) => assert_eq!(amount, SignedAmount::from_sat(0)), + } + } + } + #[test] fn mul_div() { let sat = Amount::from_sat; @@ -1939,15 +1966,6 @@ mod tests { scase("-200000000000 BTC", Err(E::TooBig)); case("18446744073709551616 sat", Err(E::TooBig)); - scase("0 msat", Err(E::TooPrecise)); - scase("-0 msat", Err(E::TooPrecise)); - scase("000 msat", Err(E::TooPrecise)); - scase("-000 msat", Err(E::TooPrecise)); - case("0 msat", Err(E::TooPrecise)); - case("-0 msat", Err(E::TooPrecise)); - case("000 msat", Err(E::TooPrecise)); - case("-000 msat", Err(E::TooPrecise)); - case(".5 bits", Ok(Amount::from_sat(50))); scase("-.5 bits", Ok(SignedAmount::from_sat(-50))); case("0.00253583 BTC", Ok(Amount::from_sat(253583)));