@@ -71,6 +71,8 @@ use crate::offers::offer::{Offer, OfferBuilder};
7171use crate::offers::parse::Bolt12SemanticError;
7272use crate::offers::refund::{Refund, RefundBuilder};
7373use crate::offers::signer;
74+ #[cfg(async_payments)]
75+ use crate::offers::static_invoice::StaticInvoice;
7476use crate::onion_message::async_payments::{AsyncPaymentsMessage, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler};
7577use crate::onion_message::messenger::{Destination, MessageRouter, Responder, ResponseInstruction, MessageSendInstructions};
7678use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
@@ -4318,6 +4320,61 @@ where
43184320 )
43194321 }
43204322
4323+ #[cfg(async_payments)]
4324+ fn initiate_async_payment(
4325+ &self, invoice: &StaticInvoice, payment_id: PaymentId
4326+ ) -> Result<(), Bolt12PaymentError> {
4327+ let mut res = Ok(());
4328+ PersistenceNotifierGuard::optionally_notify(self, || {
4329+ let outbound_pmts_res = self.pending_outbound_payments.static_invoice_received(
4330+ invoice, payment_id, &*self.entropy_source, &self.pending_events
4331+ );
4332+ let payment_release_secret = match outbound_pmts_res {
4333+ Ok(secret) => secret,
4334+ Err(Bolt12PaymentError::UnexpectedInvoice) | Err(Bolt12PaymentError::DuplicateInvoice) => {
4335+ res = outbound_pmts_res.map(|_| ());
4336+ return NotifyOption::SkipPersistNoEvents
4337+ },
4338+ Err(e) => {
4339+ res = Err(e);
4340+ return NotifyOption::DoPersist
4341+ }
4342+ };
4343+
4344+ let reply_paths = match self.create_blinded_paths(
4345+ MessageContext::AsyncPayments(AsyncPaymentsContext::OutboundPayment { payment_id })
4346+ ) {
4347+ Ok(paths) => paths,
4348+ Err(()) => {
4349+ self.abandon_payment_with_reason(payment_id, PaymentFailureReason::RouteNotFound);
4350+ res = Err(Bolt12PaymentError::SendingFailed(RetryableSendFailure::RouteNotFound));
4351+ return NotifyOption::DoPersist
4352+ }
4353+ };
4354+
4355+ let mut pending_async_payments_messages = self.pending_async_payments_messages.lock().unwrap();
4356+ const HTLC_AVAILABLE_LIMIT: usize = 10;
4357+ reply_paths
4358+ .iter()
4359+ .flat_map(|reply_path| invoice.message_paths().iter().map(move |invoice_path| (invoice_path, reply_path)))
4360+ .take(HTLC_AVAILABLE_LIMIT)
4361+ .for_each(|(invoice_path, reply_path)| {
4362+ let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
4363+ destination: Destination::BlindedPath(invoice_path.clone()),
4364+ reply_path: reply_path.clone(),
4365+ };
4366+ let message = AsyncPaymentsMessage::HeldHtlcAvailable(
4367+ HeldHtlcAvailable { payment_release_secret }
4368+ );
4369+ pending_async_payments_messages.push((message, instructions));
4370+ });
4371+
4372+ NotifyOption::DoPersist
4373+ });
4374+
4375+ res
4376+ }
4377+
43214378 /// Signals that no further attempts for the given payment should occur. Useful if you have a
43224379 /// pending outbound payment with retries remaining, but wish to stop retrying the payment before
43234380 /// retries are exhausted.
@@ -11040,14 +11097,39 @@ where
1104011097 }
1104111098 },
1104211099 #[cfg(async_payments)]
11043- OffersMessage::StaticInvoice(_invoice) => {
11100+ OffersMessage::StaticInvoice(invoice) => {
11101+ let payment_id = match context {
11102+ Some(OffersContext::OutboundPayment { payment_id, nonce, hmac: Some(hmac) }) => {
11103+ if payment_id.verify(hmac, nonce, expanded_key).is_err() {
11104+ return None
11105+ }
11106+ payment_id
11107+ },
11108+ _ => return None
11109+ };
11110+ // TODO: DRY this with the above regular invoice error handling
11111+ let error = match self.initiate_async_payment(&invoice, payment_id) {
11112+ Err(Bolt12PaymentError::UnknownRequiredFeatures) => {
11113+ log_trace!(
11114+ self.logger, "Invoice requires unknown features: {:?}",
11115+ invoice.invoice_features()
11116+ );
11117+ InvoiceError::from(Bolt12SemanticError::UnknownRequiredFeatures)
11118+ },
11119+ Err(Bolt12PaymentError::SendingFailed(e)) => {
11120+ log_trace!(self.logger, "Failed paying invoice: {:?}", e);
11121+ InvoiceError::from_string(format!("{:?}", e))
11122+ },
11123+ Err(Bolt12PaymentError::UnexpectedInvoice)
11124+ | Err(Bolt12PaymentError::DuplicateInvoice)
11125+ | Ok(()) => return None,
11126+ };
1104411127 match responder {
11045- Some(responder) => {
11046- return Some((OffersMessage::InvoiceError(
11047- InvoiceError::from_string("Static invoices not yet supported".to_string())
11048- ), responder.respond()));
11128+ Some(responder) => Some((OffersMessage::InvoiceError(error), responder.respond())),
11129+ None => {
11130+ log_trace!(self.logger, "No reply path to send error: {:?}", error);
11131+ None
1104911132 },
11050- None => return None,
1105111133 }
1105211134 },
1105311135 OffersMessage::InvoiceError(invoice_error) => {
0 commit comments