1use prelude::*;
18
19use core::{ops, default, str::FromStr, cmp::Ordering};
20use core::fmt::{self, Write};
21use core::convert::TryFrom;
22
23#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
25pub enum Denomination {
26 Bitcoin,
28 MilliBitcoin,
30 MicroBitcoin,
32 NanoBitcoin,
34 PicoBitcoin,
36 Bit,
38 Satoshi,
40 MilliSatoshi,
42}
43
44impl Denomination {
45 fn precision(self) -> i32 {
47 match self {
48 Denomination::Bitcoin => -8,
49 Denomination::MilliBitcoin => -5,
50 Denomination::MicroBitcoin => -2,
51 Denomination::NanoBitcoin => 1,
52 Denomination::PicoBitcoin => 4,
53 Denomination::Bit => -2,
54 Denomination::Satoshi => 0,
55 Denomination::MilliSatoshi => 3,
56 }
57 }
58}
59
60impl fmt::Display for Denomination {
61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 f.write_str(match *self {
63 Denomination::Bitcoin => "BTC",
64 Denomination::MilliBitcoin => "mBTC",
65 Denomination::MicroBitcoin => "uBTC",
66 Denomination::NanoBitcoin => "nBTC",
67 Denomination::PicoBitcoin => "pBTC",
68 Denomination::Bit => "bits",
69 Denomination::Satoshi => "satoshi",
70 Denomination::MilliSatoshi => "msat",
71 })
72 }
73}
74
75impl FromStr for Denomination {
76 type Err = ParseAmountError;
77
78 fn from_str(s: &str) -> Result<Self, Self::Err> {
86 use self::ParseAmountError::*;
87 use self::Denomination as D;
88
89 let starts_with_uppercase = || s.starts_with(char::is_uppercase);
90 match denomination_from_str(s) {
91 None => Err(UnknownDenomination(s.to_owned())),
92 Some(D::MilliBitcoin) | Some(D::PicoBitcoin) | Some(D::MilliSatoshi) if starts_with_uppercase() => {
93 Err(PossiblyConfusingDenomination(s.to_owned()))
94 }
95 Some(D::NanoBitcoin) | Some(D::MicroBitcoin) if starts_with_uppercase() => {
96 Err(UnknownDenomination(s.to_owned()))
97 }
98 Some(d) => Ok(d),
99 }
100 }
101}
102
103fn denomination_from_str(mut s: &str) -> Option<Denomination> {
104 if s.eq_ignore_ascii_case("BTC") {
105 return Some(Denomination::Bitcoin);
106 }
107
108 if s.eq_ignore_ascii_case("mBTC") {
109 return Some(Denomination::MilliBitcoin);
110 }
111
112 if s.eq_ignore_ascii_case("uBTC") {
113 return Some(Denomination::MicroBitcoin);
114 }
115
116 if s.eq_ignore_ascii_case("nBTC") {
117 return Some(Denomination::NanoBitcoin);
118 }
119
120 if s.eq_ignore_ascii_case("pBTC") {
121 return Some(Denomination::PicoBitcoin);
122 }
123
124 if s.ends_with('s') || s.ends_with('S') {
125 s = &s[..(s.len() - 1)];
126 }
127
128 if s.eq_ignore_ascii_case("bit") {
129 return Some(Denomination::Bit);
130 }
131 if s.eq_ignore_ascii_case("satoshi") {
132 return Some(Denomination::Satoshi);
133 }
134 if s.eq_ignore_ascii_case("sat") {
135 return Some(Denomination::Satoshi);
136 }
137
138 if s.eq_ignore_ascii_case("msat") {
139 return Some(Denomination::MilliSatoshi);
140 }
141
142 None
143}
144
145#[derive(Debug, Clone, PartialEq, Eq)]
147pub enum ParseAmountError {
148 Negative,
150 TooBig,
152 TooPrecise,
154 InvalidFormat,
156 InputTooLarge,
158 InvalidCharacter(char),
160 UnknownDenomination(String),
162 PossiblyConfusingDenomination(String)
164}
165
166impl fmt::Display for ParseAmountError {
167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 match *self {
169 ParseAmountError::Negative => f.write_str("amount is negative"),
170 ParseAmountError::TooBig => f.write_str("amount is too big"),
171 ParseAmountError::TooPrecise => f.write_str("amount has a too high precision"),
172 ParseAmountError::InvalidFormat => f.write_str("invalid number format"),
173 ParseAmountError::InputTooLarge => f.write_str("input string was too large"),
174 ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
175 ParseAmountError::UnknownDenomination(ref d) => write!(f, "unknown denomination: {}", d),
176 ParseAmountError::PossiblyConfusingDenomination(ref d) => {
177 let (letter, upper, lower) = match d.chars().next() {
178 Some('M') => ('M', "Mega", "milli"),
179 Some('P') => ('P', "Peta", "pico"),
180 _ => panic!("invalid error information"),
182 };
183 write!(f, "the '{}' at the beginning of {} should technically mean '{}' but that denomination is uncommon and maybe '{}' was intended", letter, d, upper, lower)
184 }
185 }
186 }
187}
188
189#[cfg(feature = "std")]
190#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
191impl ::std::error::Error for ParseAmountError {}
192
193fn is_too_precise(s: &str, precision: usize) -> bool {
194 s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0')
195}
196
197fn parse_signed_to_satoshi(
200 mut s: &str,
201 denom: Denomination,
202) -> Result<(bool, u64), ParseAmountError> {
203 if s.is_empty() {
204 return Err(ParseAmountError::InvalidFormat);
205 }
206 if s.len() > 50 {
207 return Err(ParseAmountError::InputTooLarge);
208 }
209
210 let is_negative = s.starts_with('-');
211 if is_negative {
212 if s.len() == 1 {
213 return Err(ParseAmountError::InvalidFormat);
214 }
215 s = &s[1..];
216 }
217
218 let max_decimals = {
219 let precision_diff = -denom.precision();
222 if precision_diff < 0 {
223 let last_n = precision_diff.abs() as usize;
228 if is_too_precise(s, last_n) {
229 return Err(ParseAmountError::TooPrecise);
230 }
231 s = &s[0..s.len() - last_n];
232 0
233 } else {
234 precision_diff
235 }
236 };
237
238 let mut decimals = None;
239 let mut value: u64 = 0; for c in s.chars() {
241 match c {
242 '0'..='9' => {
243 match 10_u64.checked_mul(value) {
245 None => return Err(ParseAmountError::TooBig),
246 Some(val) => match val.checked_add((c as u8 - b'0') as u64) {
247 None => return Err(ParseAmountError::TooBig),
248 Some(val) => value = val,
249 },
250 }
251 decimals = match decimals {
253 None => None,
254 Some(d) if d < max_decimals => Some(d + 1),
255 _ => return Err(ParseAmountError::TooPrecise),
256 };
257 }
258 '.' => match decimals {
259 None => decimals = Some(0),
260 _ => return Err(ParseAmountError::InvalidFormat),
262 },
263 c => return Err(ParseAmountError::InvalidCharacter(c)),
264 }
265 }
266
267 let scale_factor = max_decimals - decimals.unwrap_or(0);
269 for _ in 0..scale_factor {
270 value = match 10_u64.checked_mul(value) {
271 Some(v) => v,
272 None => return Err(ParseAmountError::TooBig),
273 };
274 }
275
276 Ok((is_negative, value))
277}
278
279fn fmt_satoshi_in(
283 satoshi: u64,
284 negative: bool,
285 f: &mut dyn fmt::Write,
286 denom: Denomination,
287) -> fmt::Result {
288 if negative {
289 f.write_str("-")?;
290 }
291
292 let precision = denom.precision();
293 match precision.cmp(&0) {
294 Ordering::Greater => {
295 let width = precision as usize;
297 write!(f, "{}{:0width$}", satoshi, 0, width = width)?;
298 }
299 Ordering::Less => {
300 let nb_decimals = precision.abs() as usize;
302 let real = format!("{:0width$}", satoshi, width = nb_decimals);
303 if real.len() == nb_decimals {
304 write!(f, "0.{}", &real[real.len() - nb_decimals..])?;
305 } else {
306 write!(
307 f,
308 "{}.{}",
309 &real[0..(real.len() - nb_decimals)],
310 &real[real.len() - nb_decimals..]
311 )?;
312 }
313 }
314 Ordering::Equal => write!(f, "{}", satoshi)?,
315 }
316 Ok(())
317}
318
319#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
337pub struct Amount(u64);
338
339impl Amount {
340 pub const ZERO: Amount = Amount(0);
342 pub const ONE_SAT: Amount = Amount(1);
344 pub const ONE_BTC: Amount = Amount(100_000_000);
346 pub const MAX_MONEY: Amount = Amount(21_000_000 * 100_000_000);
348
349 pub fn from_sat(satoshi: u64) -> Amount {
351 Amount(satoshi)
352 }
353
354 pub fn as_sat(self) -> u64 {
356 self.0
357 }
358
359 pub fn max_value() -> Amount {
361 Amount(u64::max_value())
362 }
363
364 pub fn min_value() -> Amount {
366 Amount(u64::min_value())
367 }
368
369 pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> {
371 Amount::from_float_in(btc, Denomination::Bitcoin)
372 }
373
374 pub fn from_str_in(s: &str, denom: Denomination) -> Result<Amount, ParseAmountError> {
379 let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
380 if negative {
381 return Err(ParseAmountError::Negative);
382 }
383 if satoshi > i64::max_value() as u64 {
384 return Err(ParseAmountError::TooBig);
385 }
386 Ok(Amount::from_sat(satoshi))
387 }
388
389 pub fn from_str_with_denomination(s: &str) -> Result<Amount, ParseAmountError> {
394 let mut split = s.splitn(3, ' ');
395 let amt_str = split.next().unwrap();
396 let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?;
397 if split.next().is_some() {
398 return Err(ParseAmountError::InvalidFormat);
399 }
400
401 Amount::from_str_in(amt_str, denom_str.parse()?)
402 }
403
404 pub fn to_float_in(self, denom: Denomination) -> f64 {
408 f64::from_str(&self.to_string_in(denom)).unwrap()
409 }
410
411 pub fn as_btc(self) -> f64 {
417 self.to_float_in(Denomination::Bitcoin)
418 }
419
420 pub fn from_float_in(value: f64, denom: Denomination) -> Result<Amount, ParseAmountError> {
426 if value < 0.0 {
427 return Err(ParseAmountError::Negative);
428 }
429 Amount::from_str_in(&value.to_string(), denom)
432 }
433
434 pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
438 fmt_satoshi_in(self.as_sat(), false, f, denom)
439 }
440
441 pub fn to_string_in(self, denom: Denomination) -> String {
445 let mut buf = String::new();
446 self.fmt_value_in(&mut buf, denom).unwrap();
447 buf
448 }
449
450 pub fn to_string_with_denomination(self, denom: Denomination) -> String {
453 let mut buf = String::new();
454 self.fmt_value_in(&mut buf, denom).unwrap();
455 write!(buf, " {}", denom).unwrap();
456 buf
457 }
458
459 pub fn checked_add(self, rhs: Amount) -> Option<Amount> {
464 self.0.checked_add(rhs.0).map(Amount)
465 }
466
467 pub fn checked_sub(self, rhs: Amount) -> Option<Amount> {
470 self.0.checked_sub(rhs.0).map(Amount)
471 }
472
473 pub fn checked_mul(self, rhs: u64) -> Option<Amount> {
476 self.0.checked_mul(rhs).map(Amount)
477 }
478
479 pub fn checked_div(self, rhs: u64) -> Option<Amount> {
484 self.0.checked_div(rhs).map(Amount)
485 }
486
487 pub fn checked_rem(self, rhs: u64) -> Option<Amount> {
490 self.0.checked_rem(rhs).map(Amount)
491 }
492
493 pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
495 if self.as_sat() > SignedAmount::max_value().as_sat() as u64 {
496 Err(ParseAmountError::TooBig)
497 } else {
498 Ok(SignedAmount::from_sat(self.as_sat() as i64))
499 }
500 }
501}
502
503impl default::Default for Amount {
504 fn default() -> Self {
505 Amount::ZERO
506 }
507}
508
509impl fmt::Debug for Amount {
510 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
511 write!(f, "Amount({:.8} BTC)", self.as_btc())
512 }
513}
514
515impl fmt::Display for Amount {
518 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
519 self.fmt_value_in(f, Denomination::Bitcoin)?;
520 write!(f, " {}", Denomination::Bitcoin)
521 }
522}
523
524impl ops::Add for Amount {
525 type Output = Amount;
526
527 fn add(self, rhs: Amount) -> Self::Output {
528 self.checked_add(rhs).expect("Amount addition error")
529 }
530}
531
532impl ops::AddAssign for Amount {
533 fn add_assign(&mut self, other: Amount) {
534 *self = *self + other
535 }
536}
537
538impl ops::Sub for Amount {
539 type Output = Amount;
540
541 fn sub(self, rhs: Amount) -> Self::Output {
542 self.checked_sub(rhs).expect("Amount subtraction error")
543 }
544}
545
546impl ops::SubAssign for Amount {
547 fn sub_assign(&mut self, other: Amount) {
548 *self = *self - other
549 }
550}
551
552impl ops::Rem<u64> for Amount {
553 type Output = Amount;
554
555 fn rem(self, modulus: u64) -> Self {
556 self.checked_rem(modulus).expect("Amount remainder error")
557 }
558}
559
560impl ops::RemAssign<u64> for Amount {
561 fn rem_assign(&mut self, modulus: u64) {
562 *self = *self % modulus
563 }
564}
565
566impl ops::Mul<u64> for Amount {
567 type Output = Amount;
568
569 fn mul(self, rhs: u64) -> Self::Output {
570 self.checked_mul(rhs).expect("Amount multiplication error")
571 }
572}
573
574impl ops::MulAssign<u64> for Amount {
575 fn mul_assign(&mut self, rhs: u64) {
576 *self = *self * rhs
577 }
578}
579
580impl ops::Div<u64> for Amount {
581 type Output = Amount;
582
583 fn div(self, rhs: u64) -> Self::Output {
584 self.checked_div(rhs).expect("Amount division error")
585 }
586}
587
588impl ops::DivAssign<u64> for Amount {
589 fn div_assign(&mut self, rhs: u64) {
590 *self = *self / rhs
591 }
592}
593
594impl FromStr for Amount {
595 type Err = ParseAmountError;
596
597 fn from_str(s: &str) -> Result<Self, Self::Err> {
598 Amount::from_str_with_denomination(s)
599 }
600}
601
602impl ::core::iter::Sum for Amount {
603 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
604 let sats: u64 = iter.map(|amt| amt.0).sum();
605 Amount::from_sat(sats)
606 }
607}
608
609#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
624pub struct SignedAmount(i64);
625
626impl SignedAmount {
627 pub const ZERO: SignedAmount = SignedAmount(0);
629 pub const ONE_SAT: SignedAmount = SignedAmount(1);
631 pub const ONE_BTC: SignedAmount = SignedAmount(100_000_000);
633 pub const MAX_MONEY: SignedAmount = SignedAmount(21_000_000 * 100_000_000);
635
636 pub fn from_sat(satoshi: i64) -> SignedAmount {
638 SignedAmount(satoshi)
639 }
640
641 pub fn as_sat(self) -> i64 {
643 self.0
644 }
645
646 pub fn max_value() -> SignedAmount {
648 SignedAmount(i64::max_value())
649 }
650
651 pub fn min_value() -> SignedAmount {
653 SignedAmount(i64::min_value())
654 }
655
656 pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
658 SignedAmount::from_float_in(btc, Denomination::Bitcoin)
659 }
660
661 pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
666 let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
667 if satoshi > i64::max_value() as u64 {
668 return Err(ParseAmountError::TooBig);
669 }
670 Ok(match negative {
671 true => SignedAmount(-(satoshi as i64)),
672 false => SignedAmount(satoshi as i64),
673 })
674 }
675
676 pub fn from_str_with_denomination(s: &str) -> Result<SignedAmount, ParseAmountError> {
681 let mut split = s.splitn(3, ' ');
682 let amt_str = split.next().unwrap();
683 let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?;
684 if split.next().is_some() {
685 return Err(ParseAmountError::InvalidFormat);
686 }
687
688 SignedAmount::from_str_in(amt_str, denom_str.parse()?)
689 }
690
691 pub fn to_float_in(self, denom: Denomination) -> f64 {
695 f64::from_str(&self.to_string_in(denom)).unwrap()
696 }
697
698 pub fn as_btc(self) -> f64 {
704 self.to_float_in(Denomination::Bitcoin)
705 }
706
707 pub fn from_float_in(
713 value: f64,
714 denom: Denomination,
715 ) -> Result<SignedAmount, ParseAmountError> {
716 SignedAmount::from_str_in(&value.to_string(), denom)
719 }
720
721 pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
725 let sats = self.as_sat().checked_abs().map(|a: i64| a as u64).unwrap_or_else(|| {
726 u64::max_value() - self.as_sat() as u64 +1
728 });
729 fmt_satoshi_in(sats, self.is_negative(), f, denom)
730 }
731
732 pub fn to_string_in(self, denom: Denomination) -> String {
736 let mut buf = String::new();
737 self.fmt_value_in(&mut buf, denom).unwrap();
738 buf
739 }
740
741 pub fn to_string_with_denomination(self, denom: Denomination) -> String {
744 let mut buf = String::new();
745 self.fmt_value_in(&mut buf, denom).unwrap();
746 write!(buf, " {}", denom).unwrap();
747 buf
748 }
749
750 pub fn abs(self) -> SignedAmount {
754 SignedAmount(self.0.abs())
755 }
756
757 pub fn signum(self) -> i64 {
763 self.0.signum()
764 }
765
766 pub fn is_positive(self) -> bool {
769 self.0.is_positive()
770 }
771
772 pub fn is_negative(self) -> bool {
775 self.0.is_negative()
776 }
777
778
779 pub fn checked_abs(self) -> Option<SignedAmount> {
782 self.0.checked_abs().map(SignedAmount)
783 }
784
785 pub fn checked_add(self, rhs: SignedAmount) -> Option<SignedAmount> {
788 self.0.checked_add(rhs.0).map(SignedAmount)
789 }
790
791 pub fn checked_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
794 self.0.checked_sub(rhs.0).map(SignedAmount)
795 }
796
797 pub fn checked_mul(self, rhs: i64) -> Option<SignedAmount> {
800 self.0.checked_mul(rhs).map(SignedAmount)
801 }
802
803 pub fn checked_div(self, rhs: i64) -> Option<SignedAmount> {
808 self.0.checked_div(rhs).map(SignedAmount)
809 }
810
811 pub fn checked_rem(self, rhs: i64) -> Option<SignedAmount> {
814 self.0.checked_rem(rhs).map(SignedAmount)
815 }
816
817 pub fn positive_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
820 if self.is_negative() || rhs.is_negative() || rhs > self {
821 None
822 } else {
823 self.checked_sub(rhs)
824 }
825 }
826
827 pub fn to_unsigned(self) -> Result<Amount, ParseAmountError> {
829 if self.is_negative() {
830 Err(ParseAmountError::Negative)
831 } else {
832 Ok(Amount::from_sat(self.as_sat() as u64))
833 }
834 }
835}
836
837impl default::Default for SignedAmount {
838 fn default() -> Self {
839 SignedAmount::ZERO
840 }
841}
842
843impl fmt::Debug for SignedAmount {
844 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
845 write!(f, "SignedAmount({:.8} BTC)", self.as_btc())
846 }
847}
848
849impl fmt::Display for SignedAmount {
852 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
853 self.fmt_value_in(f, Denomination::Bitcoin)?;
854 write!(f, " {}", Denomination::Bitcoin)
855 }
856}
857
858impl ops::Add for SignedAmount {
859 type Output = SignedAmount;
860
861 fn add(self, rhs: SignedAmount) -> Self::Output {
862 self.checked_add(rhs).expect("SignedAmount addition error")
863 }
864}
865
866impl ops::AddAssign for SignedAmount {
867 fn add_assign(&mut self, other: SignedAmount) {
868 *self = *self + other
869 }
870}
871
872impl ops::Sub for SignedAmount {
873 type Output = SignedAmount;
874
875 fn sub(self, rhs: SignedAmount) -> Self::Output {
876 self.checked_sub(rhs).expect("SignedAmount subtraction error")
877 }
878}
879
880impl ops::SubAssign for SignedAmount {
881 fn sub_assign(&mut self, other: SignedAmount) {
882 *self = *self - other
883 }
884}
885
886impl ops::Rem<i64> for SignedAmount {
887 type Output = SignedAmount;
888
889 fn rem(self, modulus: i64) -> Self {
890 self.checked_rem(modulus).expect("SignedAmount remainder error")
891 }
892}
893
894impl ops::RemAssign<i64> for SignedAmount {
895 fn rem_assign(&mut self, modulus: i64) {
896 *self = *self % modulus
897 }
898}
899
900impl ops::Mul<i64> for SignedAmount {
901 type Output = SignedAmount;
902
903 fn mul(self, rhs: i64) -> Self::Output {
904 self.checked_mul(rhs).expect("SignedAmount multiplication error")
905 }
906}
907
908impl ops::MulAssign<i64> for SignedAmount {
909 fn mul_assign(&mut self, rhs: i64) {
910 *self = *self * rhs
911 }
912}
913
914impl ops::Div<i64> for SignedAmount {
915 type Output = SignedAmount;
916
917 fn div(self, rhs: i64) -> Self::Output {
918 self.checked_div(rhs).expect("SignedAmount division error")
919 }
920}
921
922impl ops::DivAssign<i64> for SignedAmount {
923 fn div_assign(&mut self, rhs: i64) {
924 *self = *self / rhs
925 }
926}
927
928impl FromStr for SignedAmount {
929 type Err = ParseAmountError;
930
931 fn from_str(s: &str) -> Result<Self, Self::Err> {
932 SignedAmount::from_str_with_denomination(s)
933 }
934}
935
936impl ::core::iter::Sum for SignedAmount {
937 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
938 let sats: i64 = iter.map(|amt| amt.0).sum();
939 SignedAmount::from_sat(sats)
940 }
941}
942
943pub trait CheckedSum<R>: private::SumSeal<R> {
945 fn checked_sum(self) -> Option<R>;
948}
949
950impl<T> CheckedSum<Amount> for T where T: Iterator<Item=Amount> {
951 fn checked_sum(mut self) -> Option<Amount> {
952 let first = Some(self.next().unwrap_or_default());
953
954 self.fold(
955 first,
956 |acc, item| acc.and_then(|acc| acc.checked_add(item))
957 )
958 }
959}
960
961impl<T> CheckedSum<SignedAmount> for T where T: Iterator<Item=SignedAmount> {
962 fn checked_sum(mut self) -> Option<SignedAmount> {
963 let first = Some(self.next().unwrap_or_default());
964
965 self.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
966 }
967}
968
969mod private {
970 use ::{Amount, SignedAmount};
971
972 pub trait SumSeal<A> {}
974
975 impl<T> SumSeal<Amount> for T where T: Iterator<Item=Amount> {}
976 impl<T> SumSeal<SignedAmount> for T where T: Iterator<Item=SignedAmount> {}
977}
978
979#[cfg(feature = "serde")]
980#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
981pub mod serde {
982 #![allow(missing_docs)]
984
985 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1002 use util::amount::{Amount, Denomination, SignedAmount};
1003
1004 pub trait SerdeAmount: Copy + Sized {
1009 fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
1010 fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
1011 fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
1012 fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
1013 }
1014
1015 mod private {
1016 pub trait Sealed {}
1019 impl Sealed for super::Amount {}
1020 impl Sealed for super::SignedAmount {}
1021 }
1022
1023 pub trait SerdeAmountForOpt: Copy + Sized + SerdeAmount + private::Sealed {
1025 fn type_prefix() -> &'static str;
1026 fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
1027 fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
1028 }
1029
1030 impl SerdeAmount for Amount {
1031 fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1032 u64::serialize(&self.as_sat(), s)
1033 }
1034 fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
1035 Ok(Amount::from_sat(u64::deserialize(d)?))
1036 }
1037 fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1038 f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
1039 }
1040 fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
1041 use serde::de::Error;
1042 Ok(Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
1043 }
1044 }
1045
1046 impl SerdeAmountForOpt for Amount {
1047 fn type_prefix() -> &'static str {
1048 "u"
1049 }
1050 fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1051 s.serialize_some(&self.as_sat())
1052 }
1053 fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1054 s.serialize_some(&self.as_btc())
1055 }
1056 }
1057
1058 impl SerdeAmount for SignedAmount {
1059 fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1060 i64::serialize(&self.as_sat(), s)
1061 }
1062 fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
1063 Ok(SignedAmount::from_sat(i64::deserialize(d)?))
1064 }
1065 fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1066 f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
1067 }
1068 fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
1069 use serde::de::Error;
1070 Ok(SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
1071 }
1072 }
1073
1074 impl SerdeAmountForOpt for SignedAmount {
1075 fn type_prefix() -> &'static str {
1076 "i"
1077 }
1078 fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1079 s.serialize_some(&self.as_sat())
1080 }
1081 fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
1082 s.serialize_some(&self.as_btc())
1083 }
1084 }
1085
1086 pub mod as_sat {
1087 use serde::{Deserializer, Serializer};
1091 use util::amount::serde::SerdeAmount;
1092
1093 pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
1094 a.ser_sat(s)
1095 }
1096
1097 pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
1098 A::des_sat(d)
1099 }
1100
1101 pub mod opt {
1102 use serde::{Deserializer, Serializer, de};
1106 use util::amount::serde::SerdeAmountForOpt;
1107 use core::fmt;
1108 use core::marker::PhantomData;
1109
1110 pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
1111 a: &Option<A>,
1112 s: S,
1113 ) -> Result<S::Ok, S::Error> {
1114 match *a {
1115 Some(a) => a.ser_sat_opt(s),
1116 None => s.serialize_none(),
1117 }
1118 }
1119
1120 pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>(
1121 d: D,
1122 ) -> Result<Option<A>, D::Error> {
1123 struct VisitOptAmt<X>(PhantomData<X>);
1124
1125 impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt<X> {
1126 type Value = Option<X>;
1127
1128 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1129 write!(formatter, "An Option<{}64>", X::type_prefix())
1130 }
1131
1132 fn visit_none<E>(self) -> Result<Self::Value, E>
1133 where
1134 E: de::Error,
1135 {
1136 Ok(None)
1137 }
1138 fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
1139 where
1140 D: Deserializer<'de>,
1141 {
1142 Ok(Some(X::des_sat(d)?))
1143 }
1144 }
1145 d.deserialize_option(VisitOptAmt::<A>(PhantomData))
1146 }
1147 }
1148 }
1149
1150 pub mod as_btc {
1151 use serde::{Deserializer, Serializer};
1155 use util::amount::serde::SerdeAmount;
1156
1157 pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
1158 a.ser_btc(s)
1159 }
1160
1161 pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
1162 A::des_btc(d)
1163 }
1164
1165 pub mod opt {
1166 use serde::{Deserializer, Serializer, de};
1170 use util::amount::serde::SerdeAmountForOpt;
1171 use core::fmt;
1172 use core::marker::PhantomData;
1173
1174 pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
1175 a: &Option<A>,
1176 s: S,
1177 ) -> Result<S::Ok, S::Error> {
1178 match *a {
1179 Some(a) => a.ser_btc_opt(s),
1180 None => s.serialize_none(),
1181 }
1182 }
1183
1184 pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>(
1185 d: D,
1186 ) -> Result<Option<A>, D::Error> {
1187 struct VisitOptAmt<X>(PhantomData<X>);
1188
1189 impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt<X> {
1190 type Value = Option<X>;
1191
1192 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1193 write!(formatter, "An Option<f64>")
1194 }
1195
1196 fn visit_none<E>(self) -> Result<Self::Value, E>
1197 where
1198 E: de::Error,
1199 {
1200 Ok(None)
1201 }
1202 fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
1203 where
1204 D: Deserializer<'de>,
1205 {
1206 Ok(Some(X::des_btc(d)?))
1207 }
1208 }
1209 d.deserialize_option(VisitOptAmt::<A>(PhantomData))
1210 }
1211 }
1212 }
1213}
1214
1215#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1217#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
1218pub enum CoinAmount {
1219 Sats(u64),
1222 Btc(f64),
1225}
1226
1227#[cfg(feature = "serde")]
1229#[doc(hidden)]
1230#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
1231const _: () = {
1232 use std::marker::PhantomData;
1233 use std::fmt::Formatter;
1234 #[allow(rust_2018_idioms, clippy::useless_attribute)]
1235 extern crate serde as _serde;
1236 impl _serde::Serialize for CoinAmount {
1237 fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
1238 where
1239 __S: _serde::Serializer,
1240 {
1241 match *self {
1242 CoinAmount::Sats(ref __field0) => _serde::Serializer::serialize_newtype_variant(
1243 __serializer,
1244 "CoinAmount",
1245 0u32,
1246 "Sats",
1247 __field0,
1248 ),
1249 CoinAmount::Btc(ref __field0) => _serde::Serializer::serialize_newtype_variant(
1250 __serializer,
1251 "CoinAmount",
1252 1u32,
1253 "Btc",
1254 __field0,
1255 ),
1256 }
1257 }
1258 }
1259 impl<'de> _serde::Deserialize<'de> for CoinAmount {
1260 fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
1261 where
1262 __D: _serde::Deserializer<'de>,
1263 {
1264 #[allow(non_camel_case_types)]
1265 enum __Field {
1266 __field0,
1267 __field1,
1268 }
1269 struct __FieldVisitor;
1270 impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
1271 type Value = __Field;
1272 fn expecting(
1273 &self,
1274 __formatter: &mut Formatter,
1275 ) -> fmt::Result {
1276 Formatter::write_str(__formatter, "variant identifier")
1277 }
1278 fn visit_u64<__E>(self, __value: u64) -> Result<Self::Value, __E>
1279 where
1280 __E: _serde::de::Error,
1281 {
1282 match __value {
1283 0u64 => Ok(__Field::__field0),
1284 1u64 => Ok(__Field::__field1),
1285 _ => Err(_serde::de::Error::invalid_value(
1286 _serde::de::Unexpected::Unsigned(__value),
1287 &"variant index 0 <= i < 2",
1288 )),
1289 }
1290 }
1291 fn visit_str<__E>(self, __value: &str) -> Result<Self::Value, __E>
1292 where
1293 __E: _serde::de::Error,
1294 {
1295 match __value {
1296 "Sats" => Ok(__Field::__field0),
1297 "Btc" => Ok(__Field::__field1),
1298 _ => Err(_serde::de::Error::unknown_variant(
1299 __value, VARIANTS,
1300 )),
1301 }
1302 }
1303 fn visit_bytes<__E>(
1304 self,
1305 __value: &[u8],
1306 ) -> Result<Self::Value, __E>
1307 where
1308 __E: _serde::de::Error,
1309 {
1310 match __value {
1311 b"Sats" => Ok(__Field::__field0),
1312 b"Btc" => Ok(__Field::__field1),
1313 _ => {
1314 let __value = &String::from_utf8_lossy(__value);
1315 Err(_serde::de::Error::unknown_variant(
1316 __value, VARIANTS,
1317 ))
1318 }
1319 }
1320 }
1321 }
1322 impl<'de> _serde::Deserialize<'de> for __Field {
1323 #[inline]
1324 fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
1325 where
1326 __D: _serde::Deserializer<'de>,
1327 {
1328 _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
1329 }
1330 }
1331 struct __Visitor<'de> {
1332 marker: PhantomData<CoinAmount>,
1333 lifetime: PhantomData<&'de ()>,
1334 }
1335 impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
1336 type Value = CoinAmount;
1337 fn expecting(
1338 &self,
1339 __formatter: &mut Formatter,
1340 ) -> fmt::Result {
1341 Formatter::write_str(__formatter, "enum CoinAmount")
1342 }
1343 fn visit_enum<__A>(
1344 self,
1345 __data: __A,
1346 ) -> Result<Self::Value, __A::Error>
1347 where
1348 __A: _serde::de::EnumAccess<'de>,
1349 {
1350 match match _serde::de::EnumAccess::variant(__data) {
1351 Ok(__val) => __val,
1352 Err(__err) => {
1353 return Err(__err);
1354 }
1355 } {
1356 (__Field::__field0, __variant) => Result::map(
1357 _serde::de::VariantAccess::newtype_variant::<u64>(__variant),
1358 CoinAmount::Sats,
1359 ),
1360 (__Field::__field1, __variant) => Result::map(
1361 _serde::de::VariantAccess::newtype_variant::<f64>(__variant),
1362 CoinAmount::Btc,
1363 ),
1364 }
1365 }
1366 }
1367 const VARIANTS: &'static [&'static str] = &["Sats", "Btc"];
1368 _serde::Deserializer::deserialize_enum(
1369 __deserializer,
1370 "CoinAmount",
1371 VARIANTS,
1372 __Visitor {
1373 marker: PhantomData::<CoinAmount>,
1374 lifetime: PhantomData,
1375 },
1376 )
1377 }
1378 }
1379};
1380
1381impl TryFrom<CoinAmount> for Amount {
1382 type Error = ParseAmountError;
1383 fn try_from(value: CoinAmount) -> Result<Self, Self::Error> {
1384 match value {
1385 CoinAmount::Sats(x) => Ok(Amount::from_sat(x)),
1386 CoinAmount::Btc(y) => Amount::from_btc(y),
1387 }
1388 }
1389}
1390
1391impl From<Amount> for CoinAmount {
1392 fn from(a:Amount) -> Self {
1393 CoinAmount::Sats(a.as_sat())
1394 }
1395}
1396
1397
1398#[cfg(test)]
1399mod tests {
1400 use super::*;
1401 #[cfg(feature = "std")]
1402 use std::panic;
1403 use core::str::FromStr;
1404
1405 #[cfg(feature = "serde")]
1406 use serde_test;
1407
1408 #[test]
1409 fn add_sub_mul_div() {
1410 let sat = Amount::from_sat;
1411 let ssat = SignedAmount::from_sat;
1412
1413 assert_eq!(sat(15) + sat(15), sat(30));
1414 assert_eq!(sat(15) - sat(15), sat(0));
1415 assert_eq!(sat(14) * 3, sat(42));
1416 assert_eq!(sat(14) / 2, sat(7));
1417 assert_eq!(sat(14) % 3, sat(2));
1418 assert_eq!(ssat(15) - ssat(20), ssat(-5));
1419 assert_eq!(ssat(-14) * 3, ssat(-42));
1420 assert_eq!(ssat(-14) / 2, ssat(-7));
1421 assert_eq!(ssat(-14) % 3, ssat(-2));
1422
1423 let mut b = ssat(-5);
1424 b += ssat(13);
1425 assert_eq!(b, ssat(8));
1426 b -= ssat(3);
1427 assert_eq!(b, ssat(5));
1428 b *= 6;
1429 assert_eq!(b, ssat(30));
1430 b /= 3;
1431 assert_eq!(b, ssat(10));
1432 b %= 3;
1433 assert_eq!(b, ssat(1));
1434 }
1435
1436 #[cfg(feature = "std")]
1437 #[test]
1438 fn test_overflows() {
1439 let result = panic::catch_unwind(|| Amount::max_value() + Amount::from_sat(1));
1441 assert!(result.is_err());
1442 let result = panic::catch_unwind(|| Amount::from_sat(8446744073709551615) * 3);
1443 assert!(result.is_err());
1444 }
1445
1446 #[test]
1447 fn checked_arithmetic() {
1448 let sat = Amount::from_sat;
1449 let ssat = SignedAmount::from_sat;
1450
1451 assert_eq!(sat(42).checked_add(sat(1)), Some(sat(43)));
1452 assert_eq!(SignedAmount::max_value().checked_add(ssat(1)), None);
1453 assert_eq!(SignedAmount::min_value().checked_sub(ssat(1)), None);
1454 assert_eq!(Amount::max_value().checked_add(sat(1)), None);
1455 assert_eq!(Amount::min_value().checked_sub(sat(1)), None);
1456
1457 assert_eq!(sat(5).checked_sub(sat(3)), Some(sat(2)));
1458 assert_eq!(sat(5).checked_sub(sat(6)), None);
1459 assert_eq!(ssat(5).checked_sub(ssat(6)), Some(ssat(-1)));
1460 assert_eq!(sat(5).checked_rem(2), Some(sat(1)));
1461
1462 assert_eq!(sat(5).checked_div(2), Some(sat(2))); assert_eq!(ssat(-6).checked_div(2), Some(ssat(-3)));
1464
1465 assert_eq!(ssat(-5).positive_sub(ssat(3)), None);
1466 assert_eq!(ssat(5).positive_sub(ssat(-3)), None);
1467 assert_eq!(ssat(3).positive_sub(ssat(5)), None);
1468 assert_eq!(ssat(3).positive_sub(ssat(3)), Some(ssat(0)));
1469 assert_eq!(ssat(5).positive_sub(ssat(3)), Some(ssat(2)));
1470 }
1471
1472 #[test]
1473 fn floating_point() {
1474 use super::Denomination as D;
1475 let f = Amount::from_float_in;
1476 let sf = SignedAmount::from_float_in;
1477 let sat = Amount::from_sat;
1478 let ssat = SignedAmount::from_sat;
1479
1480 assert_eq!(f(11.22, D::Bitcoin), Ok(sat(1122000000)));
1481 assert_eq!(sf(-11.22, D::MilliBitcoin), Ok(ssat(-1122000)));
1482 assert_eq!(f(11.22, D::Bit), Ok(sat(1122)));
1483 assert_eq!(sf(-1000.0, D::MilliSatoshi), Ok(ssat(-1)));
1484 assert_eq!(f(0.0001234, D::Bitcoin), Ok(sat(12340)));
1485 assert_eq!(sf(-0.00012345, D::Bitcoin), Ok(ssat(-12345)));
1486
1487 assert_eq!(f(-100.0, D::MilliSatoshi), Err(ParseAmountError::Negative));
1488 assert_eq!(f(11.22, D::Satoshi), Err(ParseAmountError::TooPrecise));
1489 assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
1490 assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
1491 assert_eq!(f(42.123456781, D::Bitcoin), Err(ParseAmountError::TooPrecise));
1492 assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(ParseAmountError::TooBig));
1493 assert_eq!(f(18446744073709551617.0, D::Satoshi), Err(ParseAmountError::TooBig));
1494 assert_eq!(
1495 f(SignedAmount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi),
1496 Err(ParseAmountError::TooBig)
1497 );
1498 assert_eq!(
1499 f(Amount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi),
1500 Err(ParseAmountError::TooBig)
1501 );
1502
1503 let btc = move |f| SignedAmount::from_btc(f).unwrap();
1504 assert_eq!(btc(2.5).to_float_in(D::Bitcoin), 2.5);
1505 assert_eq!(btc(-2.5).to_float_in(D::MilliBitcoin), -2500.0);
1506 assert_eq!(btc(2.5).to_float_in(D::Satoshi), 250000000.0);
1507 assert_eq!(btc(-2.5).to_float_in(D::MilliSatoshi), -250000000000.0);
1508
1509 let btc = move |f| Amount::from_btc(f).unwrap();
1510 assert_eq!(&btc(0.0012).to_float_in(D::Bitcoin).to_string(), "0.0012")
1511 }
1512
1513 #[test]
1514 fn parsing() {
1515 use super::ParseAmountError as E;
1516 let btc = Denomination::Bitcoin;
1517 let sat = Denomination::Satoshi;
1518 let p = Amount::from_str_in;
1519 let sp = SignedAmount::from_str_in;
1520
1521 assert_eq!(p("x", btc), Err(E::InvalidCharacter('x')));
1522 assert_eq!(p("-", btc), Err(E::InvalidFormat));
1523 assert_eq!(sp("-", btc), Err(E::InvalidFormat));
1524 assert_eq!(p("-1.0x", btc), Err(E::InvalidCharacter('x')));
1525 assert_eq!(p("0.0 ", btc), Err(ParseAmountError::InvalidCharacter(' ')));
1526 assert_eq!(p("0.000.000", btc), Err(E::InvalidFormat));
1527 let more_than_max = format!("1{}", Amount::max_value());
1528 assert_eq!(p(&more_than_max, btc), Err(E::TooBig));
1529 assert_eq!(p("0.000000042", btc), Err(E::TooPrecise));
1530
1531 assert_eq!(p("1", btc), Ok(Amount::from_sat(1_000_000_00)));
1532 assert_eq!(sp("-.5", btc), Ok(SignedAmount::from_sat(-500_000_00)));
1533 assert_eq!(p("1.1", btc), Ok(Amount::from_sat(1_100_000_00)));
1534 assert_eq!(p("100", sat), Ok(Amount::from_sat(100)));
1535 assert_eq!(p("55", sat), Ok(Amount::from_sat(55)));
1536 assert_eq!(p("5500000000000000000", sat), Ok(Amount::from_sat(5_500_000_000_000_000_000)));
1537 assert_eq!(p("5500000000000000000.", sat), Ok(Amount::from_sat(5_500_000_000_000_000_000)));
1539 assert_eq!(
1540 p("12345678901.12345678", btc),
1541 Ok(Amount::from_sat(12_345_678_901__123_456_78))
1542 );
1543
1544 let amount = Amount::from_sat(i64::max_value() as u64);
1546 assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
1547 assert_eq!(Amount::from_str_in(&(amount+Amount(1)).to_string_in(sat), sat), Err(E::TooBig));
1548
1549 assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise));
1550 assert_eq!(p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin), Err(E::TooBig));
1552 assert_eq!(p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin), Err(E::InputTooLarge));
1554 }
1555
1556 #[test]
1557 fn to_string() {
1558 use super::Denomination as D;
1559
1560 assert_eq!(Amount::ONE_BTC.to_string_in(D::Bitcoin), "1.00000000");
1561 assert_eq!(Amount::ONE_BTC.to_string_in(D::Satoshi), "100000000");
1562 assert_eq!(Amount::ONE_SAT.to_string_in(D::Bitcoin), "0.00000001");
1563 assert_eq!(SignedAmount::from_sat(-42).to_string_in(D::Bitcoin), "-0.00000042");
1564
1565 assert_eq!(Amount::ONE_BTC.to_string_with_denomination(D::Bitcoin), "1.00000000 BTC");
1566 assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::MilliSatoshi), "1000 msat");
1567 assert_eq!(
1568 SignedAmount::ONE_BTC.to_string_with_denomination(D::Satoshi),
1569 "100000000 satoshi"
1570 );
1571 assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::Bitcoin), "0.00000001 BTC");
1572 assert_eq!(
1573 SignedAmount::from_sat(-42).to_string_with_denomination(D::Bitcoin),
1574 "-0.00000042 BTC"
1575 );
1576 }
1577
1578 #[test]
1579 fn test_unsigned_signed_conversion() {
1580 use super::ParseAmountError as E;
1581 let sa = SignedAmount::from_sat;
1582 let ua = Amount::from_sat;
1583
1584 assert_eq!(Amount::max_value().to_signed(), Err(E::TooBig));
1585 assert_eq!(ua(i64::max_value() as u64).to_signed(), Ok(sa(i64::max_value())));
1586 assert_eq!(ua(0).to_signed(), Ok(sa(0)));
1587 assert_eq!(ua(1).to_signed(), Ok( sa(1)));
1588 assert_eq!(ua(1).to_signed(), Ok(sa(1)));
1589 assert_eq!(ua(i64::max_value() as u64 + 1).to_signed(), Err(E::TooBig));
1590
1591 assert_eq!(sa(-1).to_unsigned(), Err(E::Negative));
1592 assert_eq!(sa(i64::max_value()).to_unsigned(), Ok(ua(i64::max_value() as u64)));
1593
1594 assert_eq!(sa(0).to_unsigned().unwrap().to_signed(), Ok(sa(0)));
1595 assert_eq!(sa(1).to_unsigned().unwrap().to_signed(), Ok(sa(1)));
1596 assert_eq!(sa(i64::max_value()).to_unsigned().unwrap().to_signed(), Ok(sa(i64::max_value())));
1597 }
1598
1599 #[test]
1600 fn from_str() {
1601 use super::ParseAmountError as E;
1602 let p = Amount::from_str;
1603 let sp = SignedAmount::from_str;
1604
1605 assert_eq!(p("x BTC"), Err(E::InvalidCharacter('x')));
1606 assert_eq!(p("5 BTC BTC"), Err(E::InvalidFormat));
1607 assert_eq!(p("5 5 BTC"), Err(E::InvalidFormat));
1608
1609 assert_eq!(p("5 BCH"), Err(E::UnknownDenomination("BCH".to_owned())));
1610
1611 assert_eq!(p("-1 BTC"), Err(E::Negative));
1612 assert_eq!(p("-0.0 BTC"), Err(E::Negative));
1613 assert_eq!(p("0.123456789 BTC"), Err(E::TooPrecise));
1614 assert_eq!(sp("-0.1 satoshi"), Err(E::TooPrecise));
1615 assert_eq!(p("0.123456 mBTC"), Err(E::TooPrecise));
1616 assert_eq!(sp("-1.001 bits"), Err(E::TooPrecise));
1617 assert_eq!(sp("-200000000000 BTC"), Err(E::TooBig));
1618 assert_eq!(p("18446744073709551616 sat"), Err(E::TooBig));
1619
1620 assert_eq!(sp("0 msat"), Err(E::TooPrecise));
1621 assert_eq!(sp("-0 msat"), Err(E::TooPrecise));
1622 assert_eq!(sp("000 msat"), Err(E::TooPrecise));
1623 assert_eq!(sp("-000 msat"), Err(E::TooPrecise));
1624 assert_eq!(p("0 msat"), Err(E::TooPrecise));
1625 assert_eq!(p("-0 msat"), Err(E::TooPrecise));
1626 assert_eq!(p("000 msat"), Err(E::TooPrecise));
1627 assert_eq!(p("-000 msat"), Err(E::TooPrecise));
1628
1629 assert_eq!(p(".5 bits"), Ok(Amount::from_sat(50)));
1630 assert_eq!(sp("-.5 bits"), Ok(SignedAmount::from_sat(-50)));
1631 assert_eq!(p("0.00253583 BTC"), Ok(Amount::from_sat(253583)));
1632 assert_eq!(sp("-5 satoshi"), Ok(SignedAmount::from_sat(-5)));
1633 assert_eq!(p("0.10000000 BTC"), Ok(Amount::from_sat(100_000_00)));
1634 assert_eq!(sp("-100 bits"), Ok(SignedAmount::from_sat(-10_000)));
1635 }
1636
1637 #[test]
1638 fn to_from_string_in() {
1639 use super::Denomination as D;
1640 let ua_str = Amount::from_str_in;
1641 let ua_sat = Amount::from_sat;
1642 let sa_str = SignedAmount::from_str_in;
1643 let sa_sat = SignedAmount::from_sat;
1644
1645 assert_eq!("0.50", Amount::from_sat(50).to_string_in(D::Bit));
1646 assert_eq!("-0.50", SignedAmount::from_sat(-50).to_string_in(D::Bit));
1647 assert_eq!("0.00253583", Amount::from_sat(253583).to_string_in(D::Bitcoin));
1648 assert_eq!("-5", SignedAmount::from_sat(-5).to_string_in(D::Satoshi));
1649 assert_eq!("0.10000000", Amount::from_sat(100_000_00).to_string_in(D::Bitcoin));
1650 assert_eq!("-100.00", SignedAmount::from_sat(-10_000).to_string_in(D::Bit));
1651 assert_eq!("2535830", Amount::from_sat(253583).to_string_in(D::NanoBitcoin));
1652 assert_eq!("-100000", SignedAmount::from_sat(-10_000).to_string_in(D::NanoBitcoin));
1653 assert_eq!("2535830000", Amount::from_sat(253583).to_string_in(D::PicoBitcoin));
1654 assert_eq!("-100000000", SignedAmount::from_sat(-10_000).to_string_in(D::PicoBitcoin));
1655
1656
1657
1658 assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0)));
1659 assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500)));
1660 assert_eq!(ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit), Ok(ua_sat(21_000_000)));
1661 assert_eq!(ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(ua_sat(1)));
1662 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)));
1663 assert_eq!(ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Err(ParseAmountError::TooBig));
1664
1665 assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(sa_sat(-1)));
1666
1667 assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
1668 assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
1670
1671 assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::NanoBitcoin), D::NanoBitcoin), Ok(sa_sat(-1)));
1672 assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::NanoBitcoin), Err(ParseAmountError::TooPrecise));
1673 assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::NanoBitcoin), Err(ParseAmountError::TooPrecise));
1674
1675 assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::PicoBitcoin), D::PicoBitcoin), Ok(sa_sat(-1)));
1676 assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::PicoBitcoin), Err(ParseAmountError::TooPrecise));
1677 assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::PicoBitcoin), Err(ParseAmountError::TooPrecise));
1678
1679
1680 }
1681
1682 #[test]
1683 fn to_string_with_denomination_from_str_roundtrip() {
1684 use super::Denomination as D;
1685 let amt = Amount::from_sat(42);
1686 let denom = Amount::to_string_with_denomination;
1687 assert_eq!(Amount::from_str(&denom(amt, D::Bitcoin)), Ok(amt));
1688 assert_eq!(Amount::from_str(&denom(amt, D::MilliBitcoin)), Ok(amt));
1689 assert_eq!(Amount::from_str(&denom(amt, D::MicroBitcoin)), Ok(amt));
1690 assert_eq!(Amount::from_str(&denom(amt, D::Bit)), Ok(amt));
1691 assert_eq!(Amount::from_str(&denom(amt, D::Satoshi)), Ok(amt));
1692 assert_eq!(Amount::from_str(&denom(amt, D::NanoBitcoin)), Ok(amt));
1693 assert_eq!(Amount::from_str(&denom(amt, D::MilliSatoshi)), Ok(amt));
1694 assert_eq!(Amount::from_str(&denom(amt, D::PicoBitcoin)), Ok(amt));
1695
1696 assert_eq!(Amount::from_str("42 satoshi BTC"), Err(ParseAmountError::InvalidFormat));
1697 assert_eq!(SignedAmount::from_str("-42 satoshi BTC"), Err(ParseAmountError::InvalidFormat));
1698 }
1699
1700 #[cfg(feature = "serde")]
1701 #[test]
1702 fn serde_as_sat() {
1703
1704 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1705 struct T {
1706 #[serde(with = "::util::amount::serde::as_sat")]
1707 pub amt: Amount,
1708 #[serde(with = "::util::amount::serde::as_sat")]
1709 pub samt: SignedAmount,
1710 }
1711
1712 serde_test::assert_tokens(
1713 &T {
1714 amt: Amount::from_sat(123456789),
1715 samt: SignedAmount::from_sat(-123456789),
1716 },
1717 &[
1718 serde_test::Token::Struct { name: "T", len: 2 },
1719 serde_test::Token::Str("amt"),
1720 serde_test::Token::U64(123456789),
1721 serde_test::Token::Str("samt"),
1722 serde_test::Token::I64(-123456789),
1723 serde_test::Token::StructEnd,
1724 ],
1725 );
1726 }
1727
1728 #[cfg(feature = "serde")]
1729 #[test]
1730 fn serde_as_btc() {
1731 use serde_json;
1732
1733 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1734 struct T {
1735 #[serde(with = "::util::amount::serde::as_btc")]
1736 pub amt: Amount,
1737 #[serde(with = "::util::amount::serde::as_btc")]
1738 pub samt: SignedAmount,
1739 }
1740
1741 let orig = T {
1742 amt: Amount::from_sat(21_000_000__000_000_01),
1743 samt: SignedAmount::from_sat(-21_000_000__000_000_01),
1744 };
1745
1746 let json = "{\"amt\": 21000000.00000001, \
1747 \"samt\": -21000000.00000001}";
1748 let t: T = serde_json::from_str(&json).unwrap();
1749 assert_eq!(t, orig);
1750
1751 let value: serde_json::Value = serde_json::from_str(&json).unwrap();
1752 assert_eq!(t, serde_json::from_value(value).unwrap());
1753
1754 let t: Result<T, serde_json::Error> =
1756 serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}");
1757 assert!(t.unwrap_err().to_string().contains(&ParseAmountError::TooPrecise.to_string()));
1758 let t: Result<T, serde_json::Error> = serde_json::from_str("{\"amt\": -1, \"samt\": 1}");
1759 assert!(t.unwrap_err().to_string().contains(&ParseAmountError::Negative.to_string()));
1760 }
1761
1762 #[cfg(feature = "serde")]
1763 #[test]
1764 fn serde_as_btc_opt() {
1765 use serde_json;
1766
1767 #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
1768 struct T {
1769 #[serde(default, with = "::util::amount::serde::as_btc::opt")]
1770 pub amt: Option<Amount>,
1771 #[serde(default, with = "::util::amount::serde::as_btc::opt")]
1772 pub samt: Option<SignedAmount>,
1773 }
1774
1775 let with = T {
1776 amt: Some(Amount::from_sat(2__500_000_00)),
1777 samt: Some(SignedAmount::from_sat(-2__500_000_00)),
1778 };
1779 let without = T {
1780 amt: None,
1781 samt: None,
1782 };
1783
1784 for s in [&with, &without].iter() {
1786 let v = serde_json::to_string(s).unwrap();
1787 let w : T = serde_json::from_str(&v).unwrap();
1788 assert_eq!(w, **s);
1789 }
1790
1791 let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
1792 assert_eq!(t, with);
1793
1794 let t: T = serde_json::from_str("{}").unwrap();
1795 assert_eq!(t, without);
1796
1797 let value_with: serde_json::Value =
1798 serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
1799 assert_eq!(with, serde_json::from_value(value_with).unwrap());
1800
1801 let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
1802 assert_eq!(without, serde_json::from_value(value_without).unwrap());
1803 }
1804
1805 #[cfg(feature = "serde")]
1806 #[test]
1807 fn serde_as_sat_opt() {
1808 use serde_json;
1809
1810 #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
1811 struct T {
1812 #[serde(default, with = "::util::amount::serde::as_sat::opt")]
1813 pub amt: Option<Amount>,
1814 #[serde(default, with = "::util::amount::serde::as_sat::opt")]
1815 pub samt: Option<SignedAmount>,
1816 }
1817
1818 let with = T {
1819 amt: Some(Amount::from_sat(2__500_000_00)),
1820 samt: Some(SignedAmount::from_sat(-2__500_000_00)),
1821 };
1822 let without = T {
1823 amt: None,
1824 samt: None,
1825 };
1826
1827 for s in [&with, &without].iter() {
1829 let v = serde_json::to_string(s).unwrap();
1830 let w : T = serde_json::from_str(&v).unwrap();
1831 assert_eq!(w, **s);
1832 }
1833
1834 let t: T = serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
1835 assert_eq!(t, with);
1836
1837 let t: T = serde_json::from_str("{}").unwrap();
1838 assert_eq!(t, without);
1839
1840 let value_with: serde_json::Value =
1841 serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
1842 assert_eq!(with, serde_json::from_value(value_with).unwrap());
1843
1844 let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
1845 assert_eq!(without, serde_json::from_value(value_without).unwrap());
1846 }
1847
1848 #[test]
1849 fn sum_amounts() {
1850 assert_eq!(Amount::from_sat(0), vec![].into_iter().sum::<Amount>());
1851 assert_eq!(SignedAmount::from_sat(0), vec![].into_iter().sum::<SignedAmount>());
1852
1853 let amounts = vec![
1854 Amount::from_sat(42),
1855 Amount::from_sat(1337),
1856 Amount::from_sat(21)
1857 ];
1858 let sum = amounts.into_iter().sum::<Amount>();
1859 assert_eq!(Amount::from_sat(1400), sum);
1860
1861 let amounts = vec![
1862 SignedAmount::from_sat(-42),
1863 SignedAmount::from_sat(1337),
1864 SignedAmount::from_sat(21)
1865 ];
1866 let sum = amounts.into_iter().sum::<SignedAmount>();
1867 assert_eq!(SignedAmount::from_sat(1316), sum);
1868 }
1869
1870 #[test]
1871 fn checked_sum_amounts() {
1872 assert_eq!(Some(Amount::from_sat(0)), vec![].into_iter().checked_sum());
1873 assert_eq!(Some(SignedAmount::from_sat(0)), vec![].into_iter().checked_sum());
1874
1875 let amounts = vec![
1876 Amount::from_sat(42),
1877 Amount::from_sat(1337),
1878 Amount::from_sat(21)
1879 ];
1880 let sum = amounts.into_iter().checked_sum();
1881 assert_eq!(Some(Amount::from_sat(1400)), sum);
1882
1883 let amounts = vec![
1884 Amount::from_sat(u64::max_value()),
1885 Amount::from_sat(1337),
1886 Amount::from_sat(21)
1887 ];
1888 let sum = amounts.into_iter().checked_sum();
1889 assert_eq!(None, sum);
1890
1891 let amounts = vec![
1892 SignedAmount::from_sat(i64::min_value()),
1893 SignedAmount::from_sat(-1),
1894 SignedAmount::from_sat(21)
1895 ];
1896 let sum = amounts.into_iter().checked_sum();
1897 assert_eq!(None, sum);
1898
1899 let amounts = vec![
1900 SignedAmount::from_sat(i64::max_value()),
1901 SignedAmount::from_sat(1),
1902 SignedAmount::from_sat(21)
1903 ];
1904 let sum = amounts.into_iter().checked_sum();
1905 assert_eq!(None, sum);
1906
1907 let amounts = vec![
1908 SignedAmount::from_sat(42),
1909 SignedAmount::from_sat(3301),
1910 SignedAmount::from_sat(21)
1911 ];
1912 let sum = amounts.into_iter().checked_sum();
1913 assert_eq!(Some(SignedAmount::from_sat(3364)), sum);
1914 }
1915
1916 #[test]
1917 fn denomination_string_acceptable_forms() {
1918 let valid = vec!["BTC", "btc", "mBTC", "mbtc", "uBTC", "ubtc", "SATOSHI","Satoshi", "Satoshis", "satoshis", "SAT", "Sat", "sats", "bit", "bits", "nBTC", "pBTC"];
1920 for denom in valid.iter() {
1921 assert!(Denomination::from_str(denom).is_ok());
1922 }
1923 }
1924
1925 #[test]
1926 fn disallow_confusing_forms() {
1927 let confusing = vec!["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"];
1929 for denom in confusing.iter() {
1930 match Denomination::from_str(denom) {
1931 Ok(_) => panic!("from_str should error for {}", denom),
1932 Err(ParseAmountError::PossiblyConfusingDenomination(_)) => {},
1933 Err(e) => panic!("unexpected error: {}", e),
1934 }
1935 }
1936 }
1937
1938 #[test]
1939 fn disallow_unknown_denomination() {
1940 let unknown = vec!["NBTC", "UBTC", "ABC", "abc"];
1942 for denom in unknown.iter() {
1943 match Denomination::from_str(denom) {
1944 Ok(_) => panic!("from_str should error for {}", denom),
1945 Err(ParseAmountError::UnknownDenomination(_)) => {},
1946 Err(e) => panic!("unexpected error: {}", e),
1947 }
1948 }
1949 }
1950
1951 #[cfg(all(feature = "serde", feature = "schemars"))]
1952 #[test]
1953 fn coinamount() {
1954 use serde_json;
1955
1956 #[derive(Serialize, Deserialize, Debug, PartialEq, schemars::JsonSchema)]
1957 struct T(Vec<CoinAmount>);
1958
1959 let obj_schem = schemars::schema_for!(T);
1960 let string_schema = serde_json::to_string_pretty(&obj_schem).unwrap();
1961 let schema = serde_json::from_str(&string_schema).unwrap();
1962
1963 let v = T(vec![CoinAmount::Sats(10), CoinAmount::Btc(5.0)]);
1964 let s = "[{\"Sats\":10},{\"Btc\":5.0}]";
1965 assert!(jsonschema_valid::is_valid(
1966 &serde_json::from_str(s).unwrap(),
1967 &schema,
1968 None,
1969 true
1970 ));
1971 let t: T = serde_json::from_str(s).unwrap();
1972 assert_eq!(t, v);
1973 let o = serde_json::to_value(&v).unwrap().to_string();
1974 assert!(jsonschema_valid::is_valid(
1975 &serde_json::from_str(&o).unwrap(),
1976 &schema,
1977 None,
1978 true
1979 ));
1980 assert_eq!(s, o);
1981 }
1982}
1983