@@ -71,6 +71,7 @@ use crate::io;
7171use crate :: ln:: channelmanager:: PaymentId ;
7272use crate :: ln:: inbound_payment:: { ExpandedKey , IV_LEN } ;
7373use crate :: ln:: msgs:: DecodeError ;
74+ use crate :: offers:: invoice:: { DerivedSigningPubkey , ExplicitSigningPubkey , SigningPubkeyStrategy } ;
7475use crate :: offers:: merkle:: {
7576 self , SignError , SignFn , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream ,
7677} ;
@@ -96,7 +97,7 @@ use bitcoin::secp256k1::schnorr::Signature;
9697use bitcoin:: secp256k1:: { self , Keypair , PublicKey , Secp256k1 } ;
9798
9899#[ cfg( not( c_bindings) ) ]
99- use crate :: offers:: invoice:: { DerivedSigningPubkey , ExplicitSigningPubkey , InvoiceBuilder } ;
100+ use crate :: offers:: invoice:: InvoiceBuilder ;
100101#[ cfg( c_bindings) ]
101102use crate :: offers:: invoice:: {
102103 InvoiceWithDerivedSigningPubkeyBuilder , InvoiceWithExplicitSigningPubkeyBuilder ,
@@ -615,6 +616,63 @@ pub struct VerifiedInvoiceRequestLegacy {
615616 pub keys : Option < Keypair > ,
616617}
617618
619+ /// An [`InvoiceRequest`] that has been verified by [`InvoiceRequest::verify_using_metadata`] or
620+ /// [`InvoiceRequest::verify_using_recipient_data`] and exposes different ways to respond depending
621+ /// on whether the signing keys were derived.
622+ #[ derive( Clone , Debug ) ]
623+ pub struct VerifiedInvoiceRequest < S : SigningPubkeyStrategy > {
624+ /// The identifier of the [`Offer`] for which the [`InvoiceRequest`] was made.
625+ pub offer_id : OfferId ,
626+
627+ /// The verified request.
628+ pub ( crate ) inner : InvoiceRequest ,
629+
630+ /// Keys for signing a [`Bolt12Invoice`] for the request.
631+ ///
632+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
633+ pub keys : S ,
634+ }
635+
636+ /// Represents a [`VerifiedInvoiceRequest`], along with information about how the resulting
637+ /// [`Bolt12Invoice`] should be signed.
638+ ///
639+ /// The signing strategy determines whether the signing keys are:
640+ /// - Derived either from the originating [`Offer`]’s metadata or recipient_data, or
641+ /// - Explicitly provided.
642+ ///
643+ /// This distinction is required to produce a valid, signed [`Bolt12Invoice`] from a verified request.
644+ ///
645+ /// For more on key derivation strategies, see:
646+ /// [`InvoiceRequest::verify_using_metadata`] and [`InvoiceRequest::verify_using_recipient_data`].
647+ ///
648+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
649+ pub enum InvoiceSigningInfo {
650+ /// A verified invoice request that uses signing keys derived from the originating [`Offer`]’s metadata or recipient_data.
651+ DerivedKeys ( VerifiedInvoiceRequest < DerivedSigningPubkey > ) ,
652+ /// A verified invoice request that requires explicitly provided signing keys to sign the resulting [`Bolt12Invoice`].
653+ ///
654+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
655+ ExplicitKeys ( VerifiedInvoiceRequest < ExplicitSigningPubkey > ) ,
656+ }
657+
658+ impl InvoiceSigningInfo {
659+ /// Returns a reference to the underlying `InvoiceRequest`.
660+ fn inner ( & self ) -> & InvoiceRequest {
661+ match self {
662+ InvoiceSigningInfo :: DerivedKeys ( req) => & req. inner ,
663+ InvoiceSigningInfo :: ExplicitKeys ( req) => & req. inner ,
664+ }
665+ }
666+
667+ /// Returns the `OfferId` of the offer this invoice request is for.
668+ pub fn offer_id ( & self ) -> OfferId {
669+ match self {
670+ InvoiceSigningInfo :: DerivedKeys ( req) => req. offer_id ,
671+ InvoiceSigningInfo :: ExplicitKeys ( req) => req. offer_id ,
672+ }
673+ }
674+ }
675+
618676/// The contents of an [`InvoiceRequest`], which may be shared with an [`Bolt12Invoice`].
619677///
620678/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
@@ -1024,6 +1082,24 @@ impl VerifiedInvoiceRequestLegacy {
10241082 ) ;
10251083}
10261084
1085+ impl VerifiedInvoiceRequest < DerivedSigningPubkey > {
1086+ offer_accessors ! ( self , self . inner. contents. inner. offer) ;
1087+ invoice_request_accessors ! ( self , self . inner. contents) ;
1088+ fields_accessor ! ( self , self . inner. contents) ;
1089+ }
1090+
1091+ impl VerifiedInvoiceRequest < ExplicitSigningPubkey > {
1092+ offer_accessors ! ( self , self . inner. contents. inner. offer) ;
1093+ invoice_request_accessors ! ( self , self . inner. contents) ;
1094+ fields_accessor ! ( self , self . inner. contents) ;
1095+ }
1096+
1097+ impl InvoiceSigningInfo {
1098+ offer_accessors ! ( self , self . inner( ) . contents. inner. offer) ;
1099+ invoice_request_accessors ! ( self , self . inner( ) . contents) ;
1100+ fields_accessor ! ( self , self . inner( ) . contents) ;
1101+ }
1102+
10271103/// `String::truncate(new_len)` panics if you split inside a UTF-8 code point,
10281104/// which would leave the `String` containing invalid UTF-8. This function will
10291105/// instead truncate the string to the next smaller code point boundary so the
0 commit comments