Skip to main content

bitcoin_units/
amount.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Bitcoin amounts.
4//!
5//! This module mainly introduces the [Amount] and [SignedAmount] types.
6//! We refer to the documentation on the types for more information.
7
8#[cfg(feature = "alloc")]
9use alloc::string::{String, ToString};
10use core::cmp::Ordering;
11use core::convert::Infallible;
12#[cfg(feature = "alloc")]
13use core::fmt::Write as _;
14use core::str::FromStr;
15use core::{default, fmt, ops};
16
17#[cfg(feature = "serde")]
18use ::serde::{Deserialize, Serialize};
19#[cfg(feature = "arbitrary")]
20use arbitrary::{Arbitrary, Unstructured};
21
22use crate::input_string::InputString;
23use crate::internal_macros::write_err;
24#[cfg(feature = "alloc")]
25use crate::{FeeRate, Weight};
26
27/// A set of denominations in which amounts can be expressed.
28///
29/// # Examples
30/// ```
31/// # use core::str::FromStr;
32/// # use bitcoin_units::Amount;
33///
34/// assert_eq!(Amount::from_str("1 BTC").unwrap(), Amount::from_sat(100_000_000));
35/// assert_eq!(Amount::from_str("1 cBTC").unwrap(), Amount::from_sat(1_000_000));
36/// assert_eq!(Amount::from_str("1 mBTC").unwrap(), Amount::from_sat(100_000));
37/// assert_eq!(Amount::from_str("1 uBTC").unwrap(), Amount::from_sat(100));
38/// assert_eq!(Amount::from_str("10 nBTC").unwrap(), Amount::from_sat(1));
39/// assert_eq!(Amount::from_str("10000 pBTC").unwrap(), Amount::from_sat(1));
40/// assert_eq!(Amount::from_str("1 bit").unwrap(), Amount::from_sat(100));
41/// assert_eq!(Amount::from_str("1 sat").unwrap(), Amount::from_sat(1));
42/// assert_eq!(Amount::from_str("1000 msats").unwrap(), Amount::from_sat(1));
43/// ```
44#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
45#[non_exhaustive]
46pub enum Denomination {
47    /// BTC
48    Bitcoin,
49    /// cBTC
50    CentiBitcoin,
51    /// mBTC
52    MilliBitcoin,
53    /// uBTC
54    MicroBitcoin,
55    /// nBTC
56    NanoBitcoin,
57    /// pBTC
58    PicoBitcoin,
59    /// bits
60    Bit,
61    /// satoshi
62    Satoshi,
63    /// msat
64    MilliSatoshi,
65}
66
67impl Denomination {
68    /// Convenience alias for `Denomination::Bitcoin`.
69    pub const BTC: Self = Denomination::Bitcoin;
70
71    /// Convenience alias for `Denomination::Satoshi`.
72    pub const SAT: Self = Denomination::Satoshi;
73
74    /// The number of decimal places more than a satoshi.
75    fn precision(self) -> i8 {
76        match self {
77            Denomination::Bitcoin => -8,
78            Denomination::CentiBitcoin => -6,
79            Denomination::MilliBitcoin => -5,
80            Denomination::MicroBitcoin => -2,
81            Denomination::NanoBitcoin => 1,
82            Denomination::PicoBitcoin => 4,
83            Denomination::Bit => -2,
84            Denomination::Satoshi => 0,
85            Denomination::MilliSatoshi => 3,
86        }
87    }
88
89    /// Returns stringly representation of this
90    fn as_str(self) -> &'static str {
91        match self {
92            Denomination::Bitcoin => "BTC",
93            Denomination::CentiBitcoin => "cBTC",
94            Denomination::MilliBitcoin => "mBTC",
95            Denomination::MicroBitcoin => "uBTC",
96            Denomination::NanoBitcoin => "nBTC",
97            Denomination::PicoBitcoin => "pBTC",
98            Denomination::Bit => "bits",
99            Denomination::Satoshi => "satoshi",
100            Denomination::MilliSatoshi => "msat",
101        }
102    }
103
104    /// The different str forms of denominations that are recognized.
105    fn forms(s: &str) -> Option<Self> {
106        match s {
107            "BTC" | "btc" => Some(Denomination::Bitcoin),
108            "cBTC" | "cbtc" => Some(Denomination::CentiBitcoin),
109            "mBTC" | "mbtc" => Some(Denomination::MilliBitcoin),
110            "uBTC" | "ubtc" => Some(Denomination::MicroBitcoin),
111            "nBTC" | "nbtc" => Some(Denomination::NanoBitcoin),
112            "pBTC" | "pbtc" => Some(Denomination::PicoBitcoin),
113            "bit" | "bits" | "BIT" | "BITS" => Some(Denomination::Bit),
114            "SATOSHI" | "satoshi" | "SATOSHIS" | "satoshis" | "SAT" | "sat" | "SATS" | "sats" =>
115                Some(Denomination::Satoshi),
116            "mSAT" | "msat" | "mSATs" | "msats" => Some(Denomination::MilliSatoshi),
117            _ => None,
118        }
119    }
120}
121
122/// These form are ambigous and could have many meanings.  For example, M could denote Mega or Milli.
123/// If any of these forms are used, an error type PossiblyConfusingDenomination is returned.
124const CONFUSING_FORMS: [&str; 9] =
125    ["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"];
126
127impl fmt::Display for Denomination {
128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) }
129}
130
131impl FromStr for Denomination {
132    type Err = ParseDenominationError;
133
134    /// Convert from a str to Denomination.
135    ///
136    /// Any combination of upper and/or lower case, excluding uppercase of SI(m, u, n, p) is considered valid.
137    /// - Singular: BTC, mBTC, uBTC, nBTC, pBTC
138    /// - Plural or singular: sat, satoshi, bit, msat
139    ///
140    /// Due to ambiguity between mega and milli, pico and peta we prohibit usage of leading capital 'M', 'P'.
141    fn from_str(s: &str) -> Result<Self, Self::Err> {
142        use self::ParseDenominationError::*;
143
144        if CONFUSING_FORMS.contains(&s) {
145            return Err(PossiblyConfusing(PossiblyConfusingDenominationError(s.into())));
146        };
147
148        let form = self::Denomination::forms(s);
149
150        form.ok_or_else(|| Unknown(UnknownDenominationError(s.into())))
151    }
152}
153
154/// An error during amount parsing amount with denomination.
155#[derive(Debug, Clone, PartialEq, Eq)]
156#[non_exhaustive]
157pub enum ParseError {
158    /// Invalid amount.
159    Amount(ParseAmountError),
160
161    /// Invalid denomination.
162    Denomination(ParseDenominationError),
163
164    /// The denomination was not identified.
165    MissingDenomination(MissingDenominationError),
166}
167
168impl From<Infallible> for ParseError {
169    fn from(never: Infallible) -> Self { match never {} }
170}
171
172impl From<ParseAmountError> for ParseError {
173    fn from(e: ParseAmountError) -> Self { Self::Amount(e) }
174}
175
176impl From<ParseDenominationError> for ParseError {
177    fn from(e: ParseDenominationError) -> Self { Self::Denomination(e) }
178}
179
180impl From<OutOfRangeError> for ParseError {
181    fn from(e: OutOfRangeError) -> Self { Self::Amount(e.into()) }
182}
183
184impl From<TooPreciseError> for ParseError {
185    fn from(e: TooPreciseError) -> Self { Self::Amount(e.into()) }
186}
187
188impl From<MissingDigitsError> for ParseError {
189    fn from(e: MissingDigitsError) -> Self { Self::Amount(e.into()) }
190}
191
192impl From<InputTooLargeError> for ParseError {
193    fn from(e: InputTooLargeError) -> Self { Self::Amount(e.into()) }
194}
195
196impl From<InvalidCharacterError> for ParseError {
197    fn from(e: InvalidCharacterError) -> Self { Self::Amount(e.into()) }
198}
199
200impl fmt::Display for ParseError {
201    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
202        match self {
203            ParseError::Amount(error) => write_err!(f, "invalid amount"; error),
204            ParseError::Denomination(error) => write_err!(f, "invalid denomination"; error),
205            // We consider this to not be a source because it currently doesn't contain useful
206            // information
207            ParseError::MissingDenomination(_) =>
208                f.write_str("the input doesn't contain a denomination"),
209        }
210    }
211}
212
213#[cfg(feature = "std")]
214impl std::error::Error for ParseError {
215    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
216        match self {
217            ParseError::Amount(error) => Some(error),
218            ParseError::Denomination(error) => Some(error),
219            // We consider this to not be a source because it currently doesn't contain useful
220            // information
221            ParseError::MissingDenomination(_) => None,
222        }
223    }
224}
225
226/// An error during amount parsing.
227#[derive(Debug, Clone, PartialEq, Eq)]
228#[non_exhaustive]
229pub enum ParseAmountError {
230    /// The amount is too big or too small.
231    OutOfRange(OutOfRangeError),
232    /// Amount has higher precision than supported by the type.
233    TooPrecise(TooPreciseError),
234    /// A digit was expected but not found.
235    MissingDigits(MissingDigitsError),
236    /// Input string was too large.
237    InputTooLarge(InputTooLargeError),
238    /// Invalid character in input.
239    InvalidCharacter(InvalidCharacterError),
240}
241
242impl From<TooPreciseError> for ParseAmountError {
243    fn from(value: TooPreciseError) -> Self { Self::TooPrecise(value) }
244}
245
246impl From<MissingDigitsError> for ParseAmountError {
247    fn from(value: MissingDigitsError) -> Self { Self::MissingDigits(value) }
248}
249
250impl From<InputTooLargeError> for ParseAmountError {
251    fn from(value: InputTooLargeError) -> Self { Self::InputTooLarge(value) }
252}
253
254impl From<InvalidCharacterError> for ParseAmountError {
255    fn from(value: InvalidCharacterError) -> Self { Self::InvalidCharacter(value) }
256}
257
258impl From<Infallible> for ParseAmountError {
259    fn from(never: Infallible) -> Self { match never {} }
260}
261
262impl fmt::Display for ParseAmountError {
263    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264        use ParseAmountError::*;
265
266        match *self {
267            OutOfRange(ref error) => write_err!(f, "amount out of range"; error),
268            TooPrecise(ref error) => write_err!(f, "amount has a too high precision"; error),
269            MissingDigits(ref error) => write_err!(f, "the input has too few digits"; error),
270            InputTooLarge(ref error) => write_err!(f, "the input is too large"; error),
271            InvalidCharacter(ref error) => write_err!(f, "invalid character in the input"; error),
272        }
273    }
274}
275
276#[cfg(feature = "std")]
277impl std::error::Error for ParseAmountError {
278    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
279        use ParseAmountError::*;
280
281        match *self {
282            TooPrecise(ref error) => Some(error),
283            InputTooLarge(ref error) => Some(error),
284            OutOfRange(ref error) => Some(error),
285            MissingDigits(ref error) => Some(error),
286            InvalidCharacter(ref error) => Some(error),
287        }
288    }
289}
290
291/// Returned when a parsed amount is too big or too small.
292#[derive(Debug, Copy, Clone, Eq, PartialEq)]
293pub struct OutOfRangeError {
294    is_signed: bool,
295    is_greater_than_max: bool,
296}
297
298impl OutOfRangeError {
299    /// Returns the minimum and maximum allowed values for the type that was parsed.
300    ///
301    /// This can be used to give a hint to the user which values are allowed.
302    pub fn valid_range(&self) -> (i64, u64) {
303        match self.is_signed {
304            true => (i64::MIN, i64::MAX as u64),
305            false => (0, u64::MAX),
306        }
307    }
308
309    /// Returns true if the input value was large than the maximum allowed value.
310    pub fn is_above_max(&self) -> bool { self.is_greater_than_max }
311
312    /// Returns true if the input value was smaller than the minimum allowed value.
313    pub fn is_below_min(&self) -> bool { !self.is_greater_than_max }
314
315    pub(crate) fn too_big(is_signed: bool) -> Self { Self { is_signed, is_greater_than_max: true } }
316
317    pub(crate) fn too_small() -> Self {
318        Self {
319            // implied - negative() is used for the other
320            is_signed: true,
321            is_greater_than_max: false,
322        }
323    }
324
325    pub(crate) fn negative() -> Self {
326        Self {
327            // implied - too_small() is used for the other
328            is_signed: false,
329            is_greater_than_max: false,
330        }
331    }
332}
333
334impl fmt::Display for OutOfRangeError {
335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336        if self.is_greater_than_max {
337            write!(f, "the amount is greater than {}", self.valid_range().1)
338        } else {
339            write!(f, "the amount is less than {}", self.valid_range().0)
340        }
341    }
342}
343
344#[cfg(feature = "std")]
345impl std::error::Error for OutOfRangeError {}
346
347impl From<OutOfRangeError> for ParseAmountError {
348    fn from(value: OutOfRangeError) -> Self { ParseAmountError::OutOfRange(value) }
349}
350
351/// Error returned when the input string has higher precision than satoshis.
352#[derive(Debug, Clone, Eq, PartialEq)]
353pub struct TooPreciseError {
354    position: usize,
355}
356
357impl fmt::Display for TooPreciseError {
358    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359        match self.position {
360            0 => f.write_str("the amount is less than 1 satoshi but it's not zero"),
361            pos => write!(
362                f,
363                "the digits starting from position {} represent a sub-satoshi amount",
364                pos
365            ),
366        }
367    }
368}
369
370#[cfg(feature = "std")]
371impl std::error::Error for TooPreciseError {}
372
373/// Error returned when the input string is too large.
374#[derive(Debug, Clone, Eq, PartialEq)]
375pub struct InputTooLargeError {
376    len: usize,
377}
378
379impl fmt::Display for InputTooLargeError {
380    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
381        match self.len - INPUT_STRING_LEN_LIMIT {
382            1 => write!(
383                f,
384                "the input is one character longer than the maximum allowed length ({})",
385                INPUT_STRING_LEN_LIMIT
386            ),
387            n => write!(
388                f,
389                "the input is {} characters longer than the maximum allowed length ({})",
390                n, INPUT_STRING_LEN_LIMIT
391            ),
392        }
393    }
394}
395
396#[cfg(feature = "std")]
397impl std::error::Error for InputTooLargeError {}
398
399/// Error returned when digits were expected in the input but there were none.
400///
401/// In particular, this is currently returned when the string is empty or only contains the minus sign.
402#[derive(Debug, Clone, Eq, PartialEq)]
403pub struct MissingDigitsError {
404    kind: MissingDigitsKind,
405}
406
407impl fmt::Display for MissingDigitsError {
408    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
409        match self.kind {
410            MissingDigitsKind::Empty => f.write_str("the input is empty"),
411            MissingDigitsKind::OnlyMinusSign =>
412                f.write_str("there are no digits following the minus (-) sign"),
413        }
414    }
415}
416
417#[cfg(feature = "std")]
418impl std::error::Error for MissingDigitsError {}
419
420#[derive(Debug, Clone, Eq, PartialEq)]
421enum MissingDigitsKind {
422    Empty,
423    OnlyMinusSign,
424}
425
426/// Returned when the input contains an invalid character.
427#[derive(Debug, Clone, PartialEq, Eq)]
428pub struct InvalidCharacterError {
429    invalid_char: char,
430    position: usize,
431}
432
433impl fmt::Display for InvalidCharacterError {
434    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
435        match self.invalid_char {
436            '.' => f.write_str("there is more than one decimal separator (dot) in the input"),
437            '-' => f.write_str("there is more than one minus sign (-) in the input"),
438            c => write!(
439                f,
440                "the character '{}' at position {} is not a valid digit",
441                c, self.position
442            ),
443        }
444    }
445}
446
447#[cfg(feature = "std")]
448impl std::error::Error for InvalidCharacterError {}
449
450/// An error during amount parsing.
451#[derive(Debug, Clone, PartialEq, Eq)]
452#[non_exhaustive]
453pub enum ParseDenominationError {
454    /// The denomination was unknown.
455    Unknown(UnknownDenominationError),
456    /// The denomination has multiple possible interpretations.
457    PossiblyConfusing(PossiblyConfusingDenominationError),
458}
459
460impl From<Infallible> for ParseDenominationError {
461    fn from(never: Infallible) -> Self { match never {} }
462}
463
464impl fmt::Display for ParseDenominationError {
465    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
466        use ParseDenominationError::*;
467
468        match *self {
469            Unknown(ref e) => write_err!(f, "denomination parse error"; e),
470            PossiblyConfusing(ref e) => write_err!(f, "denomination parse error"; e),
471        }
472    }
473}
474
475#[cfg(feature = "std")]
476impl std::error::Error for ParseDenominationError {
477    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
478        use ParseDenominationError::*;
479
480        match *self {
481            Unknown(_) | PossiblyConfusing(_) => None,
482        }
483    }
484}
485
486/// Error returned when the denomination is empty.
487#[derive(Debug, Clone, PartialEq, Eq)]
488#[non_exhaustive]
489pub struct MissingDenominationError;
490
491/// Parsing error, unknown denomination.
492#[derive(Debug, Clone, PartialEq, Eq)]
493#[non_exhaustive]
494pub struct UnknownDenominationError(InputString);
495
496impl fmt::Display for UnknownDenominationError {
497    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
498        self.0.unknown_variant("bitcoin denomination", f)
499    }
500}
501
502#[cfg(feature = "std")]
503impl std::error::Error for UnknownDenominationError {
504    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
505}
506
507/// Parsing error, possibly confusing denomination.
508#[derive(Debug, Clone, PartialEq, Eq)]
509#[non_exhaustive]
510pub struct PossiblyConfusingDenominationError(InputString);
511
512impl fmt::Display for PossiblyConfusingDenominationError {
513    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
514        write!(f, "{}: possibly confusing denomination - we intentionally do not support 'M' and 'P' so as to not confuse mega/milli and peta/pico", self.0.display_cannot_parse("bitcoin denomination"))
515    }
516}
517
518#[cfg(feature = "std")]
519impl std::error::Error for PossiblyConfusingDenominationError {
520    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
521}
522
523/// Returns `Some(position)` if the precision is not supported.
524///
525/// The position indicates the first digit that is too precise.
526fn is_too_precise(s: &str, precision: usize) -> Option<usize> {
527    match s.find('.') {
528        Some(pos) if precision >= pos => Some(0),
529        Some(pos) => s[..pos]
530            .char_indices()
531            .rev()
532            .take(precision)
533            .find(|(_, d)| *d != '0')
534            .map(|(i, _)| i)
535            .or_else(|| {
536                s[(pos + 1)..].char_indices().find(|(_, d)| *d != '0').map(|(i, _)| i + pos + 1)
537            }),
538        None if precision >= s.len() => Some(0),
539        None => s.char_indices().rev().take(precision).find(|(_, d)| *d != '0').map(|(i, _)| i),
540    }
541}
542
543const INPUT_STRING_LEN_LIMIT: usize = 50;
544
545/// Parse decimal string in the given denomination into a satoshi value and a
546/// bool indicator for a negative amount.
547fn parse_signed_to_satoshi(
548    mut s: &str,
549    denom: Denomination,
550) -> Result<(bool, u64), InnerParseError> {
551    if s.is_empty() {
552        return Err(InnerParseError::MissingDigits(MissingDigitsError {
553            kind: MissingDigitsKind::Empty,
554        }));
555    }
556    if s.len() > INPUT_STRING_LEN_LIMIT {
557        return Err(InnerParseError::InputTooLarge(s.len()));
558    }
559
560    let is_negative = s.starts_with('-');
561    if is_negative {
562        if s.len() == 1 {
563            return Err(InnerParseError::MissingDigits(MissingDigitsError {
564                kind: MissingDigitsKind::OnlyMinusSign,
565            }));
566        }
567        s = &s[1..];
568    }
569
570    let max_decimals = {
571        // The difference in precision between native (satoshi)
572        // and desired denomination.
573        let precision_diff = -denom.precision();
574        if precision_diff <= 0 {
575            // If precision diff is negative, this means we are parsing
576            // into a less precise amount. That is not allowed unless
577            // there are no decimals and the last digits are zeroes as
578            // many as the difference in precision.
579            let last_n = precision_diff.unsigned_abs().into();
580            if let Some(position) = is_too_precise(s, last_n) {
581                match s.parse::<i64>() {
582                    Ok(0) => return Ok((is_negative, 0)),
583                    _ =>
584                        return Err(InnerParseError::TooPrecise(TooPreciseError {
585                            position: position + is_negative as usize,
586                        })),
587                }
588            }
589            s = &s[0..s.find('.').unwrap_or(s.len()) - last_n];
590            0
591        } else {
592            precision_diff
593        }
594    };
595
596    let mut decimals = None;
597    let mut value: u64 = 0; // as satoshis
598    for (i, c) in s.char_indices() {
599        match c {
600            '0'..='9' => {
601                // Do `value = 10 * value + digit`, catching overflows.
602                match 10_u64.checked_mul(value) {
603                    None => return Err(InnerParseError::Overflow { is_negative }),
604                    Some(val) => match val.checked_add((c as u8 - b'0') as u64) {
605                        None => return Err(InnerParseError::Overflow { is_negative }),
606                        Some(val) => value = val,
607                    },
608                }
609                // Increment the decimal digit counter if past decimal.
610                decimals = match decimals {
611                    None => None,
612                    Some(d) if d < max_decimals => Some(d + 1),
613                    _ =>
614                        return Err(InnerParseError::TooPrecise(TooPreciseError {
615                            position: i + is_negative as usize,
616                        })),
617                };
618            }
619            '.' => match decimals {
620                None if max_decimals <= 0 => break,
621                None => decimals = Some(0),
622                // Double decimal dot.
623                _ =>
624                    return Err(InnerParseError::InvalidCharacter(InvalidCharacterError {
625                        invalid_char: '.',
626                        position: i + is_negative as usize,
627                    })),
628            },
629            c =>
630                return Err(InnerParseError::InvalidCharacter(InvalidCharacterError {
631                    invalid_char: c,
632                    position: i + is_negative as usize,
633                })),
634        }
635    }
636
637    // Decimally shift left by `max_decimals - decimals`.
638    let scale_factor = max_decimals - decimals.unwrap_or(0);
639    for _ in 0..scale_factor {
640        value = match 10_u64.checked_mul(value) {
641            Some(v) => v,
642            None => return Err(InnerParseError::Overflow { is_negative }),
643        };
644    }
645
646    Ok((is_negative, value))
647}
648
649enum InnerParseError {
650    Overflow { is_negative: bool },
651    TooPrecise(TooPreciseError),
652    MissingDigits(MissingDigitsError),
653    InputTooLarge(usize),
654    InvalidCharacter(InvalidCharacterError),
655}
656
657impl From<Infallible> for InnerParseError {
658    fn from(never: Infallible) -> Self { match never {} }
659}
660
661impl InnerParseError {
662    fn convert(self, is_signed: bool) -> ParseAmountError {
663        match self {
664            Self::Overflow { is_negative } =>
665                OutOfRangeError { is_signed, is_greater_than_max: !is_negative }.into(),
666            Self::TooPrecise(error) => ParseAmountError::TooPrecise(error),
667            Self::MissingDigits(error) => ParseAmountError::MissingDigits(error),
668            Self::InputTooLarge(len) => ParseAmountError::InputTooLarge(InputTooLargeError { len }),
669            Self::InvalidCharacter(error) => ParseAmountError::InvalidCharacter(error),
670        }
671    }
672}
673
674fn split_amount_and_denomination(s: &str) -> Result<(&str, Denomination), ParseError> {
675    let (i, j) = if let Some(i) = s.find(' ') {
676        (i, i + 1)
677    } else {
678        let i = s
679            .find(|c: char| c.is_alphabetic())
680            .ok_or(ParseError::MissingDenomination(MissingDenominationError))?;
681        (i, i)
682    };
683    Ok((&s[..i], s[j..].parse()?))
684}
685
686/// Options given by `fmt::Formatter`
687struct FormatOptions {
688    fill: char,
689    align: Option<fmt::Alignment>,
690    width: Option<usize>,
691    precision: Option<usize>,
692    sign_plus: bool,
693    sign_aware_zero_pad: bool,
694}
695
696impl FormatOptions {
697    fn from_formatter(f: &fmt::Formatter) -> Self {
698        FormatOptions {
699            fill: f.fill(),
700            align: f.align(),
701            width: f.width(),
702            precision: f.precision(),
703            sign_plus: f.sign_plus(),
704            sign_aware_zero_pad: f.sign_aware_zero_pad(),
705        }
706    }
707}
708
709impl Default for FormatOptions {
710    fn default() -> Self {
711        FormatOptions {
712            fill: ' ',
713            align: None,
714            width: None,
715            precision: None,
716            sign_plus: false,
717            sign_aware_zero_pad: false,
718        }
719    }
720}
721
722fn dec_width(mut num: u64) -> usize {
723    let mut width = 1;
724    loop {
725        num /= 10;
726        if num == 0 {
727            break;
728        }
729        width += 1;
730    }
731    width
732}
733
734fn repeat_char(f: &mut dyn fmt::Write, c: char, count: usize) -> fmt::Result {
735    for _ in 0..count {
736        f.write_char(c)?;
737    }
738    Ok(())
739}
740
741/// Format the given satoshi amount in the given denomination.
742fn fmt_satoshi_in(
743    satoshi: u64,
744    negative: bool,
745    f: &mut dyn fmt::Write,
746    denom: Denomination,
747    show_denom: bool,
748    options: FormatOptions,
749) -> fmt::Result {
750    let precision = denom.precision();
751    // First we normalize the number:
752    // {num_before_decimal_point}{:0exp}{"." if nb_decimals > 0}{:0nb_decimals}{num_after_decimal_point}{:0trailing_decimal_zeros}
753    let mut num_after_decimal_point = 0;
754    let mut norm_nb_decimals = 0;
755    let mut num_before_decimal_point = satoshi;
756    let trailing_decimal_zeros;
757    let mut exp = 0;
758    match precision.cmp(&0) {
759        // We add the number of zeroes to the end
760        Ordering::Greater => {
761            if satoshi > 0 {
762                exp = precision as usize;
763            }
764            trailing_decimal_zeros = options.precision.unwrap_or(0);
765        }
766        Ordering::Less => {
767            let precision = precision.unsigned_abs();
768            let divisor = 10u64.pow(precision.into());
769            num_before_decimal_point = satoshi / divisor;
770            num_after_decimal_point = satoshi % divisor;
771            // normalize by stripping trailing zeros
772            if num_after_decimal_point == 0 {
773                norm_nb_decimals = 0;
774            } else {
775                norm_nb_decimals = usize::from(precision);
776                while num_after_decimal_point % 10 == 0 {
777                    norm_nb_decimals -= 1;
778                    num_after_decimal_point /= 10
779                }
780            }
781            // compute requested precision
782            let opt_precision = options.precision.unwrap_or(0);
783            trailing_decimal_zeros = opt_precision.saturating_sub(norm_nb_decimals);
784        }
785        Ordering::Equal => trailing_decimal_zeros = options.precision.unwrap_or(0),
786    }
787    let total_decimals = norm_nb_decimals + trailing_decimal_zeros;
788    // Compute expected width of the number
789    let mut num_width = if total_decimals > 0 {
790        // 1 for decimal point
791        1 + total_decimals
792    } else {
793        0
794    };
795    num_width += dec_width(num_before_decimal_point) + exp;
796    if options.sign_plus || negative {
797        num_width += 1;
798    }
799
800    if show_denom {
801        // + 1 for space
802        num_width += denom.as_str().len() + 1;
803    }
804
805    let width = options.width.unwrap_or(0);
806    let align = options.align.unwrap_or(fmt::Alignment::Right);
807    let (left_pad, pad_right) = match (num_width < width, options.sign_aware_zero_pad, align) {
808        (false, _, _) => (0, 0),
809        // Alignment is always right (ignored) when zero-padding
810        (true, true, _) | (true, false, fmt::Alignment::Right) => (width - num_width, 0),
811        (true, false, fmt::Alignment::Left) => (0, width - num_width),
812        // If the required padding is odd it needs to be skewed to the left
813        (true, false, fmt::Alignment::Center) =>
814            ((width - num_width) / 2, (width - num_width + 1) / 2),
815    };
816
817    if !options.sign_aware_zero_pad {
818        repeat_char(f, options.fill, left_pad)?;
819    }
820
821    if negative {
822        write!(f, "-")?;
823    } else if options.sign_plus {
824        write!(f, "+")?;
825    }
826
827    if options.sign_aware_zero_pad {
828        repeat_char(f, '0', left_pad)?;
829    }
830
831    write!(f, "{}", num_before_decimal_point)?;
832
833    repeat_char(f, '0', exp)?;
834
835    if total_decimals > 0 {
836        write!(f, ".")?;
837    }
838    if norm_nb_decimals > 0 {
839        write!(f, "{:0width$}", num_after_decimal_point, width = norm_nb_decimals)?;
840    }
841    repeat_char(f, '0', trailing_decimal_zeros)?;
842
843    if show_denom {
844        write!(f, " {}", denom.as_str())?;
845    }
846
847    repeat_char(f, options.fill, pad_right)?;
848    Ok(())
849}
850
851/// Amount
852///
853/// The [Amount] type can be used to express Bitcoin amounts that support
854/// arithmetic and conversion to various denominations.
855///
856///
857/// Warning!
858///
859/// This type implements several arithmetic operations from [core::ops].
860/// To prevent errors due to overflow or underflow when using these operations,
861/// it is advised to instead use the checked arithmetic methods whose names
862/// start with `checked_`.  The operations from [core::ops] that [Amount]
863/// implements will panic when overflow or underflow occurs.  Also note that
864/// since the internal representation of amounts is unsigned, subtracting below
865/// zero is considered an underflow and will cause a panic if you're not using
866/// the checked arithmetic methods.
867///
868#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
869#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
870pub struct Amount(u64);
871
872impl Amount {
873    /// The zero amount.
874    pub const ZERO: Amount = Amount(0);
875    /// Exactly one satoshi.
876    pub const ONE_SAT: Amount = Amount(1);
877    /// Exactly one bitcoin.
878    pub const ONE_BTC: Amount = Self::from_int_btc(1);
879    /// The maximum value allowed as an amount. Useful for sanity checking.
880    pub const MAX_MONEY: Amount = Self::from_int_btc(21_000_000);
881    /// The minimum value of an amount.
882    pub const MIN: Amount = Amount::ZERO;
883    /// The maximum value of an amount.
884    pub const MAX: Amount = Amount(u64::MAX);
885    /// The number of bytes that an amount contributes to the size of a transaction.
886    pub const SIZE: usize = 8; // Serialized length of a u64.
887
888    /// Create an [Amount] with satoshi precision and the given number of satoshis.
889    pub const fn from_sat(satoshi: u64) -> Amount { Amount(satoshi) }
890
891    /// Gets the number of satoshis in this [`Amount`].
892    pub fn to_sat(self) -> u64 { self.0 }
893
894    /// Convert from a value expressing bitcoins to an [Amount].
895    #[cfg(feature = "alloc")]
896    pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> {
897        Amount::from_float_in(btc, Denomination::Bitcoin)
898    }
899
900    /// Convert from a value expressing integer values of bitcoins to an [Amount]
901    /// in const context.
902    ///
903    /// ## Panics
904    ///
905    /// The function panics if the argument multiplied by the number of sats
906    /// per bitcoin overflows a u64 type.
907    pub const fn from_int_btc(btc: u64) -> Amount {
908        match btc.checked_mul(100_000_000) {
909            Some(amount) => Amount::from_sat(amount),
910            None => {
911                // When MSRV is 1.57+ we can use `panic!()`.
912                #[allow(unconditional_panic)]
913                #[allow(clippy::let_unit_value)]
914                #[allow(clippy::out_of_bounds_indexing)]
915                let _int_overflow_converting_btc_to_sats = [(); 0][1];
916                Amount(0)
917            }
918        }
919    }
920
921    /// Parse a decimal string as a value in the given denomination.
922    ///
923    /// Note: This only parses the value string.  If you want to parse a value
924    /// with denomination, use [FromStr].
925    pub fn from_str_in(s: &str, denom: Denomination) -> Result<Amount, ParseAmountError> {
926        let (negative, satoshi) =
927            parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(false))?;
928        if negative {
929            return Err(ParseAmountError::OutOfRange(OutOfRangeError::negative()));
930        }
931        Ok(Amount::from_sat(satoshi))
932    }
933
934    /// Parses amounts with denomination suffix like they are produced with
935    /// [Self::to_string_with_denomination] or with [fmt::Display].
936    /// If you want to parse only the amount without the denomination,
937    /// use [Self::from_str_in].
938    pub fn from_str_with_denomination(s: &str) -> Result<Amount, ParseError> {
939        let (amt, denom) = split_amount_and_denomination(s)?;
940        Amount::from_str_in(amt, denom).map_err(Into::into)
941    }
942
943    /// Express this [Amount] as a floating-point value in the given denomination.
944    ///
945    /// Please be aware of the risk of using floating-point numbers.
946    #[cfg(feature = "alloc")]
947    pub fn to_float_in(self, denom: Denomination) -> f64 {
948        f64::from_str(&self.to_string_in(denom)).unwrap()
949    }
950
951    /// Express this [`Amount`] as a floating-point value in Bitcoin.
952    ///
953    /// Please be aware of the risk of using floating-point numbers.
954    ///
955    /// # Examples
956    /// ```
957    /// # use bitcoin_units::amount::{Amount, Denomination};
958    /// let amount = Amount::from_sat(100_000);
959    /// assert_eq!(amount.to_btc(), amount.to_float_in(Denomination::Bitcoin))
960    /// ```
961    #[cfg(feature = "alloc")]
962    pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
963
964    /// Convert this [Amount] in floating-point notation with a given
965    /// denomination.
966    /// Can return error if the amount is too big, too precise or negative.
967    ///
968    /// Please be aware of the risk of using floating-point numbers.
969    #[cfg(feature = "alloc")]
970    pub fn from_float_in(value: f64, denom: Denomination) -> Result<Amount, ParseAmountError> {
971        if value < 0.0 {
972            return Err(OutOfRangeError::negative().into());
973        }
974        // This is inefficient, but the safest way to deal with this. The parsing logic is safe.
975        // Any performance-critical application should not be dealing with floats.
976        Amount::from_str_in(&value.to_string(), denom)
977    }
978
979    /// Create an object that implements [`fmt::Display`] using specified denomination.
980    pub fn display_in(self, denomination: Denomination) -> Display {
981        Display {
982            sats_abs: self.to_sat(),
983            is_negative: false,
984            style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
985        }
986    }
987
988    /// Create an object that implements [`fmt::Display`] dynamically selecting denomination.
989    ///
990    /// This will use BTC for values greater than or equal to 1 BTC and satoshis otherwise. To
991    /// avoid confusion the denomination is always shown.
992    pub fn display_dynamic(self) -> Display {
993        Display {
994            sats_abs: self.to_sat(),
995            is_negative: false,
996            style: DisplayStyle::DynamicDenomination,
997        }
998    }
999
1000    /// Format the value of this [Amount] in the given denomination.
1001    ///
1002    /// Does not include the denomination.
1003    #[rustfmt::skip]
1004    pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
1005        fmt_satoshi_in(self.to_sat(), false, f, denom, false, FormatOptions::default())
1006    }
1007
1008    /// Get a string number of this [Amount] in the given denomination.
1009    ///
1010    /// Does not include the denomination.
1011    #[cfg(feature = "alloc")]
1012    pub fn to_string_in(self, denom: Denomination) -> String {
1013        let mut buf = String::new();
1014        self.fmt_value_in(&mut buf, denom).unwrap();
1015        buf
1016    }
1017
1018    /// Get a formatted string of this [Amount] in the given denomination,
1019    /// suffixed with the abbreviation for the denomination.
1020    #[cfg(feature = "alloc")]
1021    pub fn to_string_with_denomination(self, denom: Denomination) -> String {
1022        let mut buf = String::new();
1023        self.fmt_value_in(&mut buf, denom).unwrap();
1024        write!(buf, " {}", denom).unwrap();
1025        buf
1026    }
1027
1028    // Some arithmetic that doesn't fit in `core::ops` traits.
1029
1030    /// Checked addition.
1031    ///
1032    /// Returns [None] if overflow occurred.
1033    pub fn checked_add(self, rhs: Amount) -> Option<Amount> {
1034        self.0.checked_add(rhs.0).map(Amount)
1035    }
1036
1037    /// Checked subtraction.
1038    ///
1039    /// Returns [None] if overflow occurred.
1040    pub fn checked_sub(self, rhs: Amount) -> Option<Amount> {
1041        self.0.checked_sub(rhs.0).map(Amount)
1042    }
1043
1044    /// Checked multiplication.
1045    ///
1046    /// Returns [None] if overflow occurred.
1047    pub fn checked_mul(self, rhs: u64) -> Option<Amount> { self.0.checked_mul(rhs).map(Amount) }
1048
1049    /// Checked integer division.
1050    ///
1051    /// Be aware that integer division loses the remainder if no exact division
1052    /// can be made.
1053    /// Returns [None] if overflow occurred.
1054    pub fn checked_div(self, rhs: u64) -> Option<Amount> { self.0.checked_div(rhs).map(Amount) }
1055
1056    /// Checked weight ceiling division.
1057    ///
1058    /// Be aware that integer division loses the remainder if no exact division
1059    /// can be made.  This method rounds up ensuring the transaction fee-rate is
1060    /// sufficient.  See also [`Amount::div_by_weight_floor`].
1061    ///
1062    /// [`None`] is returned if an overflow occurred.
1063    #[cfg(feature = "alloc")]
1064    pub fn div_by_weight_ceil(self, rhs: Weight) -> Option<FeeRate> {
1065        let sats = self.0.checked_mul(1000)?;
1066        let wu = rhs.to_wu();
1067
1068        let fee_rate = sats.checked_add(wu.checked_sub(1)?)?.checked_div(wu)?;
1069        Some(FeeRate::from_sat_per_kwu(fee_rate))
1070    }
1071
1072    /// Checked weight floor division.
1073    ///
1074    /// Be aware that integer division loses the remainder if no exact division
1075    /// can be made.  See also [`Amount::div_by_weight_ceil`].
1076    ///
1077    /// Returns [`None`] if overflow occurred.
1078    #[cfg(feature = "alloc")]
1079    pub fn div_by_weight_floor(self, rhs: Weight) -> Option<FeeRate> {
1080        let fee_rate = self.0.checked_mul(1_000)?.checked_div(rhs.to_wu())?;
1081        Some(FeeRate::from_sat_per_kwu(fee_rate))
1082    }
1083
1084    /// Checked remainder.
1085    ///
1086    /// Returns [None] if overflow occurred.
1087    pub fn checked_rem(self, rhs: u64) -> Option<Amount> { self.0.checked_rem(rhs).map(Amount) }
1088
1089    /// Unchecked addition.
1090    ///
1091    /// Computes `self + rhs`.  Panics in debug mode, wraps in release mode.
1092    pub fn unchecked_add(self, rhs: Amount) -> Amount { Self(self.0 + rhs.0) }
1093
1094    /// Unchecked subtraction.
1095    ///
1096    /// Computes `self - rhs`.  Panics in debug mode, wraps in release mode.
1097    pub fn unchecked_sub(self, rhs: Amount) -> Amount { Self(self.0 - rhs.0) }
1098
1099    /// Convert to a signed amount.
1100    pub fn to_signed(self) -> Result<SignedAmount, OutOfRangeError> {
1101        if self.to_sat() > SignedAmount::MAX.to_sat() as u64 {
1102            Err(OutOfRangeError::too_big(true))
1103        } else {
1104            Ok(SignedAmount::from_sat(self.to_sat() as i64))
1105        }
1106    }
1107}
1108
1109impl default::Default for Amount {
1110    fn default() -> Self { Amount::ZERO }
1111}
1112
1113impl fmt::Debug for Amount {
1114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} SAT", self.to_sat()) }
1115}
1116
1117// No one should depend on a binding contract for Display for this type.
1118// Just using Bitcoin denominated string.
1119impl fmt::Display for Amount {
1120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1121        let satoshis = self.to_sat();
1122        let denomination = Denomination::Bitcoin;
1123        let mut format_options = FormatOptions::from_formatter(f);
1124
1125        if f.precision().is_none() && satoshis.rem_euclid(Amount::ONE_BTC.to_sat()) != 0 {
1126            format_options.precision = Some(8);
1127        }
1128
1129        fmt_satoshi_in(satoshis, false, f, denomination, true, format_options)
1130    }
1131}
1132
1133impl ops::Add for Amount {
1134    type Output = Amount;
1135
1136    fn add(self, rhs: Amount) -> Self::Output {
1137        self.checked_add(rhs).expect("Amount addition error")
1138    }
1139}
1140
1141impl ops::AddAssign for Amount {
1142    fn add_assign(&mut self, other: Amount) { *self = *self + other }
1143}
1144
1145impl ops::Sub for Amount {
1146    type Output = Amount;
1147
1148    fn sub(self, rhs: Amount) -> Self::Output {
1149        self.checked_sub(rhs).expect("Amount subtraction error")
1150    }
1151}
1152
1153impl ops::SubAssign for Amount {
1154    fn sub_assign(&mut self, other: Amount) { *self = *self - other }
1155}
1156
1157impl ops::Rem<u64> for Amount {
1158    type Output = Amount;
1159
1160    fn rem(self, modulus: u64) -> Self {
1161        self.checked_rem(modulus).expect("Amount remainder error")
1162    }
1163}
1164
1165impl ops::RemAssign<u64> for Amount {
1166    fn rem_assign(&mut self, modulus: u64) { *self = *self % modulus }
1167}
1168
1169impl ops::Mul<u64> for Amount {
1170    type Output = Amount;
1171
1172    fn mul(self, rhs: u64) -> Self::Output {
1173        self.checked_mul(rhs).expect("Amount multiplication error")
1174    }
1175}
1176
1177impl ops::MulAssign<u64> for Amount {
1178    fn mul_assign(&mut self, rhs: u64) { *self = *self * rhs }
1179}
1180
1181impl ops::Div<u64> for Amount {
1182    type Output = Amount;
1183
1184    fn div(self, rhs: u64) -> Self::Output { self.checked_div(rhs).expect("Amount division error") }
1185}
1186
1187impl ops::DivAssign<u64> for Amount {
1188    fn div_assign(&mut self, rhs: u64) { *self = *self / rhs }
1189}
1190
1191impl FromStr for Amount {
1192    type Err = ParseError;
1193
1194    fn from_str(s: &str) -> Result<Self, Self::Err> { Amount::from_str_with_denomination(s) }
1195}
1196
1197impl TryFrom<SignedAmount> for Amount {
1198    type Error = OutOfRangeError;
1199
1200    fn try_from(value: SignedAmount) -> Result<Self, Self::Error> { value.to_unsigned() }
1201}
1202
1203impl core::iter::Sum for Amount {
1204    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1205        let sats: u64 = iter.map(|amt| amt.0).sum();
1206        Amount::from_sat(sats)
1207    }
1208}
1209
1210#[cfg(feature = "encoding")]
1211impl encoding::Encode for Amount {
1212    type Encoder<'e> = AmountEncoder<'e>;
1213
1214    #[inline]
1215    fn encoder(&self) -> Self::Encoder<'_> {
1216        AmountEncoder::new(encoding::ArrayEncoder::without_length_prefix(
1217            self.to_sat().to_le_bytes(),
1218        ))
1219    }
1220}
1221
1222#[cfg(feature = "encoding")]
1223impl encoding::Decode for Amount {
1224    type Decoder = AmountDecoder;
1225}
1226
1227#[cfg(feature = "encoding")]
1228encoding::encoder_newtype_exact! {
1229    /// The encoder for the [`Amount`] type.
1230    #[derive(Debug, Clone)]
1231    pub struct AmountEncoder<'e>(encoding::ArrayEncoder<8>);
1232}
1233
1234#[cfg(feature = "encoding")]
1235crate::decoder_newtype! {
1236    /// The decoder for the [`Amount`] type.
1237    #[derive(Debug, Clone)]
1238    pub struct AmountDecoder(encoding::ArrayDecoder<8>);
1239
1240    /// Constructs a new [`Amount`] decoder.
1241    pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
1242
1243    fn end(result: Result<[u8; 8], encoding::UnexpectedEofError>) -> Result<Amount, AmountDecoderError> {
1244        let value = result.map_err(AmountDecoderError)?;
1245        let a = u64::from_le_bytes(value);
1246        Ok(Amount::from_sat(a))
1247    }
1248}
1249
1250/// An error consensus decoding an [`Amount`].
1251#[cfg(feature = "encoding")]
1252#[derive(Debug, Clone, PartialEq, Eq)]
1253pub struct AmountDecoderError(pub(super) encoding::UnexpectedEofError);
1254
1255#[cfg(feature = "encoding")]
1256impl From<Infallible> for AmountDecoderError {
1257    fn from(never: Infallible) -> Self { match never {} }
1258}
1259
1260#[cfg(feature = "encoding")]
1261impl fmt::Display for AmountDecoderError {
1262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1263        write_err!(f, "amount decoder error"; self.0)
1264    }
1265}
1266
1267#[cfg(all(feature = "std", feature = "encoding"))]
1268impl std::error::Error for AmountDecoderError {
1269    #[inline]
1270    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
1271}
1272
1273/// A helper/builder that displays amount with specified settings.
1274///
1275/// This provides richer interface than `fmt::Formatter`:
1276///
1277/// * Ability to select denomination
1278/// * Show or hide denomination
1279/// * Dynamically-selected denomination - show in sats if less than 1 BTC.
1280///
1281/// However this can still be combined with `fmt::Formatter` options to precisely control zeros,
1282/// padding, alignment... The formatting works like floats from `core` but note that precision will
1283/// **never** be lossy - that means no rounding.
1284///
1285/// See [`Amount::display_in`] and [`Amount::display_dynamic`] on how to construct this.
1286#[derive(Debug, Clone)]
1287pub struct Display {
1288    /// Absolute value of satoshis to display (sign is below)
1289    sats_abs: u64,
1290    /// The sign
1291    is_negative: bool,
1292    /// How to display the value
1293    style: DisplayStyle,
1294}
1295
1296impl Display {
1297    /// Makes subsequent calls to `Display::fmt` display denomination.
1298    pub fn show_denomination(mut self) -> Self {
1299        match &mut self.style {
1300            DisplayStyle::FixedDenomination { show_denomination, .. } => *show_denomination = true,
1301            // No-op because dynamic denomination is always shown
1302            DisplayStyle::DynamicDenomination => (),
1303        }
1304        self
1305    }
1306}
1307
1308impl fmt::Display for Display {
1309    #[rustfmt::skip]
1310    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1311        let format_options = FormatOptions::from_formatter(f);
1312        match &self.style {
1313            DisplayStyle::FixedDenomination { show_denomination, denomination } => {
1314                fmt_satoshi_in(self.sats_abs, self.is_negative, f, *denomination, *show_denomination, format_options)
1315            },
1316            DisplayStyle::DynamicDenomination if self.sats_abs >= Amount::ONE_BTC.to_sat() => {
1317                fmt_satoshi_in(self.sats_abs, self.is_negative, f, Denomination::Bitcoin, true, format_options)
1318            },
1319            DisplayStyle::DynamicDenomination => {
1320                fmt_satoshi_in(self.sats_abs, self.is_negative, f, Denomination::Satoshi, true, format_options)
1321            },
1322        }
1323    }
1324}
1325
1326#[derive(Clone, Debug)]
1327enum DisplayStyle {
1328    FixedDenomination { denomination: Denomination, show_denomination: bool },
1329    DynamicDenomination,
1330}
1331
1332/// SignedAmount
1333///
1334/// The [SignedAmount] type can be used to express Bitcoin amounts that support
1335/// arithmetic and conversion to various denominations.
1336///
1337///
1338/// Warning!
1339///
1340/// This type implements several arithmetic operations from [core::ops].
1341/// To prevent errors due to overflow or underflow when using these operations,
1342/// it is advised to instead use the checked arithmetic methods whose names
1343/// start with `checked_`.  The operations from [core::ops] that [Amount]
1344/// implements will panic when overflow or underflow occurs.
1345///
1346#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1347pub struct SignedAmount(i64);
1348
1349impl SignedAmount {
1350    /// The zero amount.
1351    pub const ZERO: SignedAmount = SignedAmount(0);
1352    /// Exactly one satoshi.
1353    pub const ONE_SAT: SignedAmount = SignedAmount(1);
1354    /// Exactly one bitcoin.
1355    pub const ONE_BTC: SignedAmount = SignedAmount(100_000_000);
1356    /// The maximum value allowed as an amount. Useful for sanity checking.
1357    pub const MAX_MONEY: SignedAmount = SignedAmount(21_000_000 * 100_000_000);
1358    /// The minimum value of an amount.
1359    pub const MIN: SignedAmount = SignedAmount(i64::MIN);
1360    /// The maximum value of an amount.
1361    pub const MAX: SignedAmount = SignedAmount(i64::MAX);
1362
1363    /// Create an [SignedAmount] with satoshi precision and the given number of satoshis.
1364    pub const fn from_sat(satoshi: i64) -> SignedAmount { SignedAmount(satoshi) }
1365
1366    /// Gets the number of satoshis in this [`SignedAmount`].
1367    pub fn to_sat(self) -> i64 { self.0 }
1368
1369    /// Convert from a value expressing bitcoins to an [SignedAmount].
1370    #[cfg(feature = "alloc")]
1371    pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
1372        SignedAmount::from_float_in(btc, Denomination::Bitcoin)
1373    }
1374
1375    /// Parse a decimal string as a value in the given denomination.
1376    ///
1377    /// Note: This only parses the value string.  If you want to parse a value
1378    /// with denomination, use [FromStr].
1379    pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
1380        match parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(true))? {
1381            // (negative, amount)
1382            (false, sat) if sat > i64::MAX as u64 =>
1383                Err(ParseAmountError::OutOfRange(OutOfRangeError::too_big(true))),
1384            (false, sat) => Ok(SignedAmount(sat as i64)),
1385            (true, sat) if sat == i64::MIN.unsigned_abs() => Ok(SignedAmount(i64::MIN)),
1386            (true, sat) if sat > i64::MIN.unsigned_abs() =>
1387                Err(ParseAmountError::OutOfRange(OutOfRangeError::too_small())),
1388            (true, sat) => Ok(SignedAmount(-(sat as i64))),
1389        }
1390    }
1391
1392    /// Parses amounts with denomination suffix like they are produced with
1393    /// [Self::to_string_with_denomination] or with [fmt::Display].
1394    /// If you want to parse only the amount without the denomination,
1395    /// use [Self::from_str_in].
1396    pub fn from_str_with_denomination(s: &str) -> Result<SignedAmount, ParseError> {
1397        let (amt, denom) = split_amount_and_denomination(s)?;
1398        SignedAmount::from_str_in(amt, denom).map_err(Into::into)
1399    }
1400
1401    /// Express this [SignedAmount] as a floating-point value in the given denomination.
1402    ///
1403    /// Please be aware of the risk of using floating-point numbers.
1404    #[cfg(feature = "alloc")]
1405    pub fn to_float_in(self, denom: Denomination) -> f64 {
1406        f64::from_str(&self.to_string_in(denom)).unwrap()
1407    }
1408
1409    /// Express this [`SignedAmount`] as a floating-point value in Bitcoin.
1410    ///
1411    /// Equivalent to `to_float_in(Denomination::Bitcoin)`.
1412    ///
1413    /// Please be aware of the risk of using floating-point numbers.
1414    #[cfg(feature = "alloc")]
1415    pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
1416
1417    /// Convert this [SignedAmount] in floating-point notation with a given
1418    /// denomination.
1419    /// Can return error if the amount is too big, too precise or negative.
1420    ///
1421    /// Please be aware of the risk of using floating-point numbers.
1422    #[cfg(feature = "alloc")]
1423    pub fn from_float_in(
1424        value: f64,
1425        denom: Denomination,
1426    ) -> Result<SignedAmount, ParseAmountError> {
1427        // This is inefficient, but the safest way to deal with this. The parsing logic is safe.
1428        // Any performance-critical application should not be dealing with floats.
1429        SignedAmount::from_str_in(&value.to_string(), denom)
1430    }
1431
1432    /// Create an object that implements [`fmt::Display`] using specified denomination.
1433    pub fn display_in(self, denomination: Denomination) -> Display {
1434        Display {
1435            sats_abs: self.unsigned_abs().to_sat(),
1436            is_negative: self.is_negative(),
1437            style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
1438        }
1439    }
1440
1441    /// Create an object that implements [`fmt::Display`] dynamically selecting denomination.
1442    ///
1443    /// This will use BTC for values greater than or equal to 1 BTC and satoshis otherwise. To
1444    /// avoid confusion the denomination is always shown.
1445    pub fn display_dynamic(self) -> Display {
1446        Display {
1447            sats_abs: self.unsigned_abs().to_sat(),
1448            is_negative: self.is_negative(),
1449            style: DisplayStyle::DynamicDenomination,
1450        }
1451    }
1452
1453    /// Format the value of this [SignedAmount] in the given denomination.
1454    ///
1455    /// Does not include the denomination.
1456    #[rustfmt::skip]
1457    pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
1458        fmt_satoshi_in(self.unsigned_abs().to_sat(), self.is_negative(), f, denom, false, FormatOptions::default())
1459    }
1460
1461    /// Get a string number of this [SignedAmount] in the given denomination.
1462    ///
1463    /// Does not include the denomination.
1464    #[cfg(feature = "alloc")]
1465    pub fn to_string_in(self, denom: Denomination) -> String {
1466        let mut buf = String::new();
1467        self.fmt_value_in(&mut buf, denom).unwrap();
1468        buf
1469    }
1470
1471    /// Get a formatted string of this [SignedAmount] in the given denomination,
1472    /// suffixed with the abbreviation for the denomination.
1473    #[cfg(feature = "alloc")]
1474    pub fn to_string_with_denomination(self, denom: Denomination) -> String {
1475        let mut buf = String::new();
1476        self.fmt_value_in(&mut buf, denom).unwrap();
1477        write!(buf, " {}", denom).unwrap();
1478        buf
1479    }
1480
1481    // Some arithmetic that doesn't fit in `core::ops` traits.
1482
1483    /// Get the absolute value of this [SignedAmount].
1484    pub fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) }
1485
1486    /// Get the absolute value of this [SignedAmount] returning `Amount`.
1487    pub fn unsigned_abs(self) -> Amount { Amount(self.0.unsigned_abs()) }
1488
1489    /// Returns a number representing sign of this [SignedAmount].
1490    ///
1491    /// - `0` if the amount is zero
1492    /// - `1` if the amount is positive
1493    /// - `-1` if the amount is negative
1494    pub fn signum(self) -> i64 { self.0.signum() }
1495
1496    /// Returns `true` if this [SignedAmount] is positive and `false` if
1497    /// this [SignedAmount] is zero or negative.
1498    pub fn is_positive(self) -> bool { self.0.is_positive() }
1499
1500    /// Returns `true` if this [SignedAmount] is negative and `false` if
1501    /// this [SignedAmount] is zero or positive.
1502    pub fn is_negative(self) -> bool { self.0.is_negative() }
1503
1504    /// Get the absolute value of this [SignedAmount].
1505    /// Returns [None] if overflow occurred. (`self == MIN`)
1506    pub fn checked_abs(self) -> Option<SignedAmount> { self.0.checked_abs().map(SignedAmount) }
1507
1508    /// Checked addition.
1509    /// Returns [None] if overflow occurred.
1510    pub fn checked_add(self, rhs: SignedAmount) -> Option<SignedAmount> {
1511        self.0.checked_add(rhs.0).map(SignedAmount)
1512    }
1513
1514    /// Checked subtraction.
1515    /// Returns [None] if overflow occurred.
1516    pub fn checked_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
1517        self.0.checked_sub(rhs.0).map(SignedAmount)
1518    }
1519
1520    /// Checked multiplication.
1521    /// Returns [None] if overflow occurred.
1522    pub fn checked_mul(self, rhs: i64) -> Option<SignedAmount> {
1523        self.0.checked_mul(rhs).map(SignedAmount)
1524    }
1525
1526    /// Checked integer division.
1527    /// Be aware that integer division loses the remainder if no exact division
1528    /// can be made.
1529    /// Returns [None] if overflow occurred.
1530    pub fn checked_div(self, rhs: i64) -> Option<SignedAmount> {
1531        self.0.checked_div(rhs).map(SignedAmount)
1532    }
1533
1534    /// Checked remainder.
1535    /// Returns [None] if overflow occurred.
1536    pub fn checked_rem(self, rhs: i64) -> Option<SignedAmount> {
1537        self.0.checked_rem(rhs).map(SignedAmount)
1538    }
1539
1540    /// Unchecked addition.
1541    ///
1542    /// Computes `self + rhs`.  Panics in debug mode, wraps in release mode.
1543    pub fn unchecked_add(self, rhs: SignedAmount) -> SignedAmount { Self(self.0 + rhs.0) }
1544
1545    /// Unchecked subtraction.
1546    ///
1547    /// Computes `self - rhs`.  Panics in debug mode, wraps in release mode.
1548    pub fn unchecked_sub(self, rhs: SignedAmount) -> SignedAmount { Self(self.0 - rhs.0) }
1549
1550    /// Subtraction that doesn't allow negative [SignedAmount]s.
1551    /// Returns [None] if either [self], `rhs` or the result is strictly negative.
1552    pub fn positive_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
1553        if self.is_negative() || rhs.is_negative() || rhs > self {
1554            None
1555        } else {
1556            self.checked_sub(rhs)
1557        }
1558    }
1559
1560    /// Convert to an unsigned amount.
1561    pub fn to_unsigned(self) -> Result<Amount, OutOfRangeError> {
1562        if self.is_negative() {
1563            Err(OutOfRangeError::negative())
1564        } else {
1565            Ok(Amount::from_sat(self.to_sat() as u64))
1566        }
1567    }
1568}
1569
1570impl default::Default for SignedAmount {
1571    fn default() -> Self { SignedAmount::ZERO }
1572}
1573
1574impl fmt::Debug for SignedAmount {
1575    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1576        write!(f, "SignedAmount({} SAT)", self.to_sat())
1577    }
1578}
1579
1580// No one should depend on a binding contract for Display for this type.
1581// Just using Bitcoin denominated string.
1582impl fmt::Display for SignedAmount {
1583    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1584        self.fmt_value_in(f, Denomination::Bitcoin)?;
1585        write!(f, " {}", Denomination::Bitcoin)
1586    }
1587}
1588
1589impl ops::Add for SignedAmount {
1590    type Output = SignedAmount;
1591
1592    fn add(self, rhs: SignedAmount) -> Self::Output {
1593        self.checked_add(rhs).expect("SignedAmount addition error")
1594    }
1595}
1596
1597impl ops::AddAssign for SignedAmount {
1598    fn add_assign(&mut self, other: SignedAmount) { *self = *self + other }
1599}
1600
1601impl ops::Sub for SignedAmount {
1602    type Output = SignedAmount;
1603
1604    fn sub(self, rhs: SignedAmount) -> Self::Output {
1605        self.checked_sub(rhs).expect("SignedAmount subtraction error")
1606    }
1607}
1608
1609impl ops::SubAssign for SignedAmount {
1610    fn sub_assign(&mut self, other: SignedAmount) { *self = *self - other }
1611}
1612
1613impl ops::Rem<i64> for SignedAmount {
1614    type Output = SignedAmount;
1615
1616    fn rem(self, modulus: i64) -> Self {
1617        self.checked_rem(modulus).expect("SignedAmount remainder error")
1618    }
1619}
1620
1621impl ops::RemAssign<i64> for SignedAmount {
1622    fn rem_assign(&mut self, modulus: i64) { *self = *self % modulus }
1623}
1624
1625impl ops::Mul<i64> for SignedAmount {
1626    type Output = SignedAmount;
1627
1628    fn mul(self, rhs: i64) -> Self::Output {
1629        self.checked_mul(rhs).expect("SignedAmount multiplication error")
1630    }
1631}
1632
1633impl ops::MulAssign<i64> for SignedAmount {
1634    fn mul_assign(&mut self, rhs: i64) { *self = *self * rhs }
1635}
1636
1637impl ops::Div<i64> for SignedAmount {
1638    type Output = SignedAmount;
1639
1640    fn div(self, rhs: i64) -> Self::Output {
1641        self.checked_div(rhs).expect("SignedAmount division error")
1642    }
1643}
1644
1645impl ops::DivAssign<i64> for SignedAmount {
1646    fn div_assign(&mut self, rhs: i64) { *self = *self / rhs }
1647}
1648
1649impl ops::Neg for SignedAmount {
1650    type Output = Self;
1651
1652    fn neg(self) -> Self::Output { Self(self.0.neg()) }
1653}
1654
1655impl FromStr for SignedAmount {
1656    type Err = ParseError;
1657
1658    fn from_str(s: &str) -> Result<Self, Self::Err> { SignedAmount::from_str_with_denomination(s) }
1659}
1660
1661impl TryFrom<Amount> for SignedAmount {
1662    type Error = OutOfRangeError;
1663
1664    fn try_from(value: Amount) -> Result<Self, Self::Error> { value.to_signed() }
1665}
1666
1667impl core::iter::Sum for SignedAmount {
1668    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1669        let sats: i64 = iter.map(|amt| amt.0).sum();
1670        SignedAmount::from_sat(sats)
1671    }
1672}
1673
1674/// Calculate the sum over the iterator using checked arithmetic.
1675pub trait CheckedSum<R>: private::SumSeal<R> {
1676    /// Calculate the sum over the iterator using checked arithmetic. If an over or underflow would
1677    /// happen it returns `None`.
1678    fn checked_sum(self) -> Option<R>;
1679}
1680
1681impl<T> CheckedSum<Amount> for T
1682where
1683    T: Iterator<Item = Amount>,
1684{
1685    fn checked_sum(mut self) -> Option<Amount> {
1686        let first = Some(self.next().unwrap_or_default());
1687
1688        self.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
1689    }
1690}
1691
1692impl<T> CheckedSum<SignedAmount> for T
1693where
1694    T: Iterator<Item = SignedAmount>,
1695{
1696    fn checked_sum(mut self) -> Option<SignedAmount> {
1697        let first = Some(self.next().unwrap_or_default());
1698
1699        self.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
1700    }
1701}
1702
1703mod private {
1704    use super::{Amount, SignedAmount};
1705
1706    /// Used to seal the `CheckedSum` trait
1707    pub trait SumSeal<A> {}
1708
1709    impl<T> SumSeal<Amount> for T where T: Iterator<Item = Amount> {}
1710    impl<T> SumSeal<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
1711}
1712
1713#[cfg(feature = "serde")]
1714pub mod serde {
1715    // methods are implementation of a standardized serde-specific signature
1716    #![allow(missing_docs)]
1717
1718    //! This module adds serde serialization and deserialization support for Amounts.
1719    //!
1720    //! Since there is not a default way to serialize and deserialize Amounts, multiple
1721    //! ways are supported and it's up to the user to decide which serialiation to use.
1722    //! The provided modules can be used as follows:
1723    //!
1724    //! ```rust,ignore
1725    //! use serde::{Serialize, Deserialize};
1726    //! use bitcoin_units::Amount;
1727    //!
1728    //! #[derive(Serialize, Deserialize)]
1729    //! pub struct HasAmount {
1730    //!     #[serde(with = "bitcoin_units::amount::serde::as_btc")]
1731    //!     pub amount: Amount,
1732    //! }
1733    //! ```
1734
1735    use core::fmt;
1736
1737    use serde::{Deserialize, Deserializer, Serialize, Serializer};
1738
1739    #[cfg(feature = "alloc")]
1740    use super::Denomination;
1741    use super::{Amount, ParseAmountError, SignedAmount};
1742
1743    /// This trait is used only to avoid code duplication and naming collisions
1744    /// of the different serde serialization crates.
1745    pub trait SerdeAmount: Copy + Sized {
1746        fn ser_sat<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error>;
1747        fn des_sat<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result<Self, D::Error>;
1748        #[cfg(feature = "alloc")]
1749        fn ser_btc<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error>;
1750        #[cfg(feature = "alloc")]
1751        fn des_btc<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result<Self, D::Error>;
1752    }
1753
1754    mod private {
1755        /// Controls access to the trait methods.
1756        pub struct Token;
1757    }
1758
1759    /// This trait is only for internal Amount type serialization/deserialization
1760    pub trait SerdeAmountForOpt: Copy + Sized + SerdeAmount {
1761        fn type_prefix(_: private::Token) -> &'static str;
1762        fn ser_sat_opt<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error>;
1763        #[cfg(feature = "alloc")]
1764        fn ser_btc_opt<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error>;
1765    }
1766
1767    struct DisplayFullError(ParseAmountError);
1768
1769    #[cfg(feature = "std")]
1770    impl fmt::Display for DisplayFullError {
1771        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1772            use std::error::Error;
1773
1774            fmt::Display::fmt(&self.0, f)?;
1775            let mut source_opt = self.0.source();
1776            while let Some(source) = source_opt {
1777                write!(f, ": {}", source)?;
1778                source_opt = source.source();
1779            }
1780            Ok(())
1781        }
1782    }
1783
1784    #[cfg(not(feature = "std"))]
1785    impl fmt::Display for DisplayFullError {
1786        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
1787    }
1788
1789    impl SerdeAmount for Amount {
1790        fn ser_sat<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1791            u64::serialize(&self.to_sat(), s)
1792        }
1793        fn des_sat<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result<Self, D::Error> {
1794            Ok(Amount::from_sat(u64::deserialize(d)?))
1795        }
1796        #[cfg(feature = "alloc")]
1797        fn ser_btc<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1798            f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
1799        }
1800        #[cfg(feature = "alloc")]
1801        fn des_btc<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result<Self, D::Error> {
1802            use serde::de::Error;
1803            Amount::from_btc(f64::deserialize(d)?)
1804                .map_err(DisplayFullError)
1805                .map_err(D::Error::custom)
1806        }
1807    }
1808
1809    impl SerdeAmountForOpt for Amount {
1810        fn type_prefix(_: private::Token) -> &'static str { "u" }
1811        fn ser_sat_opt<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1812            s.serialize_some(&self.to_sat())
1813        }
1814        #[cfg(feature = "alloc")]
1815        fn ser_btc_opt<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1816            s.serialize_some(&self.to_btc())
1817        }
1818    }
1819
1820    impl SerdeAmount for SignedAmount {
1821        fn ser_sat<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1822            i64::serialize(&self.to_sat(), s)
1823        }
1824        fn des_sat<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result<Self, D::Error> {
1825            Ok(SignedAmount::from_sat(i64::deserialize(d)?))
1826        }
1827        #[cfg(feature = "alloc")]
1828        fn ser_btc<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1829            f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
1830        }
1831        #[cfg(feature = "alloc")]
1832        fn des_btc<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result<Self, D::Error> {
1833            use serde::de::Error;
1834            SignedAmount::from_btc(f64::deserialize(d)?)
1835                .map_err(DisplayFullError)
1836                .map_err(D::Error::custom)
1837        }
1838    }
1839
1840    impl SerdeAmountForOpt for SignedAmount {
1841        fn type_prefix(_: private::Token) -> &'static str { "i" }
1842        fn ser_sat_opt<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1843            s.serialize_some(&self.to_sat())
1844        }
1845        #[cfg(feature = "alloc")]
1846        fn ser_btc_opt<S: Serializer>(self, s: S, _: private::Token) -> Result<S::Ok, S::Error> {
1847            s.serialize_some(&self.to_btc())
1848        }
1849    }
1850
1851    pub mod as_sat {
1852        //! Serialize and deserialize [`Amount`](crate::Amount) as real numbers denominated in satoshi.
1853        //! Use with `#[serde(with = "amount::serde::as_sat")]`.
1854        //!
1855        use serde::{Deserializer, Serializer};
1856
1857        use super::private;
1858        use crate::amount::serde::SerdeAmount;
1859
1860        pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
1861            a.ser_sat(s, private::Token)
1862        }
1863
1864        pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
1865            A::des_sat(d, private::Token)
1866        }
1867
1868        pub mod opt {
1869            //! Serialize and deserialize [`Option<Amount>`](crate::Amount) as real numbers denominated in satoshi.
1870            //! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`.
1871
1872            use core::fmt;
1873            use core::marker::PhantomData;
1874
1875            use serde::{de, Deserializer, Serializer};
1876
1877            use super::private;
1878            use crate::amount::serde::SerdeAmountForOpt;
1879
1880            pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
1881                a: &Option<A>,
1882                s: S,
1883            ) -> Result<S::Ok, S::Error> {
1884                match *a {
1885                    Some(a) => a.ser_sat_opt(s, private::Token),
1886                    None => s.serialize_none(),
1887                }
1888            }
1889
1890            pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>(
1891                d: D,
1892            ) -> Result<Option<A>, D::Error> {
1893                struct VisitOptAmt<X>(PhantomData<X>);
1894
1895                impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt<X> {
1896                    type Value = Option<X>;
1897
1898                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1899                        write!(formatter, "An Option<{}64>", X::type_prefix(private::Token))
1900                    }
1901
1902                    fn visit_none<E>(self) -> Result<Self::Value, E>
1903                    where
1904                        E: de::Error,
1905                    {
1906                        Ok(None)
1907                    }
1908                    fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
1909                    where
1910                        D: Deserializer<'de>,
1911                    {
1912                        Ok(Some(X::des_sat(d, private::Token)?))
1913                    }
1914                }
1915                d.deserialize_option(VisitOptAmt::<A>(PhantomData))
1916            }
1917        }
1918    }
1919
1920    #[cfg(feature = "alloc")]
1921    pub mod as_btc {
1922        //! Serialize and deserialize [`Amount`](crate::Amount) as JSON numbers denominated in BTC.
1923        //! Use with `#[serde(with = "amount::serde::as_btc")]`.
1924
1925        use serde::{Deserializer, Serializer};
1926
1927        use super::private;
1928        use crate::amount::serde::SerdeAmount;
1929
1930        pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
1931            a.ser_btc(s, private::Token)
1932        }
1933
1934        pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
1935            A::des_btc(d, private::Token)
1936        }
1937
1938        pub mod opt {
1939            //! Serialize and deserialize `Option<Amount>` as JSON numbers denominated in BTC.
1940            //! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`.
1941
1942            use core::fmt;
1943            use core::marker::PhantomData;
1944
1945            use serde::{de, Deserializer, Serializer};
1946
1947            use super::private;
1948            use crate::amount::serde::SerdeAmountForOpt;
1949
1950            pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
1951                a: &Option<A>,
1952                s: S,
1953            ) -> Result<S::Ok, S::Error> {
1954                match *a {
1955                    Some(a) => a.ser_btc_opt(s, private::Token),
1956                    None => s.serialize_none(),
1957                }
1958            }
1959
1960            pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>(
1961                d: D,
1962            ) -> Result<Option<A>, D::Error> {
1963                struct VisitOptAmt<X>(PhantomData<X>);
1964
1965                impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt<X> {
1966                    type Value = Option<X>;
1967
1968                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1969                        write!(formatter, "An Option<f64>")
1970                    }
1971
1972                    fn visit_none<E>(self) -> Result<Self::Value, E>
1973                    where
1974                        E: de::Error,
1975                    {
1976                        Ok(None)
1977                    }
1978                    fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
1979                    where
1980                        D: Deserializer<'de>,
1981                    {
1982                        Ok(Some(X::des_btc(d, private::Token)?))
1983                    }
1984                }
1985                d.deserialize_option(VisitOptAmt::<A>(PhantomData))
1986            }
1987        }
1988    }
1989}
1990
1991#[cfg(feature = "arbitrary")]
1992impl<'a> Arbitrary<'a> for Amount {
1993    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
1994        let a = u64::arbitrary(u)?;
1995        Ok(Amount(a))
1996    }
1997}
1998
1999#[cfg(feature = "arbitrary")]
2000impl<'a> Arbitrary<'a> for Denomination {
2001    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
2002        let choice = u.int_in_range(0..=5)?;
2003        match choice {
2004            0 => Ok(Denomination::Bitcoin),
2005            1 => Ok(Denomination::CentiBitcoin),
2006            2 => Ok(Denomination::MilliBitcoin),
2007            3 => Ok(Denomination::MicroBitcoin),
2008            4 => Ok(Denomination::Bit),
2009            _ => Ok(Denomination::Satoshi),
2010        }
2011    }
2012}
2013
2014#[cfg(feature = "arbitrary")]
2015impl<'a> Arbitrary<'a> for SignedAmount {
2016    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
2017        let s = i64::arbitrary(u)?;
2018        Ok(SignedAmount(s))
2019    }
2020}
2021
2022#[cfg(kani)]
2023mod verification {
2024    use std::cmp;
2025    use std::convert::TryInto;
2026
2027    use super::*;
2028
2029    // Note regarding the `unwind` parameter: this defines how many iterations
2030    // of loops kani will unwind before handing off to the SMT solver. Basically
2031    // it should be set as low as possible such that Kani still succeeds (doesn't
2032    // return "undecidable").
2033    //
2034    // There is more info here: https://model-checking.github.io/kani/tutorial-loop-unwinding.html
2035    //
2036    // Unfortunately what it means to "loop" is pretty opaque ... in this case
2037    // there appear to be loops in memcmp, which I guess comes from assert_eq!,
2038    // though I didn't see any failures until I added the to_signed() test.
2039    // Further confusing the issue, a value of 2 works fine on my system, but on
2040    // CI it fails, so we need to set it higher.
2041    #[kani::unwind(4)]
2042    #[kani::proof]
2043    fn u_amount_add_homomorphic() {
2044        let n1 = kani::any::<u64>();
2045        let n2 = kani::any::<u64>();
2046        kani::assume(n1.checked_add(n2).is_some()); // assume we don't overflow in the actual test
2047        assert_eq!(Amount::from_sat(n1) + Amount::from_sat(n2), Amount::from_sat(n1 + n2));
2048
2049        let mut amt = Amount::from_sat(n1);
2050        amt += Amount::from_sat(n2);
2051        assert_eq!(amt, Amount::from_sat(n1 + n2));
2052
2053        let max = cmp::max(n1, n2);
2054        let min = cmp::min(n1, n2);
2055        assert_eq!(Amount::from_sat(max) - Amount::from_sat(min), Amount::from_sat(max - min));
2056
2057        let mut amt = Amount::from_sat(max);
2058        amt -= Amount::from_sat(min);
2059        assert_eq!(amt, Amount::from_sat(max - min));
2060
2061        assert_eq!(
2062            Amount::from_sat(n1).to_signed(),
2063            if n1 <= i64::MAX as u64 {
2064                Ok(SignedAmount::from_sat(n1.try_into().unwrap()))
2065            } else {
2066                Err(OutOfRangeError::too_big(true))
2067            },
2068        );
2069    }
2070
2071    #[kani::unwind(4)]
2072    #[kani::proof]
2073    fn u_amount_add_homomorphic_checked() {
2074        let n1 = kani::any::<u64>();
2075        let n2 = kani::any::<u64>();
2076        assert_eq!(
2077            Amount::from_sat(n1).checked_add(Amount::from_sat(n2)),
2078            n1.checked_add(n2).map(Amount::from_sat),
2079        );
2080        assert_eq!(
2081            Amount::from_sat(n1).checked_sub(Amount::from_sat(n2)),
2082            n1.checked_sub(n2).map(Amount::from_sat),
2083        );
2084    }
2085
2086    #[kani::unwind(4)]
2087    #[kani::proof]
2088    fn s_amount_add_homomorphic() {
2089        let n1 = kani::any::<i64>();
2090        let n2 = kani::any::<i64>();
2091        kani::assume(n1.checked_add(n2).is_some()); // assume we don't overflow in the actual test
2092        kani::assume(n1.checked_sub(n2).is_some()); // assume we don't overflow in the actual test
2093        assert_eq!(
2094            SignedAmount::from_sat(n1) + SignedAmount::from_sat(n2),
2095            SignedAmount::from_sat(n1 + n2)
2096        );
2097        assert_eq!(
2098            SignedAmount::from_sat(n1) - SignedAmount::from_sat(n2),
2099            SignedAmount::from_sat(n1 - n2)
2100        );
2101
2102        let mut amt = SignedAmount::from_sat(n1);
2103        amt += SignedAmount::from_sat(n2);
2104        assert_eq!(amt, SignedAmount::from_sat(n1 + n2));
2105        let mut amt = SignedAmount::from_sat(n1);
2106        amt -= SignedAmount::from_sat(n2);
2107        assert_eq!(amt, SignedAmount::from_sat(n1 - n2));
2108
2109        assert_eq!(
2110            SignedAmount::from_sat(n1).to_unsigned(),
2111            if n1 >= 0 {
2112                Ok(Amount::from_sat(n1.try_into().unwrap()))
2113            } else {
2114                Err(OutOfRangeError { is_signed: true, is_greater_than_max: false })
2115            },
2116        );
2117    }
2118
2119    #[kani::unwind(4)]
2120    #[kani::proof]
2121    fn s_amount_add_homomorphic_checked() {
2122        let n1 = kani::any::<i64>();
2123        let n2 = kani::any::<i64>();
2124        assert_eq!(
2125            SignedAmount::from_sat(n1).checked_add(SignedAmount::from_sat(n2)),
2126            n1.checked_add(n2).map(SignedAmount::from_sat),
2127        );
2128        assert_eq!(
2129            SignedAmount::from_sat(n1).checked_sub(SignedAmount::from_sat(n2)),
2130            n1.checked_sub(n2).map(SignedAmount::from_sat),
2131        );
2132
2133        assert_eq!(
2134            SignedAmount::from_sat(n1).positive_sub(SignedAmount::from_sat(n2)),
2135            if n1 >= 0 && n2 >= 0 && n1 >= n2 {
2136                Some(SignedAmount::from_sat(n1 - n2))
2137            } else {
2138                None
2139            },
2140        );
2141    }
2142}
2143
2144#[cfg(test)]
2145mod tests {
2146    #[cfg(feature = "alloc")]
2147    use alloc::format;
2148    #[cfg(feature = "std")]
2149    use std::panic;
2150
2151    use super::*;
2152
2153    #[test]
2154    #[cfg(feature = "alloc")]
2155    fn from_str_zero() {
2156        let denoms = ["BTC", "mBTC", "uBTC", "nBTC", "pBTC", "bits", "sats", "msats"];
2157        for denom in denoms {
2158            for v in &["0", "000"] {
2159                let s = format!("{} {}", v, denom);
2160                match Amount::from_str(&s) {
2161                    Err(e) => panic!("Failed to crate amount from {}: {:?}", s, e),
2162                    Ok(amount) => assert_eq!(amount, Amount::from_sat(0)),
2163                }
2164            }
2165
2166            let s = format!("-0 {}", denom);
2167            match Amount::from_str(&s) {
2168                Err(e) => assert_eq!(
2169                    e,
2170                    ParseError::Amount(ParseAmountError::OutOfRange(OutOfRangeError::negative()))
2171                ),
2172                Ok(_) => panic!("Unsigned amount from {}", s),
2173            }
2174            match SignedAmount::from_str(&s) {
2175                Err(e) => panic!("Failed to crate amount from {}: {:?}", s, e),
2176                Ok(amount) => assert_eq!(amount, SignedAmount::from_sat(0)),
2177            }
2178        }
2179    }
2180
2181    #[test]
2182    fn from_int_btc() {
2183        let amt = Amount::from_int_btc(2);
2184        assert_eq!(Amount::from_sat(200_000_000), amt);
2185    }
2186
2187    #[should_panic]
2188    #[test]
2189    fn from_int_btc_panic() { Amount::from_int_btc(u64::MAX); }
2190
2191    #[test]
2192    fn test_signed_amount_try_from_amount() {
2193        let ua_positive = Amount::from_sat(123);
2194        let sa_positive = SignedAmount::try_from(ua_positive).unwrap();
2195        assert_eq!(sa_positive, SignedAmount(123));
2196
2197        let ua_max = Amount::MAX;
2198        let result = SignedAmount::try_from(ua_max);
2199        assert_eq!(result, Err(OutOfRangeError { is_signed: true, is_greater_than_max: true }));
2200    }
2201
2202    #[test]
2203    fn test_amount_try_from_signed_amount() {
2204        let sa_positive = SignedAmount(123);
2205        let ua_positive = Amount::try_from(sa_positive).unwrap();
2206        assert_eq!(ua_positive, Amount::from_sat(123));
2207
2208        let sa_negative = SignedAmount(-123);
2209        let result = Amount::try_from(sa_negative);
2210        assert_eq!(result, Err(OutOfRangeError { is_signed: false, is_greater_than_max: false }));
2211    }
2212
2213    #[test]
2214    fn mul_div() {
2215        let sat = Amount::from_sat;
2216        let ssat = SignedAmount::from_sat;
2217
2218        assert_eq!(sat(14) * 3, sat(42));
2219        assert_eq!(sat(14) / 2, sat(7));
2220        assert_eq!(sat(14) % 3, sat(2));
2221        assert_eq!(ssat(-14) * 3, ssat(-42));
2222        assert_eq!(ssat(-14) / 2, ssat(-7));
2223        assert_eq!(ssat(-14) % 3, ssat(-2));
2224
2225        let mut b = ssat(30);
2226        b /= 3;
2227        assert_eq!(b, ssat(10));
2228        b %= 3;
2229        assert_eq!(b, ssat(1));
2230    }
2231
2232    #[cfg(feature = "std")]
2233    #[test]
2234    fn test_overflows() {
2235        // panic on overflow
2236        let result = panic::catch_unwind(|| Amount::MAX + Amount::from_sat(1));
2237        assert!(result.is_err());
2238        let result = panic::catch_unwind(|| Amount::from_sat(8446744073709551615) * 3);
2239        assert!(result.is_err());
2240    }
2241
2242    #[test]
2243    fn checked_arithmetic() {
2244        let sat = Amount::from_sat;
2245        let ssat = SignedAmount::from_sat;
2246
2247        assert_eq!(SignedAmount::MAX.checked_add(ssat(1)), None);
2248        assert_eq!(SignedAmount::MIN.checked_sub(ssat(1)), None);
2249        assert_eq!(Amount::MAX.checked_add(sat(1)), None);
2250        assert_eq!(Amount::MIN.checked_sub(sat(1)), None);
2251
2252        assert_eq!(sat(5).checked_div(2), Some(sat(2))); // integer division
2253        assert_eq!(ssat(-6).checked_div(2), Some(ssat(-3)));
2254    }
2255
2256    #[cfg(feature = "alloc")]
2257    #[test]
2258    fn amount_checked_div_by_weight_ceil() {
2259        let weight = Weight::from_kwu(1).unwrap();
2260        let fee_rate = Amount::from_sat(1).div_by_weight_ceil(weight).unwrap();
2261        // 1 sats / 1,000 wu = 1 sats/kwu
2262        assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1));
2263
2264        let weight = Weight::from_wu(381);
2265        let fee_rate = Amount::from_sat(329).div_by_weight_ceil(weight).unwrap();
2266        // 329 sats / 381 wu = 863.5 sats/kwu
2267        // round up to 864
2268        assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864));
2269
2270        let fee_rate = Amount::MAX.div_by_weight_ceil(weight);
2271        assert!(fee_rate.is_none());
2272
2273        let fee_rate = Amount::ONE_SAT.div_by_weight_ceil(Weight::ZERO);
2274        assert!(fee_rate.is_none());
2275    }
2276
2277    #[cfg(feature = "alloc")]
2278    #[test]
2279    fn amount_checked_div_by_weight_floor() {
2280        let weight = Weight::from_kwu(1).unwrap();
2281        let fee_rate = Amount::from_sat(1).div_by_weight_floor(weight).unwrap();
2282        // 1 sats / 1,000 wu = 1 sats/kwu
2283        assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1));
2284
2285        let weight = Weight::from_wu(381);
2286        let fee_rate = Amount::from_sat(329).div_by_weight_floor(weight).unwrap();
2287        // 329 sats / 381 wu = 863.5 sats/kwu
2288        // round down to 863
2289        assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863));
2290
2291        let fee_rate = Amount::MAX.div_by_weight_floor(weight);
2292        assert!(fee_rate.is_none());
2293
2294        let fee_rate = Amount::ONE_SAT.div_by_weight_floor(Weight::ZERO);
2295        assert!(fee_rate.is_none());
2296    }
2297
2298    #[test]
2299    #[cfg(not(debug_assertions))]
2300    fn unchecked_amount_add() {
2301        let amt = Amount::MAX.unchecked_add(Amount::ONE_SAT);
2302        assert_eq!(amt, Amount::ZERO);
2303    }
2304
2305    #[test]
2306    #[cfg(not(debug_assertions))]
2307    fn unchecked_signed_amount_add() {
2308        let signed_amt = SignedAmount::MAX.unchecked_add(SignedAmount::ONE_SAT);
2309        assert_eq!(signed_amt, SignedAmount::MIN);
2310    }
2311
2312    #[test]
2313    #[cfg(not(debug_assertions))]
2314    fn unchecked_amount_subtract() {
2315        let amt = Amount::ZERO.unchecked_sub(Amount::ONE_SAT);
2316        assert_eq!(amt, Amount::MAX);
2317    }
2318
2319    #[test]
2320    #[cfg(not(debug_assertions))]
2321    fn unchecked_signed_amount_subtract() {
2322        let signed_amt = SignedAmount::MIN.unchecked_sub(SignedAmount::ONE_SAT);
2323        assert_eq!(signed_amt, SignedAmount::MAX);
2324    }
2325
2326    #[cfg(feature = "alloc")]
2327    #[test]
2328    fn floating_point() {
2329        use super::Denomination as D;
2330        let f = Amount::from_float_in;
2331        let sf = SignedAmount::from_float_in;
2332        let sat = Amount::from_sat;
2333        let ssat = SignedAmount::from_sat;
2334
2335        assert_eq!(f(11.22, D::Bitcoin), Ok(sat(1122000000)));
2336        assert_eq!(sf(-11.22, D::MilliBitcoin), Ok(ssat(-1122000)));
2337        assert_eq!(f(11.22, D::Bit), Ok(sat(1122)));
2338        assert_eq!(sf(-1000.0, D::MilliSatoshi), Ok(ssat(-1)));
2339        assert_eq!(f(0.0001234, D::Bitcoin), Ok(sat(12340)));
2340        assert_eq!(sf(-0.00012345, D::Bitcoin), Ok(ssat(-12345)));
2341
2342        assert_eq!(f(-100.0, D::MilliSatoshi), Err(OutOfRangeError::negative().into()));
2343        assert_eq!(f(11.22, D::Satoshi), Err(TooPreciseError { position: 3 }.into()));
2344        assert_eq!(sf(-100.0, D::MilliSatoshi), Err(TooPreciseError { position: 1 }.into()));
2345        assert_eq!(f(42.123456781, D::Bitcoin), Err(TooPreciseError { position: 11 }.into()));
2346        assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(OutOfRangeError::too_small().into()));
2347        assert_eq!(
2348            f(18446744073709551617.0, D::Satoshi),
2349            Err(OutOfRangeError::too_big(false).into())
2350        );
2351
2352        // Amount can be grater than the max SignedAmount.
2353        assert!(f(SignedAmount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi).is_ok());
2354
2355        assert_eq!(
2356            f(Amount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi),
2357            Err(OutOfRangeError::too_big(false).into())
2358        );
2359
2360        assert_eq!(
2361            sf(SignedAmount::MAX.to_float_in(D::Satoshi) + 1.0, D::Satoshi),
2362            Err(OutOfRangeError::too_big(true).into())
2363        );
2364
2365        let btc = move |f| SignedAmount::from_btc(f).unwrap();
2366        assert_eq!(btc(2.5).to_float_in(D::Bitcoin), 2.5);
2367        assert_eq!(btc(-2.5).to_float_in(D::MilliBitcoin), -2500.0);
2368        assert_eq!(btc(2.5).to_float_in(D::Satoshi), 250000000.0);
2369        assert_eq!(btc(-2.5).to_float_in(D::MilliSatoshi), -250000000000.0);
2370
2371        let btc = move |f| Amount::from_btc(f).unwrap();
2372        assert_eq!(&btc(0.0012).to_float_in(D::Bitcoin).to_string(), "0.0012")
2373    }
2374
2375    #[test]
2376    #[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin.
2377    fn parsing() {
2378        use super::ParseAmountError as E;
2379        let btc = Denomination::Bitcoin;
2380        let sat = Denomination::Satoshi;
2381        let msat = Denomination::MilliSatoshi;
2382        let p = Amount::from_str_in;
2383        let sp = SignedAmount::from_str_in;
2384
2385        assert_eq!(
2386            p("x", btc),
2387            Err(E::from(InvalidCharacterError { invalid_char: 'x', position: 0 }))
2388        );
2389        assert_eq!(
2390            p("-", btc),
2391            Err(E::from(MissingDigitsError { kind: MissingDigitsKind::OnlyMinusSign }))
2392        );
2393        assert_eq!(
2394            sp("-", btc),
2395            Err(E::from(MissingDigitsError { kind: MissingDigitsKind::OnlyMinusSign }))
2396        );
2397        assert_eq!(
2398            p("-1.0x", btc),
2399            Err(E::from(InvalidCharacterError { invalid_char: 'x', position: 4 }))
2400        );
2401        assert_eq!(
2402            p("0.0 ", btc),
2403            Err(E::from(InvalidCharacterError { invalid_char: ' ', position: 3 }))
2404        );
2405        assert_eq!(
2406            p("0.000.000", btc),
2407            Err(E::from(InvalidCharacterError { invalid_char: '.', position: 5 }))
2408        );
2409        #[cfg(feature = "alloc")]
2410        let more_than_max = format!("1{}", Amount::MAX);
2411        #[cfg(feature = "alloc")]
2412        assert_eq!(p(&more_than_max, btc), Err(OutOfRangeError::too_big(false).into()));
2413        assert_eq!(p("0.000000042", btc), Err(TooPreciseError { position: 10 }.into()));
2414        assert_eq!(p("999.0000000", msat), Err(TooPreciseError { position: 0 }.into()));
2415        assert_eq!(p("1.0000000", msat), Err(TooPreciseError { position: 0 }.into()));
2416        assert_eq!(p("1.1", msat), Err(TooPreciseError { position: 0 }.into()));
2417        assert_eq!(p("1000.1", msat), Err(TooPreciseError { position: 5 }.into()));
2418        assert_eq!(p("1001.0000000", msat), Err(TooPreciseError { position: 3 }.into()));
2419        assert_eq!(p("1000.0000001", msat), Err(TooPreciseError { position: 11 }.into()));
2420        assert_eq!(p("1000.1000000", msat), Err(TooPreciseError { position: 5 }.into()));
2421        assert_eq!(p("1100.0000000", msat), Err(TooPreciseError { position: 1 }.into()));
2422        assert_eq!(p("10001.0000000", msat), Err(TooPreciseError { position: 4 }.into()));
2423
2424        assert_eq!(p("1", btc), Ok(Amount::from_sat(1_000_000_00)));
2425        assert_eq!(sp("-.5", btc), Ok(SignedAmount::from_sat(-500_000_00)));
2426        #[cfg(feature = "alloc")]
2427        assert_eq!(sp(&i64::MIN.to_string(), sat), Ok(SignedAmount::from_sat(i64::MIN)));
2428        assert_eq!(p("1.1", btc), Ok(Amount::from_sat(1_100_000_00)));
2429        assert_eq!(p("100", sat), Ok(Amount::from_sat(100)));
2430        assert_eq!(p("55", sat), Ok(Amount::from_sat(55)));
2431        assert_eq!(p("5500000000000000000", sat), Ok(Amount::from_sat(55_000_000_000_000_000_00)));
2432        // Should this even pass?
2433        assert_eq!(p("5500000000000000000.", sat), Ok(Amount::from_sat(55_000_000_000_000_000_00)));
2434        assert_eq!(
2435            p("12345678901.12345678", btc),
2436            Ok(Amount::from_sat(12_345_678_901__123_456_78))
2437        );
2438        assert_eq!(p("1000.0", msat), Ok(Amount::from_sat(1)));
2439        assert_eq!(p("1000.000000000000000000000000000", msat), Ok(Amount::from_sat(1)));
2440
2441        // make sure satoshi > i64::MAX is checked.
2442        #[cfg(feature = "alloc")]
2443        {
2444            let amount = Amount::from_sat(i64::MAX as u64);
2445            assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
2446            assert!(
2447                SignedAmount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat).is_err()
2448            );
2449            assert!(Amount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat).is_ok());
2450        }
2451
2452        assert_eq!(
2453            p("12.000", Denomination::MilliSatoshi),
2454            Err(TooPreciseError { position: 0 }.into())
2455        );
2456        // exactly 50 chars.
2457        assert_eq!(
2458            p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin),
2459            Err(OutOfRangeError::too_big(false).into())
2460        );
2461        // more than 50 chars.
2462        assert_eq!(
2463            p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin),
2464            Err(E::InputTooLarge(InputTooLargeError { len: 51 }))
2465        );
2466    }
2467
2468    #[test]
2469    #[cfg(feature = "alloc")]
2470    fn to_string() {
2471        use super::Denomination as D;
2472
2473        assert_eq!(Amount::ONE_BTC.to_string_in(D::Bitcoin), "1");
2474        assert_eq!(format!("{:.8}", Amount::ONE_BTC.display_in(D::Bitcoin)), "1.00000000");
2475        assert_eq!(Amount::ONE_BTC.to_string_in(D::Satoshi), "100000000");
2476        assert_eq!(Amount::ONE_SAT.to_string_in(D::Bitcoin), "0.00000001");
2477        assert_eq!(SignedAmount::from_sat(-42).to_string_in(D::Bitcoin), "-0.00000042");
2478
2479        assert_eq!(Amount::ONE_BTC.to_string_with_denomination(D::Bitcoin), "1 BTC");
2480        assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::MilliSatoshi), "1000 msat");
2481        assert_eq!(
2482            SignedAmount::ONE_BTC.to_string_with_denomination(D::Satoshi),
2483            "100000000 satoshi"
2484        );
2485        assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::Bitcoin), "0.00000001 BTC");
2486        assert_eq!(
2487            SignedAmount::from_sat(-42).to_string_with_denomination(D::Bitcoin),
2488            "-0.00000042 BTC"
2489        );
2490    }
2491
2492    // May help identify a problem sooner
2493    #[cfg(feature = "alloc")]
2494    #[test]
2495    fn test_repeat_char() {
2496        let mut buf = String::new();
2497        repeat_char(&mut buf, '0', 0).unwrap();
2498        assert_eq!(buf.len(), 0);
2499        repeat_char(&mut buf, '0', 42).unwrap();
2500        assert_eq!(buf.len(), 42);
2501        assert!(buf.chars().all(|c| c == '0'));
2502    }
2503
2504    // Creates individual test functions to make it easier to find which check failed.
2505    macro_rules! check_format_non_negative {
2506        ($denom:ident; $($test_name:ident, $val:literal, $format_string:literal, $expected:literal);* $(;)?) => {
2507            $(
2508                #[test]
2509                #[cfg(feature = "alloc")]
2510                fn $test_name() {
2511                    assert_eq!(format!($format_string, Amount::from_sat($val).display_in(Denomination::$denom)), $expected);
2512                    assert_eq!(format!($format_string, SignedAmount::from_sat($val as i64).display_in(Denomination::$denom)), $expected);
2513                }
2514            )*
2515        }
2516    }
2517
2518    macro_rules! check_format_non_negative_show_denom {
2519        ($denom:ident, $denom_suffix:literal; $($test_name:ident, $val:literal, $format_string:literal, $expected:literal);* $(;)?) => {
2520            $(
2521                #[test]
2522                #[cfg(feature = "alloc")]
2523                fn $test_name() {
2524                    assert_eq!(format!($format_string, Amount::from_sat($val).display_in(Denomination::$denom).show_denomination()), concat!($expected, $denom_suffix));
2525                    assert_eq!(format!($format_string, SignedAmount::from_sat($val as i64).display_in(Denomination::$denom).show_denomination()), concat!($expected, $denom_suffix));
2526                }
2527            )*
2528        }
2529    }
2530
2531    check_format_non_negative! {
2532        Satoshi;
2533        sat_check_fmt_non_negative_0, 0, "{}", "0";
2534        sat_check_fmt_non_negative_1, 0, "{:2}", " 0";
2535        sat_check_fmt_non_negative_2, 0, "{:02}", "00";
2536        sat_check_fmt_non_negative_3, 0, "{:.1}", "0.0";
2537        sat_check_fmt_non_negative_4, 0, "{:4.1}", " 0.0";
2538        sat_check_fmt_non_negative_5, 0, "{:04.1}", "00.0";
2539        sat_check_fmt_non_negative_6, 1, "{}", "1";
2540        sat_check_fmt_non_negative_7, 1, "{:2}", " 1";
2541        sat_check_fmt_non_negative_8, 1, "{:02}", "01";
2542        sat_check_fmt_non_negative_9, 1, "{:.1}", "1.0";
2543        sat_check_fmt_non_negative_10, 1, "{:4.1}", " 1.0";
2544        sat_check_fmt_non_negative_11, 1, "{:04.1}", "01.0";
2545        sat_check_fmt_non_negative_12, 10, "{}", "10";
2546        sat_check_fmt_non_negative_13, 10, "{:2}", "10";
2547        sat_check_fmt_non_negative_14, 10, "{:02}", "10";
2548        sat_check_fmt_non_negative_15, 10, "{:3}", " 10";
2549        sat_check_fmt_non_negative_16, 10, "{:03}", "010";
2550        sat_check_fmt_non_negative_17, 10, "{:.1}", "10.0";
2551        sat_check_fmt_non_negative_18, 10, "{:5.1}", " 10.0";
2552        sat_check_fmt_non_negative_19, 10, "{:05.1}", "010.0";
2553        sat_check_fmt_non_negative_20, 1, "{:<2}", "1 ";
2554        sat_check_fmt_non_negative_21, 1, "{:<02}", "01";
2555        sat_check_fmt_non_negative_22, 1, "{:<3.1}", "1.0";
2556        sat_check_fmt_non_negative_23, 1, "{:<4.1}", "1.0 ";
2557    }
2558
2559    check_format_non_negative_show_denom! {
2560        Satoshi, " satoshi";
2561        sat_check_fmt_non_negative_show_denom_0, 0, "{}", "0";
2562        sat_check_fmt_non_negative_show_denom_1, 0, "{:2}", "0";
2563        sat_check_fmt_non_negative_show_denom_2, 0, "{:02}", "0";
2564        sat_check_fmt_non_negative_show_denom_3, 0, "{:9}", "0";
2565        sat_check_fmt_non_negative_show_denom_4, 0, "{:09}", "0";
2566        sat_check_fmt_non_negative_show_denom_5, 0, "{:10}", " 0";
2567        sat_check_fmt_non_negative_show_denom_6, 0, "{:010}", "00";
2568        sat_check_fmt_non_negative_show_denom_7, 0, "{:.1}", "0.0";
2569        sat_check_fmt_non_negative_show_denom_8, 0, "{:11.1}", "0.0";
2570        sat_check_fmt_non_negative_show_denom_9, 0, "{:011.1}", "0.0";
2571        sat_check_fmt_non_negative_show_denom_10, 0, "{:12.1}", " 0.0";
2572        sat_check_fmt_non_negative_show_denom_11, 0, "{:012.1}", "00.0";
2573        sat_check_fmt_non_negative_show_denom_12, 1, "{}", "1";
2574        sat_check_fmt_non_negative_show_denom_13, 1, "{:10}", " 1";
2575        sat_check_fmt_non_negative_show_denom_14, 1, "{:010}", "01";
2576        sat_check_fmt_non_negative_show_denom_15, 1, "{:.1}", "1.0";
2577        sat_check_fmt_non_negative_show_denom_16, 1, "{:12.1}", " 1.0";
2578        sat_check_fmt_non_negative_show_denom_17, 1, "{:012.1}", "01.0";
2579        sat_check_fmt_non_negative_show_denom_18, 10, "{}", "10";
2580        sat_check_fmt_non_negative_show_denom_19, 10, "{:10}", "10";
2581        sat_check_fmt_non_negative_show_denom_20, 10, "{:010}", "10";
2582        sat_check_fmt_non_negative_show_denom_21, 10, "{:11}", " 10";
2583        sat_check_fmt_non_negative_show_denom_22, 10, "{:011}", "010";
2584    }
2585
2586    check_format_non_negative! {
2587        Bitcoin;
2588        btc_check_fmt_non_negative_0, 0, "{}", "0";
2589        btc_check_fmt_non_negative_1, 0, "{:2}", " 0";
2590        btc_check_fmt_non_negative_2, 0, "{:02}", "00";
2591        btc_check_fmt_non_negative_3, 0, "{:.1}", "0.0";
2592        btc_check_fmt_non_negative_4, 0, "{:4.1}", " 0.0";
2593        btc_check_fmt_non_negative_5, 0, "{:04.1}", "00.0";
2594        btc_check_fmt_non_negative_6, 1, "{}", "0.00000001";
2595        btc_check_fmt_non_negative_7, 1, "{:2}", "0.00000001";
2596        btc_check_fmt_non_negative_8, 1, "{:02}", "0.00000001";
2597        btc_check_fmt_non_negative_9, 1, "{:.1}", "0.00000001";
2598        btc_check_fmt_non_negative_10, 1, "{:11}", " 0.00000001";
2599        btc_check_fmt_non_negative_11, 1, "{:11.1}", " 0.00000001";
2600        btc_check_fmt_non_negative_12, 1, "{:011.1}", "00.00000001";
2601        btc_check_fmt_non_negative_13, 1, "{:.9}", "0.000000010";
2602        btc_check_fmt_non_negative_14, 1, "{:11.9}", "0.000000010";
2603        btc_check_fmt_non_negative_15, 1, "{:011.9}", "0.000000010";
2604        btc_check_fmt_non_negative_16, 1, "{:12.9}", " 0.000000010";
2605        btc_check_fmt_non_negative_17, 1, "{:012.9}", "00.000000010";
2606        btc_check_fmt_non_negative_18, 100_000_000, "{}", "1";
2607        btc_check_fmt_non_negative_19, 100_000_000, "{:2}", " 1";
2608        btc_check_fmt_non_negative_20, 100_000_000, "{:02}", "01";
2609        btc_check_fmt_non_negative_21, 100_000_000, "{:.1}", "1.0";
2610        btc_check_fmt_non_negative_22, 100_000_000, "{:4.1}", " 1.0";
2611        btc_check_fmt_non_negative_23, 100_000_000, "{:04.1}", "01.0";
2612        btc_check_fmt_non_negative_24, 110_000_000, "{}", "1.1";
2613        btc_check_fmt_non_negative_25, 100_000_001, "{}", "1.00000001";
2614        btc_check_fmt_non_negative_26, 100_000_001, "{:1}", "1.00000001";
2615        btc_check_fmt_non_negative_27, 100_000_001, "{:.1}", "1.00000001";
2616        btc_check_fmt_non_negative_28, 100_000_001, "{:10}", "1.00000001";
2617        btc_check_fmt_non_negative_29, 100_000_001, "{:11}", " 1.00000001";
2618        btc_check_fmt_non_negative_30, 100_000_001, "{:011}", "01.00000001";
2619        btc_check_fmt_non_negative_31, 100_000_001, "{:.8}", "1.00000001";
2620        btc_check_fmt_non_negative_32, 100_000_001, "{:.9}", "1.000000010";
2621        btc_check_fmt_non_negative_33, 100_000_001, "{:11.9}", "1.000000010";
2622        btc_check_fmt_non_negative_34, 100_000_001, "{:12.9}", " 1.000000010";
2623        btc_check_fmt_non_negative_35, 100_000_001, "{:012.9}", "01.000000010";
2624        btc_check_fmt_non_negative_36, 100_000_001, "{:+011.8}", "+1.00000001";
2625        btc_check_fmt_non_negative_37, 100_000_001, "{:+12.8}", " +1.00000001";
2626        btc_check_fmt_non_negative_38, 100_000_001, "{:+012.8}", "+01.00000001";
2627        btc_check_fmt_non_negative_39, 100_000_001, "{:+12.9}", "+1.000000010";
2628        btc_check_fmt_non_negative_40, 100_000_001, "{:+012.9}", "+1.000000010";
2629        btc_check_fmt_non_negative_41, 100_000_001, "{:+13.9}", " +1.000000010";
2630        btc_check_fmt_non_negative_42, 100_000_001, "{:+013.9}", "+01.000000010";
2631        btc_check_fmt_non_negative_43, 100_000_001, "{:<10}", "1.00000001";
2632        btc_check_fmt_non_negative_44, 100_000_001, "{:<11}", "1.00000001 ";
2633        btc_check_fmt_non_negative_45, 100_000_001, "{:<011}", "01.00000001";
2634        btc_check_fmt_non_negative_46, 100_000_001, "{:<11.9}", "1.000000010";
2635        btc_check_fmt_non_negative_47, 100_000_001, "{:<12.9}", "1.000000010 ";
2636        btc_check_fmt_non_negative_48, 100_000_001, "{:<12}", "1.00000001  ";
2637        btc_check_fmt_non_negative_49, 100_000_001, "{:^11}", "1.00000001 ";
2638        btc_check_fmt_non_negative_50, 100_000_001, "{:^11.9}", "1.000000010";
2639        btc_check_fmt_non_negative_51, 100_000_001, "{:^12.9}", "1.000000010 ";
2640        btc_check_fmt_non_negative_52, 100_000_001, "{:^12}", " 1.00000001 ";
2641        btc_check_fmt_non_negative_53, 100_000_001, "{:^12.9}", "1.000000010 ";
2642        btc_check_fmt_non_negative_54, 100_000_001, "{:^13.9}", " 1.000000010 ";
2643    }
2644
2645    check_format_non_negative_show_denom! {
2646        Bitcoin, " BTC";
2647        btc_check_fmt_non_negative_show_denom_0, 1, "{:14.1}", "0.00000001";
2648        btc_check_fmt_non_negative_show_denom_1, 1, "{:14.8}", "0.00000001";
2649        btc_check_fmt_non_negative_show_denom_2, 1, "{:15}", " 0.00000001";
2650        btc_check_fmt_non_negative_show_denom_3, 1, "{:015}", "00.00000001";
2651        btc_check_fmt_non_negative_show_denom_4, 1, "{:.9}", "0.000000010";
2652        btc_check_fmt_non_negative_show_denom_5, 1, "{:15.9}", "0.000000010";
2653        btc_check_fmt_non_negative_show_denom_6, 1, "{:16.9}", " 0.000000010";
2654        btc_check_fmt_non_negative_show_denom_7, 1, "{:016.9}", "00.000000010";
2655    }
2656
2657    check_format_non_negative_show_denom! {
2658        Bitcoin, " BTC ";
2659        btc_check_fmt_non_negative_show_denom_align_0, 1, "{:<15}", "0.00000001";
2660        btc_check_fmt_non_negative_show_denom_align_1, 1, "{:^15}", "0.00000001";
2661        btc_check_fmt_non_negative_show_denom_align_2, 1, "{:^16}", " 0.00000001";
2662    }
2663
2664    check_format_non_negative! {
2665        MilliSatoshi;
2666        msat_check_fmt_non_negative_0, 0, "{}", "0";
2667        msat_check_fmt_non_negative_1, 1, "{}", "1000";
2668        msat_check_fmt_non_negative_2, 1, "{:5}", " 1000";
2669        msat_check_fmt_non_negative_3, 1, "{:05}", "01000";
2670        msat_check_fmt_non_negative_4, 1, "{:.1}", "1000.0";
2671        msat_check_fmt_non_negative_5, 1, "{:6.1}", "1000.0";
2672        msat_check_fmt_non_negative_6, 1, "{:06.1}", "1000.0";
2673        msat_check_fmt_non_negative_7, 1, "{:7.1}", " 1000.0";
2674        msat_check_fmt_non_negative_8, 1, "{:07.1}", "01000.0";
2675    }
2676
2677    #[test]
2678    fn test_unsigned_signed_conversion() {
2679        let sa = SignedAmount::from_sat;
2680        let ua = Amount::from_sat;
2681
2682        assert_eq!(Amount::MAX.to_signed(), Err(OutOfRangeError::too_big(true)));
2683        assert_eq!(ua(i64::MAX as u64).to_signed(), Ok(sa(i64::MAX)));
2684        assert_eq!(ua(i64::MAX as u64 + 1).to_signed(), Err(OutOfRangeError::too_big(true)));
2685
2686        assert_eq!(sa(i64::MAX).to_unsigned(), Ok(ua(i64::MAX as u64)));
2687
2688        assert_eq!(sa(i64::MAX).to_unsigned().unwrap().to_signed(), Ok(sa(i64::MAX)));
2689    }
2690
2691    #[test]
2692    #[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin.
2693    fn from_str() {
2694        use ParseDenominationError::*;
2695
2696        use super::ParseAmountError as E;
2697
2698        assert_eq!(
2699            Amount::from_str("x BTC"),
2700            Err(InvalidCharacterError { invalid_char: 'x', position: 0 }.into())
2701        );
2702        assert_eq!(
2703            Amount::from_str("xBTC"),
2704            Err(Unknown(UnknownDenominationError("xBTC".into())).into()),
2705        );
2706        assert_eq!(
2707            Amount::from_str("5 BTC BTC"),
2708            Err(Unknown(UnknownDenominationError("BTC BTC".into())).into()),
2709        );
2710        assert_eq!(
2711            Amount::from_str("5BTC BTC"),
2712            Err(E::from(InvalidCharacterError { invalid_char: 'B', position: 1 }).into())
2713        );
2714        assert_eq!(
2715            Amount::from_str("5 5 BTC"),
2716            Err(Unknown(UnknownDenominationError("5 BTC".into())).into()),
2717        );
2718
2719        #[track_caller]
2720        fn ok_case(s: &str, expected: Amount) {
2721            assert_eq!(Amount::from_str(s).unwrap(), expected);
2722            assert_eq!(Amount::from_str(&s.replace(' ', "")).unwrap(), expected);
2723        }
2724
2725        #[track_caller]
2726        fn case(s: &str, expected: Result<Amount, impl Into<ParseError>>) {
2727            let expected = expected.map_err(Into::into);
2728            assert_eq!(Amount::from_str(s), expected);
2729            assert_eq!(Amount::from_str(&s.replace(' ', "")), expected);
2730        }
2731
2732        #[track_caller]
2733        fn ok_scase(s: &str, expected: SignedAmount) {
2734            assert_eq!(SignedAmount::from_str(s).unwrap(), expected);
2735            assert_eq!(SignedAmount::from_str(&s.replace(' ', "")).unwrap(), expected);
2736        }
2737
2738        #[track_caller]
2739        fn scase(s: &str, expected: Result<SignedAmount, impl Into<ParseError>>) {
2740            let expected = expected.map_err(Into::into);
2741            assert_eq!(SignedAmount::from_str(s), expected);
2742            assert_eq!(SignedAmount::from_str(&s.replace(' ', "")), expected);
2743        }
2744
2745        case("5 BCH", Err(Unknown(UnknownDenominationError("BCH".into()))));
2746
2747        case("-1 BTC", Err(OutOfRangeError::negative()));
2748        case("-0.0 BTC", Err(OutOfRangeError::negative()));
2749        case("0.123456789 BTC", Err(TooPreciseError { position: 10 }));
2750        scase("-0.1 satoshi", Err(TooPreciseError { position: 3 }));
2751        case("0.123456 mBTC", Err(TooPreciseError { position: 7 }));
2752        scase("-1.001 bits", Err(TooPreciseError { position: 5 }));
2753        scase("-200000000000 BTC", Err(OutOfRangeError::too_small()));
2754        case("18446744073709551616 sat", Err(OutOfRangeError::too_big(false)));
2755
2756        ok_case(".5 bits", Amount::from_sat(50));
2757        ok_scase("-.5 bits", SignedAmount::from_sat(-50));
2758        ok_case("0.00253583 BTC", Amount::from_sat(253583));
2759        ok_scase("-5 satoshi", SignedAmount::from_sat(-5));
2760        ok_case("0.10000000 BTC", Amount::from_sat(100_000_00));
2761        ok_scase("-100 bits", SignedAmount::from_sat(-10_000));
2762        #[cfg(feature = "alloc")]
2763        ok_scase(&format!("{} SAT", i64::MIN), SignedAmount::from_sat(i64::MIN));
2764    }
2765
2766    #[cfg(feature = "alloc")]
2767    #[test]
2768    #[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin.
2769    fn to_from_string_in() {
2770        use super::Denomination as D;
2771        let ua_str = Amount::from_str_in;
2772        let ua_sat = Amount::from_sat;
2773        let sa_str = SignedAmount::from_str_in;
2774        let sa_sat = SignedAmount::from_sat;
2775
2776        assert_eq!("0.5", Amount::from_sat(50).to_string_in(D::Bit));
2777        assert_eq!("-0.5", SignedAmount::from_sat(-50).to_string_in(D::Bit));
2778        assert_eq!("0.00253583", Amount::from_sat(253583).to_string_in(D::Bitcoin));
2779        assert_eq!("-5", SignedAmount::from_sat(-5).to_string_in(D::Satoshi));
2780        assert_eq!("0.1", Amount::from_sat(100_000_00).to_string_in(D::Bitcoin));
2781        assert_eq!("-100", SignedAmount::from_sat(-10_000).to_string_in(D::Bit));
2782        assert_eq!("2535830", Amount::from_sat(253583).to_string_in(D::NanoBitcoin));
2783        assert_eq!("-100000", SignedAmount::from_sat(-10_000).to_string_in(D::NanoBitcoin));
2784        assert_eq!("2535830000", Amount::from_sat(253583).to_string_in(D::PicoBitcoin));
2785        assert_eq!("-100000000", SignedAmount::from_sat(-10_000).to_string_in(D::PicoBitcoin));
2786
2787        assert_eq!("0.50", format!("{:.2}", Amount::from_sat(50).display_in(D::Bit)));
2788        assert_eq!("-0.50", format!("{:.2}", SignedAmount::from_sat(-50).display_in(D::Bit)));
2789        assert_eq!(
2790            "0.10000000",
2791            format!("{:.8}", Amount::from_sat(100_000_00).display_in(D::Bitcoin))
2792        );
2793        assert_eq!("-100.00", format!("{:.2}", SignedAmount::from_sat(-10_000).display_in(D::Bit)));
2794
2795        assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0)));
2796        assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500)));
2797        assert_eq!(
2798            ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit),
2799            Ok(ua_sat(21_000_000))
2800        );
2801        assert_eq!(
2802            ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
2803            Ok(ua_sat(1))
2804        );
2805        assert_eq!(
2806            ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
2807            Ok(ua_sat(1_000_000_000_000))
2808        );
2809        assert!(ua_str(&ua_sat(u64::MAX).to_string_in(D::MilliBitcoin), D::MilliBitcoin).is_ok());
2810
2811        assert_eq!(
2812            sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
2813            Ok(sa_sat(-1))
2814        );
2815
2816        assert_eq!(
2817            sa_str(&sa_sat(i64::MAX).to_string_in(D::Satoshi), D::MicroBitcoin),
2818            Err(OutOfRangeError::too_big(true).into())
2819        );
2820        // Test an overflow bug in `abs()`
2821        assert_eq!(
2822            sa_str(&sa_sat(i64::MIN).to_string_in(D::Satoshi), D::MicroBitcoin),
2823            Err(OutOfRangeError::too_small().into())
2824        );
2825
2826        assert_eq!(
2827            sa_str(&sa_sat(-1).to_string_in(D::NanoBitcoin), D::NanoBitcoin),
2828            Ok(sa_sat(-1))
2829        );
2830        assert_eq!(
2831            sa_str(&sa_sat(i64::MAX).to_string_in(D::Satoshi), D::NanoBitcoin),
2832            Err(TooPreciseError { position: 18 }.into())
2833        );
2834        assert_eq!(
2835            sa_str(&sa_sat(i64::MIN).to_string_in(D::Satoshi), D::NanoBitcoin),
2836            Err(TooPreciseError { position: 19 }.into())
2837        );
2838
2839        assert_eq!(
2840            sa_str(&sa_sat(-1).to_string_in(D::PicoBitcoin), D::PicoBitcoin),
2841            Ok(sa_sat(-1))
2842        );
2843        assert_eq!(
2844            sa_str(&sa_sat(i64::MAX).to_string_in(D::Satoshi), D::PicoBitcoin),
2845            Err(TooPreciseError { position: 18 }.into())
2846        );
2847        assert_eq!(
2848            sa_str(&sa_sat(i64::MIN).to_string_in(D::Satoshi), D::PicoBitcoin),
2849            Err(TooPreciseError { position: 19 }.into())
2850        );
2851    }
2852
2853    #[cfg(feature = "alloc")]
2854    #[test]
2855    fn to_string_with_denomination_from_str_roundtrip() {
2856        use ParseDenominationError::*;
2857
2858        use super::Denomination as D;
2859
2860        let amt = Amount::from_sat(42);
2861        let denom = Amount::to_string_with_denomination;
2862        assert_eq!(Amount::from_str(&denom(amt, D::Bitcoin)), Ok(amt));
2863        assert_eq!(Amount::from_str(&denom(amt, D::MilliBitcoin)), Ok(amt));
2864        assert_eq!(Amount::from_str(&denom(amt, D::MicroBitcoin)), Ok(amt));
2865        assert_eq!(Amount::from_str(&denom(amt, D::Bit)), Ok(amt));
2866        assert_eq!(Amount::from_str(&denom(amt, D::Satoshi)), Ok(amt));
2867        assert_eq!(Amount::from_str(&denom(amt, D::NanoBitcoin)), Ok(amt));
2868        assert_eq!(Amount::from_str(&denom(amt, D::MilliSatoshi)), Ok(amt));
2869        assert_eq!(Amount::from_str(&denom(amt, D::PicoBitcoin)), Ok(amt));
2870
2871        assert_eq!(
2872            Amount::from_str("42 satoshi BTC"),
2873            Err(Unknown(UnknownDenominationError("satoshi BTC".into())).into()),
2874        );
2875        assert_eq!(
2876            SignedAmount::from_str("-42 satoshi BTC"),
2877            Err(Unknown(UnknownDenominationError("satoshi BTC".into())).into()),
2878        );
2879    }
2880
2881    #[cfg(feature = "serde")]
2882    #[test]
2883    fn serde_as_sat() {
2884        #[derive(Serialize, Deserialize, PartialEq, Debug)]
2885        struct T {
2886            #[serde(with = "crate::amount::serde::as_sat")]
2887            pub amt: Amount,
2888            #[serde(with = "crate::amount::serde::as_sat")]
2889            pub samt: SignedAmount,
2890        }
2891
2892        serde_test::assert_tokens(
2893            &T { amt: Amount::from_sat(123456789), samt: SignedAmount::from_sat(-123456789) },
2894            &[
2895                serde_test::Token::Struct { name: "T", len: 2 },
2896                serde_test::Token::Str("amt"),
2897                serde_test::Token::U64(123456789),
2898                serde_test::Token::Str("samt"),
2899                serde_test::Token::I64(-123456789),
2900                serde_test::Token::StructEnd,
2901            ],
2902        );
2903    }
2904
2905    #[cfg(feature = "serde")]
2906    #[cfg(feature = "alloc")]
2907    #[test]
2908    #[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin.
2909    fn serde_as_btc() {
2910        use serde_json;
2911
2912        #[derive(Serialize, Deserialize, PartialEq, Debug)]
2913        struct T {
2914            #[serde(with = "crate::amount::serde::as_btc")]
2915            pub amt: Amount,
2916            #[serde(with = "crate::amount::serde::as_btc")]
2917            pub samt: SignedAmount,
2918        }
2919
2920        let orig = T {
2921            amt: Amount::from_sat(21_000_000__000_000_01),
2922            samt: SignedAmount::from_sat(-21_000_000__000_000_01),
2923        };
2924
2925        let json = "{\"amt\": 21000000.00000001, \
2926                    \"samt\": -21000000.00000001}";
2927        let t: T = serde_json::from_str(json).unwrap();
2928        assert_eq!(t, orig);
2929
2930        let value: serde_json::Value = serde_json::from_str(json).unwrap();
2931        assert_eq!(t, serde_json::from_value(value).unwrap());
2932
2933        // errors
2934        let t: Result<T, serde_json::Error> =
2935            serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}");
2936        assert!(t
2937            .unwrap_err()
2938            .to_string()
2939            .contains(&ParseAmountError::TooPrecise(TooPreciseError { position: 16 }).to_string()));
2940        let t: Result<T, serde_json::Error> = serde_json::from_str("{\"amt\": -1, \"samt\": 1}");
2941        assert!(t.unwrap_err().to_string().contains(&OutOfRangeError::negative().to_string()));
2942    }
2943
2944    #[cfg(feature = "serde")]
2945    #[cfg(feature = "alloc")]
2946    #[test]
2947    #[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin.
2948    fn serde_as_btc_opt() {
2949        use serde_json;
2950
2951        #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
2952        struct T {
2953            #[serde(default, with = "crate::amount::serde::as_btc::opt")]
2954            pub amt: Option<Amount>,
2955            #[serde(default, with = "crate::amount::serde::as_btc::opt")]
2956            pub samt: Option<SignedAmount>,
2957        }
2958
2959        let with = T {
2960            amt: Some(Amount::from_sat(2_500_000_00)),
2961            samt: Some(SignedAmount::from_sat(-2_500_000_00)),
2962        };
2963        let without = T { amt: None, samt: None };
2964
2965        // Test Roundtripping
2966        for s in [&with, &without].iter() {
2967            let v = serde_json::to_string(s).unwrap();
2968            let w: T = serde_json::from_str(&v).unwrap();
2969            assert_eq!(w, **s);
2970        }
2971
2972        let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
2973        assert_eq!(t, with);
2974
2975        let t: T = serde_json::from_str("{}").unwrap();
2976        assert_eq!(t, without);
2977
2978        let value_with: serde_json::Value =
2979            serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
2980        assert_eq!(with, serde_json::from_value(value_with).unwrap());
2981
2982        let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
2983        assert_eq!(without, serde_json::from_value(value_without).unwrap());
2984    }
2985
2986    #[cfg(feature = "serde")]
2987    #[cfg(feature = "alloc")]
2988    #[test]
2989    #[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin.
2990    fn serde_as_sat_opt() {
2991        use serde_json;
2992
2993        #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
2994        struct T {
2995            #[serde(default, with = "crate::amount::serde::as_sat::opt")]
2996            pub amt: Option<Amount>,
2997            #[serde(default, with = "crate::amount::serde::as_sat::opt")]
2998            pub samt: Option<SignedAmount>,
2999        }
3000
3001        let with = T {
3002            amt: Some(Amount::from_sat(2_500_000_00)),
3003            samt: Some(SignedAmount::from_sat(-2_500_000_00)),
3004        };
3005        let without = T { amt: None, samt: None };
3006
3007        // Test Roundtripping
3008        for s in [&with, &without].iter() {
3009            let v = serde_json::to_string(s).unwrap();
3010            let w: T = serde_json::from_str(&v).unwrap();
3011            assert_eq!(w, **s);
3012        }
3013
3014        let t: T = serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
3015        assert_eq!(t, with);
3016
3017        let t: T = serde_json::from_str("{}").unwrap();
3018        assert_eq!(t, without);
3019
3020        let value_with: serde_json::Value =
3021            serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
3022        assert_eq!(with, serde_json::from_value(value_with).unwrap());
3023
3024        let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
3025        assert_eq!(without, serde_json::from_value(value_without).unwrap());
3026    }
3027
3028    #[test]
3029    fn sum_amounts() {
3030        assert_eq!(Amount::from_sat(0), [].into_iter().sum::<Amount>());
3031        assert_eq!(SignedAmount::from_sat(0), [].into_iter().sum::<SignedAmount>());
3032
3033        let amounts = [Amount::from_sat(42), Amount::from_sat(1337), Amount::from_sat(21)];
3034        let sum = amounts.into_iter().sum::<Amount>();
3035        assert_eq!(Amount::from_sat(1400), sum);
3036
3037        let amounts =
3038            [SignedAmount::from_sat(-42), SignedAmount::from_sat(1337), SignedAmount::from_sat(21)];
3039        let sum = amounts.into_iter().sum::<SignedAmount>();
3040        assert_eq!(SignedAmount::from_sat(1316), sum);
3041    }
3042
3043    #[test]
3044    fn checked_sum_amounts() {
3045        assert_eq!(Some(Amount::from_sat(0)), [].into_iter().checked_sum());
3046        assert_eq!(Some(SignedAmount::from_sat(0)), [].into_iter().checked_sum());
3047
3048        let amounts = [Amount::from_sat(42), Amount::from_sat(1337), Amount::from_sat(21)];
3049        let sum = amounts.into_iter().checked_sum();
3050        assert_eq!(Some(Amount::from_sat(1400)), sum);
3051
3052        let amounts = [Amount::from_sat(u64::MAX), Amount::from_sat(1337), Amount::from_sat(21)];
3053        let sum = amounts.into_iter().checked_sum();
3054        assert_eq!(None, sum);
3055
3056        let amounts = [
3057            SignedAmount::from_sat(i64::MIN),
3058            SignedAmount::from_sat(-1),
3059            SignedAmount::from_sat(21),
3060        ];
3061        let sum = amounts.into_iter().checked_sum();
3062        assert_eq!(None, sum);
3063
3064        let amounts = [
3065            SignedAmount::from_sat(i64::MAX),
3066            SignedAmount::from_sat(1),
3067            SignedAmount::from_sat(21),
3068        ];
3069        let sum = amounts.into_iter().checked_sum();
3070        assert_eq!(None, sum);
3071
3072        let amounts =
3073            [SignedAmount::from_sat(42), SignedAmount::from_sat(3301), SignedAmount::from_sat(21)];
3074        let sum = amounts.into_iter().checked_sum();
3075        assert_eq!(Some(SignedAmount::from_sat(3364)), sum);
3076    }
3077
3078    #[test]
3079    fn denomination_string_acceptable_forms() {
3080        // Non-exhaustive list of valid forms.
3081        let valid = [
3082            "BTC", "btc", "mBTC", "mbtc", "uBTC", "ubtc", "SATOSHI", "satoshi", "SATOSHIS",
3083            "satoshis", "SAT", "sat", "SATS", "sats", "bit", "bits", "nBTC", "pBTC",
3084        ];
3085        for denom in valid.iter() {
3086            assert!(Denomination::from_str(denom).is_ok());
3087        }
3088    }
3089
3090    #[test]
3091    fn disallow_confusing_forms() {
3092        let confusing = ["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"];
3093        for denom in confusing.iter() {
3094            match Denomination::from_str(denom) {
3095                Ok(_) => panic!("from_str should error for {}", denom),
3096                Err(ParseDenominationError::PossiblyConfusing(_)) => {}
3097                Err(e) => panic!("unexpected error: {}", e),
3098            }
3099        }
3100    }
3101
3102    #[test]
3103    fn disallow_unknown_denomination() {
3104        // Non-exhaustive list of unknown forms.
3105        let unknown = ["NBTC", "UBTC", "ABC", "abc", "cBtC", "Sat", "Sats"];
3106        for denom in unknown.iter() {
3107            match Denomination::from_str(denom) {
3108                Ok(_) => panic!("from_str should error for {}", denom),
3109                Err(ParseDenominationError::Unknown(_)) => (),
3110                Err(e) => panic!("unexpected error: {}", e),
3111            }
3112        }
3113    }
3114
3115    #[test]
3116    #[cfg(feature = "alloc")]
3117    fn trailing_zeros_for_amount() {
3118        assert_eq!(format!("{}", Amount::ONE_SAT), "0.00000001 BTC");
3119        assert_eq!(format!("{}", Amount::ONE_BTC), "1 BTC");
3120        assert_eq!(format!("{}", Amount::from_sat(1)), "0.00000001 BTC");
3121        assert_eq!(format!("{}", Amount::from_sat(10)), "0.00000010 BTC");
3122        assert_eq!(format!("{:.2}", Amount::from_sat(10)), "0.0000001 BTC");
3123        assert_eq!(format!("{:.2}", Amount::from_sat(100)), "0.000001 BTC");
3124        assert_eq!(format!("{:.2}", Amount::from_sat(1000)), "0.00001 BTC");
3125        assert_eq!(format!("{:.2}", Amount::from_sat(10_000)), "0.0001 BTC");
3126        assert_eq!(format!("{:.2}", Amount::from_sat(100_000)), "0.001 BTC");
3127        assert_eq!(format!("{:.2}", Amount::from_sat(1_000_000)), "0.01 BTC");
3128        assert_eq!(format!("{:.2}", Amount::from_sat(10_000_000)), "0.10 BTC");
3129        assert_eq!(format!("{:.2}", Amount::from_sat(100_000_000)), "1.00 BTC");
3130        assert_eq!(format!("{}", Amount::from_sat(100_000_000)), "1 BTC");
3131        assert_eq!(format!("{}", Amount::from_sat(40_000_000_000)), "400 BTC");
3132        assert_eq!(format!("{:.10}", Amount::from_sat(100_000_000)), "1.0000000000 BTC");
3133        assert_eq!(format!("{}", Amount::from_sat(400_000_000_000_010)), "4000000.00000010 BTC");
3134        assert_eq!(format!("{}", Amount::from_sat(400_000_000_000_000)), "4000000 BTC");
3135    }
3136}