@@ -37,11 +37,11 @@ use crate::ln::channelmanager::{
37
37
} ;
38
38
use crate :: ln:: inbound_payment;
39
39
use crate :: offers:: invoice:: {
40
- Bolt12Invoice , DerivedSigningPubkey , InvoiceBuilder , InvoiceBuilderVariant ,
41
- DEFAULT_RELATIVE_EXPIRY ,
40
+ Bolt12Invoice , Bolt12InvoiceAmountSource , DerivedSigningPubkey , InvoiceBuilder ,
41
+ InvoiceBuilderVariant , DEFAULT_RELATIVE_EXPIRY ,
42
42
} ;
43
43
use crate :: offers:: invoice_request:: {
44
- InvoiceRequest , InvoiceRequestBuilder , VerifiedInvoiceRequest ,
44
+ InvoiceRequest , InvoiceRequestAmountSource , InvoiceRequestBuilder , VerifiedInvoiceRequest ,
45
45
} ;
46
46
use crate :: offers:: nonce:: Nonce ;
47
47
use crate :: offers:: offer:: { DerivedMetadata , Offer , OfferBuilder } ;
@@ -72,6 +72,115 @@ use {
72
72
crate :: onion_message:: dns_resolution:: { DNSResolverMessage , DNSSECQuery , OMNameResolver } ,
73
73
} ;
74
74
75
+ /// Contains OfferEvents that can optionally triggered for manual
76
+ /// handling by user based on appropriate user_config.
77
+ pub enum OfferEvents {
78
+ /// Notifies that a verified [`InvoiceRequest`] has been received.
79
+ ///
80
+ /// This event is triggered when a BOLT12 [`InvoiceRequest`] is received.
81
+ /// The `amount_source` field describes how the amount is specified — in the offer,
82
+ /// the invoice request, or both.
83
+ ///
84
+ /// To respond, use [`OffersMessageFlow::create_invoice_builder_from_invoice_request`], providing an
85
+ /// amount based on the structure described in [`InvoiceRequestAmountSource`].
86
+ ///
87
+ /// See the [BOLT12 spec](https://github.com/lightning/bolts/blob/master/12-offer-encoding.md#requirements-1)
88
+ /// for protocol-level details.
89
+ InvoiceRequestReceived {
90
+ /// The verified [`InvoiceRequest`] that was received.
91
+ invoice_request : VerifiedInvoiceRequest ,
92
+
93
+ /// Indicates how the amount is specified across the [`InvoiceRequest`] and the associated [`Offer`] (if any).
94
+ ///
95
+ /// Use this to determine what amount to pass when calling [`OffersMessageFlow::create_invoice_builder_from_invoice_request`].
96
+ ///
97
+ /// ### [`InvoiceRequestAmountSource::InvoiceRequestAndOfferAmount`]
98
+ /// Both the [`InvoiceRequest`] and the [`Offer`] specify amounts.
99
+ ///
100
+ /// - If the offer uses [`Amount::Currency`], ensure that the request amount reasonably compensates
101
+ /// based on conversion rates.
102
+ ///
103
+ /// - If the offer uses [`Amount::Bitcoin`], this implementation ensures the request amount is
104
+ /// **greater than or equal to** the offer amount before constructing this variant.
105
+ ///
106
+ /// In either case, use the exact request amount when calling [`OffersMessageFlow::create_invoice_builder_from_invoice_request`].
107
+ ///
108
+ /// ### [`InvoiceRequestAmountSource::InvoiceRequestOnly`]
109
+ /// The [`InvoiceRequest`] specifies an amount, and the associated [`Offer`] does not.
110
+ ///
111
+ /// - You must pass the exact request amount to [`OffersMessageFlow::create_invoice_builder_from_invoice_request`] when responding.
112
+ ///
113
+ /// ### [`InvoiceRequestAmountSource::OfferOnly`]
114
+ /// The [`InvoiceRequest`] does not specify an amount. The amount is taken solely from the associated [`Offer`].
115
+ ///
116
+ /// - If the amount is in [`Amount::Currency`], user must convert it manually into a Bitcoin-denominated amount
117
+ /// and then pass it to [`OffersMessageFlow::create_invoice_builder_from_invoice_request`].
118
+ ///
119
+ /// - If the amount is in [`Amount::Bitcoin`], user must provide an amount that is **greater than or equal to**
120
+ /// the offer amount when calling the builder function.
121
+ ///
122
+ /// [`Amount::Currency`]: crate::offers::offer::Amount::Currency
123
+ /// [`Amount::Bitcoin`]: crate::offers::offer::Amount::Bitcoin
124
+ amount_source : InvoiceRequestAmountSource ,
125
+ } ,
126
+
127
+ /// Notified that an [`Bolt12Invoice`] was received
128
+ /// This event is triggered when a BOLT12 [`Bolt12Invoice`] is received.
129
+ ///
130
+ /// User must use their custom logic to pay the invoice, using the exact amount specified in the invoice.
131
+ Bolt12InvoiceReceived {
132
+ /// The verified [`Bolt12Invoice`] that was received.
133
+ invoice : Bolt12Invoice ,
134
+
135
+ /// The [`PaymentId`] associated with the invoice.
136
+ payment_id : PaymentId ,
137
+
138
+ /// Indicates how the amount is specified in the invoice.
139
+ invoice_amount : u64 ,
140
+
141
+ /// Indicates the source of the amount: whether from Offer, Refund, or InvoiceRequest.
142
+ /// Useful to examine the invoice's amount before deciding to pay it.
143
+ ///
144
+ /// ## [`Bolt12InvoiceAmountSource::Offer`]
145
+ ///
146
+ /// If the invoice correponds to an Offer flow, it could be based on following cases:
147
+ ///
148
+ /// ### [`InvoiceRequestAmountSource::InvoiceRequestAndOfferAmount`]:
149
+ ///
150
+ /// - If the offer uses [`Amount::Currency`], ensure that the request amount reasonably compensates
151
+ /// based on conversion rates.
152
+ ///
153
+ /// - If the offer uses [`Amount::Bitcoin`], this implementation ensures the request amount is
154
+ /// **greater than or equal to** the offer amount before constructing this variant.
155
+ ///
156
+ /// In both cases, the implementation ensures that the invoice amount is exactly equal to the request amount.
157
+ ///
158
+ /// ### [`InvoiceRequestAmountSource::InvoiceRequestOnly`]:
159
+ ///
160
+ /// If only the [`InvoiceRequest`] amount is specified, implementation ensures that the invoice amount is exactly
161
+ /// equal to the request amount abiding by the spec.
162
+ ///
163
+ /// ### [`InvoiceRequestAmountSource::OfferOnly`]:
164
+ ///
165
+ /// - If the offer amount is in [`Amount::Currency`], the user must ensures that the invoice amount sufficiently
166
+ /// compensates for the offer amount post conversion.
167
+ /// - If the offer amount is in [`Amount::Bitcoin`], the implementation ensures that the invoice amount is exactly
168
+ /// equal to the offer amount.
169
+ ///
170
+ /// For more details, see the [BOLT12 spec](https://github.com/lightning/bolts/blob/master/12-offer-encoding.md#requirements-1)
171
+ ///
172
+ /// ## [`Bolt12InvoiceAmountSource::Refund`]
173
+ ///
174
+ /// The invoice corresponds to a [`Refund`] flow, with the amount specified in the [`Refund`].
175
+ ///
176
+ /// The amount is specified in the [`Refund`] and must be equal to the invoice amount, which the implementation ensures.
177
+ ///
178
+ /// [`Amount::Currency`]: crate::offers::offer::Amount::Currency
179
+ /// [`Amount::Bitcoin`]: crate::offers::offer::Amount::Bitcoin
180
+ amount_source : Bolt12InvoiceAmountSource ,
181
+ } ,
182
+ }
183
+
75
184
/// A BOLT12 offers code and flow utility provider, which facilitates
76
185
/// BOLT12 builder generation and onion message handling.
77
186
///
96
205
#[ cfg( any( test, feature = "_test_utils" ) ) ]
97
206
pub ( crate ) pending_offers_messages : Mutex < Vec < ( OffersMessage , MessageSendInstructions ) > > ,
98
207
208
+ pending_offers_events : Mutex < Vec < OfferEvents > > ,
209
+
99
210
pending_async_payments_messages : Mutex < Vec < ( AsyncPaymentsMessage , MessageSendInstructions ) > > ,
100
211
101
212
#[ cfg( feature = "dnssec" ) ]
@@ -126,6 +237,7 @@ where
126
237
message_router,
127
238
128
239
pending_offers_messages : Mutex :: new ( Vec :: new ( ) ) ,
240
+ pending_offers_events : Mutex :: new ( Vec :: new ( ) ) ,
129
241
pending_async_payments_messages : Mutex :: new ( Vec :: new ( ) ) ,
130
242
131
243
#[ cfg( feature = "dnssec" ) ]
@@ -1048,6 +1160,13 @@ where
1048
1160
Ok ( ( ) )
1049
1161
}
1050
1162
1163
+ /// Enqueues an [`OfferEvents`] event to be processed manually by the user.
1164
+ pub fn enqueue_offers_event ( & self , event : OfferEvents ) -> Result < ( ) , ( ) > {
1165
+ let mut pending_offers_events = self . pending_offers_events . lock ( ) . unwrap ( ) ;
1166
+ pending_offers_events. push ( event) ;
1167
+ Ok ( ( ) )
1168
+ }
1169
+
1051
1170
/// Gets the enqueued [`OffersMessage`] with their corresponding [`MessageSendInstructions`].
1052
1171
pub fn release_pending_offers_messages ( & self ) -> Vec < ( OffersMessage , MessageSendInstructions ) > {
1053
1172
core:: mem:: take ( & mut self . pending_offers_messages . lock ( ) . unwrap ( ) )
@@ -1067,4 +1186,9 @@ where
1067
1186
) -> Vec < ( DNSResolverMessage , MessageSendInstructions ) > {
1068
1187
core:: mem:: take ( & mut self . pending_dns_onion_messages . lock ( ) . unwrap ( ) )
1069
1188
}
1189
+
1190
+ /// Gets the enqueued [`OfferEvents`] events.
1191
+ pub fn get_and_clear_pending_offers_events ( & self ) -> Vec < OfferEvents > {
1192
+ core:: mem:: take ( & mut self . pending_offers_events . lock ( ) . unwrap ( ) )
1193
+ }
1070
1194
}
0 commit comments