@@ -12,6 +12,8 @@ use crate::ln::channelmanager::CounterpartyForwardingInfo;
1212use crate :: ln:: features:: BlindedHopFeatures ;
1313use crate :: ln:: msgs:: DecodeError ;
1414use crate :: offers:: invoice:: BlindedPayInfo ;
15+ use crate :: offers:: invoice_request:: InvoiceRequestFields ;
16+ use crate :: offers:: offer:: OfferId ;
1517use crate :: util:: ser:: { HighZeroBytesDroppedBigSize , Readable , Writeable , Writer } ;
1618
1719#[ allow( unused_imports) ]
@@ -53,6 +55,8 @@ pub struct ReceiveTlvs {
5355 pub payment_secret : PaymentSecret ,
5456 /// Constraints for the receiver of this payment.
5557 pub payment_constraints : PaymentConstraints ,
58+ /// Context for the receiver of this payment.
59+ pub payment_context : PaymentContext ,
5660}
5761
5862/// Data to construct a [`BlindedHop`] for sending a payment over.
@@ -97,6 +101,66 @@ pub struct PaymentConstraints {
97101 pub htlc_minimum_msat : u64 ,
98102}
99103
104+ /// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`]
105+ /// and surfaced in [`PaymentPurpose`].
106+ ///
107+ /// [`BlindedPath`]: crate::blinded_path::BlindedPath
108+ /// [`PaymentPurpose`]: crate::events::PaymentPurpose
109+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
110+ pub enum PaymentContext {
111+ /// The payment context was unknown.
112+ Unknown ( UnknownPaymentContext ) ,
113+
114+ /// The payment was made for an invoice requested from a BOLT 12 [`Offer`].
115+ ///
116+ /// [`Offer`]: crate::offers::offer::Offer
117+ Bolt12Offer ( Bolt12OfferContext ) ,
118+
119+ /// The payment was made for an invoice sent for a BOLT 12 [`Refund`].
120+ ///
121+ /// [`Refund`]: crate::offers::refund::Refund
122+ Bolt12Refund ( Bolt12RefundContext ) ,
123+ }
124+
125+ // Used when writing PaymentContext in Event::PaymentClaimable to avoid cloning.
126+ pub ( crate ) enum PaymentContextRef < ' a > {
127+ Bolt12Offer ( & ' a Bolt12OfferContext ) ,
128+ Bolt12Refund ( & ' a Bolt12RefundContext ) ,
129+ }
130+
131+ /// An unknown payment context.
132+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
133+ pub struct UnknownPaymentContext ( ( ) ) ;
134+
135+ /// The context of a payment made for an invoice requested from a BOLT 12 [`Offer`].
136+ ///
137+ /// [`Offer`]: crate::offers::offer::Offer
138+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
139+ pub struct Bolt12OfferContext {
140+ /// The identifier of the [`Offer`].
141+ ///
142+ /// [`Offer`]: crate::offers::offer::Offer
143+ pub offer_id : OfferId ,
144+
145+ /// Fields from an [`InvoiceRequest`] sent for a [`Bolt12Invoice`].
146+ ///
147+ /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
148+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
149+ pub invoice_request : InvoiceRequestFields ,
150+ }
151+
152+ /// The context of a payment made for an invoice sent for a BOLT 12 [`Refund`].
153+ ///
154+ /// [`Refund`]: crate::offers::refund::Refund
155+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
156+ pub struct Bolt12RefundContext { }
157+
158+ impl PaymentContext {
159+ pub ( crate ) fn unknown ( ) -> Self {
160+ PaymentContext :: Unknown ( UnknownPaymentContext ( ( ) ) )
161+ }
162+ }
163+
100164impl TryFrom < CounterpartyForwardingInfo > for PaymentRelay {
101165 type Error = ( ) ;
102166
@@ -137,7 +201,8 @@ impl Writeable for ReceiveTlvs {
137201 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
138202 encode_tlv_stream ! ( w, {
139203 ( 12 , self . payment_constraints, required) ,
140- ( 65536 , self . payment_secret, required)
204+ ( 65536 , self . payment_secret, required) ,
205+ ( 65537 , self . payment_context, required)
141206 } ) ;
142207 Ok ( ( ) )
143208 }
@@ -163,11 +228,14 @@ impl Readable for BlindedPaymentTlvs {
163228 ( 12 , payment_constraints, required) ,
164229 ( 14 , features, option) ,
165230 ( 65536 , payment_secret, option) ,
231+ ( 65537 , payment_context, ( default_value, PaymentContext :: unknown( ) ) ) ,
166232 } ) ;
167233 let _padding: Option < utils:: Padding > = _padding;
168234
169235 if let Some ( short_channel_id) = scid {
170- if payment_secret. is_some ( ) { return Err ( DecodeError :: InvalidValue ) }
236+ if payment_secret. is_some ( ) {
237+ return Err ( DecodeError :: InvalidValue )
238+ }
171239 Ok ( BlindedPaymentTlvs :: Forward ( ForwardTlvs {
172240 short_channel_id,
173241 payment_relay : payment_relay. ok_or ( DecodeError :: InvalidValue ) ?,
@@ -179,6 +247,7 @@ impl Readable for BlindedPaymentTlvs {
179247 Ok ( BlindedPaymentTlvs :: Receive ( ReceiveTlvs {
180248 payment_secret : payment_secret. ok_or ( DecodeError :: InvalidValue ) ?,
181249 payment_constraints : payment_constraints. 0 . unwrap ( ) ,
250+ payment_context : payment_context. 0 . unwrap ( ) ,
182251 } ) )
183252 }
184253 }
@@ -309,10 +378,53 @@ impl Readable for PaymentConstraints {
309378 }
310379}
311380
381+ impl_writeable_tlv_based_enum ! ( PaymentContext ,
382+ ;
383+ ( 0 , Unknown ) ,
384+ ( 1 , Bolt12Offer ) ,
385+ ( 2 , Bolt12Refund ) ,
386+ ) ;
387+
388+ impl < ' a > Writeable for PaymentContextRef < ' a > {
389+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
390+ match self {
391+ PaymentContextRef :: Bolt12Offer ( context) => {
392+ 1u8 . write ( w) ?;
393+ context. write ( w) ?;
394+ } ,
395+ PaymentContextRef :: Bolt12Refund ( context) => {
396+ 2u8 . write ( w) ?;
397+ context. write ( w) ?;
398+ } ,
399+ }
400+
401+ Ok ( ( ) )
402+ }
403+ }
404+
405+ impl Writeable for UnknownPaymentContext {
406+ fn write < W : Writer > ( & self , _w : & mut W ) -> Result < ( ) , io:: Error > {
407+ Ok ( ( ) )
408+ }
409+ }
410+
411+ impl Readable for UnknownPaymentContext {
412+ fn read < R : io:: Read > ( _r : & mut R ) -> Result < Self , DecodeError > {
413+ Ok ( UnknownPaymentContext ( ( ) ) )
414+ }
415+ }
416+
417+ impl_writeable_tlv_based ! ( Bolt12OfferContext , {
418+ ( 0 , offer_id, required) ,
419+ ( 2 , invoice_request, required) ,
420+ } ) ;
421+
422+ impl_writeable_tlv_based ! ( Bolt12RefundContext , { } ) ;
423+
312424#[ cfg( test) ]
313425mod tests {
314426 use bitcoin:: secp256k1:: PublicKey ;
315- use crate :: blinded_path:: payment:: { ForwardNode , ForwardTlvs , ReceiveTlvs , PaymentConstraints , PaymentRelay } ;
427+ use crate :: blinded_path:: payment:: { ForwardNode , ForwardTlvs , ReceiveTlvs , PaymentConstraints , PaymentContext , PaymentRelay } ;
316428 use crate :: ln:: PaymentSecret ;
317429 use crate :: ln:: features:: BlindedHopFeatures ;
318430 use crate :: ln:: functional_test_utils:: TEST_FINAL_CLTV ;
@@ -361,6 +473,7 @@ mod tests {
361473 max_cltv_expiry : 0 ,
362474 htlc_minimum_msat : 1 ,
363475 } ,
476+ payment_context : PaymentContext :: unknown ( ) ,
364477 } ;
365478 let htlc_maximum_msat = 100_000 ;
366479 let blinded_payinfo = super :: compute_payinfo ( & intermediate_nodes[ ..] , & recv_tlvs, htlc_maximum_msat, 12 ) . unwrap ( ) ;
@@ -379,6 +492,7 @@ mod tests {
379492 max_cltv_expiry : 0 ,
380493 htlc_minimum_msat : 1 ,
381494 } ,
495+ payment_context : PaymentContext :: unknown ( ) ,
382496 } ;
383497 let blinded_payinfo = super :: compute_payinfo ( & [ ] , & recv_tlvs, 4242 , TEST_FINAL_CLTV as u16 ) . unwrap ( ) ;
384498 assert_eq ! ( blinded_payinfo. fee_base_msat, 0 ) ;
@@ -432,6 +546,7 @@ mod tests {
432546 max_cltv_expiry : 0 ,
433547 htlc_minimum_msat : 3 ,
434548 } ,
549+ payment_context : PaymentContext :: unknown ( ) ,
435550 } ;
436551 let htlc_maximum_msat = 100_000 ;
437552 let blinded_payinfo = super :: compute_payinfo ( & intermediate_nodes[ ..] , & recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16 ) . unwrap ( ) ;
@@ -482,6 +597,7 @@ mod tests {
482597 max_cltv_expiry : 0 ,
483598 htlc_minimum_msat : 1 ,
484599 } ,
600+ payment_context : PaymentContext :: unknown ( ) ,
485601 } ;
486602 let htlc_minimum_msat = 3798 ;
487603 assert ! ( super :: compute_payinfo( & intermediate_nodes[ ..] , & recv_tlvs, htlc_minimum_msat - 1 , TEST_FINAL_CLTV as u16 ) . is_err( ) ) ;
@@ -536,6 +652,7 @@ mod tests {
536652 max_cltv_expiry : 0 ,
537653 htlc_minimum_msat : 1 ,
538654 } ,
655+ payment_context : PaymentContext :: unknown ( ) ,
539656 } ;
540657
541658 let blinded_payinfo = super :: compute_payinfo ( & intermediate_nodes[ ..] , & recv_tlvs, 10_000 , TEST_FINAL_CLTV as u16 ) . unwrap ( ) ;
0 commit comments