bitcoin/util/
amount.rs

1// To the extent possible under law, the author(s) have dedicated all
2// copyright and related and neighboring rights to this software to
3// the public domain worldwide. This software is distributed without
4// any warranty.
5//
6// You should have received a copy of the CC0 Public Domain Dedication
7// along with this software.
8// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
9//
10
11//! Amounts
12//!
13//! This module mainly introduces the [Amount] and [SignedAmount] types.
14//! We refer to the documentation on the types for more information.
15//!
16
17use std::default;
18use std::error;
19use std::fmt::{self, Write};
20use std::ops;
21use std::str::FromStr;
22use std::cmp::Ordering;
23
24/// A set of denominations in which amounts can be expressed.
25#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
26pub enum Denomination {
27    /// BTC
28    Bitcoin,
29    /// mBTC
30    MilliBitcoin,
31    /// uBTC
32    MicroBitcoin,
33    /// bits
34    Bit,
35    /// satoshi
36    Satoshi,
37    /// msat
38    MilliSatoshi,
39}
40
41impl Denomination {
42    /// The number of decimal places more than a satoshi.
43    fn precision(self) -> i32 {
44        match self {
45            Denomination::Bitcoin => -8,
46            Denomination::MilliBitcoin => -5,
47            Denomination::MicroBitcoin => -2,
48            Denomination::Bit => -2,
49            Denomination::Satoshi => 0,
50            Denomination::MilliSatoshi => 3,
51        }
52    }
53}
54
55impl fmt::Display for Denomination {
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        f.write_str(match *self {
58            Denomination::Bitcoin => "BTC",
59            Denomination::MilliBitcoin => "mBTC",
60            Denomination::MicroBitcoin => "uBTC",
61            Denomination::Bit => "bits",
62            Denomination::Satoshi => "satoshi",
63            Denomination::MilliSatoshi => "msat",
64        })
65    }
66}
67
68impl FromStr for Denomination {
69    type Err = ParseAmountError;
70
71    fn from_str(s: &str) -> Result<Self, Self::Err> {
72        match s {
73            "BTC" => Ok(Denomination::Bitcoin),
74            "mBTC" => Ok(Denomination::MilliBitcoin),
75            "uBTC" => Ok(Denomination::MicroBitcoin),
76            "bits" => Ok(Denomination::Bit),
77            "satoshi" => Ok(Denomination::Satoshi),
78            "sat" => Ok(Denomination::Satoshi),
79            "msat" => Ok(Denomination::MilliSatoshi),
80            d => Err(ParseAmountError::UnknownDenomination(d.to_owned())),
81        }
82    }
83}
84
85/// An error during amount parsing.
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum ParseAmountError {
88    /// Amount is negative.
89    Negative,
90    /// Amount is too big to fit inside the type.
91    TooBig,
92    /// Amount has higher precision than supported by the type.
93    TooPrecise,
94    /// Invalid number format.
95    InvalidFormat,
96    /// Input string was too large.
97    InputTooLarge,
98    /// Invalid character in input.
99    InvalidCharacter(char),
100    /// The denomination was unknown.
101    UnknownDenomination(String),
102}
103
104impl fmt::Display for ParseAmountError {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        match *self {
107            ParseAmountError::Negative => f.write_str("amount is negative"),
108            ParseAmountError::TooBig => f.write_str("amount is too big"),
109            ParseAmountError::TooPrecise => f.write_str("amount has a too high precision"),
110            ParseAmountError::InvalidFormat => f.write_str("invalid number format"),
111            ParseAmountError::InputTooLarge => f.write_str("input string was too large"),
112            ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
113            ParseAmountError::UnknownDenomination(ref d) => write!(f, "unknown denomination: {}",d),
114        }
115    }
116}
117
118impl error::Error for ParseAmountError {}
119
120fn is_too_precise(s: &str, precision: usize) -> bool {
121    s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0')
122}
123
124/// Parse decimal string in the given denomination into a satoshi value and a
125/// bool indicator for a negative amount.
126fn parse_signed_to_satoshi(
127    mut s: &str,
128    denom: Denomination,
129) -> Result<(bool, u64), ParseAmountError> {
130    if s.is_empty() {
131        return Err(ParseAmountError::InvalidFormat);
132    }
133    if s.len() > 50 {
134        return Err(ParseAmountError::InputTooLarge);
135    }
136
137    let is_negative = s.starts_with('-');
138    if is_negative {
139        if s.len() == 1 {
140            return Err(ParseAmountError::InvalidFormat);
141        }
142        s = &s[1..];
143    }
144
145    let max_decimals = {
146        // The difference in precision between native (satoshi)
147        // and desired denomination.
148        let precision_diff = -denom.precision();
149        if precision_diff < 0 {
150            // If precision diff is negative, this means we are parsing
151            // into a less precise amount. That is not allowed unless
152            // there are no decimals and the last digits are zeroes as
153            // many as the difference in precision.
154            let last_n = precision_diff.abs() as usize;
155            if is_too_precise(s, last_n) {
156                return Err(ParseAmountError::TooPrecise);
157            }
158            s = &s[0..s.len() - last_n];
159            0
160        } else {
161            precision_diff
162        }
163    };
164
165    let mut decimals = None;
166    let mut value: u64 = 0; // as satoshis
167    for c in s.chars() {
168        match c {
169            '0'..='9' => {
170                // Do `value = 10 * value + digit`, catching overflows.
171                match 10_u64.checked_mul(value) {
172                    None => return Err(ParseAmountError::TooBig),
173                    Some(val) => match val.checked_add((c as u8 - b'0') as u64) {
174                        None => return Err(ParseAmountError::TooBig),
175                        Some(val) => value = val,
176                    },
177                }
178                // Increment the decimal digit counter if past decimal.
179                decimals = match decimals {
180                    None => None,
181                    Some(d) if d < max_decimals => Some(d + 1),
182                    _ => return Err(ParseAmountError::TooPrecise),
183                };
184            }
185            '.' => match decimals {
186                None => decimals = Some(0),
187                // Double decimal dot.
188                _ => return Err(ParseAmountError::InvalidFormat),
189            },
190            c => return Err(ParseAmountError::InvalidCharacter(c)),
191        }
192    }
193
194    // Decimally shift left by `max_decimals - decimals`.
195    let scale_factor = max_decimals - decimals.unwrap_or(0);
196    for _ in 0..scale_factor {
197        value = match 10_u64.checked_mul(value) {
198            Some(v) => v,
199            None => return Err(ParseAmountError::TooBig),
200        };
201    }
202
203    Ok((is_negative, value))
204}
205
206/// Format the given satoshi amount in the given denomination.
207///
208/// Does not include the denomination.
209fn fmt_satoshi_in(
210    satoshi: u64,
211    negative: bool,
212    f: &mut dyn fmt::Write,
213    denom: Denomination,
214) -> fmt::Result {
215    if negative {
216        f.write_str("-")?;
217    }
218
219    let precision = denom.precision();
220    match precision.cmp(&0) {
221        Ordering::Greater => {
222            // add zeroes in the end
223            let width = precision as usize;
224            write!(f, "{}{:0width$}", satoshi, 0, width = width)?;
225        }
226        Ordering::Less => {
227            // need to inject a comma in the number
228            let nb_decimals = precision.abs() as usize;
229            let real = format!("{:0width$}", satoshi, width = nb_decimals);
230            if real.len() == nb_decimals {
231                write!(f, "0.{}", &real[real.len() - nb_decimals..])?;
232            } else {
233                write!(
234                    f,
235                    "{}.{}",
236                    &real[0..(real.len() - nb_decimals)],
237                    &real[real.len() - nb_decimals..]
238                )?;
239            }
240        }
241        Ordering::Equal => write!(f, "{}", satoshi)?,
242    }
243    Ok(())
244}
245
246/// Amount
247///
248/// The [Amount] type can be used to express Bitcoin amounts that supports
249/// arithmetic and conversion to various denominations.
250///
251///
252/// Warning!
253///
254/// This type implements several arithmetic operations from [std::ops].
255/// To prevent errors due to overflow or underflow when using these operations,
256/// it is advised to instead use the checked arithmetic methods whose names
257/// start with `checked_`.  The operations from [std::ops] that [Amount]
258/// implements will panic when overflow or underflow occurs.  Also note that
259/// since the internal representation of amounts is unsigned, subtracting below
260/// zero is considered an underflow and will cause a panic if you're not using
261/// the checked arithmetic methods.
262///
263#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
264pub struct Amount(u64);
265
266impl Amount {
267    /// The zero amount.
268    pub const ZERO: Amount = Amount(0);
269    /// Exactly one satoshi.
270    pub const ONE_SAT: Amount = Amount(1);
271    /// Exactly one bitcoin.
272    pub const ONE_BTC: Amount = Amount(100_000_000);
273
274    /// Create an [Amount] with satoshi precision and the given number of satoshis.
275    pub fn from_sat(satoshi: u64) -> Amount {
276        Amount(satoshi)
277    }
278
279    /// Get the number of satoshis in this [Amount].
280    pub fn as_sat(self) -> u64 {
281        self.0
282    }
283
284    /// The maximum value of an [Amount].
285    pub fn max_value() -> Amount {
286        Amount(u64::max_value())
287    }
288
289    /// The minimum value of an [Amount].
290    pub fn min_value() -> Amount {
291        Amount(u64::min_value())
292    }
293
294    /// Convert from a value expressing bitcoins to an [Amount].
295    pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> {
296        Amount::from_float_in(btc, Denomination::Bitcoin)
297    }
298
299    /// Parse a decimal string as a value in the given denomination.
300    ///
301    /// Note: This only parses the value string.  If you want to parse a value
302    /// with denomination, use [FromStr].
303    pub fn from_str_in(s: &str, denom: Denomination) -> Result<Amount, ParseAmountError> {
304        let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
305        if negative {
306            return Err(ParseAmountError::Negative);
307        }
308        if satoshi > i64::max_value() as u64 {
309            return Err(ParseAmountError::TooBig);
310        }
311        Ok(Amount::from_sat(satoshi))
312    }
313
314    /// Parses amounts with denomination suffix like they are produced with
315    /// [to_string_with_denomination] or with [fmt::Display].
316    /// If you want to parse only the amount without the denomination,
317    /// use [from_str_in].
318    pub fn from_str_with_denomination(s: &str) -> Result<Amount, ParseAmountError> {
319        let mut split = s.splitn(3, ' ');
320        let amt_str = split.next().unwrap();
321        let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?;
322        if split.next().is_some() {
323            return Err(ParseAmountError::InvalidFormat);
324        }
325
326        Ok(Amount::from_str_in(amt_str, denom_str.parse()?)?)
327    }
328
329    /// Express this [Amount] as a floating-point value in the given denomination.
330    ///
331    /// Please be aware of the risk of using floating-point numbers.
332    pub fn to_float_in(self, denom: Denomination) -> f64 {
333        f64::from_str(&self.to_string_in(denom)).unwrap()
334    }
335
336    /// Express this [Amount] as a floating-point value in Bitcoin.
337    ///
338    /// Equivalent to `to_float_in(Denomination::Bitcoin)`.
339    ///
340    /// Please be aware of the risk of using floating-point numbers.
341    pub fn as_btc(self) -> f64 {
342        self.to_float_in(Denomination::Bitcoin)
343    }
344
345    /// Convert this [Amount] in floating-point notation with a given
346    /// denomination.
347    /// Can return error if the amount is too big, too precise or negative.
348    ///
349    /// Please be aware of the risk of using floating-point numbers.
350    pub fn from_float_in(value: f64, denom: Denomination) -> Result<Amount, ParseAmountError> {
351        if value < 0.0 {
352            return Err(ParseAmountError::Negative);
353        }
354        // This is inefficient, but the safest way to deal with this. The parsing logic is safe.
355        // Any performance-critical application should not be dealing with floats.
356        Amount::from_str_in(&value.to_string(), denom)
357    }
358
359    /// Format the value of this [Amount] in the given denomination.
360    ///
361    /// Does not include the denomination.
362    pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
363        fmt_satoshi_in(self.as_sat(), false, f, denom)
364    }
365
366    /// Get a string number of this [Amount] in the given denomination.
367    ///
368    /// Does not include the denomination.
369    pub fn to_string_in(self, denom: Denomination) -> String {
370        let mut buf = String::new();
371        self.fmt_value_in(&mut buf, denom).unwrap();
372        buf
373    }
374
375    /// Get a formatted string of this [Amount] in the given denomination,
376    /// suffixed with the abbreviation for the denomination.
377    pub fn to_string_with_denomination(self, denom: Denomination) -> String {
378        let mut buf = String::new();
379        self.fmt_value_in(&mut buf, denom).unwrap();
380        write!(buf, " {}", denom).unwrap();
381        buf
382    }
383
384    // Some arithmetic that doesn't fit in `std::ops` traits.
385
386    /// Checked addition.
387    /// Returns [None] if overflow occurred.
388    pub fn checked_add(self, rhs: Amount) -> Option<Amount> {
389        self.0.checked_add(rhs.0).map(Amount)
390    }
391
392    /// Checked subtraction.
393    /// Returns [None] if overflow occurred.
394    pub fn checked_sub(self, rhs: Amount) -> Option<Amount> {
395        self.0.checked_sub(rhs.0).map(Amount)
396    }
397
398    /// Checked multiplication.
399    /// Returns [None] if overflow occurred.
400    pub fn checked_mul(self, rhs: u64) -> Option<Amount> {
401        self.0.checked_mul(rhs).map(Amount)
402    }
403
404    /// Checked integer division.
405    /// Be aware that integer division loses the remainder if no exact division
406    /// can be made.
407    /// Returns [None] if overflow occurred.
408    pub fn checked_div(self, rhs: u64) -> Option<Amount> {
409        self.0.checked_div(rhs).map(Amount)
410    }
411
412    /// Checked remainder.
413    /// Returns [None] if overflow occurred.
414    pub fn checked_rem(self, rhs: u64) -> Option<Amount> {
415        self.0.checked_rem(rhs).map(Amount)
416    }
417
418    /// Convert to a signed amount.
419    pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
420        if self.as_sat() > SignedAmount::max_value().as_sat() as u64 {
421            Err(ParseAmountError::TooBig)
422        } else {
423            Ok(SignedAmount::from_sat(self.as_sat() as i64))
424        }
425    }
426}
427
428impl default::Default for Amount {
429    fn default() -> Self {
430        Amount::ZERO
431    }
432}
433
434impl fmt::Debug for Amount {
435    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
436        write!(f, "Amount({} satoshi)", self.as_sat())
437    }
438}
439
440// No one should depend on a binding contract for Display for this type.
441// Just using Bitcoin denominated string.
442impl fmt::Display for Amount {
443    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444        self.fmt_value_in(f, Denomination::Bitcoin)?;
445        write!(f, " {}", Denomination::Bitcoin)
446    }
447}
448
449impl ops::Add for Amount {
450    type Output = Amount;
451
452    fn add(self, rhs: Amount) -> Self::Output {
453        self.checked_add(rhs).expect("Amount addition error")
454    }
455}
456
457impl ops::AddAssign for Amount {
458    fn add_assign(&mut self, other: Amount) {
459        *self = *self + other
460    }
461}
462
463impl ops::Sub for Amount {
464    type Output = Amount;
465
466    fn sub(self, rhs: Amount) -> Self::Output {
467        self.checked_sub(rhs).expect("Amount subtraction error")
468    }
469}
470
471impl ops::SubAssign for Amount {
472    fn sub_assign(&mut self, other: Amount) {
473        *self = *self - other
474    }
475}
476
477impl ops::Rem<u64> for Amount {
478    type Output = Amount;
479
480    fn rem(self, modulus: u64) -> Self {
481        self.checked_rem(modulus).expect("Amount remainder error")
482    }
483}
484
485impl ops::RemAssign<u64> for Amount {
486    fn rem_assign(&mut self, modulus: u64) {
487        *self = *self % modulus
488    }
489}
490
491impl ops::Mul<u64> for Amount {
492    type Output = Amount;
493
494    fn mul(self, rhs: u64) -> Self::Output {
495        self.checked_mul(rhs).expect("Amount multiplication error")
496    }
497}
498
499impl ops::MulAssign<u64> for Amount {
500    fn mul_assign(&mut self, rhs: u64) {
501        *self = *self * rhs
502    }
503}
504
505impl ops::Div<u64> for Amount {
506    type Output = Amount;
507
508    fn div(self, rhs: u64) -> Self::Output {
509        self.checked_div(rhs).expect("Amount division error")
510    }
511}
512
513impl ops::DivAssign<u64> for Amount {
514    fn div_assign(&mut self, rhs: u64) {
515        *self = *self / rhs
516    }
517}
518
519impl FromStr for Amount {
520    type Err = ParseAmountError;
521
522    fn from_str(s: &str) -> Result<Self, Self::Err> {
523        Amount::from_str_with_denomination(s)
524    }
525}
526
527/// SignedAmount
528///
529/// The [SignedAmount] type can be used to express Bitcoin amounts that supports
530/// arithmetic and conversion to various denominations.
531///
532///
533/// Warning!
534///
535/// This type implements several arithmetic operations from [std::ops].
536/// To prevent errors due to overflow or underflow when using these operations,
537/// it is advised to instead use the checked arithmetic methods whose names
538/// start with `checked_`.  The operations from [std::ops] that [Amount]
539/// implements will panic when overflow or underflow occurs.
540///
541#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
542pub struct SignedAmount(i64);
543
544impl SignedAmount {
545    /// The zero amount.
546    pub const ZERO: SignedAmount = SignedAmount(0);
547    /// Exactly one satoshi.
548    pub const ONE_SAT: SignedAmount = SignedAmount(1);
549    /// Exactly one bitcoin.
550    pub const ONE_BTC: SignedAmount = SignedAmount(100_000_000);
551
552    /// Create an [SignedAmount] with satoshi precision and the given number of satoshis.
553    pub fn from_sat(satoshi: i64) -> SignedAmount {
554        SignedAmount(satoshi)
555    }
556
557    /// Get the number of satoshis in this [SignedAmount].
558    pub fn as_sat(self) -> i64 {
559        self.0
560    }
561
562    /// The maximum value of an [SignedAmount].
563    pub fn max_value() -> SignedAmount {
564        SignedAmount(i64::max_value())
565    }
566
567    /// The minimum value of an [SignedAmount].
568    pub fn min_value() -> SignedAmount {
569        SignedAmount(i64::min_value())
570    }
571
572    /// Convert from a value expressing bitcoins to an [SignedAmount].
573    pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
574        SignedAmount::from_float_in(btc, Denomination::Bitcoin)
575    }
576
577    /// Parse a decimal string as a value in the given denomination.
578    ///
579    /// Note: This only parses the value string.  If you want to parse a value
580    /// with denomination, use [FromStr].
581    pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
582        let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
583        if satoshi > i64::max_value() as u64 {
584            return Err(ParseAmountError::TooBig);
585        }
586        Ok(match negative {
587            true => SignedAmount(-(satoshi as i64)),
588            false => SignedAmount(satoshi as i64),
589        })
590    }
591
592    /// Parses amounts with denomination suffix like they are produced with
593    /// [to_string_with_denomination] or with [fmt::Display].
594    /// If you want to parse only the amount without the denomination,
595    /// use [from_str_in].
596    pub fn from_str_with_denomination(s: &str) -> Result<SignedAmount, ParseAmountError> {
597        let mut split = s.splitn(3, ' ');
598        let amt_str = split.next().unwrap();
599        let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?;
600        if split.next().is_some() {
601            return Err(ParseAmountError::InvalidFormat);
602        }
603
604        Ok(SignedAmount::from_str_in(amt_str, denom_str.parse()?)?)
605    }
606
607    /// Express this [SignedAmount] as a floating-point value in the given denomination.
608    ///
609    /// Please be aware of the risk of using floating-point numbers.
610    pub fn to_float_in(self, denom: Denomination) -> f64 {
611        f64::from_str(&self.to_string_in(denom)).unwrap()
612    }
613
614    /// Express this [SignedAmount] as a floating-point value in Bitcoin.
615    ///
616    /// Equivalent to `to_float_in(Denomination::Bitcoin)`.
617    ///
618    /// Please be aware of the risk of using floating-point numbers.
619    pub fn as_btc(self) -> f64 {
620        self.to_float_in(Denomination::Bitcoin)
621    }
622
623    /// Convert this [SignedAmount] in floating-point notation with a given
624    /// denomination.
625    /// Can return error if the amount is too big, too precise or negative.
626    ///
627    /// Please be aware of the risk of using floating-point numbers.
628    pub fn from_float_in(
629        value: f64,
630        denom: Denomination,
631    ) -> Result<SignedAmount, ParseAmountError> {
632        // This is inefficient, but the safest way to deal with this. The parsing logic is safe.
633        // Any performance-critical application should not be dealing with floats.
634        SignedAmount::from_str_in(&value.to_string(), denom)
635    }
636
637    /// Format the value of this [SignedAmount] in the given denomination.
638    ///
639    /// Does not include the denomination.
640    pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
641        let sats = self.as_sat().checked_abs().map(|a: i64| a as u64).unwrap_or_else(|| {
642            // We could also hard code this into `9223372036854775808`
643            u64::max_value() - self.as_sat() as u64 +1
644        });
645        fmt_satoshi_in(sats, self.is_negative(), f, denom)
646    }
647
648    /// Get a string number of this [SignedAmount] in the given denomination.
649    ///
650    /// Does not include the denomination.
651    pub fn to_string_in(self, denom: Denomination) -> String {
652        let mut buf = String::new();
653        self.fmt_value_in(&mut buf, denom).unwrap();
654        buf
655    }
656
657    /// Get a formatted string of this [SignedAmount] in the given denomination,
658    /// suffixed with the abbreviation for the denomination.
659    pub fn to_string_with_denomination(self, denom: Denomination) -> String {
660        let mut buf = String::new();
661        self.fmt_value_in(&mut buf, denom).unwrap();
662        write!(buf, " {}", denom).unwrap();
663        buf
664    }
665
666    // Some arithmetic that doesn't fit in `std::ops` traits.
667
668    /// Get the absolute value of this [SignedAmount].
669    pub fn abs(self) -> SignedAmount {
670        SignedAmount(self.0.abs())
671    }
672
673    /// Returns a number representing sign of this [SignedAmount].
674    ///
675    /// - `0` if the amount is zero
676    /// - `1` if the amount is positive
677    /// - `-1` if the amount is negative
678    pub fn signum(self) -> i64 {
679        self.0.signum()
680    }
681
682    /// Returns `true` if this [SignedAmount] is positive and `false` if
683    /// this [SignedAmount] is zero or negative.
684    pub fn is_positive(self) -> bool {
685        self.0.is_positive()
686    }
687
688    /// Returns `true` if this [SignedAmount] is negative and `false` if
689    /// this [SignedAmount] is zero or positive.
690    pub fn is_negative(self) -> bool {
691        self.0.is_negative()
692    }
693
694
695    /// Get the absolute value of this [SignedAmount].
696    /// Returns [None] if overflow occurred. (`self == min_value()`)
697    pub fn checked_abs(self) -> Option<SignedAmount> {
698        self.0.checked_abs().map(SignedAmount)
699    }
700
701    /// Checked addition.
702    /// Returns [None] if overflow occurred.
703    pub fn checked_add(self, rhs: SignedAmount) -> Option<SignedAmount> {
704        self.0.checked_add(rhs.0).map(SignedAmount)
705    }
706
707    /// Checked subtraction.
708    /// Returns [None] if overflow occurred.
709    pub fn checked_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
710        self.0.checked_sub(rhs.0).map(SignedAmount)
711    }
712
713    /// Checked multiplication.
714    /// Returns [None] if overflow occurred.
715    pub fn checked_mul(self, rhs: i64) -> Option<SignedAmount> {
716        self.0.checked_mul(rhs).map(SignedAmount)
717    }
718
719    /// Checked integer division.
720    /// Be aware that integer division loses the remainder if no exact division
721    /// can be made.
722    /// Returns [None] if overflow occurred.
723    pub fn checked_div(self, rhs: i64) -> Option<SignedAmount> {
724        self.0.checked_div(rhs).map(SignedAmount)
725    }
726
727    /// Checked remainder.
728    /// Returns [None] if overflow occurred.
729    pub fn checked_rem(self, rhs: i64) -> Option<SignedAmount> {
730        self.0.checked_rem(rhs).map(SignedAmount)
731    }
732
733    /// Subtraction that doesn't allow negative [SignedAmount]s.
734    /// Returns [None] if either [self], [rhs] or the result is strictly negative.
735    pub fn positive_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
736        if self.is_negative() || rhs.is_negative() || rhs > self {
737            None
738        } else {
739            self.checked_sub(rhs)
740        }
741    }
742
743    /// Convert to an unsigned amount.
744    pub fn to_unsigned(self) -> Result<Amount, ParseAmountError> {
745        if self.is_negative() {
746            Err(ParseAmountError::Negative)
747        } else {
748            Ok(Amount::from_sat(self.as_sat() as u64))
749        }
750    }
751}
752
753impl default::Default for SignedAmount {
754    fn default() -> Self {
755        SignedAmount::ZERO
756    }
757}
758
759impl fmt::Debug for SignedAmount {
760    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
761        write!(f, "SignedAmount({} satoshi)", self.as_sat())
762    }
763}
764
765// No one should depend on a binding contract for Display for this type.
766// Just using Bitcoin denominated string.
767impl fmt::Display for SignedAmount {
768    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
769        self.fmt_value_in(f, Denomination::Bitcoin)?;
770        write!(f, " {}", Denomination::Bitcoin)
771    }
772}
773
774impl ops::Add for SignedAmount {
775    type Output = SignedAmount;
776
777    fn add(self, rhs: SignedAmount) -> Self::Output {
778        self.checked_add(rhs).expect("SignedAmount addition error")
779    }
780}
781
782impl ops::AddAssign for SignedAmount {
783    fn add_assign(&mut self, other: SignedAmount) {
784        *self = *self + other
785    }
786}
787
788impl ops::Sub for SignedAmount {
789    type Output = SignedAmount;
790
791    fn sub(self, rhs: SignedAmount) -> Self::Output {
792        self.checked_sub(rhs).expect("SignedAmount subtraction error")
793    }
794}
795
796impl ops::SubAssign for SignedAmount {
797    fn sub_assign(&mut self, other: SignedAmount) {
798        *self = *self - other
799    }
800}
801
802impl ops::Rem<i64> for SignedAmount {
803    type Output = SignedAmount;
804
805    fn rem(self, modulus: i64) -> Self {
806        self.checked_rem(modulus).expect("SignedAmount remainder error")
807    }
808}
809
810impl ops::RemAssign<i64> for SignedAmount {
811    fn rem_assign(&mut self, modulus: i64) {
812        *self = *self % modulus
813    }
814}
815
816impl ops::Mul<i64> for SignedAmount {
817    type Output = SignedAmount;
818
819    fn mul(self, rhs: i64) -> Self::Output {
820        self.checked_mul(rhs).expect("SignedAmount multiplication error")
821    }
822}
823
824impl ops::MulAssign<i64> for SignedAmount {
825    fn mul_assign(&mut self, rhs: i64) {
826        *self = *self * rhs
827    }
828}
829
830impl ops::Div<i64> for SignedAmount {
831    type Output = SignedAmount;
832
833    fn div(self, rhs: i64) -> Self::Output {
834        self.checked_div(rhs).expect("SignedAmount division error")
835    }
836}
837
838impl ops::DivAssign<i64> for SignedAmount {
839    fn div_assign(&mut self, rhs: i64) {
840        *self = *self / rhs
841    }
842}
843
844impl FromStr for SignedAmount {
845    type Err = ParseAmountError;
846
847    fn from_str(s: &str) -> Result<Self, Self::Err> {
848        SignedAmount::from_str_with_denomination(s)
849    }
850}
851
852#[cfg(feature = "serde")]
853pub mod serde {
854    // methods are implementation of a standardized serde-specific signature
855    #![allow(missing_docs)]
856
857    //! This module adds serde serialization and deserialization support for Amounts.
858    //! Since there is not a default way to serialize and deserialize Amounts, multiple
859    //! ways are supported and it's up to the user to decide which serialiation to use.
860    //! The provided modules can be used as follows:
861    //!
862    //! ```rust,ignore
863    //! use serde::{Serialize, Deserialize};
864    //! use bitcoin::Amount;
865    //!
866    //! #[derive(Serialize, Deserialize)]
867    //! pub struct HasAmount {
868    //!     #[serde(with = "bitcoin::util::amount::serde::as_btc")]
869    //!     pub amount: Amount,
870    //! }
871    //! ```
872
873    use serde::{Deserialize, Deserializer, Serialize, Serializer};
874    use util::amount::{Amount, Denomination, SignedAmount};
875
876    /// This trait is used only to avoid code duplication and naming collisions
877    /// of the different serde serialization crates.
878    pub trait SerdeAmount: Copy + Sized {
879        fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
880        fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
881        fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
882        fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
883    }
884
885    impl SerdeAmount for Amount {
886        fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
887            u64::serialize(&self.as_sat(), s)
888        }
889        fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
890            Ok(Amount::from_sat(u64::deserialize(d)?))
891        }
892        fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
893            f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
894        }
895        fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
896            use serde::de::Error;
897            Ok(Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
898        }
899    }
900
901    impl SerdeAmount for SignedAmount {
902        fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
903            i64::serialize(&self.as_sat(), s)
904        }
905        fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
906            Ok(SignedAmount::from_sat(i64::deserialize(d)?))
907        }
908        fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
909            f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
910        }
911        fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
912            use serde::de::Error;
913            Ok(SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
914        }
915    }
916
917    pub mod as_sat {
918        //! Serialize and deserialize [Amount] as real numbers denominated in satoshi.
919        //! Use with `#[serde(with = "amount::serde::as_sat")]`.
920
921        use serde::{Deserializer, Serializer};
922        use util::amount::serde::SerdeAmount;
923
924        pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
925            a.ser_sat(s)
926        }
927
928        pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
929            A::des_sat(d)
930        }
931
932        pub mod opt {
933            //! Serialize and deserialize [Optoin<Amount>] as real numbers denominated in satoshi.
934            //! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`.
935
936            use serde::{Deserializer, Serializer};
937            use util::amount::serde::SerdeAmount;
938
939            pub fn serialize<A: SerdeAmount, S: Serializer>(
940                a: &Option<A>,
941                s: S,
942            ) -> Result<S::Ok, S::Error> {
943                match *a {
944                    Some(a) => a.ser_sat(s),
945                    None => s.serialize_none(),
946                }
947            }
948
949            pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(
950                d: D,
951            ) -> Result<Option<A>, D::Error> {
952                Ok(Some(A::des_sat(d)?))
953            }
954        }
955    }
956
957    pub mod as_btc {
958        //! Serialize and deserialize [Amount] as JSON numbers denominated in BTC.
959        //! Use with `#[serde(with = "amount::serde::as_btc")]`.
960
961        use serde::{Deserializer, Serializer};
962        use util::amount::serde::SerdeAmount;
963
964        pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
965            a.ser_btc(s)
966        }
967
968        pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
969            A::des_btc(d)
970        }
971
972        pub mod opt {
973            //! Serialize and deserialize [Option<Amount>] as JSON numbers denominated in BTC.
974            //! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`.
975
976            use serde::{Deserializer, Serializer};
977            use util::amount::serde::SerdeAmount;
978
979            pub fn serialize<A: SerdeAmount, S: Serializer>(
980                a: &Option<A>,
981                s: S,
982            ) -> Result<S::Ok, S::Error> {
983                match *a {
984                    Some(a) => a.ser_btc(s),
985                    None => s.serialize_none(),
986                }
987            }
988
989            pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(
990                d: D,
991            ) -> Result<Option<A>, D::Error> {
992                Ok(Some(A::des_btc(d)?))
993            }
994        }
995    }
996}
997
998#[cfg(test)]
999mod tests {
1000    use super::*;
1001    use std::panic;
1002    use std::str::FromStr;
1003
1004    #[cfg(feature = "serde")]
1005    use serde_test;
1006
1007    #[test]
1008    fn add_sub_mul_div() {
1009        let sat = Amount::from_sat;
1010        let ssat = SignedAmount::from_sat;
1011
1012        assert_eq!(sat(15) + sat(15), sat(30));
1013        assert_eq!(sat(15) - sat(15), sat(0));
1014        assert_eq!(sat(14) * 3, sat(42));
1015        assert_eq!(sat(14) / 2, sat(7));
1016        assert_eq!(sat(14) % 3, sat(2));
1017        assert_eq!(ssat(15) - ssat(20), ssat(-5));
1018        assert_eq!(ssat(-14) * 3, ssat(-42));
1019        assert_eq!(ssat(-14) / 2, ssat(-7));
1020        assert_eq!(ssat(-14) % 3, ssat(-2));
1021
1022        let mut b = ssat(-5);
1023        b += ssat(13);
1024        assert_eq!(b, ssat(8));
1025        b -= ssat(3);
1026        assert_eq!(b, ssat(5));
1027        b *= 6;
1028        assert_eq!(b, ssat(30));
1029        b /= 3;
1030        assert_eq!(b, ssat(10));
1031        b %= 3;
1032        assert_eq!(b, ssat(1));
1033
1034        // panic on overflow
1035        let result = panic::catch_unwind(|| Amount::max_value() + Amount::from_sat(1));
1036        assert!(result.is_err());
1037        let result = panic::catch_unwind(|| Amount::from_sat(8446744073709551615) * 3);
1038        assert!(result.is_err());
1039    }
1040
1041    #[test]
1042    fn checked_arithmetic() {
1043        let sat = Amount::from_sat;
1044        let ssat = SignedAmount::from_sat;
1045
1046        assert_eq!(sat(42).checked_add(sat(1)), Some(sat(43)));
1047        assert_eq!(SignedAmount::max_value().checked_add(ssat(1)), None);
1048        assert_eq!(SignedAmount::min_value().checked_sub(ssat(1)), None);
1049        assert_eq!(Amount::max_value().checked_add(sat(1)), None);
1050        assert_eq!(Amount::min_value().checked_sub(sat(1)), None);
1051
1052        assert_eq!(sat(5).checked_sub(sat(3)), Some(sat(2)));
1053        assert_eq!(sat(5).checked_sub(sat(6)), None);
1054        assert_eq!(ssat(5).checked_sub(ssat(6)), Some(ssat(-1)));
1055        assert_eq!(sat(5).checked_rem(2), Some(sat(1)));
1056
1057        assert_eq!(sat(5).checked_div(2), Some(sat(2))); // integer division
1058        assert_eq!(ssat(-6).checked_div(2), Some(ssat(-3)));
1059
1060        assert_eq!(ssat(-5).positive_sub(ssat(3)), None);
1061        assert_eq!(ssat(5).positive_sub(ssat(-3)), None);
1062        assert_eq!(ssat(3).positive_sub(ssat(5)), None);
1063        assert_eq!(ssat(3).positive_sub(ssat(3)), Some(ssat(0)));
1064        assert_eq!(ssat(5).positive_sub(ssat(3)), Some(ssat(2)));
1065    }
1066
1067    #[test]
1068    fn floating_point() {
1069        use super::Denomination as D;
1070        let f = Amount::from_float_in;
1071        let sf = SignedAmount::from_float_in;
1072        let sat = Amount::from_sat;
1073        let ssat = SignedAmount::from_sat;
1074
1075        assert_eq!(f(11.22, D::Bitcoin), Ok(sat(1122000000)));
1076        assert_eq!(sf(-11.22, D::MilliBitcoin), Ok(ssat(-1122000)));
1077        assert_eq!(f(11.22, D::Bit), Ok(sat(1122)));
1078        assert_eq!(sf(-1000.0, D::MilliSatoshi), Ok(ssat(-1)));
1079        assert_eq!(f(0.0001234, D::Bitcoin), Ok(sat(12340)));
1080        assert_eq!(sf(-0.00012345, D::Bitcoin), Ok(ssat(-12345)));
1081
1082        assert_eq!(f(-100.0, D::MilliSatoshi), Err(ParseAmountError::Negative));
1083        assert_eq!(f(11.22, D::Satoshi), Err(ParseAmountError::TooPrecise));
1084        assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
1085        assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
1086        assert_eq!(f(42.123456781, D::Bitcoin), Err(ParseAmountError::TooPrecise));
1087        assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(ParseAmountError::TooBig));
1088        assert_eq!(f(18446744073709551617.0, D::Satoshi), Err(ParseAmountError::TooBig));
1089        assert_eq!(
1090            f(SignedAmount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi),
1091            Err(ParseAmountError::TooBig)
1092        );
1093        assert_eq!(
1094            f(Amount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi),
1095            Err(ParseAmountError::TooBig)
1096        );
1097
1098        let btc = move |f| SignedAmount::from_btc(f).unwrap();
1099        assert_eq!(btc(2.5).to_float_in(D::Bitcoin), 2.5);
1100        assert_eq!(btc(-2.5).to_float_in(D::MilliBitcoin), -2500.0);
1101        assert_eq!(btc(2.5).to_float_in(D::Satoshi), 250000000.0);
1102        assert_eq!(btc(-2.5).to_float_in(D::MilliSatoshi), -250000000000.0);
1103
1104        let btc = move |f| Amount::from_btc(f).unwrap();
1105        assert_eq!(&btc(0.0012).to_float_in(D::Bitcoin).to_string(), "0.0012")
1106    }
1107
1108    #[test]
1109    fn parsing() {
1110        use super::ParseAmountError as E;
1111        let btc = Denomination::Bitcoin;
1112        let sat = Denomination::Satoshi;
1113        let p = Amount::from_str_in;
1114        let sp = SignedAmount::from_str_in;
1115
1116        assert_eq!(p("x", btc), Err(E::InvalidCharacter('x')));
1117        assert_eq!(p("-", btc), Err(E::InvalidFormat));
1118        assert_eq!(sp("-", btc), Err(E::InvalidFormat));
1119        assert_eq!(p("-1.0x", btc), Err(E::InvalidCharacter('x')));
1120        assert_eq!(p("0.0 ", btc), Err(ParseAmountError::InvalidCharacter(' ')));
1121        assert_eq!(p("0.000.000", btc), Err(E::InvalidFormat));
1122        let more_than_max = format!("1{}", Amount::max_value());
1123        assert_eq!(p(&more_than_max, btc), Err(E::TooBig));
1124        assert_eq!(p("0.000000042", btc), Err(E::TooPrecise));
1125
1126        assert_eq!(p("1", btc), Ok(Amount::from_sat(1_000_000_00)));
1127        assert_eq!(sp("-.5", btc), Ok(SignedAmount::from_sat(-500_000_00)));
1128        assert_eq!(p("1.1", btc), Ok(Amount::from_sat(1_100_000_00)));
1129        assert_eq!(p("100", sat), Ok(Amount::from_sat(100)));
1130        assert_eq!(p("55", sat), Ok(Amount::from_sat(55)));
1131        assert_eq!(p("5500000000000000000", sat), Ok(Amount::from_sat(5_500_000_000_000_000_000)));
1132        // Should this even pass?
1133        assert_eq!(p("5500000000000000000.", sat), Ok(Amount::from_sat(5_500_000_000_000_000_000)));
1134        assert_eq!(
1135            p("12345678901.12345678", btc),
1136            Ok(Amount::from_sat(12_345_678_901__123_456_78))
1137        );
1138
1139        // make sure satoshi > i64::max_value() is checked.
1140        let amount = Amount::from_sat(i64::max_value() as u64);
1141        assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
1142        assert_eq!(Amount::from_str_in(&(amount+Amount(1)).to_string_in(sat), sat), Err(E::TooBig));
1143
1144        assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise));
1145        // exactly 50 chars.
1146        assert_eq!(p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin), Err(E::TooBig));
1147        // more than 50 chars.
1148        assert_eq!(p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin), Err(E::InputTooLarge));
1149    }
1150
1151    #[test]
1152    fn to_string() {
1153        use super::Denomination as D;
1154
1155        assert_eq!(Amount::ONE_BTC.to_string_in(D::Bitcoin), "1.00000000");
1156        assert_eq!(Amount::ONE_BTC.to_string_in(D::Satoshi), "100000000");
1157        assert_eq!(Amount::ONE_SAT.to_string_in(D::Bitcoin), "0.00000001");
1158        assert_eq!(SignedAmount::from_sat(-42).to_string_in(D::Bitcoin), "-0.00000042");
1159
1160        assert_eq!(Amount::ONE_BTC.to_string_with_denomination(D::Bitcoin), "1.00000000 BTC");
1161        assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::MilliSatoshi), "1000 msat");
1162        assert_eq!(
1163            SignedAmount::ONE_BTC.to_string_with_denomination(D::Satoshi),
1164            "100000000 satoshi"
1165        );
1166        assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::Bitcoin), "0.00000001 BTC");
1167        assert_eq!(
1168            SignedAmount::from_sat(-42).to_string_with_denomination(D::Bitcoin),
1169            "-0.00000042 BTC"
1170        );
1171    }
1172
1173    #[test]
1174    fn test_unsigned_signed_conversion() {
1175        use super::ParseAmountError as E;
1176        let sa = SignedAmount::from_sat;
1177        let ua = Amount::from_sat;
1178
1179        assert_eq!(Amount::max_value().to_signed(),  Err(E::TooBig));
1180        assert_eq!(ua(i64::max_value() as u64).to_signed(),  Ok(sa(i64::max_value())));
1181        assert_eq!(ua(0).to_signed(),  Ok(sa(0)));
1182        assert_eq!(ua(1).to_signed(), Ok( sa(1)));
1183        assert_eq!(ua(1).to_signed(),  Ok(sa(1)));
1184        assert_eq!(ua(i64::max_value() as u64 + 1).to_signed(),  Err(E::TooBig));
1185
1186        assert_eq!(sa(-1).to_unsigned(), Err(E::Negative));
1187        assert_eq!(sa(i64::max_value()).to_unsigned(), Ok(ua(i64::max_value() as u64)));
1188
1189        assert_eq!(sa(0).to_unsigned().unwrap().to_signed(), Ok(sa(0)));
1190        assert_eq!(sa(1).to_unsigned().unwrap().to_signed(), Ok(sa(1)));
1191        assert_eq!(sa(i64::max_value()).to_unsigned().unwrap().to_signed(), Ok(sa(i64::max_value())));
1192    }
1193
1194    #[test]
1195    fn from_str() {
1196        use super::ParseAmountError as E;
1197        let p = Amount::from_str;
1198        let sp = SignedAmount::from_str;
1199
1200        assert_eq!(p("x BTC"), Err(E::InvalidCharacter('x')));
1201        assert_eq!(p("5 BTC BTC"), Err(E::InvalidFormat));
1202        assert_eq!(p("5 5 BTC"), Err(E::InvalidFormat));
1203
1204        assert_eq!(p("5 BCH"), Err(E::UnknownDenomination("BCH".to_owned())));
1205
1206        assert_eq!(p("-1 BTC"), Err(E::Negative));
1207        assert_eq!(p("-0.0 BTC"), Err(E::Negative));
1208        assert_eq!(p("0.123456789 BTC"), Err(E::TooPrecise));
1209        assert_eq!(sp("-0.1 satoshi"), Err(E::TooPrecise));
1210        assert_eq!(p("0.123456 mBTC"), Err(E::TooPrecise));
1211        assert_eq!(sp("-1.001 bits"), Err(E::TooPrecise));
1212        assert_eq!(sp("-200000000000 BTC"), Err(E::TooBig));
1213        assert_eq!(p("18446744073709551616 sat"), Err(E::TooBig));
1214
1215        assert_eq!(sp("0 msat"), Err(E::TooPrecise));
1216        assert_eq!(sp("-0 msat"), Err(E::TooPrecise));
1217        assert_eq!(sp("000 msat"), Err(E::TooPrecise));
1218        assert_eq!(sp("-000 msat"), Err(E::TooPrecise));
1219        assert_eq!(p("0 msat"), Err(E::TooPrecise));
1220        assert_eq!(p("-0 msat"), Err(E::TooPrecise));
1221        assert_eq!(p("000 msat"), Err(E::TooPrecise));
1222        assert_eq!(p("-000 msat"), Err(E::TooPrecise));
1223
1224        assert_eq!(p(".5 bits"), Ok(Amount::from_sat(50)));
1225        assert_eq!(sp("-.5 bits"), Ok(SignedAmount::from_sat(-50)));
1226        assert_eq!(p("0.00253583 BTC"), Ok(Amount::from_sat(253583)));
1227        assert_eq!(sp("-5 satoshi"), Ok(SignedAmount::from_sat(-5)));
1228        assert_eq!(p("0.10000000 BTC"), Ok(Amount::from_sat(100_000_00)));
1229        assert_eq!(sp("-100 bits"), Ok(SignedAmount::from_sat(-10_000)));
1230    }
1231
1232    #[test]
1233    fn to_from_string_in() {
1234        use super::Denomination as D;
1235        let ua_str = Amount::from_str_in;
1236        let ua_sat = Amount::from_sat;
1237        let sa_str = SignedAmount::from_str_in;
1238        let sa_sat = SignedAmount::from_sat;
1239
1240        assert_eq!("0.50", Amount::from_sat(50).to_string_in(D::Bit));
1241        assert_eq!("-0.50", SignedAmount::from_sat(-50).to_string_in(D::Bit));
1242        assert_eq!("0.00253583", Amount::from_sat(253583).to_string_in(D::Bitcoin));
1243        assert_eq!("-5", SignedAmount::from_sat(-5).to_string_in(D::Satoshi));
1244        assert_eq!("0.10000000", Amount::from_sat(100_000_00).to_string_in(D::Bitcoin));
1245        assert_eq!("-100.00", SignedAmount::from_sat(-10_000).to_string_in(D::Bit));
1246
1247        assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0)));
1248        assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500)));
1249        assert_eq!(ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit), Ok(ua_sat(21_000_000)));
1250        assert_eq!(ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(ua_sat(1)));
1251        assert_eq!(ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Ok(ua_sat(1_000_000_000_000)));
1252        assert_eq!(ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin),  Err(ParseAmountError::TooBig));
1253
1254        assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(sa_sat(-1)));
1255
1256        assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
1257        // Test an overflow bug in `abs()`
1258        assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
1259
1260    }
1261
1262    #[test]
1263    fn to_string_with_denomination_from_str_roundtrip() {
1264        use super::Denomination as D;
1265        let amt = Amount::from_sat(42);
1266        let denom = Amount::to_string_with_denomination;
1267        assert_eq!(Amount::from_str(&denom(amt, D::Bitcoin)), Ok(amt));
1268        assert_eq!(Amount::from_str(&denom(amt, D::MilliBitcoin)), Ok(amt));
1269        assert_eq!(Amount::from_str(&denom(amt, D::MicroBitcoin)), Ok(amt));
1270        assert_eq!(Amount::from_str(&denom(amt, D::Bit)), Ok(amt));
1271        assert_eq!(Amount::from_str(&denom(amt, D::Satoshi)), Ok(amt));
1272        assert_eq!(Amount::from_str(&denom(amt, D::MilliSatoshi)), Ok(amt));
1273
1274        assert_eq!(Amount::from_str("42 satoshi BTC"), Err(ParseAmountError::InvalidFormat));
1275        assert_eq!(SignedAmount::from_str("-42 satoshi BTC"), Err(ParseAmountError::InvalidFormat));
1276    }
1277
1278    #[cfg(feature = "serde")]
1279    #[test]
1280    fn serde_as_sat() {
1281
1282        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1283        struct T {
1284            #[serde(with = "::util::amount::serde::as_sat")]
1285            pub amt: Amount,
1286            #[serde(with = "::util::amount::serde::as_sat")]
1287            pub samt: SignedAmount,
1288        }
1289
1290        serde_test::assert_tokens(
1291            &T {
1292                amt: Amount::from_sat(123456789),
1293                samt: SignedAmount::from_sat(-123456789),
1294            },
1295            &[
1296                serde_test::Token::Struct {
1297                    name: "T",
1298                    len: 2,
1299                },
1300                serde_test::Token::Str("amt"),
1301                serde_test::Token::U64(123456789),
1302                serde_test::Token::Str("samt"),
1303                serde_test::Token::I64(-123456789),
1304                serde_test::Token::StructEnd,
1305            ],
1306        );
1307    }
1308
1309    #[cfg(feature = "serde")]
1310    #[test]
1311    fn serde_as_btc() {
1312        use serde_json;
1313
1314        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1315        struct T {
1316            #[serde(with = "::util::amount::serde::as_btc")]
1317            pub amt: Amount,
1318            #[serde(with = "::util::amount::serde::as_btc")]
1319            pub samt: SignedAmount,
1320        }
1321
1322        let orig = T {
1323            amt: Amount::from_sat(21_000_000__000_000_01),
1324            samt: SignedAmount::from_sat(-21_000_000__000_000_01),
1325        };
1326
1327        let json = "{\"amt\": 21000000.00000001, \
1328                    \"samt\": -21000000.00000001}";
1329        let t: T = serde_json::from_str(&json).unwrap();
1330        assert_eq!(t, orig);
1331
1332        let value: serde_json::Value = serde_json::from_str(&json).unwrap();
1333        assert_eq!(t, serde_json::from_value(value).unwrap());
1334
1335        // errors
1336        let t: Result<T, serde_json::Error> =
1337            serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}");
1338        assert!(t.unwrap_err().to_string().contains(&ParseAmountError::TooPrecise.to_string()));
1339        let t: Result<T, serde_json::Error> = serde_json::from_str("{\"amt\": -1, \"samt\": 1}");
1340        assert!(t.unwrap_err().to_string().contains(&ParseAmountError::Negative.to_string()));
1341    }
1342
1343    #[cfg(feature = "serde")]
1344    #[test]
1345    fn serde_as_btc_opt() {
1346        use serde_json;
1347
1348        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1349        struct T {
1350            #[serde(default, with = "::util::amount::serde::as_btc::opt")]
1351            pub amt: Option<Amount>,
1352            #[serde(default, with = "::util::amount::serde::as_btc::opt")]
1353            pub samt: Option<SignedAmount>,
1354        }
1355
1356        let with = T {
1357            amt: Some(Amount::from_sat(2__500_000_00)),
1358            samt: Some(SignedAmount::from_sat(-2__500_000_00)),
1359        };
1360        let without = T {
1361            amt: None,
1362            samt: None,
1363        };
1364
1365        let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
1366        assert_eq!(t, with);
1367
1368        let t: T = serde_json::from_str("{}").unwrap();
1369        assert_eq!(t, without);
1370
1371        let value_with: serde_json::Value =
1372            serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
1373        assert_eq!(with, serde_json::from_value(value_with).unwrap());
1374
1375        let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
1376        assert_eq!(without, serde_json::from_value(value_without).unwrap());
1377    }
1378}