@@ -151,19 +151,26 @@ impl OfferBuilder {
151151
152152 /// Sets the [`Offer::metadata`] to the given bytes.
153153 ///
154- /// Successive calls to this method will override the previous setting and any previous calls to
155- /// [`OfferBuilder::metadata_derived`].
156- pub fn metadata ( mut self , metadata : Vec < u8 > ) -> Self {
154+ /// Successive calls to this method will override the previous setting. Errors if the builder
155+ /// was constructed with [`SigningPubkey::Derived`].
156+ pub fn metadata ( mut self , metadata : Vec < u8 > ) -> Result < Self , SemanticError > {
157+ if self . offer . signing_pubkey . is_none ( ) {
158+ return Err ( SemanticError :: UnexpectedMetadata ) ;
159+ }
160+
157161 self . offer . metadata = Some ( metadata) ;
158162 self . hmac = None ;
159- self
163+ Ok ( self )
160164 }
161165
162166 /// Sets the [`Offer::metadata`] derived from the given `key` and any fields set prior to
163- /// calling [`OfferBuilder::build`].
167+ /// calling [`OfferBuilder::build`]. Allows for stateless verification of an [`InvoiceRequest`].
164168 ///
165169 /// Successive calls to this method will override the previous setting and any previous calls to
166- /// [`OfferBuilder::metadata`].
170+ /// [`OfferBuilder::metadata`]. Must be called if the builder was constructed with
171+ /// [`SigningPubkey::Derived`] in order to derive [`Offer::signing_pubkey`].
172+ ///
173+ /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
167174 pub fn metadata_derived ( mut self , key : & ExpandedKey ) -> Self {
168175 self . offer . metadata = None ;
169176 self . hmac = Some ( key. hmac_for_offer ( ) ) ;
@@ -239,8 +246,13 @@ impl OfferBuilder {
239246 }
240247 }
241248
249+ // Created the metadata for stateless verification and derive the signing_pubkey, if needed.
242250 if let Some ( mut hmac) = self . hmac {
243- self . offer . write ( & mut hmac) . unwrap ( ) ;
251+ debug_assert ! ( self . offer. metadata. is_none( ) ) ;
252+ let mut tlv_stream = self . offer . as_tlv_stream ( ) ;
253+ tlv_stream. node_id = None ;
254+ tlv_stream. write ( & mut hmac) . unwrap ( ) ;
255+
244256 self . offer . metadata = Some ( Hmac :: from_engine ( hmac) . into_inner ( ) . to_vec ( ) ) ;
245257 }
246258
@@ -533,10 +545,11 @@ impl OfferContents {
533545 let mut hmac = key. hmac_for_offer ( ) ;
534546
535547 for record in tlv_stream. range ( OFFER_TYPES ) {
536- if record. r#type != OFFER_METADATA_TYPE {
537- hmac. input ( record. record_bytes ) ;
538- } else {
548+ match record. r#type {
539549 // TODO: Assert value bytes == metadata?
550+ OFFER_METADATA_TYPE => { } ,
551+ OFFER_NODE_ID_TYPE => { } ,
552+ _ => hmac. input ( record. record_bytes ) ,
540553 }
541554 }
542555
@@ -639,6 +652,9 @@ const OFFER_TYPES: core::ops::Range<u64> = 1..80;
639652/// TLV record type for [`Offer::metadata`].
640653const OFFER_METADATA_TYPE : u64 = 4 ;
641654
655+ /// TLV record type for [`Offer::signing_pubkey`].
656+ const OFFER_NODE_ID_TYPE : u64 = 22 ;
657+
642658tlv_stream ! ( OfferTlvStream , OfferTlvStreamRef , OFFER_TYPES , {
643659 ( 2 , chains: ( Vec <ChainHash >, WithoutLength ) ) ,
644660 ( OFFER_METADATA_TYPE , metadata: ( Vec <u8 >, WithoutLength ) ) ,
@@ -650,7 +666,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, OFFER_TYPES, {
650666 ( 16 , paths: ( Vec <BlindedPath >, WithoutLength ) ) ,
651667 ( 18 , issuer: ( String , WithoutLength ) ) ,
652668 ( 20 , quantity_max: ( u64 , HighZeroBytesDroppedBigSize ) ) ,
653- ( 22 , node_id: PublicKey ) ,
669+ ( OFFER_NODE_ID_TYPE , node_id: PublicKey ) ,
654670} ) ;
655671
656672impl Bech32Encode for Offer {
@@ -866,15 +882,15 @@ mod tests {
866882 #[ test]
867883 fn builds_offer_with_metadata ( ) {
868884 let offer = OfferBuilder :: new ( "foo" . into ( ) , pubkey ( 42 ) . into ( ) )
869- . metadata ( vec ! [ 42 ; 32 ] )
885+ . metadata ( vec ! [ 42 ; 32 ] ) . unwrap ( )
870886 . build ( )
871887 . unwrap ( ) ;
872888 assert_eq ! ( offer. metadata( ) , Some ( & vec![ 42 ; 32 ] ) ) ;
873889 assert_eq ! ( offer. as_tlv_stream( ) . metadata, Some ( & vec![ 42 ; 32 ] ) ) ;
874890
875891 let offer = OfferBuilder :: new ( "foo" . into ( ) , pubkey ( 42 ) . into ( ) )
876- . metadata ( vec ! [ 42 ; 32 ] )
877- . metadata ( vec ! [ 43 ; 32 ] )
892+ . metadata ( vec ! [ 42 ; 32 ] ) . unwrap ( )
893+ . metadata ( vec ! [ 43 ; 32 ] ) . unwrap ( )
878894 . build ( )
879895 . unwrap ( ) ;
880896 assert_eq ! ( offer. metadata( ) , Some ( & vec![ 43 ; 32 ] ) ) ;
0 commit comments