Skip to content

Commit abffc78

Browse files
committed
Introduce OfferEvents
1 parent f2b8f96 commit abffc78

File tree

1 file changed

+127
-3
lines changed

1 file changed

+127
-3
lines changed

lightning/src/offers/flow.rs

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ use crate::ln::channelmanager::{
3737
};
3838
use crate::ln::inbound_payment;
3939
use crate::offers::invoice::{
40-
Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder, InvoiceBuilderVariant,
41-
DEFAULT_RELATIVE_EXPIRY,
40+
Bolt12Invoice, Bolt12InvoiceAmountSource, DerivedSigningPubkey, InvoiceBuilder,
41+
InvoiceBuilderVariant, DEFAULT_RELATIVE_EXPIRY,
4242
};
4343
use crate::offers::invoice_request::{
44-
InvoiceRequest, InvoiceRequestBuilder, VerifiedInvoiceRequest,
44+
InvoiceRequest, InvoiceRequestAmountSource, InvoiceRequestBuilder, VerifiedInvoiceRequest,
4545
};
4646
use crate::offers::nonce::Nonce;
4747
use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
@@ -72,6 +72,115 @@ use {
7272
crate::onion_message::dns_resolution::{DNSResolverMessage, DNSSECQuery, OMNameResolver},
7373
};
7474

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+
75184
/// A BOLT12 offers code and flow utility provider, which facilitates
76185
/// BOLT12 builder generation and onion message handling.
77186
///
@@ -96,6 +205,8 @@ where
96205
#[cfg(any(test, feature = "_test_utils"))]
97206
pub(crate) pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
98207

208+
pending_offers_events: Mutex<Vec<OfferEvents>>,
209+
99210
pending_async_payments_messages: Mutex<Vec<(AsyncPaymentsMessage, MessageSendInstructions)>>,
100211

101212
#[cfg(feature = "dnssec")]
@@ -126,6 +237,7 @@ where
126237
message_router,
127238

128239
pending_offers_messages: Mutex::new(Vec::new()),
240+
pending_offers_events: Mutex::new(Vec::new()),
129241
pending_async_payments_messages: Mutex::new(Vec::new()),
130242

131243
#[cfg(feature = "dnssec")]
@@ -1048,6 +1160,13 @@ where
10481160
Ok(())
10491161
}
10501162

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+
10511170
/// Gets the enqueued [`OffersMessage`] with their corresponding [`MessageSendInstructions`].
10521171
pub fn release_pending_offers_messages(&self) -> Vec<(OffersMessage, MessageSendInstructions)> {
10531172
core::mem::take(&mut self.pending_offers_messages.lock().unwrap())
@@ -1067,4 +1186,9 @@ where
10671186
) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
10681187
core::mem::take(&mut self.pending_dns_onion_messages.lock().unwrap())
10691188
}
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+
}
10701194
}

0 commit comments

Comments
 (0)