@@ -431,10 +431,13 @@ pub struct RecipientOnionFields {
431431 /// [`Self::payment_secret`] and while nearly all lightning senders support secrets, metadata
432432 /// may not be supported as universally.
433433 pub payment_metadata : Option < Vec < u8 > > ,
434+ /// See [`Self::custom_tlvs`] for more info.
435+ pub ( super ) custom_tlvs : Vec < ( u64 , Vec < u8 > ) > ,
434436}
435437
436438impl_writeable_tlv_based ! ( RecipientOnionFields , {
437439 ( 0 , payment_secret, option) ,
440+ ( 1 , custom_tlvs, optional_vec) ,
438441 ( 2 , payment_metadata, option) ,
439442} ) ;
440443
@@ -443,7 +446,7 @@ impl RecipientOnionFields {
443446 /// set of onion fields for today's BOLT11 invoices - most nodes require a [`PaymentSecret`]
444447 /// but do not require or provide any further data.
445448 pub fn secret_only ( payment_secret : PaymentSecret ) -> Self {
446- Self { payment_secret : Some ( payment_secret) , payment_metadata : None }
449+ Self { payment_secret : Some ( payment_secret) , payment_metadata : None , custom_tlvs : Vec :: new ( ) }
447450 }
448451
449452 /// Creates a new [`RecipientOnionFields`] with no fields. This generally does not create
@@ -455,7 +458,46 @@ impl RecipientOnionFields {
455458 /// [`ChannelManager::send_spontaneous_payment`]: super::channelmanager::ChannelManager::send_spontaneous_payment
456459 /// [`RecipientOnionFields::secret_only`]: RecipientOnionFields::secret_only
457460 pub fn spontaneous_empty ( ) -> Self {
458- Self { payment_secret : None , payment_metadata : None }
461+ Self { payment_secret : None , payment_metadata : None , custom_tlvs : Vec :: new ( ) }
462+ }
463+
464+ /// Creates a new [`RecipientOnionFields`] from an existing one, adding custom TLVs. Each
465+ /// TLV is provided as a `(u64, Vec<u8>)` for the type number and serialized value
466+ /// respectively. TLV type numbers must be unique and within the range
467+ /// reserved for custom types, i.e. >= 2^16, otherwise this method will return `Err(())`.
468+ ///
469+ /// This method will also error for types in the experimental range which have been
470+ /// standardized within the protocol, which only includes 5482373484 (keysend) for now.
471+ ///
472+ /// See [`Self::custom_tlvs`] for more info.
473+ pub fn with_custom_tlvs ( mut self , mut custom_tlvs : Vec < ( u64 , Vec < u8 > ) > ) -> Result < Self , ( ) > {
474+ custom_tlvs. sort_unstable_by_key ( |( typ, _) | * typ) ;
475+ let mut prev_type = None ;
476+ for ( typ, _) in custom_tlvs. iter ( ) {
477+ if * typ < 1 << 16 { return Err ( ( ) ) ; }
478+ if * typ == 5482373484 { return Err ( ( ) ) ; } // keysend
479+ match prev_type {
480+ Some ( prev) if prev >= * typ => return Err ( ( ) ) ,
481+ _ => { } ,
482+ }
483+ prev_type = Some ( * typ) ;
484+ }
485+ self . custom_tlvs = custom_tlvs;
486+ Ok ( self )
487+ }
488+
489+ /// Gets the custom TLVs that will be sent or have been received.
490+ ///
491+ /// Custom TLVs allow sending extra application-specific data with a payment. They provide
492+ /// additional flexibility on top of payment metadata, as while other implementations may
493+ /// require `payment_metadata` to reflect metadata provided in an invoice, custom TLVs
494+ /// do not have this restriction.
495+ ///
496+ /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each
497+ /// represented by a `(u64, Vec<u8>)` for its type number and serialized value respectively.
498+ /// This is validated when setting this field using [`Self::with_custom_tlvs`].
499+ pub fn custom_tlvs ( & self ) -> & Vec < ( u64 , Vec < u8 > ) > {
500+ & self . custom_tlvs
459501 }
460502
461503 /// When we have received some HTLC(s) towards an MPP payment, as we receive further HTLC(s) we
@@ -773,6 +815,7 @@ impl OutboundPayments {
773815 ( * total_msat, RecipientOnionFields {
774816 payment_secret : * payment_secret,
775817 payment_metadata : payment_metadata. clone ( ) ,
818+ custom_tlvs : Vec :: new ( ) ,
776819 } , * keysend_preimage)
777820 } ,
778821 PendingOutboundPayment :: Legacy { .. } => {
@@ -1450,6 +1493,28 @@ mod tests {
14501493
14511494 use alloc:: collections:: VecDeque ;
14521495
1496+ #[ test]
1497+ fn test_recipient_onion_fields_with_custom_tlvs ( ) {
1498+ let onion_fields = RecipientOnionFields :: spontaneous_empty ( ) ;
1499+
1500+ let bad_type_range_tlvs = vec ! [
1501+ ( 0 , vec![ 42 ] ) ,
1502+ ( 1 , vec![ 42 ; 32 ] ) ,
1503+ ] ;
1504+ assert ! ( onion_fields. clone( ) . with_custom_tlvs( bad_type_range_tlvs) . is_err( ) ) ;
1505+
1506+ let keysend_tlv = vec ! [
1507+ ( 5482373484 , vec![ 42 ; 32 ] ) ,
1508+ ] ;
1509+ assert ! ( onion_fields. clone( ) . with_custom_tlvs( keysend_tlv) . is_err( ) ) ;
1510+
1511+ let good_tlvs = vec ! [
1512+ ( ( 1 << 16 ) + 1 , vec![ 42 ] ) ,
1513+ ( ( 1 << 16 ) + 3 , vec![ 42 ; 32 ] ) ,
1514+ ] ;
1515+ assert ! ( onion_fields. with_custom_tlvs( good_tlvs) . is_ok( ) ) ;
1516+ }
1517+
14531518 #[ test]
14541519 #[ cfg( feature = "std" ) ]
14551520 fn fails_paying_after_expiration ( ) {
0 commit comments