1#![deny(rustdoc::broken_intra_doc_links)]
2#![deny(rustdoc::private_intra_doc_links)]
3#![deny(missing_docs)]
4#![deny(non_upper_case_globals)]
5#![deny(non_camel_case_types)]
6#![deny(non_snake_case)]
7#![deny(unused_mut)]
8#![cfg_attr(docsrs, feature(doc_cfg))]
9#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
10
11extern crate alloc;
23extern crate bech32;
24#[cfg(any(test, feature = "std"))]
25extern crate core;
26extern crate lightning_types;
27#[cfg(feature = "serde")]
28extern crate serde;
29
30#[cfg(feature = "std")]
31use std::time::SystemTime;
32
33use bech32::primitives::decode::CheckedHrpstringError;
34use bech32::{Checksum, Fe32};
35use bitcoin::hashes::{sha256, Hash};
36use bitcoin::{Address, Network, PubkeyHash, ScriptHash, WitnessProgram, WitnessVersion};
37use lightning_types::features::Bolt11InvoiceFeatures;
38
39use bitcoin::secp256k1::ecdsa::RecoverableSignature;
40use bitcoin::secp256k1::PublicKey;
41use bitcoin::secp256k1::{Message, Secp256k1};
42
43use alloc::boxed::Box;
44use alloc::string;
45use core::cmp::Ordering;
46use core::fmt::{self, Display, Formatter};
47use core::iter::FilterMap;
48use core::num::ParseIntError;
49use core::ops::Deref;
50use core::slice::Iter;
51use core::str::FromStr;
52use core::time::Duration;
53
54#[cfg(feature = "serde")]
55use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
56
57#[doc(no_inline)]
58pub use lightning_types::payment::PaymentSecret;
59#[doc(no_inline)]
60pub use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
61use lightning_types::string::UntrustedString;
62
63mod de;
64mod ser;
65mod tb;
66
67#[cfg(test)]
68mod test_ser_de;
69
70#[allow(unused_imports)]
71mod prelude {
72 pub use alloc::{string::String, vec, vec::Vec};
73
74 pub use alloc::string::ToString;
75}
76
77use crate::prelude::*;
78
79#[cfg(fuzzing)]
81pub use crate::de::FromBase32;
82#[cfg(not(fuzzing))]
83use crate::de::FromBase32;
84#[cfg(fuzzing)]
85pub use crate::ser::Base32Iterable;
86#[cfg(not(fuzzing))]
87use crate::ser::Base32Iterable;
88
89#[allow(missing_docs)]
92#[derive(PartialEq, Eq, Debug, Clone)]
93pub enum Bolt11ParseError {
94 Bech32Error(
95 CheckedHrpstringError,
97 ),
98 ParseAmountError(ParseIntError),
99 MalformedSignature(bitcoin::secp256k1::Error),
100 BadPrefix,
101 UnknownCurrency,
102 UnknownSiPrefix,
103 MalformedHRP,
104 TooShortDataPart,
105 UnexpectedEndOfTaggedFields,
106 DescriptionDecodeError(string::FromUtf8Error),
107 PaddingError,
108 IntegerOverflowError,
109 InvalidSegWitProgramLength,
110 InvalidPubKeyHashLength,
111 InvalidScriptHashLength,
112 InvalidSliceLength(usize, usize, &'static str),
114
115 Skip,
118}
119
120#[derive(PartialEq, Eq, Debug, Clone)]
124pub enum ParseOrSemanticError {
125 ParseError(Bolt11ParseError),
127
128 SemanticError(crate::Bolt11SemanticError),
130}
131
132const TIMESTAMP_BITS: usize = 35;
134
135pub const MAX_TIMESTAMP: u64 = (1 << TIMESTAMP_BITS) - 1;
139
140pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
144
145pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
151
152pub const MAX_LENGTH: usize = 7089;
162
163pub enum Bolt11Bech32 {}
166
167impl Checksum for Bolt11Bech32 {
168 const CODE_LENGTH: usize = MAX_LENGTH;
170
171 type MidstateRepr = <bech32::Bech32 as Checksum>::MidstateRepr;
173 const CHECKSUM_LENGTH: usize = bech32::Bech32::CHECKSUM_LENGTH;
174 const GENERATOR_SH: [Self::MidstateRepr; 5] = bech32::Bech32::GENERATOR_SH;
175 const TARGET_RESIDUE: Self::MidstateRepr = bech32::Bech32::TARGET_RESIDUE;
176}
177
178#[derive(Eq, PartialEq, Debug, Clone)]
237pub struct InvoiceBuilder<
238 D: tb::Bool,
239 H: tb::Bool,
240 T: tb::Bool,
241 C: tb::Bool,
242 S: tb::Bool,
243 M: tb::Bool,
244> {
245 currency: Currency,
246 amount: Option<u64>,
247 si_prefix: Option<SiPrefix>,
248 timestamp: Option<PositiveTimestamp>,
249 tagged_fields: Vec<TaggedField>,
250 error: Option<CreationError>,
251
252 phantom_d: core::marker::PhantomData<D>,
253 phantom_h: core::marker::PhantomData<H>,
254 phantom_t: core::marker::PhantomData<T>,
255 phantom_c: core::marker::PhantomData<C>,
256 phantom_s: core::marker::PhantomData<S>,
257 phantom_m: core::marker::PhantomData<M>,
258}
259
260#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
269pub struct Bolt11Invoice {
270 signed_invoice: SignedRawBolt11Invoice,
271}
272
273#[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)]
276pub enum Bolt11InvoiceDescription {
277 Direct(Description),
279
280 Hash(Sha256),
282}
283
284impl Display for Bolt11InvoiceDescription {
285 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
286 match self {
287 Bolt11InvoiceDescription::Direct(desc) => write!(f, "{}", desc.0),
288 Bolt11InvoiceDescription::Hash(hash) => write!(f, "{}", hash.0),
289 }
290 }
291}
292
293#[derive(Eq, PartialEq, Debug, Clone, Copy, Ord, PartialOrd)]
299pub enum Bolt11InvoiceDescriptionRef<'f> {
300 Direct(&'f Description),
302
303 Hash(&'f Sha256),
305}
306
307impl<'f> Display for Bolt11InvoiceDescriptionRef<'f> {
308 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
309 match self {
310 Bolt11InvoiceDescriptionRef::Direct(desc) => write!(f, "{}", desc.0),
311 Bolt11InvoiceDescriptionRef::Hash(hash) => write!(f, "{}", hash.0),
312 }
313 }
314}
315
316#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
322pub struct SignedRawBolt11Invoice {
323 raw_invoice: RawBolt11Invoice,
325
326 hash: [u8; 32],
334
335 signature: Bolt11InvoiceSignature,
337}
338
339#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
345pub struct RawBolt11Invoice {
346 pub hrp: RawHrp,
348
349 pub data: RawDataPart,
351}
352
353#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
357pub struct RawHrp {
358 pub currency: Currency,
360
361 pub raw_amount: Option<u64>,
363
364 pub si_prefix: Option<SiPrefix>,
366}
367
368impl RawHrp {
369 pub fn to_hrp(&self) -> bech32::Hrp {
371 let hrp_str = self.to_string();
372 let s = core::str::from_utf8(&hrp_str.as_bytes()).expect("HRP bytes should be ASCII");
373 debug_assert!(bech32::Hrp::parse(s).is_ok(), "We should always build BIP 173-valid HRPs");
374 bech32::Hrp::parse_unchecked(s)
375 }
376}
377
378#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
380pub struct RawDataPart {
381 pub timestamp: PositiveTimestamp,
383
384 pub tagged_fields: Vec<RawTaggedField>,
386}
387
388#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
395pub struct PositiveTimestamp(Duration);
396
397#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Ord, PartialOrd)]
399pub enum SiPrefix {
400 Milli,
402 Micro,
404 Nano,
406 Pico,
408}
409
410impl SiPrefix {
411 pub fn multiplier(&self) -> u64 {
414 match *self {
415 SiPrefix::Milli => 1_000_000_000,
416 SiPrefix::Micro => 1_000_000,
417 SiPrefix::Nano => 1_000,
418 SiPrefix::Pico => 1,
419 }
420 }
421
422 pub fn values_desc() -> &'static [SiPrefix] {
428 use crate::SiPrefix::*;
429 static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
430 &VALUES
431 }
432}
433
434#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
436pub enum Currency {
437 Bitcoin,
439
440 BitcoinTestnet,
442
443 Regtest,
445
446 Simnet,
448
449 Signet,
451}
452
453impl From<Network> for Currency {
454 fn from(network: Network) -> Self {
455 match network {
456 Network::Bitcoin => Currency::Bitcoin,
457 Network::Testnet => Currency::BitcoinTestnet,
458 Network::Regtest => Currency::Regtest,
459 Network::Signet => Currency::Signet,
460 _ => {
461 debug_assert!(false, "Need to handle new rust-bitcoin network type");
462 Currency::Regtest
463 },
464 }
465 }
466}
467
468impl From<Currency> for Network {
469 fn from(currency: Currency) -> Self {
470 match currency {
471 Currency::Bitcoin => Network::Bitcoin,
472 Currency::BitcoinTestnet => Network::Testnet,
473 Currency::Regtest => Network::Regtest,
474 Currency::Simnet => Network::Regtest,
475 Currency::Signet => Network::Signet,
476 }
477 }
478}
479
480#[derive(Clone, Debug, Hash, Eq, PartialEq)]
484pub enum RawTaggedField {
485 KnownSemantics(TaggedField),
487 UnknownSemantics(Vec<Fe32>),
489}
490
491impl PartialOrd for RawTaggedField {
492 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
493 Some(self.cmp(other))
494 }
495}
496
497impl Ord for RawTaggedField {
499 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
500 match (self, other) {
501 (RawTaggedField::KnownSemantics(ref a), RawTaggedField::KnownSemantics(ref b)) => {
502 a.cmp(b)
503 },
504 (RawTaggedField::UnknownSemantics(ref a), RawTaggedField::UnknownSemantics(ref b)) => {
505 a.iter().map(|a| a.to_u8()).cmp(b.iter().map(|b| b.to_u8()))
506 },
507 (RawTaggedField::KnownSemantics(..), RawTaggedField::UnknownSemantics(..)) => {
508 core::cmp::Ordering::Less
509 },
510 (RawTaggedField::UnknownSemantics(..), RawTaggedField::KnownSemantics(..)) => {
511 core::cmp::Ordering::Greater
512 },
513 }
514 }
515}
516
517#[allow(missing_docs)]
524#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
525pub enum TaggedField {
526 PaymentHash(Sha256),
527 Description(Description),
528 PayeePubKey(PayeePubKey),
529 DescriptionHash(Sha256),
530 ExpiryTime(ExpiryTime),
531 MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta),
532 Fallback(Fallback),
533 PrivateRoute(PrivateRoute),
534 PaymentSecret(PaymentSecret),
535 PaymentMetadata(Vec<u8>),
536 Features(Bolt11InvoiceFeatures),
537}
538
539#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
541pub struct Sha256(
542 pub sha256::Hash,
544);
545
546impl Sha256 {
547 #[cfg(c_bindings)]
550 pub fn from_bytes(bytes: &[u8; 32]) -> Self {
551 Self(sha256::Hash::from_slice(bytes).expect("from_slice only fails if len is not 32"))
552 }
553}
554
555#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
560pub struct Description(UntrustedString);
561
562#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
564pub struct PayeePubKey(pub PublicKey);
565
566#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
569pub struct ExpiryTime(Duration);
570
571#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
573pub struct MinFinalCltvExpiryDelta(pub u64);
574
575#[allow(missing_docs)]
577#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
578pub enum Fallback {
579 SegWitProgram { version: WitnessVersion, program: Vec<u8> },
580 PubKeyHash(PubkeyHash),
581 ScriptHash(ScriptHash),
582}
583
584#[derive(Clone, Debug, Hash, Eq, PartialEq)]
586pub struct Bolt11InvoiceSignature(pub RecoverableSignature);
587
588impl PartialOrd for Bolt11InvoiceSignature {
589 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
590 Some(self.cmp(other))
591 }
592}
593
594impl Ord for Bolt11InvoiceSignature {
595 fn cmp(&self, other: &Self) -> Ordering {
596 self.0.serialize_compact().1.cmp(&other.0.serialize_compact().1)
597 }
598}
599
600#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
606pub struct PrivateRoute(RouteHint);
607
608#[allow(missing_docs)]
610pub mod constants {
611 pub const TAG_PAYMENT_HASH: u8 = 1;
612 pub const TAG_DESCRIPTION: u8 = 13;
613 pub const TAG_PAYEE_PUB_KEY: u8 = 19;
614 pub const TAG_DESCRIPTION_HASH: u8 = 23;
615 pub const TAG_EXPIRY_TIME: u8 = 6;
616 pub const TAG_MIN_FINAL_CLTV_EXPIRY_DELTA: u8 = 24;
617 pub const TAG_FALLBACK: u8 = 9;
618 pub const TAG_PRIVATE_ROUTE: u8 = 3;
619 pub const TAG_PAYMENT_SECRET: u8 = 16;
620 pub const TAG_PAYMENT_METADATA: u8 = 27;
621 pub const TAG_FEATURES: u8 = 5;
622}
623
624impl InvoiceBuilder<tb::False, tb::False, tb::False, tb::False, tb::False, tb::False> {
625 pub fn new(currency: Currency) -> Self {
628 InvoiceBuilder {
629 currency,
630 amount: None,
631 si_prefix: None,
632 timestamp: None,
633 tagged_fields: Vec::with_capacity(8),
634 error: None,
635
636 phantom_d: core::marker::PhantomData,
637 phantom_h: core::marker::PhantomData,
638 phantom_t: core::marker::PhantomData,
639 phantom_c: core::marker::PhantomData,
640 phantom_s: core::marker::PhantomData,
641 phantom_m: core::marker::PhantomData,
642 }
643 }
644}
645
646impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
647 InvoiceBuilder<D, H, T, C, S, M>
648{
649 fn set_flags<
651 DN: tb::Bool,
652 HN: tb::Bool,
653 TN: tb::Bool,
654 CN: tb::Bool,
655 SN: tb::Bool,
656 MN: tb::Bool,
657 >(
658 self,
659 ) -> InvoiceBuilder<DN, HN, TN, CN, SN, MN> {
660 InvoiceBuilder::<DN, HN, TN, CN, SN, MN> {
661 currency: self.currency,
662 amount: self.amount,
663 si_prefix: self.si_prefix,
664 timestamp: self.timestamp,
665 tagged_fields: self.tagged_fields,
666 error: self.error,
667
668 phantom_d: core::marker::PhantomData,
669 phantom_h: core::marker::PhantomData,
670 phantom_t: core::marker::PhantomData,
671 phantom_c: core::marker::PhantomData,
672 phantom_s: core::marker::PhantomData,
673 phantom_m: core::marker::PhantomData,
674 }
675 }
676
677 pub fn amount_milli_satoshis(mut self, amount_msat: u64) -> Self {
679 let amount = match amount_msat.checked_mul(10) {
681 Some(amt) => amt,
682 None => {
683 self.error = Some(CreationError::InvalidAmount);
684 return self;
685 },
686 };
687 let biggest_possible_si_prefix = SiPrefix::values_desc()
688 .iter()
689 .find(|prefix| amount % prefix.multiplier() == 0)
690 .expect("Pico should always match");
691 self.amount = Some(amount / biggest_possible_si_prefix.multiplier());
692 self.si_prefix = Some(*biggest_possible_si_prefix);
693 self
694 }
695
696 pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
698 self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
699 self
700 }
701
702 pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
705 self.tagged_fields.push(TaggedField::ExpiryTime(ExpiryTime::from_duration(expiry_time)));
706 self
707 }
708
709 pub fn fallback(mut self, fallback: Fallback) -> Self {
711 self.tagged_fields.push(TaggedField::Fallback(fallback));
712 self
713 }
714
715 pub fn private_route(mut self, hint: RouteHint) -> Self {
717 match PrivateRoute::new(hint) {
718 Ok(r) => self.tagged_fields.push(TaggedField::PrivateRoute(r)),
719 Err(e) => self.error = Some(e),
720 }
721 self
722 }
723}
724
725impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
726 InvoiceBuilder<D, H, tb::True, C, S, M>
727{
728 pub fn build_raw(self) -> Result<RawBolt11Invoice, CreationError> {
731 if let Some(e) = self.error {
733 return Err(e);
734 }
735
736 let hrp =
737 RawHrp { currency: self.currency, raw_amount: self.amount, si_prefix: self.si_prefix };
738
739 let timestamp = self.timestamp.expect("ensured to be Some(t) by type T");
740
741 let tagged_fields = self
742 .tagged_fields
743 .into_iter()
744 .map(|tf| RawTaggedField::KnownSemantics(tf))
745 .collect::<Vec<_>>();
746
747 let data = RawDataPart { timestamp, tagged_fields };
748
749 Ok(RawBolt11Invoice { hrp, data })
750 }
751}
752
753impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
754 InvoiceBuilder<tb::False, H, T, C, S, M>
755{
756 pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
758 match Description::new(description) {
759 Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
760 Err(e) => self.error = Some(e),
761 }
762 self.set_flags()
763 }
764
765 pub fn description_hash(
767 mut self, description_hash: sha256::Hash,
768 ) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
769 self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
770 self.set_flags()
771 }
772
773 pub fn invoice_description(
775 self, description: Bolt11InvoiceDescription,
776 ) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
777 match description {
778 Bolt11InvoiceDescription::Direct(desc) => self.description(desc.0 .0),
779 Bolt11InvoiceDescription::Hash(hash) => self.description_hash(hash.0),
780 }
781 }
782
783 pub fn invoice_description_ref(
785 self, description_ref: Bolt11InvoiceDescriptionRef<'_>,
786 ) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
787 match description_ref {
788 Bolt11InvoiceDescriptionRef::Direct(desc) => self.description(desc.clone().0 .0),
789 Bolt11InvoiceDescriptionRef::Hash(hash) => self.description_hash(hash.0),
790 }
791 }
792}
793
794impl<D: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
795 InvoiceBuilder<D, tb::False, T, C, S, M>
796{
797 pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder<D, tb::True, T, C, S, M> {
799 self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
800 self.set_flags()
801 }
802}
803
804impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
805 InvoiceBuilder<D, H, tb::False, C, S, M>
806{
807 #[cfg(feature = "std")]
809 pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True, C, S, M> {
810 match PositiveTimestamp::from_system_time(time) {
811 Ok(t) => self.timestamp = Some(t),
812 Err(e) => self.error = Some(e),
813 }
814
815 self.set_flags()
816 }
817
818 pub fn duration_since_epoch(
821 mut self, time: Duration,
822 ) -> InvoiceBuilder<D, H, tb::True, C, S, M> {
823 match PositiveTimestamp::from_duration_since_epoch(time) {
824 Ok(t) => self.timestamp = Some(t),
825 Err(e) => self.error = Some(e),
826 }
827
828 self.set_flags()
829 }
830
831 #[cfg(feature = "std")]
833 pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True, C, S, M> {
834 let now = PositiveTimestamp::from_system_time(SystemTime::now());
835 self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
836 self.set_flags()
837 }
838}
839
840impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, S: tb::Bool, M: tb::Bool>
841 InvoiceBuilder<D, H, T, tb::False, S, M>
842{
843 pub fn min_final_cltv_expiry_delta(
845 mut self, min_final_cltv_expiry_delta: u64,
846 ) -> InvoiceBuilder<D, H, T, tb::True, S, M> {
847 self.tagged_fields.push(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta(
848 min_final_cltv_expiry_delta,
849 )));
850 self.set_flags()
851 }
852}
853
854impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, M: tb::Bool>
855 InvoiceBuilder<D, H, T, C, tb::False, M>
856{
857 pub fn payment_secret(
859 mut self, payment_secret: PaymentSecret,
860 ) -> InvoiceBuilder<D, H, T, C, tb::True, M> {
861 let mut found_features = false;
862 for field in self.tagged_fields.iter_mut() {
863 if let TaggedField::Features(f) = field {
864 found_features = true;
865 f.set_variable_length_onion_required();
866 f.set_payment_secret_required();
867 }
868 }
869 self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
870 if !found_features {
871 let mut features = Bolt11InvoiceFeatures::empty();
872 features.set_variable_length_onion_required();
873 features.set_payment_secret_required();
874 self.tagged_fields.push(TaggedField::Features(features));
875 }
876 self.set_flags()
877 }
878}
879
880impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool>
881 InvoiceBuilder<D, H, T, C, S, tb::False>
882{
883 pub fn payment_metadata(
890 mut self, payment_metadata: Vec<u8>,
891 ) -> InvoiceBuilder<D, H, T, C, S, tb::True> {
892 self.tagged_fields.push(TaggedField::PaymentMetadata(payment_metadata));
893 let mut found_features = false;
894 for field in self.tagged_fields.iter_mut() {
895 if let TaggedField::Features(f) = field {
896 found_features = true;
897 f.set_payment_metadata_optional();
898 }
899 }
900 if !found_features {
901 let mut features = Bolt11InvoiceFeatures::empty();
902 features.set_payment_metadata_optional();
903 self.tagged_fields.push(TaggedField::Features(features));
904 }
905 self.set_flags()
906 }
907}
908
909impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool>
910 InvoiceBuilder<D, H, T, C, S, tb::True>
911{
912 pub fn require_payment_metadata(mut self) -> InvoiceBuilder<D, H, T, C, S, tb::True> {
915 for field in self.tagged_fields.iter_mut() {
916 if let TaggedField::Features(f) = field {
917 f.set_payment_metadata_required();
918 }
919 }
920 self
921 }
922}
923
924impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, M: tb::Bool>
925 InvoiceBuilder<D, H, T, C, tb::True, M>
926{
927 pub fn basic_mpp(mut self) -> Self {
929 for field in self.tagged_fields.iter_mut() {
930 if let TaggedField::Features(f) = field {
931 f.set_basic_mpp_optional();
932 }
933 }
934 self
935 }
936}
937
938impl<M: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::True, M> {
939 pub fn build_signed<F>(self, sign_function: F) -> Result<Bolt11Invoice, CreationError>
943 where
944 F: FnOnce(&Message) -> RecoverableSignature,
945 {
946 let invoice = self.try_build_signed::<_, ()>(|hash| Ok(sign_function(hash)));
947
948 match invoice {
949 Ok(i) => Ok(i),
950 Err(SignOrCreationError::CreationError(e)) => Err(e),
951 Err(SignOrCreationError::SignError(())) => unreachable!(),
952 }
953 }
954
955 pub fn try_build_signed<F, E>(
959 self, sign_function: F,
960 ) -> Result<Bolt11Invoice, SignOrCreationError<E>>
961 where
962 F: FnOnce(&Message) -> Result<RecoverableSignature, E>,
963 {
964 let raw = match self.build_raw() {
965 Ok(r) => r,
966 Err(e) => return Err(SignOrCreationError::CreationError(e)),
967 };
968
969 let signed = match raw.sign(sign_function) {
970 Ok(s) => s,
971 Err(e) => return Err(SignOrCreationError::SignError(e)),
972 };
973
974 let invoice = Bolt11Invoice { signed_invoice: signed };
975
976 invoice.check_field_counts().expect("should be ensured by type signature of builder");
977 invoice.check_feature_bits().expect("should be ensured by type signature of builder");
978 invoice.check_amount().expect("should be ensured by type signature of builder");
979
980 Ok(invoice)
981 }
982}
983
984impl SignedRawBolt11Invoice {
985 pub fn into_parts(self) -> (RawBolt11Invoice, [u8; 32], Bolt11InvoiceSignature) {
990 (self.raw_invoice, self.hash, self.signature)
991 }
992
993 pub fn raw_invoice(&self) -> &RawBolt11Invoice {
995 &self.raw_invoice
996 }
997
998 pub fn signable_hash(&self) -> &[u8; 32] {
1000 &self.hash
1001 }
1002
1003 pub fn signature(&self) -> &Bolt11InvoiceSignature {
1005 &self.signature
1006 }
1007
1008 pub fn recover_payee_pub_key(&self) -> Result<PayeePubKey, bitcoin::secp256k1::Error> {
1010 let hash = Message::from_digest(self.hash);
1011
1012 Ok(PayeePubKey(Secp256k1::new().recover_ecdsa(&hash, &self.signature)?))
1013 }
1014
1015 pub fn check_signature(&self) -> bool {
1018 match self.raw_invoice.payee_pub_key() {
1019 Some(pk) => {
1020 let hash = Message::from_digest(self.hash);
1021
1022 let secp_context = Secp256k1::new();
1023 let verification_result =
1024 secp_context.verify_ecdsa(&hash, &self.signature.to_standard(), pk);
1025
1026 verification_result.is_ok()
1027 },
1028 None => self.recover_payee_pub_key().is_ok(),
1029 }
1030 }
1031}
1032
1033macro_rules! find_extract {
1049 ($iter:expr, $enm:pat, $enm_var:ident) => {
1050 find_all_extract!($iter, $enm, $enm_var).next()
1051 };
1052}
1053
1054macro_rules! find_all_extract {
1073 ($iter:expr, $enm:pat, $enm_var:ident) => {
1074 $iter.filter_map(|tf| match *tf {
1075 $enm => Some($enm_var),
1076 _ => None,
1077 })
1078 };
1079}
1080
1081#[allow(missing_docs)]
1082impl RawBolt11Invoice {
1083 fn hash_from_parts<'s>(
1085 hrp_bytes: &[u8], data_without_signature: Box<dyn Iterator<Item = Fe32> + 's>,
1086 ) -> [u8; 32] {
1087 use crate::bech32::Fe32IterExt;
1088 use bitcoin::hashes::HashEngine;
1089
1090 let mut data_part = data_without_signature.collect::<Vec<Fe32>>();
1091
1092 let overhang = (data_part.len() * 5) % 8;
1094 if overhang > 0 {
1095 data_part.push(Fe32::try_from(0).unwrap());
1097
1098 if overhang < 3 {
1100 data_part.push(Fe32::try_from(0).unwrap());
1101 }
1102 }
1103
1104 let mut engine = sha256::Hash::engine();
1106 engine.input(hrp_bytes);
1107 data_part.into_iter().fes_to_bytes().for_each(|v| engine.input(&[v]));
1111 let raw_hash = sha256::Hash::from_engine(engine);
1112
1113 let mut hash: [u8; 32] = Default::default();
1114 hash.copy_from_slice(raw_hash.as_ref());
1115 hash
1116 }
1117
1118 pub fn signable_hash(&self) -> [u8; 32] {
1120 Self::hash_from_parts(self.hrp.to_string().as_bytes(), self.data.fe_iter())
1121 }
1122
1123 pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawBolt11Invoice, E>
1130 where
1131 F: FnOnce(&Message) -> Result<RecoverableSignature, E>,
1132 {
1133 let raw_hash = self.signable_hash();
1134 let hash = Message::from_digest(raw_hash);
1135 let signature = sign_method(&hash)?;
1136
1137 Ok(SignedRawBolt11Invoice {
1138 raw_invoice: self,
1139 hash: raw_hash,
1140 signature: Bolt11InvoiceSignature(signature),
1141 })
1142 }
1143
1144 pub fn known_tagged_fields(
1148 &self,
1149 ) -> FilterMap<Iter<'_, RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
1150 fn match_raw(raw: &RawTaggedField) -> Option<&TaggedField> {
1154 match *raw {
1155 RawTaggedField::KnownSemantics(ref tf) => Some(tf),
1156 _ => None,
1157 }
1158 }
1159
1160 self.data.tagged_fields.iter().filter_map(match_raw)
1161 }
1162
1163 pub fn payment_hash(&self) -> Option<&Sha256> {
1164 find_extract!(self.known_tagged_fields(), TaggedField::PaymentHash(ref x), x)
1165 }
1166
1167 pub fn description(&self) -> Option<&Description> {
1168 find_extract!(self.known_tagged_fields(), TaggedField::Description(ref x), x)
1169 }
1170
1171 pub fn payee_pub_key(&self) -> Option<&PayeePubKey> {
1172 find_extract!(self.known_tagged_fields(), TaggedField::PayeePubKey(ref x), x)
1173 }
1174
1175 pub fn description_hash(&self) -> Option<&Sha256> {
1176 find_extract!(self.known_tagged_fields(), TaggedField::DescriptionHash(ref x), x)
1177 }
1178
1179 pub fn expiry_time(&self) -> Option<&ExpiryTime> {
1180 find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
1181 }
1182
1183 pub fn min_final_cltv_expiry_delta(&self) -> Option<&MinFinalCltvExpiryDelta> {
1184 find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiryDelta(ref x), x)
1185 }
1186
1187 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
1188 find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
1189 }
1190
1191 pub fn payment_metadata(&self) -> Option<&Vec<u8>> {
1192 find_extract!(self.known_tagged_fields(), TaggedField::PaymentMetadata(ref x), x)
1193 }
1194
1195 pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> {
1196 find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
1197 }
1198
1199 pub fn fallbacks(&self) -> Vec<&Fallback> {
1201 find_all_extract!(self.known_tagged_fields(), TaggedField::Fallback(ref x), x).collect()
1202 }
1203
1204 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1205 find_all_extract!(self.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x).collect()
1206 }
1207
1208 pub fn amount_pico_btc(&self) -> Option<u64> {
1210 self.hrp.raw_amount.and_then(|v| {
1211 v.checked_mul(
1212 self.hrp.si_prefix.as_ref().map_or(1_000_000_000_000, |si| si.multiplier()),
1213 )
1214 })
1215 }
1216
1217 pub fn currency(&self) -> Currency {
1218 self.hrp.currency.clone()
1219 }
1220
1221 pub fn to_raw(&self) -> (String, Vec<Fe32>) {
1224 (self.hrp.to_string(), self.data.fe_iter().collect())
1225 }
1226
1227 pub fn from_raw(hrp: &str, data: &[Fe32]) -> Result<Self, Bolt11ParseError> {
1230 let raw_hrp: RawHrp = RawHrp::from_str(hrp)?;
1231 let data_part = RawDataPart::from_base32(data)?;
1232
1233 Ok(Self { hrp: raw_hrp, data: data_part })
1234 }
1235}
1236
1237impl PositiveTimestamp {
1238 pub fn from_unix_timestamp(unix_seconds: u64) -> Result<Self, CreationError> {
1242 if unix_seconds <= MAX_TIMESTAMP {
1243 Ok(Self(Duration::from_secs(unix_seconds)))
1244 } else {
1245 Err(CreationError::TimestampOutOfBounds)
1246 }
1247 }
1248
1249 #[cfg(feature = "std")]
1256 pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
1257 time.duration_since(SystemTime::UNIX_EPOCH)
1258 .map(Self::from_duration_since_epoch)
1259 .unwrap_or(Err(CreationError::TimestampOutOfBounds))
1260 }
1261
1262 pub fn from_duration_since_epoch(duration: Duration) -> Result<Self, CreationError> {
1269 Self::from_unix_timestamp(duration.as_secs())
1270 }
1271
1272 pub fn as_unix_timestamp(&self) -> u64 {
1274 self.0.as_secs()
1275 }
1276
1277 pub fn as_duration_since_epoch(&self) -> Duration {
1279 self.0
1280 }
1281
1282 #[cfg(feature = "std")]
1284 pub fn as_time(&self) -> SystemTime {
1285 SystemTime::UNIX_EPOCH + self.0
1286 }
1287}
1288
1289impl From<PositiveTimestamp> for Duration {
1290 fn from(val: PositiveTimestamp) -> Self {
1291 val.0
1292 }
1293}
1294
1295#[cfg(feature = "std")]
1296impl From<PositiveTimestamp> for SystemTime {
1297 fn from(val: PositiveTimestamp) -> Self {
1298 SystemTime::UNIX_EPOCH + val.0
1299 }
1300}
1301
1302impl Bolt11Invoice {
1303 pub fn signable_hash(&self) -> [u8; 32] {
1305 self.signed_invoice.hash
1306 }
1307
1308 pub fn into_signed_raw(self) -> SignedRawBolt11Invoice {
1310 self.signed_invoice
1311 }
1312
1313 fn check_field_counts(&self) -> Result<(), Bolt11SemanticError> {
1315 let payment_hash_cnt = self
1317 .tagged_fields()
1318 .filter(|&tf| match *tf {
1319 TaggedField::PaymentHash(_) => true,
1320 _ => false,
1321 })
1322 .count();
1323 if payment_hash_cnt < 1 {
1324 return Err(Bolt11SemanticError::NoPaymentHash);
1325 } else if payment_hash_cnt > 1 {
1326 return Err(Bolt11SemanticError::MultiplePaymentHashes);
1327 }
1328
1329 let description_cnt = self
1331 .tagged_fields()
1332 .filter(|&tf| match *tf {
1333 TaggedField::Description(_) | TaggedField::DescriptionHash(_) => true,
1334 _ => false,
1335 })
1336 .count();
1337 if description_cnt < 1 {
1338 return Err(Bolt11SemanticError::NoDescription);
1339 } else if description_cnt > 1 {
1340 return Err(Bolt11SemanticError::MultipleDescriptions);
1341 }
1342
1343 self.check_payment_secret()?;
1344
1345 Ok(())
1346 }
1347
1348 fn check_payment_secret(&self) -> Result<(), Bolt11SemanticError> {
1350 let payment_secret_count = self
1352 .tagged_fields()
1353 .filter(|&tf| match *tf {
1354 TaggedField::PaymentSecret(_) => true,
1355 _ => false,
1356 })
1357 .count();
1358 if payment_secret_count < 1 {
1359 return Err(Bolt11SemanticError::NoPaymentSecret);
1360 } else if payment_secret_count > 1 {
1361 return Err(Bolt11SemanticError::MultiplePaymentSecrets);
1362 }
1363
1364 Ok(())
1365 }
1366
1367 fn check_amount(&self) -> Result<(), Bolt11SemanticError> {
1369 if let Some(amount_pico_btc) = self.amount_pico_btc() {
1370 if amount_pico_btc % 10 != 0 {
1371 return Err(Bolt11SemanticError::ImpreciseAmount);
1372 }
1373 }
1374 Ok(())
1375 }
1376
1377 fn check_feature_bits(&self) -> Result<(), Bolt11SemanticError> {
1379 self.check_payment_secret()?;
1380
1381 let features = self.tagged_fields().find(|&tf| match *tf {
1385 TaggedField::Features(_) => true,
1386 _ => false,
1387 });
1388 match features {
1389 None => Err(Bolt11SemanticError::InvalidFeatures),
1390 Some(TaggedField::Features(features)) => {
1391 if features.requires_unknown_bits() {
1392 Err(Bolt11SemanticError::InvalidFeatures)
1393 } else if !features.supports_payment_secret() {
1394 Err(Bolt11SemanticError::InvalidFeatures)
1395 } else {
1396 Ok(())
1397 }
1398 },
1399 Some(_) => unreachable!(),
1400 }
1401 }
1402
1403 pub fn check_signature(&self) -> Result<(), Bolt11SemanticError> {
1405 if !self.signed_invoice.check_signature() {
1406 return Err(Bolt11SemanticError::InvalidSignature);
1407 }
1408
1409 Ok(())
1410 }
1411
1412 pub fn from_signed(
1433 signed_invoice: SignedRawBolt11Invoice,
1434 ) -> Result<Self, Bolt11SemanticError> {
1435 let invoice = Bolt11Invoice { signed_invoice };
1436 invoice.check_field_counts()?;
1437 invoice.check_feature_bits()?;
1438 invoice.check_signature()?;
1439 invoice.check_amount()?;
1440
1441 Ok(invoice)
1442 }
1443
1444 #[cfg(feature = "std")]
1446 pub fn timestamp(&self) -> SystemTime {
1447 self.signed_invoice.raw_invoice().data.timestamp.as_time()
1448 }
1449
1450 pub fn duration_since_epoch(&self) -> Duration {
1452 self.signed_invoice.raw_invoice().data.timestamp.0
1453 }
1454
1455 pub fn tagged_fields(
1459 &self,
1460 ) -> FilterMap<Iter<'_, RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
1461 self.signed_invoice.raw_invoice().known_tagged_fields()
1462 }
1463
1464 pub fn payment_hash(&self) -> &sha256::Hash {
1466 &self.signed_invoice.payment_hash().expect("checked by constructor").0
1467 }
1468
1469 pub fn description(&self) -> Bolt11InvoiceDescriptionRef<'_> {
1473 if let Some(direct) = self.signed_invoice.description() {
1474 return Bolt11InvoiceDescriptionRef::Direct(direct);
1475 } else if let Some(hash) = self.signed_invoice.description_hash() {
1476 return Bolt11InvoiceDescriptionRef::Hash(hash);
1477 }
1478 unreachable!("ensured by constructor");
1479 }
1480
1481 pub fn payee_pub_key(&self) -> Option<&PublicKey> {
1483 self.signed_invoice.payee_pub_key().map(|x| &x.0)
1484 }
1485
1486 pub fn payment_secret(&self) -> &PaymentSecret {
1488 self.signed_invoice.payment_secret().expect("was checked by constructor")
1489 }
1490
1491 pub fn payment_metadata(&self) -> Option<&Vec<u8>> {
1493 self.signed_invoice.payment_metadata()
1494 }
1495
1496 pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> {
1498 self.signed_invoice.features()
1499 }
1500
1501 pub fn recover_payee_pub_key(&self) -> PublicKey {
1503 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1504 }
1505
1506 pub fn get_payee_pub_key(&self) -> PublicKey {
1509 match self.payee_pub_key() {
1510 Some(pk) => *pk,
1511 None => self.recover_payee_pub_key(),
1512 }
1513 }
1514
1515 pub fn expires_at(&self) -> Option<Duration> {
1518 self.duration_since_epoch().checked_add(self.expiry_time())
1519 }
1520
1521 pub fn expiry_time(&self) -> Duration {
1523 self.signed_invoice
1524 .expiry_time()
1525 .map(|x| x.0)
1526 .unwrap_or(Duration::from_secs(DEFAULT_EXPIRY_TIME))
1527 }
1528
1529 #[cfg(feature = "std")]
1531 pub fn is_expired(&self) -> bool {
1532 Self::is_expired_from_epoch(&self.timestamp(), self.expiry_time())
1533 }
1534
1535 #[cfg(feature = "std")]
1537 pub(crate) fn is_expired_from_epoch(epoch: &SystemTime, expiry_time: Duration) -> bool {
1538 match epoch.elapsed() {
1539 Ok(elapsed) => elapsed > expiry_time,
1540 Err(_) => false,
1541 }
1542 }
1543
1544 #[cfg(feature = "std")]
1546 pub fn duration_until_expiry(&self) -> Duration {
1547 SystemTime::now()
1548 .duration_since(SystemTime::UNIX_EPOCH)
1549 .map(|now| self.expiration_remaining_from_epoch(now))
1550 .unwrap_or(Duration::from_nanos(0))
1551 }
1552
1553 pub fn expiration_remaining_from_epoch(&self, time: Duration) -> Duration {
1556 self.expires_at().map(|x| x.checked_sub(time)).flatten().unwrap_or(Duration::from_nanos(0))
1557 }
1558
1559 pub fn would_expire(&self, at_time: Duration) -> bool {
1562 self.duration_since_epoch()
1563 .checked_add(self.expiry_time())
1564 .unwrap_or_else(|| Duration::new(u64::max_value(), 1_000_000_000 - 1))
1565 < at_time
1566 }
1567
1568 pub fn min_final_cltv_expiry_delta(&self) -> u64 {
1571 self.signed_invoice
1572 .min_final_cltv_expiry_delta()
1573 .map(|x| x.0)
1574 .unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA)
1575 }
1576
1577 pub fn fallbacks(&self) -> Vec<&Fallback> {
1581 self.signed_invoice.fallbacks()
1582 }
1583
1584 pub fn fallback_addresses(&self) -> Vec<Address> {
1586 let filter_fn = |fallback: &&Fallback| {
1587 let address = match fallback {
1588 Fallback::SegWitProgram { version, program } => {
1589 match WitnessProgram::new(*version, &program) {
1590 Ok(witness_program) => {
1591 Address::from_witness_program(witness_program, self.network())
1592 },
1593 Err(_) => return None,
1594 }
1595 },
1596 Fallback::PubKeyHash(pkh) => Address::p2pkh(*pkh, self.network()),
1597 Fallback::ScriptHash(sh) => Address::p2sh_from_hash(*sh, self.network()),
1598 };
1599
1600 Some(address)
1601 };
1602 self.fallbacks().iter().filter_map(filter_fn).collect()
1603 }
1604
1605 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1607 self.signed_invoice.private_routes()
1608 }
1609
1610 pub fn route_hints(&self) -> Vec<RouteHint> {
1612 find_all_extract!(
1613 self.signed_invoice.known_tagged_fields(),
1614 TaggedField::PrivateRoute(ref x),
1615 x
1616 )
1617 .map(|route| (**route).clone())
1618 .collect()
1619 }
1620
1621 pub fn currency(&self) -> Currency {
1623 self.signed_invoice.currency()
1624 }
1625
1626 pub fn network(&self) -> Network {
1630 self.signed_invoice.currency().into()
1631 }
1632
1633 pub fn amount_milli_satoshis(&self) -> Option<u64> {
1635 self.signed_invoice.amount_pico_btc().map(|v| v / 10)
1636 }
1637
1638 fn amount_pico_btc(&self) -> Option<u64> {
1640 self.signed_invoice.amount_pico_btc()
1641 }
1642}
1643
1644impl From<TaggedField> for RawTaggedField {
1645 fn from(tf: TaggedField) -> Self {
1646 RawTaggedField::KnownSemantics(tf)
1647 }
1648}
1649
1650impl TaggedField {
1651 pub fn tag(&self) -> Fe32 {
1653 let tag = match *self {
1654 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1655 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1656 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1657 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1658 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1659 TaggedField::MinFinalCltvExpiryDelta(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA,
1660 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1661 TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
1662 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1663 TaggedField::PaymentMetadata(_) => constants::TAG_PAYMENT_METADATA,
1664 TaggedField::Features(_) => constants::TAG_FEATURES,
1665 };
1666
1667 Fe32::try_from(tag).expect("all tags defined are <32")
1668 }
1669}
1670
1671impl Description {
1672 pub fn new(description: String) -> Result<Description, CreationError> {
1677 if description.len() > 639 {
1678 Err(CreationError::DescriptionTooLong)
1679 } else {
1680 Ok(Description(UntrustedString(description)))
1681 }
1682 }
1683
1684 pub fn empty() -> Self {
1686 Description(UntrustedString(String::new()))
1687 }
1688
1689 pub fn into_inner(self) -> UntrustedString {
1691 self.0
1692 }
1693
1694 pub fn as_inner(&self) -> &UntrustedString {
1696 &self.0
1697 }
1698}
1699
1700impl Display for Description {
1701 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1702 write!(f, "{}", self.0)
1703 }
1704}
1705
1706impl From<PublicKey> for PayeePubKey {
1707 fn from(pk: PublicKey) -> Self {
1708 PayeePubKey(pk)
1709 }
1710}
1711
1712impl Deref for PayeePubKey {
1713 type Target = PublicKey;
1714
1715 fn deref(&self) -> &PublicKey {
1716 &self.0
1717 }
1718}
1719
1720impl ExpiryTime {
1721 pub fn from_seconds(seconds: u64) -> ExpiryTime {
1723 ExpiryTime(Duration::from_secs(seconds))
1724 }
1725
1726 pub fn from_duration(duration: Duration) -> ExpiryTime {
1728 Self::from_seconds(duration.as_secs())
1729 }
1730
1731 pub fn as_seconds(&self) -> u64 {
1733 self.0.as_secs()
1734 }
1735
1736 pub fn as_duration(&self) -> &Duration {
1738 &self.0
1739 }
1740}
1741
1742impl PrivateRoute {
1743 pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
1745 if hops.0.len() <= 12 {
1746 Ok(PrivateRoute(hops))
1747 } else {
1748 Err(CreationError::RouteTooLong)
1749 }
1750 }
1751
1752 pub fn into_inner(self) -> RouteHint {
1754 self.0
1755 }
1756}
1757
1758impl From<PrivateRoute> for RouteHint {
1759 fn from(val: PrivateRoute) -> Self {
1760 val.into_inner()
1761 }
1762}
1763
1764impl Deref for PrivateRoute {
1765 type Target = RouteHint;
1766
1767 fn deref(&self) -> &RouteHint {
1768 &self.0
1769 }
1770}
1771
1772impl Deref for Bolt11InvoiceSignature {
1773 type Target = RecoverableSignature;
1774
1775 fn deref(&self) -> &RecoverableSignature {
1776 &self.0
1777 }
1778}
1779
1780impl Deref for SignedRawBolt11Invoice {
1781 type Target = RawBolt11Invoice;
1782
1783 fn deref(&self) -> &RawBolt11Invoice {
1784 &self.raw_invoice
1785 }
1786}
1787
1788#[derive(Eq, PartialEq, Debug, Clone)]
1790pub enum CreationError {
1791 DescriptionTooLong,
1793
1794 RouteTooLong,
1796
1797 TimestampOutOfBounds,
1799
1800 InvalidAmount,
1802
1803 MissingRouteHints,
1807
1808 MinFinalCltvExpiryDeltaTooShort,
1810}
1811
1812impl Display for CreationError {
1813 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1814 match self {
1815 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1816 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1817 CreationError::TimestampOutOfBounds => f.write_str("The Unix timestamp of the supplied date is less than zero or greater than 35-bits"),
1818 CreationError::InvalidAmount => f.write_str("The supplied millisatoshi amount was greater than the total bitcoin supply"),
1819 CreationError::MissingRouteHints => f.write_str("The invoice required route hints and they weren't provided"),
1820 CreationError::MinFinalCltvExpiryDeltaTooShort => f.write_str(
1821 "The supplied final CLTV expiry delta was less than LDK's `MIN_FINAL_CLTV_EXPIRY_DELTA`"),
1822 }
1823 }
1824}
1825
1826#[cfg(feature = "std")]
1827impl std::error::Error for CreationError {}
1828
1829#[derive(Eq, PartialEq, Debug, Clone)]
1832pub enum Bolt11SemanticError {
1833 NoPaymentHash,
1835
1836 MultiplePaymentHashes,
1838
1839 NoDescription,
1841
1842 MultipleDescriptions,
1844
1845 NoPaymentSecret,
1848
1849 MultiplePaymentSecrets,
1851
1852 InvalidFeatures,
1854
1855 InvalidSignature,
1857
1858 ImpreciseAmount,
1860}
1861
1862impl Display for Bolt11SemanticError {
1863 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1864 match self {
1865 Bolt11SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1866 Bolt11SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1867 Bolt11SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1868 Bolt11SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1869 Bolt11SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
1870 Bolt11SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1871 Bolt11SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1872 Bolt11SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1873 Bolt11SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
1874 }
1875 }
1876}
1877
1878#[cfg(feature = "std")]
1879impl std::error::Error for Bolt11SemanticError {}
1880
1881#[derive(Eq, PartialEq, Debug, Clone)]
1884pub enum SignOrCreationError<S = ()> {
1885 SignError(S),
1887
1888 CreationError(CreationError),
1890}
1891
1892impl<S> Display for SignOrCreationError<S> {
1893 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1894 match self {
1895 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1896 SignOrCreationError::CreationError(err) => err.fmt(f),
1897 }
1898 }
1899}
1900
1901#[cfg(feature = "serde")]
1902impl Serialize for Bolt11Invoice {
1903 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1904 where
1905 S: Serializer,
1906 {
1907 serializer.serialize_str(self.to_string().as_str())
1908 }
1909}
1910#[cfg(feature = "serde")]
1911impl<'de> Deserialize<'de> for Bolt11Invoice {
1912 fn deserialize<D>(deserializer: D) -> Result<Bolt11Invoice, D::Error>
1913 where
1914 D: Deserializer<'de>,
1915 {
1916 let bolt11 = String::deserialize(deserializer)?
1917 .parse::<Bolt11Invoice>()
1918 .map_err(|e| D::Error::custom(format_args!("{:?}", e)))?;
1919
1920 Ok(bolt11)
1921 }
1922}
1923
1924#[cfg(test)]
1925mod test {
1926 use bitcoin::hashes::sha256;
1927 use bitcoin::ScriptBuf;
1928 use std::str::FromStr;
1929
1930 #[test]
1931 fn test_system_time_bounds_assumptions() {
1932 assert_eq!(
1933 crate::PositiveTimestamp::from_unix_timestamp(crate::MAX_TIMESTAMP + 1),
1934 Err(crate::CreationError::TimestampOutOfBounds)
1935 );
1936 }
1937
1938 #[test]
1939 fn test_calc_invoice_hash() {
1940 use crate::TaggedField::*;
1941 use crate::{Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart, RawHrp};
1942
1943 let invoice = RawBolt11Invoice {
1944 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
1945 data: RawDataPart {
1946 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1947 tagged_fields: vec![
1948 PaymentHash(crate::Sha256(
1949 sha256::Hash::from_str(
1950 "0001020304050607080900010203040506070809000102030405060708090102",
1951 )
1952 .unwrap(),
1953 ))
1954 .into(),
1955 Description(
1956 crate::Description::new(
1957 "Please consider supporting this project".to_owned(),
1958 )
1959 .unwrap(),
1960 )
1961 .into(),
1962 ],
1963 },
1964 };
1965
1966 let expected_hash = [
1967 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1968 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1969 0xd5, 0x18, 0xe1, 0xc9,
1970 ];
1971
1972 assert_eq!(invoice.signable_hash(), expected_hash)
1973 }
1974
1975 #[test]
1976 fn test_check_signature() {
1977 use crate::TaggedField::*;
1978 use crate::{
1979 Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1980 RawHrp, Sha256, SignedRawBolt11Invoice,
1981 };
1982 use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1983 use bitcoin::secp256k1::Secp256k1;
1984 use bitcoin::secp256k1::{PublicKey, SecretKey};
1985
1986 let invoice =
1987 SignedRawBolt11Invoice {
1988 raw_invoice: RawBolt11Invoice {
1989 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
1990 data: RawDataPart {
1991 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1992 tagged_fields: vec ! [
1993 PaymentHash(Sha256(sha256::Hash::from_str(
1994 "0001020304050607080900010203040506070809000102030405060708090102"
1995 ).unwrap())).into(),
1996 Description(
1997 crate::Description::new(
1998 "Please consider supporting this project".to_owned()
1999 ).unwrap()
2000 ).into(),
2001 ],
2002 },
2003 },
2004 hash: [
2005 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b,
2006 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d,
2007 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9,
2008 ],
2009 signature: Bolt11InvoiceSignature(
2010 RecoverableSignature::from_compact(
2011 &[
2012 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
2013 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43, 0x4e,
2014 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f, 0x42, 0x5f,
2015 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad, 0x0d, 0x6e, 0x35,
2016 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9, 0xaa, 0xb1, 0x5e, 0x57,
2017 0x38, 0xb1, 0x1f, 0x12, 0x7f,
2018 ],
2019 RecoveryId::from_i32(0).unwrap(),
2020 )
2021 .unwrap(),
2022 ),
2023 };
2024
2025 assert!(invoice.check_signature());
2026
2027 let private_key = SecretKey::from_slice(
2028 &[
2029 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
2030 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
2031 0x3b, 0x2d, 0xb7, 0x34,
2032 ][..],
2033 )
2034 .unwrap();
2035 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
2036
2037 assert_eq!(invoice.recover_payee_pub_key(), Ok(crate::PayeePubKey(public_key)));
2038
2039 let (raw_invoice, _, _) = invoice.into_parts();
2040 let new_signed = raw_invoice
2041 .sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
2042 .unwrap();
2043
2044 assert!(new_signed.check_signature());
2045 }
2046
2047 #[test]
2048 fn test_check_feature_bits() {
2049 use crate::TaggedField::*;
2050 use crate::{
2051 Bolt11Invoice, Bolt11SemanticError, Currency, PositiveTimestamp, RawBolt11Invoice,
2052 RawDataPart, RawHrp, Sha256,
2053 };
2054 use bitcoin::secp256k1::Secp256k1;
2055 use bitcoin::secp256k1::SecretKey;
2056 use lightning_types::features::Bolt11InvoiceFeatures;
2057
2058 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
2059 let payment_secret = lightning_types::payment::PaymentSecret([21; 32]);
2060 let invoice_template = RawBolt11Invoice {
2061 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
2062 data: RawDataPart {
2063 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
2064 tagged_fields: vec![
2065 PaymentHash(Sha256(
2066 sha256::Hash::from_str(
2067 "0001020304050607080900010203040506070809000102030405060708090102",
2068 )
2069 .unwrap(),
2070 ))
2071 .into(),
2072 Description(
2073 crate::Description::new(
2074 "Please consider supporting this project".to_owned(),
2075 )
2076 .unwrap(),
2077 )
2078 .into(),
2079 ],
2080 },
2081 };
2082
2083 let invoice = {
2085 let mut invoice = invoice_template.clone();
2086 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2087 invoice.sign::<_, ()>(|hash| {
2088 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2089 })
2090 }
2091 .unwrap();
2092 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
2093
2094 let invoice = {
2096 let mut invoice = invoice_template.clone();
2097 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2098 invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
2099 invoice.sign::<_, ()>(|hash| {
2100 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2101 })
2102 }
2103 .unwrap();
2104 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
2105
2106 let mut payment_secret_features = Bolt11InvoiceFeatures::empty();
2107 payment_secret_features.set_payment_secret_required();
2108
2109 let invoice = {
2111 let mut invoice = invoice_template.clone();
2112 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2113 invoice.data.tagged_fields.push(Features(payment_secret_features.clone()).into());
2114 invoice.sign::<_, ()>(|hash| {
2115 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2116 })
2117 }
2118 .unwrap();
2119 assert!(Bolt11Invoice::from_signed(invoice).is_ok());
2120
2121 let invoice = {
2123 let invoice = invoice_template.clone();
2124 invoice.sign::<_, ()>(|hash| {
2125 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2126 })
2127 }
2128 .unwrap();
2129 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2130
2131 let invoice = {
2133 let mut invoice = invoice_template.clone();
2134 invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
2135 invoice.sign::<_, ()>(|hash| {
2136 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2137 })
2138 }
2139 .unwrap();
2140 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2141
2142 let invoice = {
2144 let mut invoice = invoice_template.clone();
2145 invoice.data.tagged_fields.push(Features(payment_secret_features).into());
2146 invoice.sign::<_, ()>(|hash| {
2147 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2148 })
2149 }
2150 .unwrap();
2151 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2152
2153 let invoice = {
2155 let mut invoice = invoice_template;
2156 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2157 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2158 invoice.sign::<_, ()>(|hash| {
2159 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2160 })
2161 }
2162 .unwrap();
2163 assert_eq!(
2164 Bolt11Invoice::from_signed(invoice),
2165 Err(Bolt11SemanticError::MultiplePaymentSecrets)
2166 );
2167 }
2168
2169 #[test]
2170 fn test_builder_amount() {
2171 use crate::*;
2172
2173 let builder = InvoiceBuilder::new(Currency::Bitcoin)
2174 .description("Test".into())
2175 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2176 .duration_since_epoch(Duration::from_secs(1234567));
2177
2178 let invoice = builder.clone().amount_milli_satoshis(1500).build_raw().unwrap();
2179
2180 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
2181 assert_eq!(invoice.hrp.raw_amount, Some(15));
2182
2183 let invoice = builder.amount_milli_satoshis(150).build_raw().unwrap();
2184
2185 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
2186 assert_eq!(invoice.hrp.raw_amount, Some(1500));
2187 }
2188
2189 #[test]
2190 fn test_builder_fail() {
2191 use crate::*;
2192 use bitcoin::secp256k1::PublicKey;
2193 use lightning_types::routing::RouteHintHop;
2194 use std::iter::FromIterator;
2195
2196 let builder = InvoiceBuilder::new(Currency::Bitcoin)
2197 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2198 .duration_since_epoch(Duration::from_secs(1234567))
2199 .min_final_cltv_expiry_delta(144);
2200
2201 let too_long_string = String::from_iter((0..1024).map(|_| '?'));
2202
2203 let long_desc_res = builder.clone().description(too_long_string).build_raw();
2204 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
2205
2206 let route_hop = RouteHintHop {
2207 src_node_id: PublicKey::from_slice(
2208 &[
2209 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
2210 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
2211 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
2212 ][..],
2213 )
2214 .unwrap(),
2215 short_channel_id: 0,
2216 fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
2217 cltv_expiry_delta: 0,
2218 htlc_minimum_msat: None,
2219 htlc_maximum_msat: None,
2220 };
2221 let too_long_route = RouteHint(vec![route_hop; 13]);
2222 let long_route_res =
2223 builder.clone().description("Test".into()).private_route(too_long_route).build_raw();
2224 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
2225
2226 let sign_error_res = builder
2227 .description("Test".into())
2228 .payment_secret(PaymentSecret([0; 32]))
2229 .try_build_signed(|_| Err("ImaginaryError"));
2230 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
2231 }
2232
2233 #[test]
2234 fn test_builder_ok() {
2235 use crate::*;
2236 use bitcoin::secp256k1::Secp256k1;
2237 use bitcoin::secp256k1::{PublicKey, SecretKey};
2238 use lightning_types::routing::RouteHintHop;
2239 use std::time::Duration;
2240
2241 let secp_ctx = Secp256k1::new();
2242
2243 let private_key = SecretKey::from_slice(
2244 &[
2245 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
2246 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
2247 0x3b, 0x2d, 0xb7, 0x34,
2248 ][..],
2249 )
2250 .unwrap();
2251 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
2252
2253 let route_1 = RouteHint(vec![
2254 RouteHintHop {
2255 src_node_id: public_key,
2256 short_channel_id: u64::from_be_bytes([123; 8]),
2257 fees: RoutingFees { base_msat: 2, proportional_millionths: 1 },
2258 cltv_expiry_delta: 145,
2259 htlc_minimum_msat: None,
2260 htlc_maximum_msat: None,
2261 },
2262 RouteHintHop {
2263 src_node_id: public_key,
2264 short_channel_id: u64::from_be_bytes([42; 8]),
2265 fees: RoutingFees { base_msat: 3, proportional_millionths: 2 },
2266 cltv_expiry_delta: 146,
2267 htlc_minimum_msat: None,
2268 htlc_maximum_msat: None,
2269 },
2270 ]);
2271
2272 let route_2 = RouteHint(vec![
2273 RouteHintHop {
2274 src_node_id: public_key,
2275 short_channel_id: 0,
2276 fees: RoutingFees { base_msat: 4, proportional_millionths: 3 },
2277 cltv_expiry_delta: 147,
2278 htlc_minimum_msat: None,
2279 htlc_maximum_msat: None,
2280 },
2281 RouteHintHop {
2282 src_node_id: public_key,
2283 short_channel_id: u64::from_be_bytes([1; 8]),
2284 fees: RoutingFees { base_msat: 5, proportional_millionths: 4 },
2285 cltv_expiry_delta: 148,
2286 htlc_minimum_msat: None,
2287 htlc_maximum_msat: None,
2288 },
2289 ]);
2290
2291 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
2292 .amount_milli_satoshis(123)
2293 .duration_since_epoch(Duration::from_secs(1234567))
2294 .payee_pub_key(public_key)
2295 .expiry_time(Duration::from_secs(54321))
2296 .min_final_cltv_expiry_delta(144)
2297 .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[0; 20]).unwrap()))
2298 .private_route(route_1.clone())
2299 .private_route(route_2.clone())
2300 .description_hash(sha256::Hash::from_slice(&[3; 32][..]).unwrap())
2301 .payment_hash(sha256::Hash::from_slice(&[21; 32][..]).unwrap())
2302 .payment_secret(PaymentSecret([42; 32]))
2303 .basic_mpp();
2304
2305 let invoice = builder
2306 .clone()
2307 .build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &private_key))
2308 .unwrap();
2309
2310 assert!(invoice.check_signature().is_ok());
2311 assert_eq!(invoice.tagged_fields().count(), 10);
2312
2313 assert_eq!(invoice.amount_milli_satoshis(), Some(123));
2314 assert_eq!(invoice.amount_pico_btc(), Some(1230));
2315 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
2316 #[cfg(feature = "std")]
2317 assert_eq!(
2318 invoice.timestamp().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(),
2319 1234567
2320 );
2321 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
2322 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
2323 assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
2324 assert_eq!(
2325 invoice.fallbacks(),
2326 vec![&Fallback::PubKeyHash(PubkeyHash::from_slice(&[0; 20]).unwrap())]
2327 );
2328 let address = Address::from_script(
2329 &ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[0; 20]).unwrap()),
2330 Network::Testnet,
2331 )
2332 .unwrap();
2333 assert_eq!(invoice.fallback_addresses(), vec![address]);
2334 assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
2335 assert_eq!(
2336 invoice.description(),
2337 Bolt11InvoiceDescriptionRef::Hash(&Sha256(
2338 sha256::Hash::from_slice(&[3; 32][..]).unwrap()
2339 ))
2340 );
2341 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21; 32][..]).unwrap());
2342 assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
2343
2344 let mut expected_features = Bolt11InvoiceFeatures::empty();
2345 expected_features.set_variable_length_onion_required();
2346 expected_features.set_payment_secret_required();
2347 expected_features.set_basic_mpp_optional();
2348 assert_eq!(invoice.features(), Some(&expected_features));
2349
2350 let raw_invoice = builder.build_raw().unwrap();
2351 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
2352 }
2353
2354 #[test]
2355 fn test_default_values() {
2356 use crate::*;
2357 use bitcoin::secp256k1::Secp256k1;
2358 use bitcoin::secp256k1::SecretKey;
2359
2360 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
2361 .description("Test".into())
2362 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2363 .payment_secret(PaymentSecret([0; 32]))
2364 .duration_since_epoch(Duration::from_secs(1234567))
2365 .build_raw()
2366 .unwrap()
2367 .sign::<_, ()>(|hash| {
2368 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
2369 let secp_ctx = Secp256k1::new();
2370 Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
2371 })
2372 .unwrap();
2373 let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
2374
2375 assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA);
2376 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
2377 assert!(!invoice.would_expire(Duration::from_secs(1234568)));
2378 }
2379
2380 #[test]
2381 fn test_expiration() {
2382 use crate::*;
2383 use bitcoin::secp256k1::Secp256k1;
2384 use bitcoin::secp256k1::SecretKey;
2385
2386 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
2387 .description("Test".into())
2388 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2389 .payment_secret(PaymentSecret([0; 32]))
2390 .duration_since_epoch(Duration::from_secs(1234567))
2391 .build_raw()
2392 .unwrap()
2393 .sign::<_, ()>(|hash| {
2394 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
2395 let secp_ctx = Secp256k1::new();
2396 Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
2397 })
2398 .unwrap();
2399 let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
2400
2401 assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1)));
2402 }
2403
2404 #[cfg(feature = "serde")]
2405 #[test]
2406 fn test_serde() {
2407 let invoice_str = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
2408 h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
2409 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
2410 h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
2411 j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
2412 ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
2413 guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
2414 ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
2415 p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
2416 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
2417 j5r6drg6k6zcqj0fcwg";
2418 let invoice = invoice_str.parse::<super::Bolt11Invoice>().unwrap();
2419 let serialized_invoice = serde_json::to_string(&invoice).unwrap();
2420 let deserialized_invoice: super::Bolt11Invoice =
2421 serde_json::from_str(serialized_invoice.as_str()).unwrap();
2422 assert_eq!(invoice, deserialized_invoice);
2423 assert_eq!(invoice_str, deserialized_invoice.to_string().as_str());
2424 assert_eq!(invoice_str, serialized_invoice.as_str().trim_matches('\"'));
2425 }
2426
2427 #[test]
2428 fn raw_tagged_field_ordering() {
2429 use crate::{
2430 sha256, Description, Fe32, RawTaggedField, Sha256, TaggedField, UntrustedString,
2431 };
2432
2433 let field10 = RawTaggedField::KnownSemantics(TaggedField::PaymentHash(Sha256(
2434 sha256::Hash::from_str(
2435 "0001020304050607080900010203040506070809000102030405060708090102",
2436 )
2437 .unwrap(),
2438 )));
2439 let field11 = RawTaggedField::KnownSemantics(TaggedField::Description(Description(
2440 UntrustedString("Description".to_string()),
2441 )));
2442 let field20 = RawTaggedField::UnknownSemantics(vec![Fe32::Q]);
2443 let field21 = RawTaggedField::UnknownSemantics(vec![Fe32::R]);
2444
2445 assert!(field10 < field20);
2446 assert!(field20 > field10);
2447 assert_eq!(field10.cmp(&field20), std::cmp::Ordering::Less);
2448 assert_eq!(field20.cmp(&field10), std::cmp::Ordering::Greater);
2449 assert_eq!(field10.cmp(&field10), std::cmp::Ordering::Equal);
2450 assert_eq!(field20.cmp(&field20), std::cmp::Ordering::Equal);
2451 assert_eq!(field10.partial_cmp(&field20).unwrap(), std::cmp::Ordering::Less);
2452 assert_eq!(field20.partial_cmp(&field10).unwrap(), std::cmp::Ordering::Greater);
2453
2454 assert_eq!(field10.partial_cmp(&field11).unwrap(), std::cmp::Ordering::Less);
2455 assert_eq!(field20.partial_cmp(&field21).unwrap(), std::cmp::Ordering::Less);
2456 }
2457}