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