7070 crate :: onion_message:: dns_resolution:: { DNSResolverMessage , DNSSECQuery , OMNameResolver } ,
7171} ;
7272
73+ /// Defines the events that can be optionally triggered when processing offers messages.
74+ ///
75+ /// Once generated, these events are stored in the [`OffersMessageFlow`], where they can be
76+ /// manually inspected and responded to.
77+ pub enum OfferMessageFlowEvent {
78+ /// Notifies that an [`InvoiceRequest`] has been received.
79+ ///
80+ /// To respond to this message:
81+ /// - Based on the variant of [`InvoiceRequestVerifiedFromOffer`], create the appropriate invoice builder:
82+ /// - [`InvoiceRequestVerifiedFromOffer::DerivedKeys`] → use
83+ /// [`OffersMessageFlow::create_invoice_builder_from_invoice_request_with_keys`]
84+ /// - [`InvoiceRequestVerifiedFromOffer::ExplicitKeys`] → use
85+ /// [`OffersMessageFlow::create_invoice_builder_from_invoice_request_without_keys`]
86+ /// - After building the invoice, sign it and send it back using the provided reply path via
87+ /// [`OffersMessageFlow::enqueue_invoice_using_reply_paths`].
88+ ///
89+ /// If the invoice request is invalid, respond with an [`InvoiceError`] using
90+ /// [`OffersMessageFlow::enqueue_invoice_error`].
91+ InvoiceRequestReceived {
92+ /// The received, verified invoice request.
93+ invoice_request : InvoiceRequestVerifiedFromOffer ,
94+ /// The reply path to use when responding to the invoice request.
95+ reply_path : BlindedMessagePath ,
96+ } ,
97+ }
98+
7399/// A BOLT12 offers code and flow utility provider, which facilitates
74100/// BOLT12 builder generation and onion message handling.
75101///
91117 secp_ctx : Secp256k1 < secp256k1:: All > ,
92118 message_router : MR ,
93119
120+ pub ( crate ) enable_events : bool ,
121+
94122 #[ cfg( not( any( test, feature = "_test_utils" ) ) ) ]
95123 pending_offers_messages : Mutex < Vec < ( OffersMessage , MessageSendInstructions ) > > ,
96124 #[ cfg( any( test, feature = "_test_utils" ) ) ]
@@ -103,6 +131,8 @@ where
103131 pub ( crate ) hrn_resolver : OMNameResolver ,
104132 #[ cfg( feature = "dnssec" ) ]
105133 pending_dns_onion_messages : Mutex < Vec < ( DNSResolverMessage , MessageSendInstructions ) > > ,
134+
135+ pending_flow_events : Mutex < Vec < OfferMessageFlowEvent > > ,
106136}
107137
108138impl < MR : Deref > OffersMessageFlow < MR >
@@ -114,6 +144,7 @@ where
114144 chain_hash : ChainHash , best_block : BestBlock , our_network_pubkey : PublicKey ,
115145 current_timestamp : u32 , inbound_payment_key : inbound_payment:: ExpandedKey ,
116146 receive_auth_key : ReceiveAuthKey , secp_ctx : Secp256k1 < secp256k1:: All > , message_router : MR ,
147+ enable_events : bool ,
117148 ) -> Self {
118149 Self {
119150 chain_hash,
@@ -128,6 +159,8 @@ where
128159 secp_ctx,
129160 message_router,
130161
162+ enable_events,
163+
131164 pending_offers_messages : Mutex :: new ( Vec :: new ( ) ) ,
132165 pending_async_payments_messages : Mutex :: new ( Vec :: new ( ) ) ,
133166
@@ -137,6 +170,8 @@ where
137170 pending_dns_onion_messages : Mutex :: new ( Vec :: new ( ) ) ,
138171
139172 async_receive_offer_cache : Mutex :: new ( AsyncReceiveOfferCache :: new ( ) ) ,
173+
174+ pending_flow_events : Mutex :: new ( Vec :: new ( ) ) ,
140175 }
141176 }
142177
@@ -152,6 +187,18 @@ where
152187 self
153188 }
154189
190+ /// Enables [`OfferMessageFlowEvent`] for this flow.
191+ ///
192+ /// By default, events are not emitted when processing offers messages. Calling this method
193+ /// sets the internal `enable_events` flag to `true`, allowing you to receive [`OfferMessageFlowEvent`]
194+ /// such as [`OfferMessageFlowEvent::InvoiceRequestReceived`].
195+ ///
196+ /// This is useful when you want to manually inspect, handle, or respond to incoming
197+ /// offers messages rather than having them processed automatically.
198+ pub fn enable_events ( & mut self ) {
199+ self . enable_events = true ;
200+ }
201+
155202 /// Sets the [`BlindedMessagePath`]s that we will use as an async recipient to interactively build
156203 /// [`Offer`]s with a static invoice server, so the server can serve [`StaticInvoice`]s to payers
157204 /// on our behalf when we're offline.
@@ -407,13 +454,16 @@ pub enum InvreqResponseInstructions {
407454 /// An identifier for the specific invoice being requested by the payer.
408455 invoice_id : u128 ,
409456 } ,
457+ /// We are recipient of this payment, and should handle the response asynchronously.
458+ AsynchronouslyHandleResponse ,
410459}
411460
412461impl < MR : Deref > OffersMessageFlow < MR >
413462where
414463 MR :: Target : MessageRouter ,
415464{
416465 /// Verifies an [`InvoiceRequest`] using the provided [`OffersContext`] or the [`InvoiceRequest::metadata`].
466+ /// It also helps determine the response instructions, corresponding to the verified invoice request must be taken.
417467 ///
418468 /// - If an [`OffersContext::InvoiceRequest`] with a `nonce` is provided, verification is performed using recipient context data.
419469 /// - If no context is provided but the [`InvoiceRequest`] contains [`Offer`] metadata, verification is performed using that metadata.
@@ -426,27 +476,26 @@ where
426476 /// - The verification process (via recipient context data or metadata) fails.
427477 pub fn verify_invoice_request (
428478 & self , invoice_request : InvoiceRequest , context : Option < OffersContext > ,
479+ responder : Responder ,
429480 ) -> Result < InvreqResponseInstructions , ( ) > {
430481 let secp_ctx = & self . secp_ctx ;
431482 let expanded_key = & self . inbound_payment_key ;
432483
484+ if let Some ( OffersContext :: StaticInvoiceRequested {
485+ recipient_id,
486+ invoice_id,
487+ path_absolute_expiry,
488+ } ) = context
489+ {
490+ if path_absolute_expiry < self . duration_since_epoch ( ) {
491+ return Err ( ( ) ) ;
492+ }
493+ return Ok ( InvreqResponseInstructions :: SendStaticInvoice { recipient_id, invoice_id } ) ;
494+ }
495+
433496 let nonce = match context {
434- None if invoice_request. metadata ( ) . is_some ( ) => None ,
435497 Some ( OffersContext :: InvoiceRequest { nonce } ) => Some ( nonce) ,
436- Some ( OffersContext :: StaticInvoiceRequested {
437- recipient_id,
438- invoice_id,
439- path_absolute_expiry,
440- } ) => {
441- if path_absolute_expiry < self . duration_since_epoch ( ) {
442- return Err ( ( ) ) ;
443- }
444-
445- return Ok ( InvreqResponseInstructions :: SendStaticInvoice {
446- recipient_id,
447- invoice_id,
448- } ) ;
449- } ,
498+ None if invoice_request. metadata ( ) . is_some ( ) => None ,
450499 _ => return Err ( ( ) ) ,
451500 } ;
452501
@@ -457,7 +506,16 @@ where
457506 None => invoice_request. verify_using_metadata ( expanded_key, secp_ctx) ,
458507 } ?;
459508
460- Ok ( InvreqResponseInstructions :: SendInvoice ( invoice_request) )
509+ if self . enable_events {
510+ self . pending_flow_events . lock ( ) . unwrap ( ) . push ( OfferMessageFlowEvent :: InvoiceRequestReceived {
511+ invoice_request,
512+ reply_path : responder. into_blinded_path ( ) ,
513+ } ) ;
514+
515+ Ok ( InvreqResponseInstructions :: AsynchronouslyHandleResponse )
516+ } else {
517+ Ok ( InvreqResponseInstructions :: SendInvoice ( invoice_request) )
518+ }
461519 }
462520
463521 /// Verifies a [`Bolt12Invoice`] using the provided [`OffersContext`] or the invoice's payer metadata,
@@ -1288,6 +1346,11 @@ where
12881346 Ok ( ( ) )
12891347 }
12901348
1349+ /// Enqueues the generated [`OfferMessageFlowEvent`] to be processed.
1350+ pub fn enqueue_flow_event ( & self , flow_event : OfferMessageFlowEvent ) {
1351+ self . pending_flow_events . lock ( ) . unwrap ( ) . push ( flow_event) ;
1352+ }
1353+
12911354 /// Gets the enqueued [`OffersMessage`] with their corresponding [`MessageSendInstructions`].
12921355 pub fn release_pending_offers_messages ( & self ) -> Vec < ( OffersMessage , MessageSendInstructions ) > {
12931356 core:: mem:: take ( & mut self . pending_offers_messages . lock ( ) . unwrap ( ) )
@@ -1300,6 +1363,11 @@ where
13001363 core:: mem:: take ( & mut self . pending_async_payments_messages . lock ( ) . unwrap ( ) )
13011364 }
13021365
1366+ /// Gets the enqueued [`OfferMessageFlowEvent`] to be processed.
1367+ pub fn release_pending_flow_events ( & self ) -> Vec < OfferMessageFlowEvent > {
1368+ core:: mem:: take ( & mut self . pending_flow_events . lock ( ) . unwrap ( ) )
1369+ }
1370+
13031371 /// Gets the enqueued [`DNSResolverMessage`] with their corresponding [`MessageSendInstructions`].
13041372 #[ cfg( feature = "dnssec" ) ]
13051373 pub fn release_pending_dns_messages (
0 commit comments