@@ -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
@@ -638,6 +651,9 @@ const OFFER_TYPES: core::ops::Range<u64> = 1..80;
638651/// TLV record type for [`Offer::metadata`].
639652const OFFER_METADATA_TYPE : u64 = 4 ;
640653
654+ /// TLV record type for [`Offer::signing_pubkey`].
655+ const OFFER_NODE_ID_TYPE : u64 = 22 ;
656+
641657tlv_stream ! ( OfferTlvStream , OfferTlvStreamRef , OFFER_TYPES , {
642658 ( 2 , chains: ( Vec <ChainHash >, WithoutLength ) ) ,
643659 ( OFFER_METADATA_TYPE , metadata: ( Vec <u8 >, WithoutLength ) ) ,
@@ -649,7 +665,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, OFFER_TYPES, {
649665 ( 16 , paths: ( Vec <BlindedPath >, WithoutLength ) ) ,
650666 ( 18 , issuer: ( String , WithoutLength ) ) ,
651667 ( 20 , quantity_max: ( u64 , HighZeroBytesDroppedBigSize ) ) ,
652- ( 22 , node_id: PublicKey ) ,
668+ ( OFFER_NODE_ID_TYPE , node_id: PublicKey ) ,
653669} ) ;
654670
655671impl Bech32Encode for Offer {
@@ -865,15 +881,15 @@ mod tests {
865881 #[ test]
866882 fn builds_offer_with_metadata ( ) {
867883 let offer = OfferBuilder :: new ( "foo" . into ( ) , pubkey ( 42 ) . into ( ) )
868- . metadata ( vec ! [ 42 ; 32 ] )
884+ . metadata ( vec ! [ 42 ; 32 ] ) . unwrap ( )
869885 . build ( )
870886 . unwrap ( ) ;
871887 assert_eq ! ( offer. metadata( ) , Some ( & vec![ 42 ; 32 ] ) ) ;
872888 assert_eq ! ( offer. as_tlv_stream( ) . metadata, Some ( & vec![ 42 ; 32 ] ) ) ;
873889
874890 let offer = OfferBuilder :: new ( "foo" . into ( ) , pubkey ( 42 ) . into ( ) )
875- . metadata ( vec ! [ 42 ; 32 ] )
876- . metadata ( vec ! [ 43 ; 32 ] )
891+ . metadata ( vec ! [ 42 ; 32 ] ) . unwrap ( )
892+ . metadata ( vec ! [ 43 ; 32 ] ) . unwrap ( )
877893 . build ( )
878894 . unwrap ( ) ;
879895 assert_eq ! ( offer. metadata( ) , Some ( & vec![ 43 ; 32 ] ) ) ;
0 commit comments