@@ -56,10 +56,10 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
56
56
use crate::ln::outbound_payment;
57
57
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs};
58
58
use crate::ln::wire::Encode;
59
- use crate::offers::offer::{DerivedMetadata, OfferBuilder};
59
+ use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
60
60
use crate::offers::parse::Bolt12SemanticError;
61
61
use crate::offers::refund::RefundBuilder;
62
- use crate::onion_message::{OffersMessage, PendingOnionMessage};
62
+ use crate::onion_message::{Destination, OffersMessage, PendingOnionMessage};
63
63
use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, WriteableEcdsaChannelSigner};
64
64
use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
65
65
use crate::util::wakers::{Future, Notifier};
@@ -7158,6 +7158,91 @@ where
7158
7158
Ok(builder)
7159
7159
}
7160
7160
7161
+ /// Pays for an [`Offer`] using the given parameters by creating an [`InvoiceRequest`] and
7162
+ /// enqueuing it to be sent via an onion message. [`ChannelManager`] will pay the actual
7163
+ /// [`Bolt12Invoice`] once it is received.
7164
+ ///
7165
+ /// Uses [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized by
7166
+ /// the [`ChannelManager`] when handling a [`Bolt12Invoice`] message in response to the request.
7167
+ /// The optional parameters are used in the builder, if `Some`:
7168
+ /// - `quantity` for [`InvoiceRequest::quantity`] which must be set if
7169
+ /// [`Offer::expects_quantity`] is `true`.
7170
+ /// - `amount_msats` if overpaying what is required for the given `quantity` is desired, and
7171
+ /// - `payer_note` for [`InvoiceRequest::payer_note`].
7172
+ ///
7173
+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the request
7174
+ /// when received. See [Avoiding Duplicate Payments] for other requirements once the payment has
7175
+ /// been sent. Errors if a duplicate `payment_id` is provided given the caveats in the
7176
+ /// aforementioned link.
7177
+ ///
7178
+ /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
7179
+ /// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
7180
+ /// [`InvoiceRequest::payer_note`]: crate::offers::invoice_request::InvoiceRequest::payer_note
7181
+ /// [`InvoiceRequestBuilder`]: crate::offers::invoice_request::InvoiceRequestBuilder
7182
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
7183
+ /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
7184
+ pub fn pay_for_offer(
7185
+ &self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
7186
+ payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry,
7187
+ max_total_routing_fee_msat: Option<u64>
7188
+ ) -> Result<(), Bolt12SemanticError> {
7189
+ let expanded_key = &self.inbound_payment_key;
7190
+ let entropy = &*self.entropy_source;
7191
+ let secp_ctx = &self.secp_ctx;
7192
+
7193
+ if !offer.supports_chain(self.chain_hash) {
7194
+ return Err(Bolt12SemanticError::UnsupportedChain);
7195
+ }
7196
+
7197
+ let builder = offer.request_invoice_deriving_payer_id(
7198
+ expanded_key, entropy, secp_ctx, payment_id
7199
+ )?;
7200
+ let builder = match quantity {
7201
+ None => builder,
7202
+ Some(quantity) => builder.quantity(quantity)?,
7203
+ };
7204
+ let builder = match amount_msats {
7205
+ None => builder,
7206
+ Some(amount_msats) => builder.amount_msats(amount_msats)?,
7207
+ };
7208
+ let builder = match payer_note {
7209
+ None => builder,
7210
+ Some(payer_note) => builder.payer_note(payer_note),
7211
+ };
7212
+
7213
+ let invoice_request = builder.build_and_sign()?;
7214
+ let reply_path = self.create_one_hop_blinded_path();
7215
+
7216
+ self.pending_outbound_payments
7217
+ .add_new_awaiting_invoice(payment_id, retry_strategy, max_total_routing_fee_msat)
7218
+ .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
7219
+
7220
+ let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
7221
+ if offer.paths().is_empty() {
7222
+ let message = PendingOnionMessage {
7223
+ contents: OffersMessage::InvoiceRequest(invoice_request),
7224
+ destination: Destination::Node(offer.signing_pubkey()),
7225
+ reply_path: Some(reply_path),
7226
+ };
7227
+ pending_offers_messages.push(message);
7228
+ } else {
7229
+ // Send as many invoice requests as there are paths in the offer (with an upper bound).
7230
+ // Using only one path could result in a failure if the path no longer exists. But only
7231
+ // one invoice for a given payment id will be paid, even if more than one is received.
7232
+ const REQUEST_LIMIT: usize = 10;
7233
+ for path in offer.paths().into_iter().take(REQUEST_LIMIT) {
7234
+ let message = PendingOnionMessage {
7235
+ contents: OffersMessage::InvoiceRequest(invoice_request.clone()),
7236
+ destination: Destination::BlindedPath(path.clone()),
7237
+ reply_path: Some(reply_path.clone()),
7238
+ };
7239
+ pending_offers_messages.push(message);
7240
+ }
7241
+ }
7242
+
7243
+ Ok(())
7244
+ }
7245
+
7161
7246
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
7162
7247
/// to pay us.
7163
7248
///
0 commit comments