70
70
crate :: onion_message:: dns_resolution:: { DNSResolverMessage , DNSSECQuery , OMNameResolver } ,
71
71
} ;
72
72
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 FlowEvents {
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
+
73
99
/// A BOLT12 offers code and flow utility provider, which facilitates
74
100
/// BOLT12 builder generation and onion message handling.
75
101
///
91
117
secp_ctx : Secp256k1 < secp256k1:: All > ,
92
118
message_router : MR ,
93
119
120
+ pub ( crate ) enable_events : bool ,
121
+
94
122
#[ cfg( not( any( test, feature = "_test_utils" ) ) ) ]
95
123
pending_offers_messages : Mutex < Vec < ( OffersMessage , MessageSendInstructions ) > > ,
96
124
#[ cfg( any( test, feature = "_test_utils" ) ) ]
@@ -103,6 +131,8 @@ where
103
131
pub ( crate ) hrn_resolver : OMNameResolver ,
104
132
#[ cfg( feature = "dnssec" ) ]
105
133
pending_dns_onion_messages : Mutex < Vec < ( DNSResolverMessage , MessageSendInstructions ) > > ,
134
+
135
+ pending_flow_events : Mutex < Vec < FlowEvents > > ,
106
136
}
107
137
108
138
impl < MR : Deref > OffersMessageFlow < MR >
@@ -114,6 +144,7 @@ where
114
144
chain_hash : ChainHash , best_block : BestBlock , our_network_pubkey : PublicKey ,
115
145
current_timestamp : u32 , inbound_payment_key : inbound_payment:: ExpandedKey ,
116
146
receive_auth_key : ReceiveAuthKey , secp_ctx : Secp256k1 < secp256k1:: All > , message_router : MR ,
147
+ enable_events : bool ,
117
148
) -> Self {
118
149
Self {
119
150
chain_hash,
@@ -128,6 +159,8 @@ where
128
159
secp_ctx,
129
160
message_router,
130
161
162
+ enable_events,
163
+
131
164
pending_offers_messages : Mutex :: new ( Vec :: new ( ) ) ,
132
165
pending_async_payments_messages : Mutex :: new ( Vec :: new ( ) ) ,
133
166
@@ -137,6 +170,8 @@ where
137
170
pending_dns_onion_messages : Mutex :: new ( Vec :: new ( ) ) ,
138
171
139
172
async_receive_offer_cache : Mutex :: new ( AsyncReceiveOfferCache :: new ( ) ) ,
173
+
174
+ pending_flow_events : Mutex :: new ( Vec :: new ( ) ) ,
140
175
}
141
176
}
142
177
@@ -152,6 +187,18 @@ where
152
187
self
153
188
}
154
189
190
+ /// Enables [`FlowEvents`] 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 [`FlowEvents`]
194
+ /// such as [`FlowEvents::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
+
155
202
/// Sets the [`BlindedMessagePath`]s that we will use as an async recipient to interactively build
156
203
/// [`Offer`]s with a static invoice server, so the server can serve [`StaticInvoice`]s to payers
157
204
/// on our behalf when we're offline.
@@ -407,13 +454,16 @@ pub enum InvreqResponseInstructions {
407
454
/// An identifier for the specific invoice being requested by the payer.
408
455
invoice_id : u128 ,
409
456
} ,
457
+ /// We are recipient of this payment, and should handle the response asynchronously.
458
+ AsynchronouslyHandleResponse ,
410
459
}
411
460
412
461
impl < MR : Deref > OffersMessageFlow < MR >
413
462
where
414
463
MR :: Target : MessageRouter ,
415
464
{
416
465
/// 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.
417
467
///
418
468
/// - If an [`OffersContext::InvoiceRequest`] with a `nonce` is provided, verification is performed using recipient context data.
419
469
/// - If no context is provided but the [`InvoiceRequest`] contains [`Offer`] metadata, verification is performed using that metadata.
@@ -426,27 +476,26 @@ where
426
476
/// - The verification process (via recipient context data or metadata) fails.
427
477
pub fn verify_invoice_request (
428
478
& self , invoice_request : InvoiceRequest , context : Option < OffersContext > ,
479
+ responder : Responder ,
429
480
) -> Result < InvreqResponseInstructions , ( ) > {
430
481
let secp_ctx = & self . secp_ctx ;
431
482
let expanded_key = & self . inbound_payment_key ;
432
483
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
+
433
496
let nonce = match context {
434
- None if invoice_request. metadata ( ) . is_some ( ) => None ,
435
497
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 ,
450
499
_ => return Err ( ( ) ) ,
451
500
} ;
452
501
@@ -457,7 +506,16 @@ where
457
506
None => invoice_request. verify_using_metadata ( expanded_key, secp_ctx) ,
458
507
} ?;
459
508
460
- Ok ( InvreqResponseInstructions :: SendInvoice ( invoice_request) )
509
+ if self . enable_events {
510
+ self . pending_flow_events . lock ( ) . unwrap ( ) . push ( FlowEvents :: 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
+ }
461
519
}
462
520
463
521
/// Verifies a [`Bolt12Invoice`] using the provided [`OffersContext`] or the invoice's payer metadata,
@@ -1288,6 +1346,11 @@ where
1288
1346
Ok ( ( ) )
1289
1347
}
1290
1348
1349
+ /// Enqueues the generated [`FlowEvents`] to be processed.
1350
+ pub fn enqueue_flow_event ( & self , flow_event : FlowEvents ) {
1351
+ self . pending_flow_events . lock ( ) . unwrap ( ) . push ( flow_event) ;
1352
+ }
1353
+
1291
1354
/// Gets the enqueued [`OffersMessage`] with their corresponding [`MessageSendInstructions`].
1292
1355
pub fn release_pending_offers_messages ( & self ) -> Vec < ( OffersMessage , MessageSendInstructions ) > {
1293
1356
core:: mem:: take ( & mut self . pending_offers_messages . lock ( ) . unwrap ( ) )
@@ -1300,6 +1363,11 @@ where
1300
1363
core:: mem:: take ( & mut self . pending_async_payments_messages . lock ( ) . unwrap ( ) )
1301
1364
}
1302
1365
1366
+ /// Gets the enqueued [`FlowEvents`] to be processed.
1367
+ pub fn release_pending_flow_events ( & self ) -> Vec < FlowEvents > {
1368
+ core:: mem:: take ( & mut self . pending_flow_events . lock ( ) . unwrap ( ) )
1369
+ }
1370
+
1303
1371
/// Gets the enqueued [`DNSResolverMessage`] with their corresponding [`MessageSendInstructions`].
1304
1372
#[ cfg( feature = "dnssec" ) ]
1305
1373
pub fn release_pending_dns_messages (
0 commit comments