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_auto_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(CheckedHrpstringError),
95 ParseAmountError(ParseIntError),
96 MalformedSignature(bitcoin::secp256k1::Error),
97 BadPrefix,
98 UnknownCurrency,
99 UnknownSiPrefix,
100 MalformedHRP,
101 TooShortDataPart,
102 UnexpectedEndOfTaggedFields,
103 DescriptionDecodeError(string::FromUtf8Error),
104 PaddingError,
105 IntegerOverflowError,
106 InvalidSegWitProgramLength,
107 InvalidPubKeyHashLength,
108 InvalidScriptHashLength,
109 InvalidRecoveryId,
110 InvalidSliceLength(usize, usize, &'static str),
112
113 Skip,
116}
117
118#[derive(PartialEq, Eq, Debug, Clone)]
122pub enum ParseOrSemanticError {
123 ParseError(Bolt11ParseError),
125
126 SemanticError(crate::Bolt11SemanticError),
128}
129
130const TIMESTAMP_BITS: usize = 35;
132
133pub const MAX_TIMESTAMP: u64 = (1 << TIMESTAMP_BITS) - 1;
137
138pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
142
143pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
149
150pub const MAX_LENGTH: usize = 7089;
160
161pub enum Bolt11Bech32 {}
164
165impl Checksum for Bolt11Bech32 {
166 const CODE_LENGTH: usize = MAX_LENGTH;
168
169 type MidstateRepr = <bech32::Bech32 as Checksum>::MidstateRepr;
171 const CHECKSUM_LENGTH: usize = bech32::Bech32::CHECKSUM_LENGTH;
172 const GENERATOR_SH: [Self::MidstateRepr; 5] = bech32::Bech32::GENERATOR_SH;
173 const TARGET_RESIDUE: Self::MidstateRepr = bech32::Bech32::TARGET_RESIDUE;
174}
175
176#[derive(Eq, PartialEq, Debug, Clone)]
235pub struct InvoiceBuilder<
236 D: tb::Bool,
237 H: tb::Bool,
238 T: tb::Bool,
239 C: tb::Bool,
240 S: tb::Bool,
241 M: tb::Bool,
242> {
243 currency: Currency,
244 amount: Option<u64>,
245 si_prefix: Option<SiPrefix>,
246 timestamp: Option<PositiveTimestamp>,
247 tagged_fields: Vec<TaggedField>,
248 error: Option<CreationError>,
249
250 phantom_d: core::marker::PhantomData<D>,
251 phantom_h: core::marker::PhantomData<H>,
252 phantom_t: core::marker::PhantomData<T>,
253 phantom_c: core::marker::PhantomData<C>,
254 phantom_s: core::marker::PhantomData<S>,
255 phantom_m: core::marker::PhantomData<M>,
256}
257
258#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
267pub struct Bolt11Invoice {
268 signed_invoice: SignedRawBolt11Invoice,
269}
270
271#[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)]
274pub enum Bolt11InvoiceDescription {
275 Direct(Description),
277
278 Hash(Sha256),
280}
281
282impl Display for Bolt11InvoiceDescription {
283 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
284 match self {
285 Bolt11InvoiceDescription::Direct(desc) => write!(f, "{}", desc.0),
286 Bolt11InvoiceDescription::Hash(hash) => write!(f, "{}", hash.0),
287 }
288 }
289}
290
291#[derive(Eq, PartialEq, Debug, Clone, Copy, Ord, PartialOrd)]
297pub enum Bolt11InvoiceDescriptionRef<'f> {
298 Direct(&'f Description),
300
301 Hash(&'f Sha256),
303}
304
305impl<'f> Display for Bolt11InvoiceDescriptionRef<'f> {
306 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
307 match self {
308 Bolt11InvoiceDescriptionRef::Direct(desc) => write!(f, "{}", desc.0),
309 Bolt11InvoiceDescriptionRef::Hash(hash) => write!(f, "{}", hash.0),
310 }
311 }
312}
313
314#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
320pub struct SignedRawBolt11Invoice {
321 raw_invoice: RawBolt11Invoice,
323
324 hash: [u8; 32],
332
333 signature: Bolt11InvoiceSignature,
335}
336
337#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
343pub struct RawBolt11Invoice {
344 pub hrp: RawHrp,
346
347 pub data: RawDataPart,
349}
350
351#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
355pub struct RawHrp {
356 pub currency: Currency,
358
359 pub raw_amount: Option<u64>,
361
362 pub si_prefix: Option<SiPrefix>,
364}
365
366impl RawHrp {
367 pub fn to_hrp(&self) -> bech32::Hrp {
369 let hrp_str = self.to_string();
370 let s = core::str::from_utf8(&hrp_str.as_bytes()).expect("HRP bytes should be ASCII");
371 debug_assert!(bech32::Hrp::parse(s).is_ok(), "We should always build BIP 173-valid HRPs");
372 bech32::Hrp::parse_unchecked(s)
373 }
374}
375
376#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
378pub struct RawDataPart {
379 pub timestamp: PositiveTimestamp,
381
382 pub tagged_fields: Vec<RawTaggedField>,
384}
385
386#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)]
393pub struct PositiveTimestamp(Duration);
394
395#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Ord, PartialOrd)]
397pub enum SiPrefix {
398 Milli,
400 Micro,
402 Nano,
404 Pico,
406}
407
408impl SiPrefix {
409 pub fn multiplier(&self) -> u64 {
412 match *self {
413 SiPrefix::Milli => 1_000_000_000,
414 SiPrefix::Micro => 1_000_000,
415 SiPrefix::Nano => 1_000,
416 SiPrefix::Pico => 1,
417 }
418 }
419
420 pub fn values_desc() -> &'static [SiPrefix] {
426 use crate::SiPrefix::*;
427 static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
428 &VALUES
429 }
430}
431
432#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
434pub enum Currency {
435 Bitcoin,
437
438 BitcoinTestnet,
440
441 Regtest,
443
444 Simnet,
446
447 Signet,
449}
450
451impl From<Network> for Currency {
452 fn from(network: Network) -> Self {
453 match network {
454 Network::Bitcoin => Currency::Bitcoin,
455 Network::Testnet => Currency::BitcoinTestnet,
456 Network::Regtest => Currency::Regtest,
457 Network::Signet => Currency::Signet,
458 _ => {
459 debug_assert!(false, "Need to handle new rust-bitcoin network type");
460 Currency::Regtest
461 },
462 }
463 }
464}
465
466impl From<Currency> for Network {
467 fn from(currency: Currency) -> Self {
468 match currency {
469 Currency::Bitcoin => Network::Bitcoin,
470 Currency::BitcoinTestnet => Network::Testnet,
471 Currency::Regtest => Network::Regtest,
472 Currency::Simnet => Network::Regtest,
473 Currency::Signet => Network::Signet,
474 }
475 }
476}
477
478#[derive(Clone, Debug, Hash, Eq, PartialEq)]
482pub enum RawTaggedField {
483 KnownSemantics(TaggedField),
485 UnknownSemantics(Vec<Fe32>),
487}
488
489impl PartialOrd for RawTaggedField {
490 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
491 Some(self.cmp(other))
492 }
493}
494
495impl Ord for RawTaggedField {
497 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
498 match (self, other) {
499 (RawTaggedField::KnownSemantics(ref a), RawTaggedField::KnownSemantics(ref b)) => {
500 a.cmp(b)
501 },
502 (RawTaggedField::UnknownSemantics(ref a), RawTaggedField::UnknownSemantics(ref b)) => {
503 a.iter().map(|a| a.to_u8()).cmp(b.iter().map(|b| b.to_u8()))
504 },
505 (RawTaggedField::KnownSemantics(..), RawTaggedField::UnknownSemantics(..)) => {
506 core::cmp::Ordering::Less
507 },
508 (RawTaggedField::UnknownSemantics(..), RawTaggedField::KnownSemantics(..)) => {
509 core::cmp::Ordering::Greater
510 },
511 }
512 }
513}
514
515#[allow(missing_docs)]
522#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
523pub enum TaggedField {
524 PaymentHash(Sha256),
525 Description(Description),
526 PayeePubKey(PayeePubKey),
527 DescriptionHash(Sha256),
528 ExpiryTime(ExpiryTime),
529 MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta),
530 Fallback(Fallback),
531 PrivateRoute(PrivateRoute),
532 PaymentSecret(PaymentSecret),
533 PaymentMetadata(Vec<u8>),
534 Features(Bolt11InvoiceFeatures),
535}
536
537#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
539pub struct Sha256(
540 pub sha256::Hash,
542);
543
544impl Sha256 {
545 #[cfg(c_bindings)]
548 pub fn from_bytes(bytes: &[u8; 32]) -> Self {
549 Self(sha256::Hash::from_slice(bytes).expect("from_slice only fails if len is not 32"))
550 }
551}
552
553#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
558pub struct Description(UntrustedString);
559
560#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
562pub struct PayeePubKey(pub PublicKey);
563
564#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
567pub struct ExpiryTime(Duration);
568
569#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
571pub struct MinFinalCltvExpiryDelta(pub u64);
572
573#[allow(missing_docs)]
575#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
576pub enum Fallback {
577 SegWitProgram { version: WitnessVersion, program: Vec<u8> },
578 PubKeyHash(PubkeyHash),
579 ScriptHash(ScriptHash),
580}
581
582#[derive(Clone, Debug, Hash, Eq, PartialEq)]
584pub struct Bolt11InvoiceSignature(pub RecoverableSignature);
585
586impl PartialOrd for Bolt11InvoiceSignature {
587 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
588 Some(self.cmp(other))
589 }
590}
591
592impl Ord for Bolt11InvoiceSignature {
593 fn cmp(&self, other: &Self) -> Ordering {
594 self.0.serialize_compact().1.cmp(&other.0.serialize_compact().1)
595 }
596}
597
598#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
604pub struct PrivateRoute(RouteHint);
605
606#[allow(missing_docs)]
608pub mod constants {
609 pub const TAG_PAYMENT_HASH: u8 = 1;
610 pub const TAG_DESCRIPTION: u8 = 13;
611 pub const TAG_PAYEE_PUB_KEY: u8 = 19;
612 pub const TAG_DESCRIPTION_HASH: u8 = 23;
613 pub const TAG_EXPIRY_TIME: u8 = 6;
614 pub const TAG_MIN_FINAL_CLTV_EXPIRY_DELTA: u8 = 24;
615 pub const TAG_FALLBACK: u8 = 9;
616 pub const TAG_PRIVATE_ROUTE: u8 = 3;
617 pub const TAG_PAYMENT_SECRET: u8 = 16;
618 pub const TAG_PAYMENT_METADATA: u8 = 27;
619 pub const TAG_FEATURES: u8 = 5;
620}
621
622impl InvoiceBuilder<tb::False, tb::False, tb::False, tb::False, tb::False, tb::False> {
623 pub fn new(currency: Currency) -> Self {
626 InvoiceBuilder {
627 currency,
628 amount: None,
629 si_prefix: None,
630 timestamp: None,
631 tagged_fields: Vec::with_capacity(8),
632 error: None,
633
634 phantom_d: core::marker::PhantomData,
635 phantom_h: core::marker::PhantomData,
636 phantom_t: core::marker::PhantomData,
637 phantom_c: core::marker::PhantomData,
638 phantom_s: core::marker::PhantomData,
639 phantom_m: core::marker::PhantomData,
640 }
641 }
642}
643
644impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
645 InvoiceBuilder<D, H, T, C, S, M>
646{
647 fn set_flags<
649 DN: tb::Bool,
650 HN: tb::Bool,
651 TN: tb::Bool,
652 CN: tb::Bool,
653 SN: tb::Bool,
654 MN: tb::Bool,
655 >(
656 self,
657 ) -> InvoiceBuilder<DN, HN, TN, CN, SN, MN> {
658 InvoiceBuilder::<DN, HN, TN, CN, SN, MN> {
659 currency: self.currency,
660 amount: self.amount,
661 si_prefix: self.si_prefix,
662 timestamp: self.timestamp,
663 tagged_fields: self.tagged_fields,
664 error: self.error,
665
666 phantom_d: core::marker::PhantomData,
667 phantom_h: core::marker::PhantomData,
668 phantom_t: core::marker::PhantomData,
669 phantom_c: core::marker::PhantomData,
670 phantom_s: core::marker::PhantomData,
671 phantom_m: core::marker::PhantomData,
672 }
673 }
674
675 pub fn amount_milli_satoshis(mut self, amount_msat: u64) -> Self {
677 let amount = match amount_msat.checked_mul(10) {
679 Some(amt) => amt,
680 None => {
681 self.error = Some(CreationError::InvalidAmount);
682 return self;
683 },
684 };
685 let biggest_possible_si_prefix = SiPrefix::values_desc()
686 .iter()
687 .find(|prefix| amount % prefix.multiplier() == 0)
688 .expect("Pico should always match");
689 self.amount = Some(amount / biggest_possible_si_prefix.multiplier());
690 self.si_prefix = Some(*biggest_possible_si_prefix);
691 self
692 }
693
694 pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
696 self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
697 self
698 }
699
700 pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
703 self.tagged_fields.push(TaggedField::ExpiryTime(ExpiryTime::from_duration(expiry_time)));
704 self
705 }
706
707 pub fn fallback(mut self, fallback: Fallback) -> Self {
709 self.tagged_fields.push(TaggedField::Fallback(fallback));
710 self
711 }
712
713 pub fn private_route(mut self, hint: RouteHint) -> Self {
715 match PrivateRoute::new(hint) {
716 Ok(r) => self.tagged_fields.push(TaggedField::PrivateRoute(r)),
717 Err(e) => self.error = Some(e),
718 }
719 self
720 }
721}
722
723impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
724 InvoiceBuilder<D, H, tb::True, C, S, M>
725{
726 pub fn build_raw(self) -> Result<RawBolt11Invoice, CreationError> {
729 if let Some(e) = self.error {
731 return Err(e);
732 }
733
734 let hrp =
735 RawHrp { currency: self.currency, raw_amount: self.amount, si_prefix: self.si_prefix };
736
737 let timestamp = self.timestamp.expect("ensured to be Some(t) by type T");
738
739 let tagged_fields = self
740 .tagged_fields
741 .into_iter()
742 .map(|tf| RawTaggedField::KnownSemantics(tf))
743 .collect::<Vec<_>>();
744
745 let data = RawDataPart { timestamp, tagged_fields };
746
747 Ok(RawBolt11Invoice { hrp, data })
748 }
749}
750
751impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
752 InvoiceBuilder<tb::False, H, T, C, S, M>
753{
754 pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
756 match Description::new(description) {
757 Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
758 Err(e) => self.error = Some(e),
759 }
760 self.set_flags()
761 }
762
763 pub fn description_hash(
765 mut self, description_hash: sha256::Hash,
766 ) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
767 self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
768 self.set_flags()
769 }
770
771 pub fn invoice_description(
773 self, description: Bolt11InvoiceDescription,
774 ) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
775 match description {
776 Bolt11InvoiceDescription::Direct(desc) => self.description(desc.0 .0),
777 Bolt11InvoiceDescription::Hash(hash) => self.description_hash(hash.0),
778 }
779 }
780}
781
782impl<D: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
783 InvoiceBuilder<D, tb::False, T, C, S, M>
784{
785 pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder<D, tb::True, T, C, S, M> {
787 self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
788 self.set_flags()
789 }
790}
791
792impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool>
793 InvoiceBuilder<D, H, tb::False, C, S, M>
794{
795 #[cfg(feature = "std")]
797 pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True, C, S, M> {
798 match PositiveTimestamp::from_system_time(time) {
799 Ok(t) => self.timestamp = Some(t),
800 Err(e) => self.error = Some(e),
801 }
802
803 self.set_flags()
804 }
805
806 pub fn duration_since_epoch(
809 mut self, time: Duration,
810 ) -> InvoiceBuilder<D, H, tb::True, C, S, M> {
811 match PositiveTimestamp::from_duration_since_epoch(time) {
812 Ok(t) => self.timestamp = Some(t),
813 Err(e) => self.error = Some(e),
814 }
815
816 self.set_flags()
817 }
818
819 #[cfg(feature = "std")]
821 pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True, C, S, M> {
822 let now = PositiveTimestamp::from_system_time(SystemTime::now());
823 self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
824 self.set_flags()
825 }
826}
827
828impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, S: tb::Bool, M: tb::Bool>
829 InvoiceBuilder<D, H, T, tb::False, S, M>
830{
831 pub fn min_final_cltv_expiry_delta(
833 mut self, min_final_cltv_expiry_delta: u64,
834 ) -> InvoiceBuilder<D, H, T, tb::True, S, M> {
835 self.tagged_fields.push(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta(
836 min_final_cltv_expiry_delta,
837 )));
838 self.set_flags()
839 }
840}
841
842impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, M: tb::Bool>
843 InvoiceBuilder<D, H, T, C, tb::False, M>
844{
845 pub fn payment_secret(
847 mut self, payment_secret: PaymentSecret,
848 ) -> InvoiceBuilder<D, H, T, C, tb::True, M> {
849 let mut found_features = false;
850 for field in self.tagged_fields.iter_mut() {
851 if let TaggedField::Features(f) = field {
852 found_features = true;
853 f.set_variable_length_onion_required();
854 f.set_payment_secret_required();
855 }
856 }
857 self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
858 if !found_features {
859 let mut features = Bolt11InvoiceFeatures::empty();
860 features.set_variable_length_onion_required();
861 features.set_payment_secret_required();
862 self.tagged_fields.push(TaggedField::Features(features));
863 }
864 self.set_flags()
865 }
866}
867
868impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool>
869 InvoiceBuilder<D, H, T, C, S, tb::False>
870{
871 pub fn payment_metadata(
878 mut self, payment_metadata: Vec<u8>,
879 ) -> InvoiceBuilder<D, H, T, C, S, tb::True> {
880 self.tagged_fields.push(TaggedField::PaymentMetadata(payment_metadata));
881 let mut found_features = false;
882 for field in self.tagged_fields.iter_mut() {
883 if let TaggedField::Features(f) = field {
884 found_features = true;
885 f.set_payment_metadata_optional();
886 }
887 }
888 if !found_features {
889 let mut features = Bolt11InvoiceFeatures::empty();
890 features.set_payment_metadata_optional();
891 self.tagged_fields.push(TaggedField::Features(features));
892 }
893 self.set_flags()
894 }
895}
896
897impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool>
898 InvoiceBuilder<D, H, T, C, S, tb::True>
899{
900 pub fn require_payment_metadata(mut self) -> InvoiceBuilder<D, H, T, C, S, tb::True> {
903 for field in self.tagged_fields.iter_mut() {
904 if let TaggedField::Features(f) = field {
905 f.set_payment_metadata_required();
906 }
907 }
908 self
909 }
910}
911
912impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, M: tb::Bool>
913 InvoiceBuilder<D, H, T, C, tb::True, M>
914{
915 pub fn basic_mpp(mut self) -> Self {
917 for field in self.tagged_fields.iter_mut() {
918 if let TaggedField::Features(f) = field {
919 f.set_basic_mpp_optional();
920 }
921 }
922 self
923 }
924}
925
926impl<M: tb::Bool> InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::True, M> {
927 pub fn build_signed<F>(self, sign_function: F) -> Result<Bolt11Invoice, CreationError>
931 where
932 F: FnOnce(&Message) -> RecoverableSignature,
933 {
934 let invoice = self.try_build_signed::<_, ()>(|hash| Ok(sign_function(hash)));
935
936 match invoice {
937 Ok(i) => Ok(i),
938 Err(SignOrCreationError::CreationError(e)) => Err(e),
939 Err(SignOrCreationError::SignError(())) => unreachable!(),
940 }
941 }
942
943 pub fn try_build_signed<F, E>(
947 self, sign_function: F,
948 ) -> Result<Bolt11Invoice, SignOrCreationError<E>>
949 where
950 F: FnOnce(&Message) -> Result<RecoverableSignature, E>,
951 {
952 let raw = match self.build_raw() {
953 Ok(r) => r,
954 Err(e) => return Err(SignOrCreationError::CreationError(e)),
955 };
956
957 let signed = match raw.sign(sign_function) {
958 Ok(s) => s,
959 Err(e) => return Err(SignOrCreationError::SignError(e)),
960 };
961
962 let invoice = Bolt11Invoice { signed_invoice: signed };
963
964 invoice.check_field_counts().expect("should be ensured by type signature of builder");
965 invoice.check_feature_bits().expect("should be ensured by type signature of builder");
966 invoice.check_amount().expect("should be ensured by type signature of builder");
967
968 Ok(invoice)
969 }
970}
971
972impl SignedRawBolt11Invoice {
973 pub fn into_parts(self) -> (RawBolt11Invoice, [u8; 32], Bolt11InvoiceSignature) {
978 (self.raw_invoice, self.hash, self.signature)
979 }
980
981 pub fn raw_invoice(&self) -> &RawBolt11Invoice {
983 &self.raw_invoice
984 }
985
986 pub fn signable_hash(&self) -> &[u8; 32] {
988 &self.hash
989 }
990
991 pub fn signature(&self) -> &Bolt11InvoiceSignature {
993 &self.signature
994 }
995
996 pub fn recover_payee_pub_key(&self) -> Result<PayeePubKey, bitcoin::secp256k1::Error> {
998 let hash = Message::from_digest(self.hash);
999
1000 Ok(PayeePubKey(Secp256k1::new().recover_ecdsa(&hash, &self.signature)?))
1001 }
1002
1003 pub fn check_signature(&self) -> bool {
1006 let included_pub_key = self.raw_invoice.payee_pub_key();
1007
1008 let mut recovered_pub_key = Option::None;
1009 if recovered_pub_key.is_none() {
1010 let recovered = match self.recover_payee_pub_key() {
1011 Ok(pk) => pk,
1012 Err(_) => return false,
1013 };
1014 recovered_pub_key = Some(recovered);
1015 }
1016
1017 let pub_key =
1018 included_pub_key.or(recovered_pub_key.as_ref()).expect("One is always present");
1019
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(), pub_key);
1025
1026 match verification_result {
1027 Ok(()) => true,
1028 Err(_) => false,
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 match self.signed_invoice.recover_payee_pub_key() {
1406 Err(bitcoin::secp256k1::Error::InvalidRecoveryId) => {
1407 return Err(Bolt11SemanticError::InvalidRecoveryId)
1408 },
1409 Err(bitcoin::secp256k1::Error::InvalidSignature) => {
1410 return Err(Bolt11SemanticError::InvalidSignature)
1411 },
1412 Err(e) => panic!("no other error may occur, got {:?}", e),
1413 Ok(_) => {},
1414 }
1415
1416 if !self.signed_invoice.check_signature() {
1417 return Err(Bolt11SemanticError::InvalidSignature);
1418 }
1419
1420 Ok(())
1421 }
1422
1423 pub fn from_signed(
1444 signed_invoice: SignedRawBolt11Invoice,
1445 ) -> Result<Self, Bolt11SemanticError> {
1446 let invoice = Bolt11Invoice { signed_invoice };
1447 invoice.check_field_counts()?;
1448 invoice.check_feature_bits()?;
1449 invoice.check_signature()?;
1450 invoice.check_amount()?;
1451
1452 Ok(invoice)
1453 }
1454
1455 #[cfg(feature = "std")]
1457 pub fn timestamp(&self) -> SystemTime {
1458 self.signed_invoice.raw_invoice().data.timestamp.as_time()
1459 }
1460
1461 pub fn duration_since_epoch(&self) -> Duration {
1463 self.signed_invoice.raw_invoice().data.timestamp.0
1464 }
1465
1466 pub fn tagged_fields(
1470 &self,
1471 ) -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
1472 self.signed_invoice.raw_invoice().known_tagged_fields()
1473 }
1474
1475 pub fn payment_hash(&self) -> &sha256::Hash {
1477 &self.signed_invoice.payment_hash().expect("checked by constructor").0
1478 }
1479
1480 pub fn description(&self) -> Bolt11InvoiceDescriptionRef {
1484 if let Some(direct) = self.signed_invoice.description() {
1485 return Bolt11InvoiceDescriptionRef::Direct(direct);
1486 } else if let Some(hash) = self.signed_invoice.description_hash() {
1487 return Bolt11InvoiceDescriptionRef::Hash(hash);
1488 }
1489 unreachable!("ensured by constructor");
1490 }
1491
1492 pub fn payee_pub_key(&self) -> Option<&PublicKey> {
1494 self.signed_invoice.payee_pub_key().map(|x| &x.0)
1495 }
1496
1497 pub fn payment_secret(&self) -> &PaymentSecret {
1499 self.signed_invoice.payment_secret().expect("was checked by constructor")
1500 }
1501
1502 pub fn payment_metadata(&self) -> Option<&Vec<u8>> {
1504 self.signed_invoice.payment_metadata()
1505 }
1506
1507 pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> {
1509 self.signed_invoice.features()
1510 }
1511
1512 pub fn recover_payee_pub_key(&self) -> PublicKey {
1514 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1515 }
1516
1517 pub fn get_payee_pub_key(&self) -> PublicKey {
1520 match self.payee_pub_key() {
1521 Some(pk) => *pk,
1522 None => self.recover_payee_pub_key(),
1523 }
1524 }
1525
1526 pub fn expires_at(&self) -> Option<Duration> {
1529 self.duration_since_epoch().checked_add(self.expiry_time())
1530 }
1531
1532 pub fn expiry_time(&self) -> Duration {
1534 self.signed_invoice
1535 .expiry_time()
1536 .map(|x| x.0)
1537 .unwrap_or(Duration::from_secs(DEFAULT_EXPIRY_TIME))
1538 }
1539
1540 #[cfg(feature = "std")]
1542 pub fn is_expired(&self) -> bool {
1543 Self::is_expired_from_epoch(&self.timestamp(), self.expiry_time())
1544 }
1545
1546 #[cfg(feature = "std")]
1548 pub(crate) fn is_expired_from_epoch(epoch: &SystemTime, expiry_time: Duration) -> bool {
1549 match epoch.elapsed() {
1550 Ok(elapsed) => elapsed > expiry_time,
1551 Err(_) => false,
1552 }
1553 }
1554
1555 #[cfg(feature = "std")]
1557 pub fn duration_until_expiry(&self) -> Duration {
1558 SystemTime::now()
1559 .duration_since(SystemTime::UNIX_EPOCH)
1560 .map(|now| self.expiration_remaining_from_epoch(now))
1561 .unwrap_or(Duration::from_nanos(0))
1562 }
1563
1564 pub fn expiration_remaining_from_epoch(&self, time: Duration) -> Duration {
1567 self.expires_at().map(|x| x.checked_sub(time)).flatten().unwrap_or(Duration::from_nanos(0))
1568 }
1569
1570 pub fn would_expire(&self, at_time: Duration) -> bool {
1573 self.duration_since_epoch()
1574 .checked_add(self.expiry_time())
1575 .unwrap_or_else(|| Duration::new(u64::max_value(), 1_000_000_000 - 1))
1576 < at_time
1577 }
1578
1579 pub fn min_final_cltv_expiry_delta(&self) -> u64 {
1582 self.signed_invoice
1583 .min_final_cltv_expiry_delta()
1584 .map(|x| x.0)
1585 .unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA)
1586 }
1587
1588 pub fn fallbacks(&self) -> Vec<&Fallback> {
1592 self.signed_invoice.fallbacks()
1593 }
1594
1595 pub fn fallback_addresses(&self) -> Vec<Address> {
1597 let filter_fn = |fallback: &&Fallback| {
1598 let address = match fallback {
1599 Fallback::SegWitProgram { version, program } => {
1600 match WitnessProgram::new(*version, &program) {
1601 Ok(witness_program) => {
1602 Address::from_witness_program(witness_program, self.network())
1603 },
1604 Err(_) => return None,
1605 }
1606 },
1607 Fallback::PubKeyHash(pkh) => Address::p2pkh(*pkh, self.network()),
1608 Fallback::ScriptHash(sh) => Address::p2sh_from_hash(*sh, self.network()),
1609 };
1610
1611 Some(address)
1612 };
1613 self.fallbacks().iter().filter_map(filter_fn).collect()
1614 }
1615
1616 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1618 self.signed_invoice.private_routes()
1619 }
1620
1621 pub fn route_hints(&self) -> Vec<RouteHint> {
1623 find_all_extract!(
1624 self.signed_invoice.known_tagged_fields(),
1625 TaggedField::PrivateRoute(ref x),
1626 x
1627 )
1628 .map(|route| (**route).clone())
1629 .collect()
1630 }
1631
1632 pub fn currency(&self) -> Currency {
1634 self.signed_invoice.currency()
1635 }
1636
1637 pub fn network(&self) -> Network {
1641 self.signed_invoice.currency().into()
1642 }
1643
1644 pub fn amount_milli_satoshis(&self) -> Option<u64> {
1646 self.signed_invoice.amount_pico_btc().map(|v| v / 10)
1647 }
1648
1649 fn amount_pico_btc(&self) -> Option<u64> {
1651 self.signed_invoice.amount_pico_btc()
1652 }
1653}
1654
1655impl From<TaggedField> for RawTaggedField {
1656 fn from(tf: TaggedField) -> Self {
1657 RawTaggedField::KnownSemantics(tf)
1658 }
1659}
1660
1661impl TaggedField {
1662 pub fn tag(&self) -> Fe32 {
1664 let tag = match *self {
1665 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1666 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1667 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1668 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1669 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1670 TaggedField::MinFinalCltvExpiryDelta(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA,
1671 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1672 TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
1673 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1674 TaggedField::PaymentMetadata(_) => constants::TAG_PAYMENT_METADATA,
1675 TaggedField::Features(_) => constants::TAG_FEATURES,
1676 };
1677
1678 Fe32::try_from(tag).expect("all tags defined are <32")
1679 }
1680}
1681
1682impl Description {
1683 pub fn new(description: String) -> Result<Description, CreationError> {
1688 if description.len() > 639 {
1689 Err(CreationError::DescriptionTooLong)
1690 } else {
1691 Ok(Description(UntrustedString(description)))
1692 }
1693 }
1694
1695 pub fn empty() -> Self {
1697 Description(UntrustedString(String::new()))
1698 }
1699
1700 pub fn into_inner(self) -> UntrustedString {
1702 self.0
1703 }
1704
1705 pub fn as_inner(&self) -> &UntrustedString {
1707 &self.0
1708 }
1709}
1710
1711impl Display for Description {
1712 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1713 write!(f, "{}", self.0)
1714 }
1715}
1716
1717impl From<PublicKey> for PayeePubKey {
1718 fn from(pk: PublicKey) -> Self {
1719 PayeePubKey(pk)
1720 }
1721}
1722
1723impl Deref for PayeePubKey {
1724 type Target = PublicKey;
1725
1726 fn deref(&self) -> &PublicKey {
1727 &self.0
1728 }
1729}
1730
1731impl ExpiryTime {
1732 pub fn from_seconds(seconds: u64) -> ExpiryTime {
1734 ExpiryTime(Duration::from_secs(seconds))
1735 }
1736
1737 pub fn from_duration(duration: Duration) -> ExpiryTime {
1739 Self::from_seconds(duration.as_secs())
1740 }
1741
1742 pub fn as_seconds(&self) -> u64 {
1744 self.0.as_secs()
1745 }
1746
1747 pub fn as_duration(&self) -> &Duration {
1749 &self.0
1750 }
1751}
1752
1753impl PrivateRoute {
1754 pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
1756 if hops.0.len() <= 12 {
1757 Ok(PrivateRoute(hops))
1758 } else {
1759 Err(CreationError::RouteTooLong)
1760 }
1761 }
1762
1763 pub fn into_inner(self) -> RouteHint {
1765 self.0
1766 }
1767}
1768
1769impl From<PrivateRoute> for RouteHint {
1770 fn from(val: PrivateRoute) -> Self {
1771 val.into_inner()
1772 }
1773}
1774
1775impl Deref for PrivateRoute {
1776 type Target = RouteHint;
1777
1778 fn deref(&self) -> &RouteHint {
1779 &self.0
1780 }
1781}
1782
1783impl Deref for Bolt11InvoiceSignature {
1784 type Target = RecoverableSignature;
1785
1786 fn deref(&self) -> &RecoverableSignature {
1787 &self.0
1788 }
1789}
1790
1791impl Deref for SignedRawBolt11Invoice {
1792 type Target = RawBolt11Invoice;
1793
1794 fn deref(&self) -> &RawBolt11Invoice {
1795 &self.raw_invoice
1796 }
1797}
1798
1799#[derive(Eq, PartialEq, Debug, Clone)]
1801pub enum CreationError {
1802 DescriptionTooLong,
1804
1805 RouteTooLong,
1807
1808 TimestampOutOfBounds,
1810
1811 InvalidAmount,
1813
1814 MissingRouteHints,
1818
1819 MinFinalCltvExpiryDeltaTooShort,
1821}
1822
1823impl Display for CreationError {
1824 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1825 match self {
1826 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1827 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1828 CreationError::TimestampOutOfBounds => f.write_str("The Unix timestamp of the supplied date is less than zero or greater than 35-bits"),
1829 CreationError::InvalidAmount => f.write_str("The supplied millisatoshi amount was greater than the total bitcoin supply"),
1830 CreationError::MissingRouteHints => f.write_str("The invoice required route hints and they weren't provided"),
1831 CreationError::MinFinalCltvExpiryDeltaTooShort => f.write_str(
1832 "The supplied final CLTV expiry delta was less than LDK's `MIN_FINAL_CLTV_EXPIRY_DELTA`"),
1833 }
1834 }
1835}
1836
1837#[cfg(feature = "std")]
1838impl std::error::Error for CreationError {}
1839
1840#[derive(Eq, PartialEq, Debug, Clone)]
1843pub enum Bolt11SemanticError {
1844 NoPaymentHash,
1846
1847 MultiplePaymentHashes,
1849
1850 NoDescription,
1852
1853 MultipleDescriptions,
1855
1856 NoPaymentSecret,
1859
1860 MultiplePaymentSecrets,
1862
1863 InvalidFeatures,
1865
1866 InvalidRecoveryId,
1868
1869 InvalidSignature,
1871
1872 ImpreciseAmount,
1874}
1875
1876impl Display for Bolt11SemanticError {
1877 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1878 match self {
1879 Bolt11SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1880 Bolt11SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1881 Bolt11SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1882 Bolt11SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1883 Bolt11SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
1884 Bolt11SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1885 Bolt11SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1886 Bolt11SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1887 Bolt11SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1888 Bolt11SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
1889 }
1890 }
1891}
1892
1893#[cfg(feature = "std")]
1894impl std::error::Error for Bolt11SemanticError {}
1895
1896#[derive(Eq, PartialEq, Debug, Clone)]
1899pub enum SignOrCreationError<S = ()> {
1900 SignError(S),
1902
1903 CreationError(CreationError),
1905}
1906
1907impl<S> Display for SignOrCreationError<S> {
1908 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1909 match self {
1910 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1911 SignOrCreationError::CreationError(err) => err.fmt(f),
1912 }
1913 }
1914}
1915
1916#[cfg(feature = "serde")]
1917impl Serialize for Bolt11Invoice {
1918 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1919 where
1920 S: Serializer,
1921 {
1922 serializer.serialize_str(self.to_string().as_str())
1923 }
1924}
1925#[cfg(feature = "serde")]
1926impl<'de> Deserialize<'de> for Bolt11Invoice {
1927 fn deserialize<D>(deserializer: D) -> Result<Bolt11Invoice, D::Error>
1928 where
1929 D: Deserializer<'de>,
1930 {
1931 let bolt11 = String::deserialize(deserializer)?
1932 .parse::<Bolt11Invoice>()
1933 .map_err(|e| D::Error::custom(format_args!("{:?}", e)))?;
1934
1935 Ok(bolt11)
1936 }
1937}
1938
1939#[cfg(test)]
1940mod test {
1941 use bitcoin::hashes::sha256;
1942 use bitcoin::ScriptBuf;
1943 use std::str::FromStr;
1944
1945 #[test]
1946 fn test_system_time_bounds_assumptions() {
1947 assert_eq!(
1948 crate::PositiveTimestamp::from_unix_timestamp(crate::MAX_TIMESTAMP + 1),
1949 Err(crate::CreationError::TimestampOutOfBounds)
1950 );
1951 }
1952
1953 #[test]
1954 fn test_calc_invoice_hash() {
1955 use crate::TaggedField::*;
1956 use crate::{Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart, RawHrp};
1957
1958 let invoice = RawBolt11Invoice {
1959 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
1960 data: RawDataPart {
1961 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1962 tagged_fields: vec![
1963 PaymentHash(crate::Sha256(
1964 sha256::Hash::from_str(
1965 "0001020304050607080900010203040506070809000102030405060708090102",
1966 )
1967 .unwrap(),
1968 ))
1969 .into(),
1970 Description(
1971 crate::Description::new(
1972 "Please consider supporting this project".to_owned(),
1973 )
1974 .unwrap(),
1975 )
1976 .into(),
1977 ],
1978 },
1979 };
1980
1981 let expected_hash = [
1982 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1983 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1984 0xd5, 0x18, 0xe1, 0xc9,
1985 ];
1986
1987 assert_eq!(invoice.signable_hash(), expected_hash)
1988 }
1989
1990 #[test]
1991 fn test_check_signature() {
1992 use crate::TaggedField::*;
1993 use crate::{
1994 Bolt11InvoiceSignature, Currency, PositiveTimestamp, RawBolt11Invoice, RawDataPart,
1995 RawHrp, Sha256, SignedRawBolt11Invoice,
1996 };
1997 use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1998 use bitcoin::secp256k1::Secp256k1;
1999 use bitcoin::secp256k1::{PublicKey, SecretKey};
2000
2001 let invoice =
2002 SignedRawBolt11Invoice {
2003 raw_invoice: RawBolt11Invoice {
2004 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
2005 data: RawDataPart {
2006 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
2007 tagged_fields: vec ! [
2008 PaymentHash(Sha256(sha256::Hash::from_str(
2009 "0001020304050607080900010203040506070809000102030405060708090102"
2010 ).unwrap())).into(),
2011 Description(
2012 crate::Description::new(
2013 "Please consider supporting this project".to_owned()
2014 ).unwrap()
2015 ).into(),
2016 ],
2017 },
2018 },
2019 hash: [
2020 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b,
2021 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d,
2022 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9,
2023 ],
2024 signature: Bolt11InvoiceSignature(
2025 RecoverableSignature::from_compact(
2026 &[
2027 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
2028 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43, 0x4e,
2029 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f, 0x42, 0x5f,
2030 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad, 0x0d, 0x6e, 0x35,
2031 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9, 0xaa, 0xb1, 0x5e, 0x57,
2032 0x38, 0xb1, 0x1f, 0x12, 0x7f,
2033 ],
2034 RecoveryId::from_i32(0).unwrap(),
2035 )
2036 .unwrap(),
2037 ),
2038 };
2039
2040 assert!(invoice.check_signature());
2041
2042 let private_key = SecretKey::from_slice(
2043 &[
2044 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
2045 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
2046 0x3b, 0x2d, 0xb7, 0x34,
2047 ][..],
2048 )
2049 .unwrap();
2050 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
2051
2052 assert_eq!(invoice.recover_payee_pub_key(), Ok(crate::PayeePubKey(public_key)));
2053
2054 let (raw_invoice, _, _) = invoice.into_parts();
2055 let new_signed = raw_invoice
2056 .sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
2057 .unwrap();
2058
2059 assert!(new_signed.check_signature());
2060 }
2061
2062 #[test]
2063 fn test_check_feature_bits() {
2064 use crate::TaggedField::*;
2065 use crate::{
2066 Bolt11Invoice, Bolt11SemanticError, Currency, PositiveTimestamp, RawBolt11Invoice,
2067 RawDataPart, RawHrp, Sha256,
2068 };
2069 use bitcoin::secp256k1::Secp256k1;
2070 use bitcoin::secp256k1::SecretKey;
2071 use lightning_types::features::Bolt11InvoiceFeatures;
2072
2073 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
2074 let payment_secret = lightning_types::payment::PaymentSecret([21; 32]);
2075 let invoice_template = RawBolt11Invoice {
2076 hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, si_prefix: None },
2077 data: RawDataPart {
2078 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
2079 tagged_fields: vec![
2080 PaymentHash(Sha256(
2081 sha256::Hash::from_str(
2082 "0001020304050607080900010203040506070809000102030405060708090102",
2083 )
2084 .unwrap(),
2085 ))
2086 .into(),
2087 Description(
2088 crate::Description::new(
2089 "Please consider supporting this project".to_owned(),
2090 )
2091 .unwrap(),
2092 )
2093 .into(),
2094 ],
2095 },
2096 };
2097
2098 let invoice = {
2100 let mut invoice = invoice_template.clone();
2101 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2102 invoice.sign::<_, ()>(|hash| {
2103 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2104 })
2105 }
2106 .unwrap();
2107 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
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(Bolt11InvoiceFeatures::empty()).into());
2114 invoice.sign::<_, ()>(|hash| {
2115 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2116 })
2117 }
2118 .unwrap();
2119 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
2120
2121 let mut payment_secret_features = Bolt11InvoiceFeatures::empty();
2122 payment_secret_features.set_payment_secret_required();
2123
2124 let invoice = {
2126 let mut invoice = invoice_template.clone();
2127 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2128 invoice.data.tagged_fields.push(Features(payment_secret_features.clone()).into());
2129 invoice.sign::<_, ()>(|hash| {
2130 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2131 })
2132 }
2133 .unwrap();
2134 assert!(Bolt11Invoice::from_signed(invoice).is_ok());
2135
2136 let invoice = {
2138 let invoice = invoice_template.clone();
2139 invoice.sign::<_, ()>(|hash| {
2140 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2141 })
2142 }
2143 .unwrap();
2144 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2145
2146 let invoice = {
2148 let mut invoice = invoice_template.clone();
2149 invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into());
2150 invoice.sign::<_, ()>(|hash| {
2151 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2152 })
2153 }
2154 .unwrap();
2155 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2156
2157 let invoice = {
2159 let mut invoice = invoice_template.clone();
2160 invoice.data.tagged_fields.push(Features(payment_secret_features).into());
2161 invoice.sign::<_, ()>(|hash| {
2162 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2163 })
2164 }
2165 .unwrap();
2166 assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
2167
2168 let invoice = {
2170 let mut invoice = invoice_template;
2171 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2172 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
2173 invoice.sign::<_, ()>(|hash| {
2174 Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))
2175 })
2176 }
2177 .unwrap();
2178 assert_eq!(
2179 Bolt11Invoice::from_signed(invoice),
2180 Err(Bolt11SemanticError::MultiplePaymentSecrets)
2181 );
2182 }
2183
2184 #[test]
2185 fn test_builder_amount() {
2186 use crate::*;
2187
2188 let builder = InvoiceBuilder::new(Currency::Bitcoin)
2189 .description("Test".into())
2190 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2191 .duration_since_epoch(Duration::from_secs(1234567));
2192
2193 let invoice = builder.clone().amount_milli_satoshis(1500).build_raw().unwrap();
2194
2195 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
2196 assert_eq!(invoice.hrp.raw_amount, Some(15));
2197
2198 let invoice = builder.amount_milli_satoshis(150).build_raw().unwrap();
2199
2200 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
2201 assert_eq!(invoice.hrp.raw_amount, Some(1500));
2202 }
2203
2204 #[test]
2205 fn test_builder_fail() {
2206 use crate::*;
2207 use bitcoin::secp256k1::PublicKey;
2208 use lightning_types::routing::RouteHintHop;
2209 use std::iter::FromIterator;
2210
2211 let builder = InvoiceBuilder::new(Currency::Bitcoin)
2212 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2213 .duration_since_epoch(Duration::from_secs(1234567))
2214 .min_final_cltv_expiry_delta(144);
2215
2216 let too_long_string = String::from_iter((0..1024).map(|_| '?'));
2217
2218 let long_desc_res = builder.clone().description(too_long_string).build_raw();
2219 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
2220
2221 let route_hop = RouteHintHop {
2222 src_node_id: PublicKey::from_slice(
2223 &[
2224 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
2225 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
2226 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55,
2227 ][..],
2228 )
2229 .unwrap(),
2230 short_channel_id: 0,
2231 fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
2232 cltv_expiry_delta: 0,
2233 htlc_minimum_msat: None,
2234 htlc_maximum_msat: None,
2235 };
2236 let too_long_route = RouteHint(vec![route_hop; 13]);
2237 let long_route_res =
2238 builder.clone().description("Test".into()).private_route(too_long_route).build_raw();
2239 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
2240
2241 let sign_error_res = builder
2242 .description("Test".into())
2243 .payment_secret(PaymentSecret([0; 32]))
2244 .try_build_signed(|_| Err("ImaginaryError"));
2245 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
2246 }
2247
2248 #[test]
2249 fn test_builder_ok() {
2250 use crate::*;
2251 use bitcoin::secp256k1::Secp256k1;
2252 use bitcoin::secp256k1::{PublicKey, SecretKey};
2253 use lightning_types::routing::RouteHintHop;
2254 use std::time::Duration;
2255
2256 let secp_ctx = Secp256k1::new();
2257
2258 let private_key = SecretKey::from_slice(
2259 &[
2260 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
2261 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
2262 0x3b, 0x2d, 0xb7, 0x34,
2263 ][..],
2264 )
2265 .unwrap();
2266 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
2267
2268 let route_1 = RouteHint(vec![
2269 RouteHintHop {
2270 src_node_id: public_key,
2271 short_channel_id: u64::from_be_bytes([123; 8]),
2272 fees: RoutingFees { base_msat: 2, proportional_millionths: 1 },
2273 cltv_expiry_delta: 145,
2274 htlc_minimum_msat: None,
2275 htlc_maximum_msat: None,
2276 },
2277 RouteHintHop {
2278 src_node_id: public_key,
2279 short_channel_id: u64::from_be_bytes([42; 8]),
2280 fees: RoutingFees { base_msat: 3, proportional_millionths: 2 },
2281 cltv_expiry_delta: 146,
2282 htlc_minimum_msat: None,
2283 htlc_maximum_msat: None,
2284 },
2285 ]);
2286
2287 let route_2 = RouteHint(vec![
2288 RouteHintHop {
2289 src_node_id: public_key,
2290 short_channel_id: 0,
2291 fees: RoutingFees { base_msat: 4, proportional_millionths: 3 },
2292 cltv_expiry_delta: 147,
2293 htlc_minimum_msat: None,
2294 htlc_maximum_msat: None,
2295 },
2296 RouteHintHop {
2297 src_node_id: public_key,
2298 short_channel_id: u64::from_be_bytes([1; 8]),
2299 fees: RoutingFees { base_msat: 5, proportional_millionths: 4 },
2300 cltv_expiry_delta: 148,
2301 htlc_minimum_msat: None,
2302 htlc_maximum_msat: None,
2303 },
2304 ]);
2305
2306 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
2307 .amount_milli_satoshis(123)
2308 .duration_since_epoch(Duration::from_secs(1234567))
2309 .payee_pub_key(public_key)
2310 .expiry_time(Duration::from_secs(54321))
2311 .min_final_cltv_expiry_delta(144)
2312 .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[0; 20]).unwrap()))
2313 .private_route(route_1.clone())
2314 .private_route(route_2.clone())
2315 .description_hash(sha256::Hash::from_slice(&[3; 32][..]).unwrap())
2316 .payment_hash(sha256::Hash::from_slice(&[21; 32][..]).unwrap())
2317 .payment_secret(PaymentSecret([42; 32]))
2318 .basic_mpp();
2319
2320 let invoice = builder
2321 .clone()
2322 .build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &private_key))
2323 .unwrap();
2324
2325 assert!(invoice.check_signature().is_ok());
2326 assert_eq!(invoice.tagged_fields().count(), 10);
2327
2328 assert_eq!(invoice.amount_milli_satoshis(), Some(123));
2329 assert_eq!(invoice.amount_pico_btc(), Some(1230));
2330 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
2331 #[cfg(feature = "std")]
2332 assert_eq!(
2333 invoice.timestamp().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(),
2334 1234567
2335 );
2336 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
2337 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
2338 assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
2339 assert_eq!(
2340 invoice.fallbacks(),
2341 vec![&Fallback::PubKeyHash(PubkeyHash::from_slice(&[0; 20]).unwrap())]
2342 );
2343 let address = Address::from_script(
2344 &ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[0; 20]).unwrap()),
2345 Network::Testnet,
2346 )
2347 .unwrap();
2348 assert_eq!(invoice.fallback_addresses(), vec![address]);
2349 assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
2350 assert_eq!(
2351 invoice.description(),
2352 Bolt11InvoiceDescriptionRef::Hash(&Sha256(
2353 sha256::Hash::from_slice(&[3; 32][..]).unwrap()
2354 ))
2355 );
2356 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21; 32][..]).unwrap());
2357 assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
2358
2359 let mut expected_features = Bolt11InvoiceFeatures::empty();
2360 expected_features.set_variable_length_onion_required();
2361 expected_features.set_payment_secret_required();
2362 expected_features.set_basic_mpp_optional();
2363 assert_eq!(invoice.features(), Some(&expected_features));
2364
2365 let raw_invoice = builder.build_raw().unwrap();
2366 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
2367 }
2368
2369 #[test]
2370 fn test_default_values() {
2371 use crate::*;
2372 use bitcoin::secp256k1::Secp256k1;
2373 use bitcoin::secp256k1::SecretKey;
2374
2375 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
2376 .description("Test".into())
2377 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2378 .payment_secret(PaymentSecret([0; 32]))
2379 .duration_since_epoch(Duration::from_secs(1234567))
2380 .build_raw()
2381 .unwrap()
2382 .sign::<_, ()>(|hash| {
2383 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
2384 let secp_ctx = Secp256k1::new();
2385 Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
2386 })
2387 .unwrap();
2388 let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
2389
2390 assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA);
2391 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
2392 assert!(!invoice.would_expire(Duration::from_secs(1234568)));
2393 }
2394
2395 #[test]
2396 fn test_expiration() {
2397 use crate::*;
2398 use bitcoin::secp256k1::Secp256k1;
2399 use bitcoin::secp256k1::SecretKey;
2400
2401 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
2402 .description("Test".into())
2403 .payment_hash(sha256::Hash::from_slice(&[0; 32][..]).unwrap())
2404 .payment_secret(PaymentSecret([0; 32]))
2405 .duration_since_epoch(Duration::from_secs(1234567))
2406 .build_raw()
2407 .unwrap()
2408 .sign::<_, ()>(|hash| {
2409 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
2410 let secp_ctx = Secp256k1::new();
2411 Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey))
2412 })
2413 .unwrap();
2414 let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
2415
2416 assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1)));
2417 }
2418
2419 #[cfg(feature = "serde")]
2420 #[test]
2421 fn test_serde() {
2422 let invoice_str = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
2423 h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
2424 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
2425 h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
2426 j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
2427 ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
2428 guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
2429 ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
2430 p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
2431 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
2432 j5r6drg6k6zcqj0fcwg";
2433 let invoice = invoice_str.parse::<super::Bolt11Invoice>().unwrap();
2434 let serialized_invoice = serde_json::to_string(&invoice).unwrap();
2435 let deserialized_invoice: super::Bolt11Invoice =
2436 serde_json::from_str(serialized_invoice.as_str()).unwrap();
2437 assert_eq!(invoice, deserialized_invoice);
2438 assert_eq!(invoice_str, deserialized_invoice.to_string().as_str());
2439 assert_eq!(invoice_str, serialized_invoice.as_str().trim_matches('\"'));
2440 }
2441
2442 #[test]
2443 fn raw_tagged_field_ordering() {
2444 use crate::{
2445 sha256, Description, Fe32, RawTaggedField, Sha256, TaggedField, UntrustedString,
2446 };
2447
2448 let field10 = RawTaggedField::KnownSemantics(TaggedField::PaymentHash(Sha256(
2449 sha256::Hash::from_str(
2450 "0001020304050607080900010203040506070809000102030405060708090102",
2451 )
2452 .unwrap(),
2453 )));
2454 let field11 = RawTaggedField::KnownSemantics(TaggedField::Description(Description(
2455 UntrustedString("Description".to_string()),
2456 )));
2457 let field20 = RawTaggedField::UnknownSemantics(vec![Fe32::Q]);
2458 let field21 = RawTaggedField::UnknownSemantics(vec![Fe32::R]);
2459
2460 assert!(field10 < field20);
2461 assert!(field20 > field10);
2462 assert_eq!(field10.cmp(&field20), std::cmp::Ordering::Less);
2463 assert_eq!(field20.cmp(&field10), std::cmp::Ordering::Greater);
2464 assert_eq!(field10.cmp(&field10), std::cmp::Ordering::Equal);
2465 assert_eq!(field20.cmp(&field20), std::cmp::Ordering::Equal);
2466 assert_eq!(field10.partial_cmp(&field20).unwrap(), std::cmp::Ordering::Less);
2467 assert_eq!(field20.partial_cmp(&field10).unwrap(), std::cmp::Ordering::Greater);
2468
2469 assert_eq!(field10.partial_cmp(&field11).unwrap(), std::cmp::Ordering::Less);
2470 assert_eq!(field20.partial_cmp(&field21).unwrap(), std::cmp::Ordering::Less);
2471 }
2472}