@@ -110,12 +110,12 @@ use core::time::Duration;
110
110
use crate :: io;
111
111
use crate :: blinded_path:: BlindedPath ;
112
112
use crate :: ln:: PaymentHash ;
113
- use crate :: ln:: features:: { BlindedHopFeatures , Bolt12InvoiceFeatures } ;
113
+ use crate :: ln:: features:: { BlindedHopFeatures , Bolt12InvoiceFeatures , InvoiceRequestFeatures , OfferFeatures } ;
114
114
use crate :: ln:: inbound_payment:: ExpandedKey ;
115
115
use crate :: ln:: msgs:: DecodeError ;
116
116
use crate :: offers:: invoice_request:: { INVOICE_REQUEST_PAYER_ID_TYPE , INVOICE_REQUEST_TYPES , IV_BYTES as INVOICE_REQUEST_IV_BYTES , InvoiceRequest , InvoiceRequestContents , InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef } ;
117
117
use crate :: offers:: merkle:: { SignError , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , WithoutSignatures , self } ;
118
- use crate :: offers:: offer:: { Amount , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef } ;
118
+ use crate :: offers:: offer:: { Amount , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef , Quantity } ;
119
119
use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
120
120
use crate :: offers:: payer:: { PAYER_METADATA_TYPE , PayerTlvStream , PayerTlvStreamRef } ;
121
121
use crate :: offers:: refund:: { IV_BYTES as REFUND_IV_BYTES , Refund , RefundContents } ;
@@ -482,12 +482,139 @@ struct InvoiceFields {
482
482
}
483
483
484
484
macro_rules! invoice_accessors { ( $self: ident, $contents: expr) => {
485
- /// A complete description of the purpose of the originating offer or refund. Intended to be
486
- /// displayed to the user but with the caveat that it has not been verified in any way.
485
+ /// The chains that may be used when paying a requested invoice.
486
+ ///
487
+ /// From [`Offer::chains`]; `None` if the invoice was created in response to a [`Refund`].
488
+ ///
489
+ /// [`Offer::chains`]: crate::offers::offer::Offer::chains
490
+ pub fn chains( & $self) -> Option <Vec <ChainHash >> {
491
+ $contents. chains( )
492
+ }
493
+
494
+ /// A chain that the originating offer or refund is valid for.
495
+ ///
496
+ /// From [`InvoiceRequest::chain`] or [`Refund::chain`].
497
+ ///
498
+ /// [`InvoiceRequest::chain`]: crate::offers::invoice_request::InvoiceRequest::chain
499
+ pub fn chain( & $self) -> ChainHash {
500
+ $contents. chain( )
501
+ }
502
+
503
+ /// Opaque bytes set by the originating [`Offer`].
504
+ ///
505
+ /// From [`Offer::metadata`]; `None` if the invoice was created in response to a [`Refund`] or
506
+ /// if the [`Offer`] did not set it.
507
+ ///
508
+ /// [`Offer`]: crate::offers::offer::Offer
509
+ /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
510
+ pub fn metadata( & $self) -> Option <& Vec <u8 >> {
511
+ $contents. metadata( )
512
+ }
513
+
514
+ /// The minimum amount required for a successful payment of a single item.
515
+ ///
516
+ /// From [`Offer::amount`]; `None` if the invoice was created in response to a [`Refund`] or if
517
+ /// the [`Offer`] did not set it.
518
+ ///
519
+ /// [`Offer`]: crate::offers::offer::Offer
520
+ /// [`Offer::amount`]: crate::offers::offer::Offer::amount
521
+ pub fn amount( & $self) -> Option <& Amount > {
522
+ $contents. amount( )
523
+ }
524
+
525
+ /// Features pertaining to the originating [`Offer`].
526
+ ///
527
+ /// From [`Offer::offer_features`]; `None` if the invoice was created in response to a
528
+ /// [`Refund`].
529
+ ///
530
+ /// [`Offer`]: crate::offers::offer::Offer
531
+ /// [`Offer::offer_features`]: crate::offers::offer::Offer::offer_features
532
+ pub fn offer_features( & $self) -> Option <& OfferFeatures > {
533
+ $contents. offer_features( )
534
+ }
535
+
536
+ /// A complete description of the purpose of the originating offer or refund.
537
+ ///
538
+ /// From [`Offer::description`] or [`Refund::description`].
539
+ ///
540
+ /// [`Offer::description`]: crate::offers::offer::Offer::description
487
541
pub fn description( & $self) -> PrintableString {
488
542
$contents. description( )
489
543
}
490
544
545
+ /// Duration since the Unix epoch when an invoice should no longer be requested.
546
+ ///
547
+ /// From [`Offer::absolute_expiry`] or [`Refund::absolute_expiry`].
548
+ ///
549
+ /// [`Offer::absolute_expiry`]: crate::offers::offer::Offer::absolute_expiry
550
+ pub fn absolute_expiry( & $self) -> Option <Duration > {
551
+ $contents. absolute_expiry( )
552
+ }
553
+
554
+ /// The issuer of the offer or refund.
555
+ ///
556
+ /// From [`Offer::issuer`] or [`Refund::issuer`].
557
+ ///
558
+ /// [`Offer::issuer`]: crate::offers::offer::Offer::issuer
559
+ pub fn issuer( & $self) -> Option <PrintableString > {
560
+ $contents. issuer( )
561
+ }
562
+
563
+ /// Paths to the recipient originating from publicly reachable nodes.
564
+ ///
565
+ /// From [`Offer::paths`] or [`Refund::paths`].
566
+ ///
567
+ /// [`Offer::paths`]: crate::offers::offer::Offer::paths
568
+ pub fn paths( & $self) -> & [ BlindedPath ] {
569
+ $contents. paths( )
570
+ }
571
+
572
+ /// The quantity of items supported.
573
+ ///
574
+ /// From [`Offer::supported_quantity`]; `None` if the invoice was created in response to a
575
+ /// [`Refund`].
576
+ ///
577
+ /// [`Offer::supported_quantity`]: crate::offers::offer::Offer::supported_quantity
578
+ pub fn supported_quantity( & $self) -> Option <Quantity > {
579
+ $contents. supported_quantity( )
580
+ }
581
+
582
+ /// An unpredictable series of bytes from the payer.
583
+ ///
584
+ /// From [`InvoiceRequest::payer_metadata`] or [`Refund::payer_metadata`].
585
+ pub fn payer_metadata( & $self) -> & [ u8 ] {
586
+ $contents. payer_metadata( )
587
+ }
588
+
589
+ /// Features pertaining to requesting an invoice.
590
+ ///
591
+ /// From [`InvoiceRequest::invoice_request_features`] or [`Refund::features`].
592
+ pub fn invoice_request_features( & $self) -> & InvoiceRequestFeatures {
593
+ & $contents. invoice_request_features( )
594
+ }
595
+
596
+ /// The quantity of items requested or refunded for.
597
+ ///
598
+ /// From [`InvoiceRequest::quantity`] or [`Refund::quantity`].
599
+ pub fn quantity( & $self) -> Option <u64 > {
600
+ $contents. quantity( )
601
+ }
602
+
603
+ /// A possibly transient pubkey used to sign the invoice request or to send an invoice for a
604
+ /// refund in case there are no [`paths`].
605
+ ///
606
+ /// [`paths`]: Self::paths
607
+ pub fn payer_id( & $self) -> PublicKey {
608
+ $contents. payer_id( )
609
+ }
610
+
611
+ /// A payer-provided note reflected back in the invoice.
612
+ ///
613
+ /// From [`InvoiceRequest::payer_note`] or [`Refund::payer_note`].
614
+ pub fn payer_note( & $self) -> Option <PrintableString > {
615
+ $contents. payer_note( )
616
+ }
617
+
491
618
/// Paths to the recipient originating from publicly reachable nodes, including information
492
619
/// needed for routing payments across them.
493
620
///
@@ -591,13 +718,37 @@ impl InvoiceContents {
591
718
}
592
719
}
593
720
721
+ fn chains ( & self ) -> Option < Vec < ChainHash > > {
722
+ match self {
723
+ InvoiceContents :: ForOffer { invoice_request, .. } =>
724
+ Some ( invoice_request. inner . offer . chains ( ) ) ,
725
+ InvoiceContents :: ForRefund { .. } => None ,
726
+ }
727
+ }
728
+
594
729
fn chain ( & self ) -> ChainHash {
595
730
match self {
596
731
InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. chain ( ) ,
597
732
InvoiceContents :: ForRefund { refund, .. } => refund. chain ( ) ,
598
733
}
599
734
}
600
735
736
+ fn metadata ( & self ) -> Option < & Vec < u8 > > {
737
+ match self {
738
+ InvoiceContents :: ForOffer { invoice_request, .. } =>
739
+ invoice_request. inner . offer . metadata ( ) ,
740
+ InvoiceContents :: ForRefund { .. } => None ,
741
+ }
742
+ }
743
+
744
+ fn amount ( & self ) -> Option < & Amount > {
745
+ match self {
746
+ InvoiceContents :: ForOffer { invoice_request, .. } =>
747
+ invoice_request. inner . offer . amount ( ) ,
748
+ InvoiceContents :: ForRefund { .. } => None ,
749
+ }
750
+ }
751
+
601
752
fn description ( & self ) -> PrintableString {
602
753
match self {
603
754
InvoiceContents :: ForOffer { invoice_request, .. } => {
@@ -607,6 +758,86 @@ impl InvoiceContents {
607
758
}
608
759
}
609
760
761
+ fn offer_features ( & self ) -> Option < & OfferFeatures > {
762
+ match self {
763
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
764
+ Some ( invoice_request. inner . offer . features ( ) )
765
+ } ,
766
+ InvoiceContents :: ForRefund { .. } => None ,
767
+ }
768
+ }
769
+
770
+ fn absolute_expiry ( & self ) -> Option < Duration > {
771
+ match self {
772
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
773
+ invoice_request. inner . offer . absolute_expiry ( )
774
+ } ,
775
+ InvoiceContents :: ForRefund { refund, .. } => refund. absolute_expiry ( ) ,
776
+ }
777
+ }
778
+
779
+ fn issuer ( & self ) -> Option < PrintableString > {
780
+ match self {
781
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
782
+ invoice_request. inner . offer . issuer ( )
783
+ } ,
784
+ InvoiceContents :: ForRefund { refund, .. } => refund. issuer ( ) ,
785
+ }
786
+ }
787
+
788
+ fn paths ( & self ) -> & [ BlindedPath ] {
789
+ match self {
790
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
791
+ invoice_request. inner . offer . paths ( )
792
+ } ,
793
+ InvoiceContents :: ForRefund { refund, .. } => refund. paths ( ) ,
794
+ }
795
+ }
796
+
797
+ fn supported_quantity ( & self ) -> Option < Quantity > {
798
+ match self {
799
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
800
+ Some ( invoice_request. inner . offer . supported_quantity ( ) )
801
+ } ,
802
+ InvoiceContents :: ForRefund { .. } => None ,
803
+ }
804
+ }
805
+
806
+ fn payer_metadata ( & self ) -> & [ u8 ] {
807
+ match self {
808
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. metadata ( ) ,
809
+ InvoiceContents :: ForRefund { refund, .. } => refund. metadata ( ) ,
810
+ }
811
+ }
812
+
813
+ fn invoice_request_features ( & self ) -> & InvoiceRequestFeatures {
814
+ match self {
815
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. features ( ) ,
816
+ InvoiceContents :: ForRefund { refund, .. } => refund. features ( ) ,
817
+ }
818
+ }
819
+
820
+ fn quantity ( & self ) -> Option < u64 > {
821
+ match self {
822
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. quantity ( ) ,
823
+ InvoiceContents :: ForRefund { refund, .. } => refund. quantity ( ) ,
824
+ }
825
+ }
826
+
827
+ fn payer_id ( & self ) -> PublicKey {
828
+ match self {
829
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. payer_id ( ) ,
830
+ InvoiceContents :: ForRefund { refund, .. } => refund. payer_id ( ) ,
831
+ }
832
+ }
833
+
834
+ fn payer_note ( & self ) -> Option < PrintableString > {
835
+ match self {
836
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. payer_note ( ) ,
837
+ InvoiceContents :: ForRefund { refund, .. } => refund. payer_note ( ) ,
838
+ }
839
+ }
840
+
610
841
fn payment_paths ( & self ) -> & [ ( BlindedPayInfo , BlindedPath ) ] {
611
842
& self . fields ( ) . payment_paths [ ..]
612
843
}
@@ -1040,6 +1271,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1040
1271
mod tests {
1041
1272
use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , FallbackAddress , FullInvoiceTlvStreamRef , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1042
1273
1274
+ use bitcoin:: blockdata:: constants:: ChainHash ;
1043
1275
use bitcoin:: blockdata:: script:: Script ;
1044
1276
use bitcoin:: hashes:: Hash ;
1045
1277
use bitcoin:: network:: constants:: Network ;
@@ -1050,12 +1282,12 @@ mod tests {
1050
1282
use core:: time:: Duration ;
1051
1283
use crate :: blinded_path:: { BlindedHop , BlindedPath } ;
1052
1284
use crate :: sign:: KeyMaterial ;
1053
- use crate :: ln:: features:: Bolt12InvoiceFeatures ;
1285
+ use crate :: ln:: features:: { Bolt12InvoiceFeatures , InvoiceRequestFeatures , OfferFeatures } ;
1054
1286
use crate :: ln:: inbound_payment:: ExpandedKey ;
1055
1287
use crate :: ln:: msgs:: DecodeError ;
1056
1288
use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
1057
1289
use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , self } ;
1058
- use crate :: offers:: offer:: { OfferBuilder , OfferTlvStreamRef , Quantity } ;
1290
+ use crate :: offers:: offer:: { Amount , OfferBuilder , OfferTlvStreamRef , Quantity } ;
1059
1291
use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError } ;
1060
1292
use crate :: offers:: payer:: PayerTlvStreamRef ;
1061
1293
use crate :: offers:: refund:: RefundBuilder ;
@@ -1097,7 +1329,23 @@ mod tests {
1097
1329
unsigned_invoice. write ( & mut buffer) . unwrap ( ) ;
1098
1330
1099
1331
assert_eq ! ( unsigned_invoice. bytes, buffer. as_slice( ) ) ;
1332
+ assert_eq ! ( unsigned_invoice. payer_metadata( ) , & [ 1 ; 32 ] ) ;
1333
+ assert_eq ! ( unsigned_invoice. chains( ) , Some ( vec![ ChainHash :: using_genesis_block( Network :: Bitcoin ) ] ) ) ;
1334
+ assert_eq ! ( unsigned_invoice. metadata( ) , None ) ;
1335
+ assert_eq ! ( unsigned_invoice. amount( ) , Some ( & Amount :: Bitcoin { amount_msats: 1000 } ) ) ;
1100
1336
assert_eq ! ( unsigned_invoice. description( ) , PrintableString ( "foo" ) ) ;
1337
+ assert_eq ! ( unsigned_invoice. offer_features( ) , Some ( & OfferFeatures :: empty( ) ) ) ;
1338
+ assert_eq ! ( unsigned_invoice. absolute_expiry( ) , None ) ;
1339
+ assert_eq ! ( unsigned_invoice. paths( ) , & [ ] ) ;
1340
+ assert_eq ! ( unsigned_invoice. issuer( ) , None ) ;
1341
+ assert_eq ! ( unsigned_invoice. supported_quantity( ) , Some ( Quantity :: One ) ) ;
1342
+ assert_eq ! ( unsigned_invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
1343
+ assert_eq ! ( unsigned_invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1344
+ assert_eq ! ( unsigned_invoice. amount_msats( ) , 1000 ) ;
1345
+ assert_eq ! ( unsigned_invoice. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1346
+ assert_eq ! ( unsigned_invoice. quantity( ) , None ) ;
1347
+ assert_eq ! ( unsigned_invoice. payer_id( ) , payer_pubkey( ) ) ;
1348
+ assert_eq ! ( unsigned_invoice. payer_note( ) , None ) ;
1101
1349
assert_eq ! ( unsigned_invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
1102
1350
assert_eq ! ( unsigned_invoice. created_at( ) , now) ;
1103
1351
assert_eq ! ( unsigned_invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
@@ -1123,7 +1371,23 @@ mod tests {
1123
1371
invoice. write ( & mut buffer) . unwrap ( ) ;
1124
1372
1125
1373
assert_eq ! ( invoice. bytes, buffer. as_slice( ) ) ;
1374
+ assert_eq ! ( invoice. payer_metadata( ) , & [ 1 ; 32 ] ) ;
1375
+ assert_eq ! ( invoice. chains( ) , Some ( vec![ ChainHash :: using_genesis_block( Network :: Bitcoin ) ] ) ) ;
1376
+ assert_eq ! ( invoice. metadata( ) , None ) ;
1377
+ assert_eq ! ( invoice. amount( ) , Some ( & Amount :: Bitcoin { amount_msats: 1000 } ) ) ;
1126
1378
assert_eq ! ( invoice. description( ) , PrintableString ( "foo" ) ) ;
1379
+ assert_eq ! ( invoice. offer_features( ) , Some ( & OfferFeatures :: empty( ) ) ) ;
1380
+ assert_eq ! ( invoice. absolute_expiry( ) , None ) ;
1381
+ assert_eq ! ( invoice. paths( ) , & [ ] ) ;
1382
+ assert_eq ! ( invoice. issuer( ) , None ) ;
1383
+ assert_eq ! ( invoice. supported_quantity( ) , Some ( Quantity :: One ) ) ;
1384
+ assert_eq ! ( invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
1385
+ assert_eq ! ( invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1386
+ assert_eq ! ( invoice. amount_msats( ) , 1000 ) ;
1387
+ assert_eq ! ( invoice. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1388
+ assert_eq ! ( invoice. quantity( ) , None ) ;
1389
+ assert_eq ! ( invoice. payer_id( ) , payer_pubkey( ) ) ;
1390
+ assert_eq ! ( invoice. payer_note( ) , None ) ;
1127
1391
assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
1128
1392
assert_eq ! ( invoice. created_at( ) , now) ;
1129
1393
assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
@@ -1206,7 +1470,23 @@ mod tests {
1206
1470
invoice. write ( & mut buffer) . unwrap ( ) ;
1207
1471
1208
1472
assert_eq ! ( invoice. bytes, buffer. as_slice( ) ) ;
1473
+ assert_eq ! ( invoice. payer_metadata( ) , & [ 1 ; 32 ] ) ;
1474
+ assert_eq ! ( invoice. chains( ) , None ) ;
1475
+ assert_eq ! ( invoice. metadata( ) , None ) ;
1476
+ assert_eq ! ( invoice. amount( ) , None ) ;
1209
1477
assert_eq ! ( invoice. description( ) , PrintableString ( "foo" ) ) ;
1478
+ assert_eq ! ( invoice. offer_features( ) , None ) ;
1479
+ assert_eq ! ( invoice. absolute_expiry( ) , None ) ;
1480
+ assert_eq ! ( invoice. paths( ) , & [ ] ) ;
1481
+ assert_eq ! ( invoice. issuer( ) , None ) ;
1482
+ assert_eq ! ( invoice. supported_quantity( ) , None ) ;
1483
+ assert_eq ! ( invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
1484
+ assert_eq ! ( invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1485
+ assert_eq ! ( invoice. amount_msats( ) , 1000 ) ;
1486
+ assert_eq ! ( invoice. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1487
+ assert_eq ! ( invoice. quantity( ) , None ) ;
1488
+ assert_eq ! ( invoice. payer_id( ) , payer_pubkey( ) ) ;
1489
+ assert_eq ! ( invoice. payer_note( ) , None ) ;
1210
1490
assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
1211
1491
assert_eq ! ( invoice. created_at( ) , now) ;
1212
1492
assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
0 commit comments