@@ -135,7 +135,7 @@ use crate::offers::merkle::{
135135} ; 
136136use  crate :: offers:: nonce:: Nonce ; 
137137use  crate :: offers:: offer:: { 
138- 	Amount ,  ExperimentalOfferTlvStream ,  ExperimentalOfferTlvStreamRef ,  OfferTlvStream , 
138+ 	Amount ,  ExperimentalOfferTlvStream ,  ExperimentalOfferTlvStreamRef ,  OfferId ,   OfferTlvStream , 
139139	OfferTlvStreamRef ,  Quantity ,  EXPERIMENTAL_OFFER_TYPES ,  OFFER_TYPES , 
140140} ; 
141141use  crate :: offers:: parse:: { Bolt12ParseError ,  Bolt12SemanticError ,  ParsedMessage } ; 
@@ -686,6 +686,13 @@ macro_rules! unsigned_invoice_sign_method { ($self: ident, $self_type: ty $(, $s
686686		// Append the experimental bytes after the signature. 
687687		$self. bytes. extend_from_slice( & $self. experimental_bytes) ; 
688688
689+ 		let  offer_id = match  & $self. contents { 
690+ 			InvoiceContents :: ForOffer  {  .. }  => { 
691+ 				Some ( OfferId :: from_valid_bolt12_tlv_stream( & $self. bytes) ) 
692+ 			} , 
693+ 			InvoiceContents :: ForRefund  {  .. }  => None , 
694+ 		} ; 
695+ 
689696		Ok ( Bolt12Invoice  { 
690697			#[ cfg( not( c_bindings) ) ] 
691698			bytes:  $self. bytes, 
@@ -700,6 +707,7 @@ macro_rules! unsigned_invoice_sign_method { ($self: ident, $self_type: ty $(, $s
700707			tagged_hash:  $self. tagged_hash, 
701708			#[ cfg( c_bindings) ] 
702709			tagged_hash:  $self. tagged_hash. clone( ) , 
710+ 			offer_id, 
703711		} ) 
704712	} 
705713}  } 
@@ -734,6 +742,7 @@ pub struct Bolt12Invoice {
734742	contents :  InvoiceContents , 
735743	signature :  Signature , 
736744	tagged_hash :  TaggedHash , 
745+ 	offer_id :  Option < OfferId > , 
737746} 
738747
739748/// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`]. 
@@ -967,6 +976,13 @@ impl Bolt12Invoice {
967976		self . tagged_hash . as_digest ( ) . as_ref ( ) . clone ( ) 
968977	} 
969978
979+ 	/// Returns the [`OfferId`] if this invoice corresponds to an [`Offer`]. 
980+  	/// 
981+  	/// [`Offer`]: crate::offers::offer::Offer 
982+  	pub  fn  offer_id ( & self )  -> Option < OfferId >  { 
983+ 		self . offer_id 
984+ 	} 
985+ 
970986	/// Verifies that the invoice was for a request or refund created using the given key by 
971987 	/// checking the payer metadata from the invoice request. 
972988 	/// 
@@ -1626,7 +1642,11 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
16261642		let  pubkey = contents. fields ( ) . signing_pubkey ; 
16271643		merkle:: verify_signature ( & signature,  & tagged_hash,  pubkey) ?; 
16281644
1629- 		Ok ( Bolt12Invoice  {  bytes,  contents,  signature,  tagged_hash } ) 
1645+ 		let  offer_id = match  & contents { 
1646+ 			InvoiceContents :: ForOffer  {  .. }  => Some ( OfferId :: from_valid_bolt12_tlv_stream ( & bytes) ) , 
1647+ 			InvoiceContents :: ForRefund  {  .. }  => None , 
1648+ 		} ; 
1649+ 		Ok ( Bolt12Invoice  {  bytes,  contents,  signature,  tagged_hash,  offer_id } ) 
16301650	} 
16311651} 
16321652
@@ -3560,4 +3580,49 @@ mod tests {
35603580			) , 
35613581		} 
35623582	} 
3583+ 
3584+ 	#[ test]  
3585+ 	fn  invoice_offer_id_matches_offer_id ( )  { 
3586+ 		let  expanded_key = ExpandedKey :: new ( [ 42 ;  32 ] ) ; 
3587+ 		let  entropy = FixedEntropy  { } ; 
3588+ 		let  nonce = Nonce :: from_entropy_source ( & entropy) ; 
3589+ 		let  secp_ctx = Secp256k1 :: new ( ) ; 
3590+ 		let  payment_id = PaymentId ( [ 1 ;  32 ] ) ; 
3591+ 
3592+ 		let  offer = OfferBuilder :: new ( recipient_pubkey ( ) ) . amount_msats ( 1000 ) . build ( ) . unwrap ( ) ; 
3593+ 
3594+ 		let  offer_id = offer. id ( ) ; 
3595+ 
3596+ 		let  invoice_request = offer
3597+ 			. request_invoice ( & expanded_key,  nonce,  & secp_ctx,  payment_id) 
3598+ 			. unwrap ( ) 
3599+ 			. build_and_sign ( ) 
3600+ 			. unwrap ( ) ; 
3601+ 
3602+ 		let  invoice = invoice_request
3603+ 			. respond_with_no_std ( payment_paths ( ) ,  payment_hash ( ) ,  now ( ) ) 
3604+ 			. unwrap ( ) 
3605+ 			. build ( ) 
3606+ 			. unwrap ( ) 
3607+ 			. sign ( recipient_sign) 
3608+ 			. unwrap ( ) ; 
3609+ 
3610+ 		assert_eq ! ( invoice. offer_id( ) ,  Some ( offer_id) ) ; 
3611+ 	} 
3612+ 
3613+ 	#[ test]  
3614+ 	fn  refund_invoice_has_no_offer_id ( )  { 
3615+ 		let  refund =
3616+ 			RefundBuilder :: new ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ,  1000 ) . unwrap ( ) . build ( ) . unwrap ( ) ; 
3617+ 
3618+ 		let  invoice = refund
3619+ 			. respond_with_no_std ( payment_paths ( ) ,  payment_hash ( ) ,  recipient_pubkey ( ) ,  now ( ) ) 
3620+ 			. unwrap ( ) 
3621+ 			. build ( ) 
3622+ 			. unwrap ( ) 
3623+ 			. sign ( recipient_sign) 
3624+ 			. unwrap ( ) ; 
3625+ 
3626+ 		assert_eq ! ( invoice. offer_id( ) ,  None ) ; 
3627+ 	} 
35633628} 
0 commit comments