@@ -110,12 +110,12 @@ use core::time::Duration;
110110use crate :: io;
111111use crate :: blinded_path:: BlindedPath ;
112112use crate :: ln:: PaymentHash ;
113- use crate :: ln:: features:: { BlindedHopFeatures , Bolt12InvoiceFeatures } ;
113+ use crate :: ln:: features:: { BlindedHopFeatures , Bolt12InvoiceFeatures , InvoiceRequestFeatures , OfferFeatures } ;
114114use crate :: ln:: inbound_payment:: ExpandedKey ;
115115use crate :: ln:: msgs:: DecodeError ;
116116use crate :: offers:: invoice_request:: { INVOICE_REQUEST_PAYER_ID_TYPE , INVOICE_REQUEST_TYPES , IV_BYTES as INVOICE_REQUEST_IV_BYTES , InvoiceRequest , InvoiceRequestContents , InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef } ;
117117use 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 } ;
119119use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
120120use crate :: offers:: payer:: { PAYER_METADATA_TYPE , PayerTlvStream , PayerTlvStreamRef } ;
121121use crate :: offers:: refund:: { IV_BYTES as REFUND_IV_BYTES , Refund , RefundContents } ;
@@ -482,12 +482,141 @@ struct InvoiceFields {
482482}
483483
484484macro_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
487543 pub fn description( & $self) -> PrintableString {
488544 $contents. description( )
489545 }
490546
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+
491620 /// Paths to the recipient originating from publicly reachable nodes, including information
492621 /// needed for routing payments across them.
493622 ///
@@ -591,13 +720,37 @@ impl InvoiceContents {
591720 }
592721 }
593722
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+
594731 fn chain ( & self ) -> ChainHash {
595732 match self {
596733 InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. chain ( ) ,
597734 InvoiceContents :: ForRefund { refund, .. } => refund. chain ( ) ,
598735 }
599736 }
600737
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+
601754 fn description ( & self ) -> PrintableString {
602755 match self {
603756 InvoiceContents :: ForOffer { invoice_request, .. } => {
@@ -607,6 +760,86 @@ impl InvoiceContents {
607760 }
608761 }
609762
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+
610843 fn payment_paths ( & self ) -> & [ ( BlindedPayInfo , BlindedPath ) ] {
611844 & self . fields ( ) . payment_paths [ ..]
612845 }
@@ -1040,6 +1273,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
10401273mod tests {
10411274 use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , FallbackAddress , FullInvoiceTlvStreamRef , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
10421275
1276+ use bitcoin:: blockdata:: constants:: ChainHash ;
10431277 use bitcoin:: blockdata:: script:: Script ;
10441278 use bitcoin:: hashes:: Hash ;
10451279 use bitcoin:: network:: constants:: Network ;
@@ -1050,12 +1284,12 @@ mod tests {
10501284 use core:: time:: Duration ;
10511285 use crate :: blinded_path:: { BlindedHop , BlindedPath } ;
10521286 use crate :: sign:: KeyMaterial ;
1053- use crate :: ln:: features:: Bolt12InvoiceFeatures ;
1287+ use crate :: ln:: features:: { Bolt12InvoiceFeatures , InvoiceRequestFeatures , OfferFeatures } ;
10541288 use crate :: ln:: inbound_payment:: ExpandedKey ;
10551289 use crate :: ln:: msgs:: DecodeError ;
10561290 use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
10571291 use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , self } ;
1058- use crate :: offers:: offer:: { OfferBuilder , OfferTlvStreamRef , Quantity } ;
1292+ use crate :: offers:: offer:: { Amount , OfferBuilder , OfferTlvStreamRef , Quantity } ;
10591293 use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError } ;
10601294 use crate :: offers:: payer:: PayerTlvStreamRef ;
10611295 use crate :: offers:: refund:: RefundBuilder ;
@@ -1097,7 +1331,23 @@ mod tests {
10971331 unsigned_invoice. write ( & mut buffer) . unwrap ( ) ;
10981332
10991333 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 } ) ) ;
11001338 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 ) ;
11011351 assert_eq ! ( unsigned_invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
11021352 assert_eq ! ( unsigned_invoice. created_at( ) , now) ;
11031353 assert_eq ! ( unsigned_invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
@@ -1123,7 +1373,23 @@ mod tests {
11231373 invoice. write ( & mut buffer) . unwrap ( ) ;
11241374
11251375 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 } ) ) ;
11261380 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 ) ;
11271393 assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
11281394 assert_eq ! ( invoice. created_at( ) , now) ;
11291395 assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
@@ -1206,7 +1472,23 @@ mod tests {
12061472 invoice. write ( & mut buffer) . unwrap ( ) ;
12071473
12081474 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 ) ;
12091479 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 ) ;
12101492 assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
12111493 assert_eq ! ( invoice. created_at( ) , now) ;
12121494 assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
0 commit comments