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