@@ -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 } ;
@@ -476,12 +476,139 @@ struct InvoiceFields {
476
476
}
477
477
478
478
macro_rules! invoice_accessors { ( $self: ident, $contents: expr) => {
479
- /// A complete description of the purpose of the originating offer or refund. Intended to be
480
- /// displayed to the user but with the caveat that it has not been verified in any way.
479
+ /// The chains that may be used when paying a requested invoice.
480
+ ///
481
+ /// From [`Offer::chains`]; `None` if the invoice was created in response to a [`Refund`].
482
+ ///
483
+ /// [`Offer::chains`]: crate::offers::offer::Offer::chains
484
+ pub fn chains( & $self) -> Option <Vec <ChainHash >> {
485
+ $contents. chains( )
486
+ }
487
+
488
+ /// A chain that the originating offer or refund is valid for.
489
+ ///
490
+ /// From [`InvoiceRequest::chain`] or [`Refund::chain`].
491
+ ///
492
+ /// [`InvoiceRequest::chain`]: crate::offers::invoice_request::InvoiceRequest::chain
493
+ pub fn chain( & $self) -> ChainHash {
494
+ $contents. chain( )
495
+ }
496
+
497
+ /// Opaque bytes set by the originating [`Offer`].
498
+ ///
499
+ /// From [`Offer::metadata`]; `None` if the invoice was created in response to a [`Refund`] or
500
+ /// if the [`Offer`] did not set it.
501
+ ///
502
+ /// [`Offer`]: crate::offers::offer::Offer
503
+ /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
504
+ pub fn metadata( & $self) -> Option <& Vec <u8 >> {
505
+ $contents. metadata( )
506
+ }
507
+
508
+ /// The minimum amount required for a successful payment of a single item.
509
+ ///
510
+ /// From [`Offer::amount`]; `None` if the invoice was created in response to a [`Refund`] or if
511
+ /// the [`Offer`] did not set it.
512
+ ///
513
+ /// [`Offer`]: crate::offers::offer::Offer
514
+ /// [`Offer::amount`]: crate::offers::offer::Offer::amount
515
+ pub fn amount( & $self) -> Option <& Amount > {
516
+ $contents. amount( )
517
+ }
518
+
519
+ /// Features pertaining to the originating [`Offer`].
520
+ ///
521
+ /// From [`Offer::offer_features`]; `None` if the invoice was created in response to a
522
+ /// [`Refund`].
523
+ ///
524
+ /// [`Offer`]: crate::offers::offer::Offer
525
+ /// [`Offer::offer_features`]: crate::offers::offer::Offer::offer_features
526
+ pub fn offer_features( & $self) -> Option <& OfferFeatures > {
527
+ $contents. offer_features( )
528
+ }
529
+
530
+ /// A complete description of the purpose of the originating offer or refund.
531
+ ///
532
+ /// From [`Offer::description`] or [`Refund::description`].
533
+ ///
534
+ /// [`Offer::description`]: crate::offers::offer::Offer::description
481
535
pub fn description( & $self) -> PrintableString {
482
536
$contents. description( )
483
537
}
484
538
539
+ /// Duration since the Unix epoch when an invoice should no longer be requested.
540
+ ///
541
+ /// From [`Offer::absolute_expiry`] or [`Refund::absolute_expiry`].
542
+ ///
543
+ /// [`Offer::absolute_expiry`]: crate::offers::offer::Offer::absolute_expiry
544
+ pub fn absolute_expiry( & $self) -> Option <Duration > {
545
+ $contents. absolute_expiry( )
546
+ }
547
+
548
+ /// The issuer of the offer or refund.
549
+ ///
550
+ /// From [`Offer::issuer`] or [`Refund::issuer`].
551
+ ///
552
+ /// [`Offer::issuer`]: crate::offers::offer::Offer::issuer
553
+ pub fn issuer( & $self) -> Option <PrintableString > {
554
+ $contents. issuer( )
555
+ }
556
+
557
+ /// Paths to the recipient originating from publicly reachable nodes.
558
+ ///
559
+ /// From [`Offer::paths`] or [`Refund::paths`].
560
+ ///
561
+ /// [`Offer::paths`]: crate::offers::offer::Offer::paths
562
+ pub fn paths( & $self) -> & [ BlindedPath ] {
563
+ $contents. paths( )
564
+ }
565
+
566
+ /// The quantity of items supported.
567
+ ///
568
+ /// From [`Offer::supported_quantity`]; `None` if the invoice was created in response to a
569
+ /// [`Refund`].
570
+ ///
571
+ /// [`Offer::supported_quantity`]: crate::offers::offer::Offer::supported_quantity
572
+ pub fn supported_quantity( & $self) -> Option <Quantity > {
573
+ $contents. supported_quantity( )
574
+ }
575
+
576
+ /// An unpredictable series of bytes from the payer.
577
+ ///
578
+ /// From [`InvoiceRequest::payer_metadata`] or [`Refund::payer_metadata`].
579
+ pub fn payer_metadata( & $self) -> & [ u8 ] {
580
+ $contents. payer_metadata( )
581
+ }
582
+
583
+ /// Features pertaining to requesting an invoice.
584
+ ///
585
+ /// From [`InvoiceRequest::invoice_request_features`] or [`Refund::features`].
586
+ pub fn invoice_request_features( & $self) -> & InvoiceRequestFeatures {
587
+ & $contents. invoice_request_features( )
588
+ }
589
+
590
+ /// The quantity of items requested or refunded for.
591
+ ///
592
+ /// From [`InvoiceRequest::quantity`] or [`Refund::quantity`].
593
+ pub fn quantity( & $self) -> Option <u64 > {
594
+ $contents. quantity( )
595
+ }
596
+
597
+ /// A possibly transient pubkey used to sign the invoice request or to send an invoice for a
598
+ /// refund in case there are no [`paths`].
599
+ ///
600
+ /// [`paths`]: Self::paths
601
+ pub fn payer_id( & $self) -> PublicKey {
602
+ $contents. payer_id( )
603
+ }
604
+
605
+ /// A payer-provided note reflected back in the invoice.
606
+ ///
607
+ /// From [`InvoiceRequest::payer_note`] or [`Refund::payer_note`].
608
+ pub fn payer_note( & $self) -> Option <PrintableString > {
609
+ $contents. payer_note( )
610
+ }
611
+
485
612
/// Paths to the recipient originating from publicly reachable nodes, including information
486
613
/// needed for routing payments across them.
487
614
///
@@ -585,13 +712,37 @@ impl InvoiceContents {
585
712
}
586
713
}
587
714
715
+ fn chains ( & self ) -> Option < Vec < ChainHash > > {
716
+ match self {
717
+ InvoiceContents :: ForOffer { invoice_request, .. } =>
718
+ Some ( invoice_request. inner . offer . chains ( ) ) ,
719
+ InvoiceContents :: ForRefund { .. } => None ,
720
+ }
721
+ }
722
+
588
723
fn chain ( & self ) -> ChainHash {
589
724
match self {
590
725
InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. chain ( ) ,
591
726
InvoiceContents :: ForRefund { refund, .. } => refund. chain ( ) ,
592
727
}
593
728
}
594
729
730
+ fn metadata ( & self ) -> Option < & Vec < u8 > > {
731
+ match self {
732
+ InvoiceContents :: ForOffer { invoice_request, .. } =>
733
+ invoice_request. inner . offer . metadata ( ) ,
734
+ InvoiceContents :: ForRefund { .. } => None ,
735
+ }
736
+ }
737
+
738
+ fn amount ( & self ) -> Option < & Amount > {
739
+ match self {
740
+ InvoiceContents :: ForOffer { invoice_request, .. } =>
741
+ invoice_request. inner . offer . amount ( ) ,
742
+ InvoiceContents :: ForRefund { .. } => None ,
743
+ }
744
+ }
745
+
595
746
fn description ( & self ) -> PrintableString {
596
747
match self {
597
748
InvoiceContents :: ForOffer { invoice_request, .. } => {
@@ -601,6 +752,86 @@ impl InvoiceContents {
601
752
}
602
753
}
603
754
755
+ fn offer_features ( & self ) -> Option < & OfferFeatures > {
756
+ match self {
757
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
758
+ Some ( invoice_request. inner . offer . features ( ) )
759
+ } ,
760
+ InvoiceContents :: ForRefund { .. } => None ,
761
+ }
762
+ }
763
+
764
+ fn absolute_expiry ( & self ) -> Option < Duration > {
765
+ match self {
766
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
767
+ invoice_request. inner . offer . absolute_expiry ( )
768
+ } ,
769
+ InvoiceContents :: ForRefund { refund, .. } => refund. absolute_expiry ( ) ,
770
+ }
771
+ }
772
+
773
+ fn issuer ( & self ) -> Option < PrintableString > {
774
+ match self {
775
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
776
+ invoice_request. inner . offer . issuer ( )
777
+ } ,
778
+ InvoiceContents :: ForRefund { refund, .. } => refund. issuer ( ) ,
779
+ }
780
+ }
781
+
782
+ fn paths ( & self ) -> & [ BlindedPath ] {
783
+ match self {
784
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
785
+ invoice_request. inner . offer . paths ( )
786
+ } ,
787
+ InvoiceContents :: ForRefund { refund, .. } => refund. paths ( ) ,
788
+ }
789
+ }
790
+
791
+ fn supported_quantity ( & self ) -> Option < Quantity > {
792
+ match self {
793
+ InvoiceContents :: ForOffer { invoice_request, .. } => {
794
+ Some ( invoice_request. inner . offer . supported_quantity ( ) )
795
+ } ,
796
+ InvoiceContents :: ForRefund { .. } => None ,
797
+ }
798
+ }
799
+
800
+ fn payer_metadata ( & self ) -> & [ u8 ] {
801
+ match self {
802
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. metadata ( ) ,
803
+ InvoiceContents :: ForRefund { refund, .. } => refund. metadata ( ) ,
804
+ }
805
+ }
806
+
807
+ fn invoice_request_features ( & self ) -> & InvoiceRequestFeatures {
808
+ match self {
809
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. features ( ) ,
810
+ InvoiceContents :: ForRefund { refund, .. } => refund. features ( ) ,
811
+ }
812
+ }
813
+
814
+ fn quantity ( & self ) -> Option < u64 > {
815
+ match self {
816
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. quantity ( ) ,
817
+ InvoiceContents :: ForRefund { refund, .. } => refund. quantity ( ) ,
818
+ }
819
+ }
820
+
821
+ fn payer_id ( & self ) -> PublicKey {
822
+ match self {
823
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. payer_id ( ) ,
824
+ InvoiceContents :: ForRefund { refund, .. } => refund. payer_id ( ) ,
825
+ }
826
+ }
827
+
828
+ fn payer_note ( & self ) -> Option < PrintableString > {
829
+ match self {
830
+ InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. payer_note ( ) ,
831
+ InvoiceContents :: ForRefund { refund, .. } => refund. payer_note ( ) ,
832
+ }
833
+ }
834
+
604
835
fn payment_paths ( & self ) -> & [ ( BlindedPayInfo , BlindedPath ) ] {
605
836
& self . fields ( ) . payment_paths [ ..]
606
837
}
@@ -1034,6 +1265,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1034
1265
mod tests {
1035
1266
use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , FallbackAddress , FullInvoiceTlvStreamRef , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1036
1267
1268
+ use bitcoin:: blockdata:: constants:: ChainHash ;
1037
1269
use bitcoin:: blockdata:: script:: Script ;
1038
1270
use bitcoin:: hashes:: Hash ;
1039
1271
use bitcoin:: network:: constants:: Network ;
@@ -1044,12 +1276,12 @@ mod tests {
1044
1276
use core:: time:: Duration ;
1045
1277
use crate :: blinded_path:: { BlindedHop , BlindedPath } ;
1046
1278
use crate :: sign:: KeyMaterial ;
1047
- use crate :: ln:: features:: Bolt12InvoiceFeatures ;
1279
+ use crate :: ln:: features:: { Bolt12InvoiceFeatures , InvoiceRequestFeatures , OfferFeatures } ;
1048
1280
use crate :: ln:: inbound_payment:: ExpandedKey ;
1049
1281
use crate :: ln:: msgs:: DecodeError ;
1050
1282
use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
1051
1283
use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , self } ;
1052
- use crate :: offers:: offer:: { OfferBuilder , OfferTlvStreamRef , Quantity } ;
1284
+ use crate :: offers:: offer:: { Amount , OfferBuilder , OfferTlvStreamRef , Quantity } ;
1053
1285
use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError } ;
1054
1286
use crate :: offers:: payer:: PayerTlvStreamRef ;
1055
1287
use crate :: offers:: refund:: RefundBuilder ;
@@ -1091,7 +1323,23 @@ mod tests {
1091
1323
unsigned_invoice. write ( & mut buffer) . unwrap ( ) ;
1092
1324
1093
1325
assert_eq ! ( unsigned_invoice. bytes, buffer. as_slice( ) ) ;
1326
+ assert_eq ! ( unsigned_invoice. payer_metadata( ) , & [ 1 ; 32 ] ) ;
1327
+ assert_eq ! ( unsigned_invoice. chains( ) , Some ( vec![ ChainHash :: using_genesis_block( Network :: Bitcoin ) ] ) ) ;
1328
+ assert_eq ! ( unsigned_invoice. metadata( ) , None ) ;
1329
+ assert_eq ! ( unsigned_invoice. amount( ) , Some ( & Amount :: Bitcoin { amount_msats: 1000 } ) ) ;
1094
1330
assert_eq ! ( unsigned_invoice. description( ) , PrintableString ( "foo" ) ) ;
1331
+ assert_eq ! ( unsigned_invoice. offer_features( ) , Some ( & OfferFeatures :: empty( ) ) ) ;
1332
+ assert_eq ! ( unsigned_invoice. absolute_expiry( ) , None ) ;
1333
+ assert_eq ! ( unsigned_invoice. paths( ) , & [ ] ) ;
1334
+ assert_eq ! ( unsigned_invoice. issuer( ) , None ) ;
1335
+ assert_eq ! ( unsigned_invoice. supported_quantity( ) , Some ( Quantity :: One ) ) ;
1336
+ assert_eq ! ( unsigned_invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
1337
+ assert_eq ! ( unsigned_invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1338
+ assert_eq ! ( unsigned_invoice. amount_msats( ) , 1000 ) ;
1339
+ assert_eq ! ( unsigned_invoice. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1340
+ assert_eq ! ( unsigned_invoice. quantity( ) , None ) ;
1341
+ assert_eq ! ( unsigned_invoice. payer_id( ) , payer_pubkey( ) ) ;
1342
+ assert_eq ! ( unsigned_invoice. payer_note( ) , None ) ;
1095
1343
assert_eq ! ( unsigned_invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
1096
1344
assert_eq ! ( unsigned_invoice. created_at( ) , now) ;
1097
1345
assert_eq ! ( unsigned_invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
@@ -1117,7 +1365,23 @@ mod tests {
1117
1365
invoice. write ( & mut buffer) . unwrap ( ) ;
1118
1366
1119
1367
assert_eq ! ( invoice. bytes, buffer. as_slice( ) ) ;
1368
+ assert_eq ! ( invoice. payer_metadata( ) , & [ 1 ; 32 ] ) ;
1369
+ assert_eq ! ( invoice. chains( ) , Some ( vec![ ChainHash :: using_genesis_block( Network :: Bitcoin ) ] ) ) ;
1370
+ assert_eq ! ( invoice. metadata( ) , None ) ;
1371
+ assert_eq ! ( invoice. amount( ) , Some ( & Amount :: Bitcoin { amount_msats: 1000 } ) ) ;
1120
1372
assert_eq ! ( invoice. description( ) , PrintableString ( "foo" ) ) ;
1373
+ assert_eq ! ( invoice. offer_features( ) , Some ( & OfferFeatures :: empty( ) ) ) ;
1374
+ assert_eq ! ( invoice. absolute_expiry( ) , None ) ;
1375
+ assert_eq ! ( invoice. paths( ) , & [ ] ) ;
1376
+ assert_eq ! ( invoice. issuer( ) , None ) ;
1377
+ assert_eq ! ( invoice. supported_quantity( ) , Some ( Quantity :: One ) ) ;
1378
+ assert_eq ! ( invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
1379
+ assert_eq ! ( invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1380
+ assert_eq ! ( invoice. amount_msats( ) , 1000 ) ;
1381
+ assert_eq ! ( invoice. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1382
+ assert_eq ! ( invoice. quantity( ) , None ) ;
1383
+ assert_eq ! ( invoice. payer_id( ) , payer_pubkey( ) ) ;
1384
+ assert_eq ! ( invoice. payer_note( ) , None ) ;
1121
1385
assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
1122
1386
assert_eq ! ( invoice. created_at( ) , now) ;
1123
1387
assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
@@ -1200,7 +1464,23 @@ mod tests {
1200
1464
invoice. write ( & mut buffer) . unwrap ( ) ;
1201
1465
1202
1466
assert_eq ! ( invoice. bytes, buffer. as_slice( ) ) ;
1467
+ assert_eq ! ( invoice. payer_metadata( ) , & [ 1 ; 32 ] ) ;
1468
+ assert_eq ! ( invoice. chains( ) , None ) ;
1469
+ assert_eq ! ( invoice. metadata( ) , None ) ;
1470
+ assert_eq ! ( invoice. amount( ) , None ) ;
1203
1471
assert_eq ! ( invoice. description( ) , PrintableString ( "foo" ) ) ;
1472
+ assert_eq ! ( invoice. offer_features( ) , None ) ;
1473
+ assert_eq ! ( invoice. absolute_expiry( ) , None ) ;
1474
+ assert_eq ! ( invoice. paths( ) , & [ ] ) ;
1475
+ assert_eq ! ( invoice. issuer( ) , None ) ;
1476
+ assert_eq ! ( invoice. supported_quantity( ) , None ) ;
1477
+ assert_eq ! ( invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
1478
+ assert_eq ! ( invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
1479
+ assert_eq ! ( invoice. amount_msats( ) , 1000 ) ;
1480
+ assert_eq ! ( invoice. invoice_request_features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
1481
+ assert_eq ! ( invoice. quantity( ) , None ) ;
1482
+ assert_eq ! ( invoice. payer_id( ) , payer_pubkey( ) ) ;
1483
+ assert_eq ! ( invoice. payer_note( ) , None ) ;
1204
1484
assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
1205
1485
assert_eq ! ( invoice. created_at( ) , now) ;
1206
1486
assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
0 commit comments