Allow parsing sub-sat denoms with decimal points

Numbers with only zeros after decimal points are valid if they are also
multiples of `10^precision` (e.g. 1000 for msats). These were
artificially disallowed as "too precise" which was at least misleading.

This change allows parsing such numbers.
This commit is contained in:
Martin Habovstiak 2023-05-07 08:45:25 +02:00
parent b3d9a267ea
commit f1a3dc6719
1 changed files with 10 additions and 3 deletions

View File

@ -199,7 +199,13 @@ impl std::error::Error for ParseAmountError {
} }
fn is_too_precise(s: &str, precision: usize) -> bool { fn is_too_precise(s: &str, precision: usize) -> bool {
s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0') match s.find('.') {
Some(pos) =>
s[(pos + 1)..].chars().any(|d| d != '0')
|| precision >= pos
|| s[..pos].chars().rev().take(precision).any(|d| d != '0'),
None => precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0'),
}
} }
/// Parse decimal string in the given denomination into a satoshi value and a /// Parse decimal string in the given denomination into a satoshi value and a
@ -227,7 +233,7 @@ fn parse_signed_to_satoshi(
// The difference in precision between native (satoshi) // The difference in precision between native (satoshi)
// and desired denomination. // and desired denomination.
let precision_diff = -denom.precision(); let precision_diff = -denom.precision();
if precision_diff < 0 { if precision_diff <= 0 {
// If precision diff is negative, this means we are parsing // If precision diff is negative, this means we are parsing
// into a less precise amount. That is not allowed unless // into a less precise amount. That is not allowed unless
// there are no decimals and the last digits are zeroes as // there are no decimals and the last digits are zeroes as
@ -239,7 +245,7 @@ fn parse_signed_to_satoshi(
_ => return Err(ParseAmountError::TooPrecise), _ => return Err(ParseAmountError::TooPrecise),
} }
} }
s = &s[0..s.len() - last_n]; s = &s[0..s.find('.').unwrap_or(s.len()) - last_n];
0 0
} else { } else {
precision_diff precision_diff
@ -267,6 +273,7 @@ fn parse_signed_to_satoshi(
}; };
} }
'.' => match decimals { '.' => match decimals {
None if max_decimals <= 0 => break,
None => decimals = Some(0), None => decimals = Some(0),
// Double decimal dot. // Double decimal dot.
_ => return Err(ParseAmountError::InvalidFormat), _ => return Err(ParseAmountError::InvalidFormat),