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 {
1506 self.get_payee_pub_key()
1507 }
1508
1509 pub fn get_payee_pub_key(&self) -> PublicKey {
1512 match self.payee_pub_key() {
1513 Some(pk) => *pk,
1514 None => {
1515 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1516 },
1517 }
1518 }
1519
1520 pub fn expires_at(&self) -> Option<Duration> {
1523 self.duration_since_epoch().checked_add(self.expiry_time())
1524 }
1525
1526 pub fn expiry_time(&self) -> Duration {
1528 self.signed_invoice
1529 .expiry_time()
1530 .map(|x| x.0)
1531 .unwrap_or(Duration::from_secs(DEFAULT_EXPIRY_TIME))
1532 }
1533
1534 #[cfg(feature = "std")]
1536 pub fn is_expired(&self) -> bool {
1537 Self::is_expired_from_epoch(&self.timestamp(), self.expiry_time())
1538 }
1539
1540 #[cfg(feature = "std")]
1542 pub(crate) fn is_expired_from_epoch(epoch: &SystemTime, expiry_time: Duration) -> bool {
1543 match epoch.elapsed() {
1544 Ok(elapsed) => elapsed > expiry_time,
1545 Err(_) => false,
1546 }
1547 }
1548
1549 #[cfg(feature = "std")]
1551 pub fn duration_until_expiry(&self) -> Duration {
1552 SystemTime::now()
1553 .duration_since(SystemTime::UNIX_EPOCH)
1554 .map(|now| self.expiration_remaining_from_epoch(now))
1555 .unwrap_or(Duration::from_nanos(0))
1556 }
1557
1558 pub fn expiration_remaining_from_epoch(&self, time: Duration) -> Duration {
1561 self.expires_at().map(|x| x.checked_sub(time)).flatten().unwrap_or(Duration::from_nanos(0))
1562 }
1563
1564 pub fn would_expire(&self, at_time: Duration) -> bool {
1567 self.duration_since_epoch()
1568 .checked_add(self.expiry_time())
1569 .unwrap_or_else(|| Duration::new(u64::max_value(), 1_000_000_000 - 1))
1570 < at_time
1571 }
1572
1573 pub fn min_final_cltv_expiry_delta(&self) -> u64 {
1576 self.signed_invoice
1577 .min_final_cltv_expiry_delta()
1578 .map(|x| x.0)
1579 .unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA)
1580 }
1581
1582 pub fn fallbacks(&self) -> Vec<&Fallback> {
1586 self.signed_invoice.fallbacks()
1587 }
1588
1589 pub fn fallback_addresses(&self) -> Vec<Address> {
1591 let filter_fn = |fallback: &&Fallback| {
1592 let address = match fallback {
1593 Fallback::SegWitProgram { version, program } => {
1594 match WitnessProgram::new(*version, &program) {
1595 Ok(witness_program) => {
1596 Address::from_witness_program(witness_program, self.network())
1597 },
1598 Err(_) => return None,
1599 }
1600 },
1601 Fallback::PubKeyHash(pkh) => Address::p2pkh(*pkh, self.network()),
1602 Fallback::ScriptHash(sh) => Address::p2sh_from_hash(*sh, self.network()),
1603 };
1604
1605 Some(address)
1606 };
1607 self.fallbacks().iter().filter_map(filter_fn).collect()
1608 }
1609
1610 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1612 self.signed_invoice.private_routes()
1613 }
1614
1615 pub fn route_hints(&self) -> Vec<RouteHint> {
1617 find_all_extract!(
1618 self.signed_invoice.known_tagged_fields(),
1619 TaggedField::PrivateRoute(ref x),
1620 x
1621 )
1622 .map(|route| (**route).clone())
1623 .collect()
1624 }
1625
1626 pub fn currency(&self) -> Currency {
1628 self.signed_invoice.currency()
1629 }
1630
1631 pub fn network(&self) -> Network {
1635 self.signed_invoice.currency().into()
1636 }
1637
1638 pub fn amount_milli_satoshis(&self) -> Option<u64> {
1640 self.signed_invoice.amount_pico_btc().map(|v| v / 10)
1641 }
1642
1643 fn amount_pico_btc(&self) -> Option<u64> {
1645 self.signed_invoice.amount_pico_btc()
1646 }
1647}
1648
1649impl From<TaggedField> for RawTaggedField {
1650 fn from(tf: TaggedField) -> Self {
1651 RawTaggedField::KnownSemantics(tf)
1652 }
1653}
1654
1655impl TaggedField {
1656 pub fn tag(&self) -> Fe32 {
1658 let tag = match *self {
1659 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1660 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1661 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1662 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1663 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1664 TaggedField::MinFinalCltvExpiryDelta(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA,
1665 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1666 TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
1667 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1668 TaggedField::PaymentMetadata(_) => constants::TAG_PAYMENT_METADATA,
1669 TaggedField::Features(_) => constants::TAG_FEATURES,
1670 };
1671
1672 Fe32::try_from(tag).expect("all tags defined are <32")
1673 }
1674}
1675
1676impl Description {
1677 pub fn new(description: String) -> Result<Description, CreationError> {
1682 if description.len() > 639 {
1683 Err(CreationError::DescriptionTooLong)
1684 } else {
1685 Ok(Description(UntrustedString(description)))
1686 }
1687 }
1688
1689 pub fn empty() -> Self {
1691 Description(UntrustedString(String::new()))
1692 }
1693
1694 pub fn into_inner(self) -> UntrustedString {
1696 self.0
1697 }
1698
1699 pub fn as_inner(&self) -> &UntrustedString {
1701 &self.0
1702 }
1703}
1704
1705impl Display for Description {
1706 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1707 write!(f, "{}", self.0)
1708 }
1709}
1710
1711impl From<PublicKey> for PayeePubKey {
1712 fn from(pk: PublicKey) -> Self {
1713 PayeePubKey(pk)
1714 }
1715}
1716
1717impl Deref for PayeePubKey {
1718 type Target = PublicKey;
1719
1720 fn deref(&self) -> &PublicKey {
1721 &self.0
1722 }
1723}
1724
1725impl ExpiryTime {
1726 pub fn from_seconds(seconds: u64) -> ExpiryTime {
1728 ExpiryTime(Duration::from_secs(seconds))
1729 }
1730
1731 pub fn from_duration(duration: Duration) -> ExpiryTime {
1733 Self::from_seconds(duration.as_secs())
1734 }
1735
1736 pub fn as_seconds(&self) -> u64 {
1738 self.0.as_secs()
1739 }
1740
1741 pub fn as_duration(&self) -> &Duration {
1743 &self.0
1744 }
1745}
1746
1747impl PrivateRoute {
1748 pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
1750 if hops.0.len() <= 12 {
1751 Ok(PrivateRoute(hops))
1752 } else {
1753 Err(CreationError::RouteTooLong)
1754 }
1755 }
1756
1757 pub fn into_inner(self) -> RouteHint {
1759 self.0
1760 }
1761}
1762
1763impl From<PrivateRoute> for RouteHint {
1764 fn from(val: PrivateRoute) -> Self {
1765 val.into_inner()
1766 }
1767}
1768
1769impl Deref for PrivateRoute {
1770 type Target = RouteHint;
1771
1772 fn deref(&self) -> &RouteHint {
1773 &self.0
1774 }
1775}
1776
1777impl Deref for Bolt11InvoiceSignature {
1778 type Target = RecoverableSignature;
1779
1780 fn deref(&self) -> &RecoverableSignature {
1781 &self.0
1782 }
1783}
1784
1785impl Deref for SignedRawBolt11Invoice {
1786 type Target = RawBolt11Invoice;
1787
1788 fn deref(&self) -> &RawBolt11Invoice {
1789 &self.raw_invoice
1790 }
1791}
1792
1793#[derive(Eq, PartialEq, Debug, Clone)]
1795pub enum CreationError {
1796 DescriptionTooLong,
1798
1799 RouteTooLong,
1801
1802 TimestampOutOfBounds,
1804
1805 InvalidAmount,
1807
1808 MissingRouteHints,
1812
1813 MinFinalCltvExpiryDeltaTooShort,
1815}
1816
1817impl Display for CreationError {
1818 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1819 match self {
1820 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1821 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1822 CreationError::TimestampOutOfBounds => f.write_str("The Unix timestamp of the supplied date is less than zero or greater than 35-bits"),
1823 CreationError::InvalidAmount => f.write_str("The supplied millisatoshi amount was greater than the total bitcoin supply"),
1824 CreationError::MissingRouteHints => f.write_str("The invoice required route hints and they weren't provided"),
1825 CreationError::MinFinalCltvExpiryDeltaTooShort => f.write_str(
1826 "The supplied final CLTV expiry delta was less than LDK's `MIN_FINAL_CLTV_EXPIRY_DELTA`"),
1827 }
1828 }
1829}
1830
1831#[cfg(feature = "std")]
1832impl std::error::Error for CreationError {}
1833
1834#[derive(Eq, PartialEq, Debug, Clone)]
1837pub enum Bolt11SemanticError {
1838 NoPaymentHash,
1840
1841 MultiplePaymentHashes,
1843
1844 NoDescription,
1846
1847 MultipleDescriptions,
1849
1850 NoPaymentSecret,
1853
1854 MultiplePaymentSecrets,
1856
1857 InvalidFeatures,
1859
1860 InvalidSignature,
1862
1863 ImpreciseAmount,
1865}
1866
1867impl Display for Bolt11SemanticError {
1868 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1869 match self {
1870 Bolt11SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1871 Bolt11SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1872 Bolt11SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1873 Bolt11SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1874 Bolt11SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
1875 Bolt11SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1876 Bolt11SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1877 Bolt11SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1878 Bolt11SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
1879 }
1880 }
1881}
1882
1883#[cfg(feature = "std")]
1884impl std::error::Error for Bolt11SemanticError {}
1885
1886#[derive(Eq, PartialEq, Debug, Clone)]
1889pub enum SignOrCreationError<S = ()> {
1890 SignError(S),
1892
1893 CreationError(CreationError),
1895}
1896
1897impl<S> Display for SignOrCreationError<S> {
1898 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1899 match self {
1900 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1901 SignOrCreationError::CreationError(err) => err.fmt(f),
1902 }
1903 }
1904}
1905
1906#[cfg(feature = "serde")]
1907impl Serialize for Bolt11Invoice {
1908 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1909 where
1910 S: Serializer,
1911 {
1912 serializer.serialize_str(self.to_string().as_str())
1913 }
1914}
1915#[cfg(feature = "serde")]
1916impl<'de> Deserialize<'de> for Bolt11Invoice {
1917 fn deserialize<D>(deserializer: D) -> Result<Bolt11Invoice, D::Error>
1918 where
1919 D: Deserializer<'de>,
1920 {
1921 let bolt11 = String::deserialize(deserializer)?
1922 .parse::<Bolt11Invoice>()
1923 .map_err(|e| D::Error::custom(format_args!("{:?}", e)))?;
1924
1925 Ok(bolt11)
1926 }
1927}
1928
1929#[cfg(test)]
1930mod test {
1931 use bitcoin::hashes::sha256;
1932 use bitcoin::ScriptBuf;
1933 use std::str::FromStr;
1934
1935 #[test]
1936 fn test_system_time_bounds_assumptions() {
1937 assert_eq!(
1938 crate::PositiveTimestamp::from_unix_timestamp(crate::MAX_TIMESTAMP + 1),
1939 Err(crate::CreationError::TimestampOutOfBounds)
1940 );
1941 }
1942
1943 #[test]
1944 fn test_calc_invoice_hash() {
1945 use crate::TaggedField::*;
1946 use crate::{Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart, RawHrp};
1947
1948 let invoice = RawBolt11Invoice {
1949 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
1950 data: RawDataPart {
1951 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1952 tagged_fields: vec![
1953 PaymentHash(crate::Sha256(
1954 sha256::Hash::from_str(
1955 "0001020304050607080900010203040506070809000102030405060708090102",
1956 )
1957 .unwrap(),
1958 ))
1959 .into(),
1960 Description(
1961 crate::Description::new(
1962 "Please consider supporting this project".to_owned(),
1963 )
1964 .unwrap(),
1965 )
1966 .into(),
1967 ],
1968 },
1969 };
1970
1971 let expected_hash = [
1972 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1973 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1974 0xd5, 0x18, 0xe1, 0xc9,
1975 ];
1976
1977 assert_eq!(invoice.signable_hash(), expected_hash)
1978 }
1979
1980 #[test]
1981 fn test_check_signature() {
1982 use crate::TaggedField::*;
1983 use crate::{
1984 Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1985 RawHrp, Sha256, SignedRawBolt11Invoice,
1986 };
1987 use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1988 use bitcoin::secp256k1::Secp256k1;
1989 use bitcoin::secp256k1::{PublicKey, SecretKey};
1990
1991 let invoice =
1992 SignedRawBolt11Invoice {
1993 raw_invoice: RawBolt11Invoice {
1994 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
1995 data: RawDataPart {
1996 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1997 tagged_fields: vec ! [
1998 PaymentHash(Sha256(sha256::Hash::from_str(
1999 "0001020304050607080900010203040506070809000102030405060708090102"
2000 ).unwrap())).into(),
2001 Description(
2002 crate::Description::new(
2003 "Please consider supporting this project".to_owned()
2004 ).unwrap()
2005 ).into(),
2006 ],
2007 },
2008 },
2009 hash: [
2010 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b,
2011 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d,
2012 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9,
2013 ],
2014 signature: Bolt11InvoiceSignature(
2015 RecoverableSignature::from_compact(
2016 &[
2017 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
2018 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43, 0x4e,
2019 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f, 0x42, 0x5f,
2020 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad, 0x0d, 0x6e, 0x35,
2021 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9, 0xaa, 0xb1, 0x5e, 0x57,
2022 0x38, 0xb1, 0x1f, 0x12, 0x7f,
2023 ],
2024 RecoveryId::from_i32(0).unwrap(),
2025 )
2026 .unwrap(),
2027 ),
2028 };
2029
2030 assert!(invoice.check_signature());
2031
2032 let private_key = SecretKey::from_slice(
2033 &[
2034 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
2035 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
2036 0x3b, 0x2d, 0xb7, 0x34,
2037 ][..],
2038 )
2039 .unwrap();
2040 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
2041
2042 assert_eq!(invoice.recover_payee_pub_key(), Ok(crate::PayeePubKey(public_key)));
2043
2044 let (raw_invoice, _, _) = invoice.into_parts();
2045 let new_signed = raw_invoice
2046 .sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
2047 .unwrap();
2048
2049 assert!(new_signed.check_signature());
2050 }
2051
2052 #[test]
2053 fn recover_payee_pub_key_uses_included_payee_pub_key() {
2054 use crate::*;
2055 use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
2056 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
2057 use core::time::Duration;
2058
2059 let secp_ctx = Secp256k1::new();
2060 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
2061 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
2062
2063 let invoice = InvoiceBuilder::new(Currency::Bitcoin)
2064 .description("Test".to_string())
2065 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2066 .payment_secret(PaymentSecret([21; 32]))
2067 .payee_pub_key(public_key)
2068 .min_final_cltv_expiry_delta(144)
2069 .duration_since_epoch(Duration::from_secs(1234567))
2070 .build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &private_key))
2071 .unwrap();
2072
2073 let signed_raw = invoice.into_signed_raw();
2074 let (raw_invoice, hash, signature) = signed_raw.into_parts();
2075 let (_orig_rid, sig_bytes) = signature.0.serialize_compact();
2076 let bad_rid = RecoveryId::from_i32(2).unwrap();
2077 let bad_sig = RecoverableSignature::from_compact(&sig_bytes, bad_rid).unwrap();
2078 let bad_signed_raw = SignedRawBolt11Invoice {
2079 raw_invoice,
2080 hash,
2081 signature: Bolt11InvoiceSignature(bad_sig),
2082 };
2083 let bad_invoice = Bolt11Invoice::from_signed(bad_signed_raw).unwrap();
2084
2085 assert_eq!(bad_invoice.payee_pub_key(), Some(&public_key));
2086 assert_eq!(bad_invoice.recover_payee_pub_key(), public_key);
2087 assert_eq!(bad_invoice.get_payee_pub_key(), public_key);
2088 }
2089
2090 #[test]
2091 fn test_check_feature_bits() {
2092 use crate::TaggedField::*;
2093 use crate::{
2094 Bolt11Invoice, Bolt11SemanticError, Currency, PositiveTimestamp, RawBolt11Invoice,
2095 RawDataPart, RawHrp, Sha256,
2096 };
2097 use bitcoin::secp256k1::Secp256k1;
2098 use bitcoin::secp256k1::SecretKey;
2099 use lightning_types::features::Bolt11InvoiceFeatures;
2100
2101 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
2102 let payment_secret = lightning_types::payment::PaymentSecret([21; 32]);
2103 let invoice_template = RawBolt11Invoice {
2104 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
2105 data: RawDataPart {
2106 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
2107 tagged_fields: vec![
2108 PaymentHash(Sha256(
2109 sha256::Hash::from_str(
2110 "0001020304050607080900010203040506070809000102030405060708090102",
2111 )
2112 .unwrap(),
2113 ))
2114 .into(),
2115 Description(
2116 crate::Description::new(
2117 "Please consider supporting this project".to_owned(),
2118 )
2119 .unwrap(),
2120 )
2121 .into(),
2122 ],
2123 },
2124 };
2125
2126 let invoice = {
2128 let mut invoice = invoice_template.clone();
2129 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2130 invoice.sign::<_, ()>(|hash| {
2131 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2132 })
2133 }
2134 .unwrap();
2135 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
2136
2137 let invoice = {
2139 let mut invoice = invoice_template.clone();
2140 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2141 invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
2142 invoice.sign::<_, ()>(|hash| {
2143 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2144 })
2145 }
2146 .unwrap();
2147 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
2148
2149 let mut payment_secret_features = Bolt11InvoiceFeatures::empty();
2150 payment_secret_features.set_payment_secret_required();
2151
2152 let invoice = {
2154 let mut invoice = invoice_template.clone();
2155 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2156 invoice.data.tagged_fields.push(Features(payment_secret_features.clone()).into());
2157 invoice.sign::<_, ()>(|hash| {
2158 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2159 })
2160 }
2161 .unwrap();
2162 assert!(Bolt11Invoice::from_signed(invoice).is_ok());
2163
2164 let invoice = {
2166 let invoice = invoice_template.clone();
2167 invoice.sign::<_, ()>(|hash| {
2168 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2169 })
2170 }
2171 .unwrap();
2172 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2173
2174 let invoice = {
2176 let mut invoice = invoice_template.clone();
2177 invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
2178 invoice.sign::<_, ()>(|hash| {
2179 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2180 })
2181 }
2182 .unwrap();
2183 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2184
2185 let invoice = {
2187 let mut invoice = invoice_template.clone();
2188 invoice.data.tagged_fields.push(Features(payment_secret_features).into());
2189 invoice.sign::<_, ()>(|hash| {
2190 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2191 })
2192 }
2193 .unwrap();
2194 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2195
2196 let invoice = {
2198 let mut invoice = invoice_template;
2199 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2200 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2201 invoice.sign::<_, ()>(|hash| {
2202 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2203 })
2204 }
2205 .unwrap();
2206 assert_eq!(
2207 Bolt11Invoice::from_signed(invoice),
2208 Err(Bolt11SemanticError::MultiplePaymentSecrets)
2209 );
2210 }
2211
2212 #[test]
2213 fn test_builder_amount() {
2214 use crate::*;
2215
2216 let builder = InvoiceBuilder::new(Currency::Bitcoin)
2217 .description("Test".into())
2218 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2219 .duration_since_epoch(Duration::from_secs(1234567));
2220
2221 let invoice = builder.clone().amount_milli_satoshis(1500).build_raw().unwrap();
2222
2223 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
2224 assert_eq!(invoice.hrp.raw_amount, Some(15));
2225
2226 let invoice = builder.amount_milli_satoshis(150).build_raw().unwrap();
2227
2228 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
2229 assert_eq!(invoice.hrp.raw_amount, Some(1500));
2230 }
2231
2232 #[test]
2233 fn test_builder_fail() {
2234 use crate::*;
2235 use bitcoin::secp256k1::PublicKey;
2236 use lightning_types::routing::RouteHintHop;
2237 use std::iter::FromIterator;
2238
2239 let builder = InvoiceBuilder::new(Currency::Bitcoin)
2240 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2241 .duration_since_epoch(Duration::from_secs(1234567))
2242 .min_final_cltv_expiry_delta(144);
2243
2244 let too_long_string = String::from_iter((0..1024).map(|_| '?'));
2245
2246 let long_desc_res = builder.clone().description(too_long_string).build_raw();
2247 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
2248
2249 let route_hop = RouteHintHop {
2250 src_node_id: PublicKey::from_slice(
2251 &[
2252 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
2253 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
2254 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
2255 ][..],
2256 )
2257 .unwrap(),
2258 short_channel_id: 0,
2259 fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
2260 cltv_expiry_delta: 0,
2261 htlc_minimum_msat: None,
2262 htlc_maximum_msat: None,
2263 };
2264 let too_long_route = RouteHint(vec![route_hop; 13]);
2265 let long_route_res =
2266 builder.clone().description("Test".into()).private_route(too_long_route).build_raw();
2267 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
2268
2269 let sign_error_res = builder
2270 .description("Test".into())
2271 .payment_secret(PaymentSecret([0; 32]))
2272 .try_build_signed(|_| Err("ImaginaryError"));
2273 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
2274 }
2275
2276 #[test]
2277 fn test_builder_ok() {
2278 use crate::*;
2279 use bitcoin::secp256k1::Secp256k1;
2280 use bitcoin::secp256k1::{PublicKey, SecretKey};
2281 use lightning_types::routing::RouteHintHop;
2282 use std::time::Duration;
2283
2284 let secp_ctx = Secp256k1::new();
2285
2286 let private_key = SecretKey::from_slice(
2287 &[
2288 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
2289 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
2290 0x3b, 0x2d, 0xb7, 0x34,
2291 ][..],
2292 )
2293 .unwrap();
2294 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
2295
2296 let route_1 = RouteHint(vec![
2297 RouteHintHop {
2298 src_node_id: public_key,
2299 short_channel_id: u64::from_be_bytes([123; 8]),
2300 fees: RoutingFees { base_msat: 2, proportional_millionths: 1 },
2301 cltv_expiry_delta: 145,
2302 htlc_minimum_msat: None,
2303 htlc_maximum_msat: None,
2304 },
2305 RouteHintHop {
2306 src_node_id: public_key,
2307 short_channel_id: u64::from_be_bytes([42; 8]),
2308 fees: RoutingFees { base_msat: 3, proportional_millionths: 2 },
2309 cltv_expiry_delta: 146,
2310 htlc_minimum_msat: None,
2311 htlc_maximum_msat: None,
2312 },
2313 ]);
2314
2315 let route_2 = RouteHint(vec![
2316 RouteHintHop {
2317 src_node_id: public_key,
2318 short_channel_id: 0,
2319 fees: RoutingFees { base_msat: 4, proportional_millionths: 3 },
2320 cltv_expiry_delta: 147,
2321 htlc_minimum_msat: None,
2322 htlc_maximum_msat: None,
2323 },
2324 RouteHintHop {
2325 src_node_id: public_key,
2326 short_channel_id: u64::from_be_bytes([1; 8]),
2327 fees: RoutingFees { base_msat: 5, proportional_millionths: 4 },
2328 cltv_expiry_delta: 148,
2329 htlc_minimum_msat: None,
2330 htlc_maximum_msat: None,
2331 },
2332 ]);
2333
2334 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
2335 .amount_milli_satoshis(123)
2336 .duration_since_epoch(Duration::from_secs(1234567))
2337 .payee_pub_key(public_key)
2338 .expiry_time(Duration::from_secs(54321))
2339 .min_final_cltv_expiry_delta(144)
2340 .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[0; 20]).unwrap()))
2341 .private_route(route_1.clone())
2342 .private_route(route_2.clone())
2343 .description_hash(sha256::Hash::from_slice(&[3; 32][..]).unwrap())
2344 .payment_hash(sha256::Hash::from_slice(&[21; 32][..]).unwrap())
2345 .payment_secret(PaymentSecret([42; 32]))
2346 .basic_mpp();
2347
2348 let invoice = builder
2349 .clone()
2350 .build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &private_key))
2351 .unwrap();
2352
2353 assert!(invoice.check_signature().is_ok());
2354 assert_eq!(invoice.tagged_fields().count(), 10);
2355
2356 assert_eq!(invoice.amount_milli_satoshis(), Some(123));
2357 assert_eq!(invoice.amount_pico_btc(), Some(1230));
2358 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
2359 #[cfg(feature = "std")]
2360 assert_eq!(
2361 invoice.timestamp().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(),
2362 1234567
2363 );
2364 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
2365 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
2366 assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
2367 assert_eq!(
2368 invoice.fallbacks(),
2369 vec![&Fallback::PubKeyHash(PubkeyHash::from_slice(&[0; 20]).unwrap())]
2370 );
2371 let address = Address::from_script(
2372 &ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[0; 20]).unwrap()),
2373 Network::Testnet,
2374 )
2375 .unwrap();
2376 assert_eq!(invoice.fallback_addresses(), vec![address]);
2377 assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
2378 assert_eq!(
2379 invoice.description(),
2380 Bolt11InvoiceDescriptionRef::Hash(&Sha256(
2381 sha256::Hash::from_slice(&[3; 32][..]).unwrap()
2382 ))
2383 );
2384 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21; 32][..]).unwrap());
2385 assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
2386
2387 let mut expected_features = Bolt11InvoiceFeatures::empty();
2388 expected_features.set_variable_length_onion_required();
2389 expected_features.set_payment_secret_required();
2390 expected_features.set_basic_mpp_optional();
2391 assert_eq!(invoice.features(), Some(&expected_features));
2392
2393 let raw_invoice = builder.build_raw().unwrap();
2394 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
2395 }
2396
2397 #[test]
2398 fn test_default_values() {
2399 use crate::*;
2400 use bitcoin::secp256k1::Secp256k1;
2401 use bitcoin::secp256k1::SecretKey;
2402
2403 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
2404 .description("Test".into())
2405 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2406 .payment_secret(PaymentSecret([0; 32]))
2407 .duration_since_epoch(Duration::from_secs(1234567))
2408 .build_raw()
2409 .unwrap()
2410 .sign::<_, ()>(|hash| {
2411 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
2412 let secp_ctx = Secp256k1::new();
2413 Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
2414 })
2415 .unwrap();
2416 let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
2417
2418 assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA);
2419 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
2420 assert!(!invoice.would_expire(Duration::from_secs(1234568)));
2421 }
2422
2423 #[test]
2424 fn test_expiration() {
2425 use crate::*;
2426 use bitcoin::secp256k1::Secp256k1;
2427 use bitcoin::secp256k1::SecretKey;
2428
2429 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
2430 .description("Test".into())
2431 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2432 .payment_secret(PaymentSecret([0; 32]))
2433 .duration_since_epoch(Duration::from_secs(1234567))
2434 .build_raw()
2435 .unwrap()
2436 .sign::<_, ()>(|hash| {
2437 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
2438 let secp_ctx = Secp256k1::new();
2439 Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
2440 })
2441 .unwrap();
2442 let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
2443
2444 assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1)));
2445 }
2446
2447 #[cfg(feature = "serde")]
2448 #[test]
2449 fn test_serde() {
2450 let invoice_str = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
2451 h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
2452 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
2453 h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
2454 j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
2455 ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
2456 guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
2457 ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
2458 p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
2459 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
2460 j5r6drg6k6zcqj0fcwg";
2461 let invoice = invoice_str.parse::<super::Bolt11Invoice>().unwrap();
2462 let serialized_invoice = serde_json::to_string(&invoice).unwrap();
2463 let deserialized_invoice: super::Bolt11Invoice =
2464 serde_json::from_str(serialized_invoice.as_str()).unwrap();
2465 assert_eq!(invoice, deserialized_invoice);
2466 assert_eq!(invoice_str, deserialized_invoice.to_string().as_str());
2467 assert_eq!(invoice_str, serialized_invoice.as_str().trim_matches('\"'));
2468 }
2469
2470 #[test]
2471 fn raw_tagged_field_ordering() {
2472 use crate::{
2473 sha256, Description, Fe32, RawTaggedField, Sha256, TaggedField, UntrustedString,
2474 };
2475
2476 let field10 = RawTaggedField::KnownSemantics(TaggedField::PaymentHash(Sha256(
2477 sha256::Hash::from_str(
2478 "0001020304050607080900010203040506070809000102030405060708090102",
2479 )
2480 .unwrap(),
2481 )));
2482 let field11 = RawTaggedField::KnownSemantics(TaggedField::Description(Description(
2483 UntrustedString("Description".to_string()),
2484 )));
2485 let field20 = RawTaggedField::UnknownSemantics(vec![Fe32::Q]);
2486 let field21 = RawTaggedField::UnknownSemantics(vec![Fe32::R]);
2487
2488 assert!(field10 < field20);
2489 assert!(field20 > field10);
2490 assert_eq!(field10.cmp(&field20), std::cmp::Ordering::Less);
2491 assert_eq!(field20.cmp(&field10), std::cmp::Ordering::Greater);
2492 assert_eq!(field10.cmp(&field10), std::cmp::Ordering::Equal);
2493 assert_eq!(field20.cmp(&field20), std::cmp::Ordering::Equal);
2494 assert_eq!(field10.partial_cmp(&field20).unwrap(), std::cmp::Ordering::Less);
2495 assert_eq!(field20.partial_cmp(&field10).unwrap(), std::cmp::Ordering::Greater);
2496
2497 assert_eq!(field10.partial_cmp(&field11).unwrap(), std::cmp::Ordering::Less);
2498 assert_eq!(field20.partial_cmp(&field21).unwrap(), std::cmp::Ordering::Less);
2499 }
2500}