lightning/offers/
flow.rs

1// This file is Copyright its original authors, visible in version control
2// history.
3//
4// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7// You may not use this file except in accordance with one or both of these
8// licenses.
9
10//! Provides data structures and functions for creating and managing Offers messages,
11//! facilitating communication, and handling BOLT12 messages and payments.
12
13use core::ops::Deref;
14use core::sync::atomic::{AtomicUsize, Ordering};
15use core::time::Duration;
16
17use bitcoin::block::Header;
18use bitcoin::constants::ChainHash;
19use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
20
21use crate::blinded_path::message::{
22	AsyncPaymentsContext, BlindedMessagePath, MessageContext, MessageForwardNode, OffersContext,
23};
24use crate::blinded_path::payment::{
25	AsyncBolt12OfferContext, BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext,
26	PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs,
27};
28use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS;
29
30#[allow(unused_imports)]
31use crate::prelude::*;
32
33use crate::chain::BestBlock;
34use crate::ln::channel_state::ChannelDetails;
35use crate::ln::channelmanager::{InterceptId, PaymentId, CLTV_FAR_FAR_AWAY};
36use crate::ln::inbound_payment;
37use crate::offers::async_receive_offer_cache::AsyncReceiveOfferCache;
38use crate::offers::invoice::{
39	Bolt12Invoice, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder,
40	UnsignedBolt12Invoice, DEFAULT_RELATIVE_EXPIRY,
41};
42use crate::offers::invoice_error::InvoiceError;
43use crate::offers::invoice_request::{
44	InvoiceRequest, InvoiceRequestBuilder, VerifiedInvoiceRequest,
45};
46use crate::offers::nonce::Nonce;
47use crate::offers::offer::{Amount, DerivedMetadata, Offer, OfferBuilder};
48use crate::offers::parse::Bolt12SemanticError;
49use crate::offers::refund::{Refund, RefundBuilder};
50use crate::onion_message::async_payments::{
51	AsyncPaymentsMessage, HeldHtlcAvailable, OfferPaths, OfferPathsRequest, ServeStaticInvoice,
52	StaticInvoicePersisted,
53};
54use crate::onion_message::messenger::{
55	Destination, MessageRouter, MessageSendInstructions, Responder, PADDED_PATH_LENGTH,
56};
57use crate::onion_message::offers::OffersMessage;
58use crate::onion_message::packet::OnionMessageContents;
59use crate::routing::router::Router;
60use crate::sign::{EntropySource, NodeSigner, ReceiveAuthKey};
61
62use crate::offers::static_invoice::{StaticInvoice, StaticInvoiceBuilder};
63use crate::sync::{Mutex, RwLock};
64use crate::types::payment::{PaymentHash, PaymentSecret};
65use crate::util::logger::Logger;
66use crate::util::ser::Writeable;
67
68#[cfg(feature = "dnssec")]
69use {
70	crate::blinded_path::message::DNSResolverContext,
71	crate::onion_message::dns_resolution::{DNSResolverMessage, DNSSECQuery, OMNameResolver},
72};
73
74/// A BOLT12 offers code and flow utility provider, which facilitates
75/// BOLT12 builder generation and onion message handling.
76///
77/// [`OffersMessageFlow`] is parameterized by a [`MessageRouter`], which is responsible
78/// for finding message paths when initiating and retrying onion messages.
79pub struct OffersMessageFlow<MR: Deref, L: Deref>
80where
81	MR::Target: MessageRouter,
82	L::Target: Logger,
83{
84	chain_hash: ChainHash,
85	best_block: RwLock<BestBlock>,
86
87	our_network_pubkey: PublicKey,
88	highest_seen_timestamp: AtomicUsize,
89	inbound_payment_key: inbound_payment::ExpandedKey,
90
91	receive_auth_key: ReceiveAuthKey,
92
93	secp_ctx: Secp256k1<secp256k1::All>,
94	message_router: MR,
95
96	#[cfg(not(any(test, feature = "_test_utils")))]
97	pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
98	#[cfg(any(test, feature = "_test_utils"))]
99	pub(crate) pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
100
101	pending_async_payments_messages: Mutex<Vec<(AsyncPaymentsMessage, MessageSendInstructions)>>,
102	async_receive_offer_cache: Mutex<AsyncReceiveOfferCache>,
103
104	#[cfg(feature = "dnssec")]
105	pub(crate) hrn_resolver: OMNameResolver,
106	#[cfg(feature = "dnssec")]
107	pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
108
109	logger: L,
110}
111
112impl<MR: Deref, L: Deref> OffersMessageFlow<MR, L>
113where
114	MR::Target: MessageRouter,
115	L::Target: Logger,
116{
117	/// Creates a new [`OffersMessageFlow`]
118	pub fn new(
119		chain_hash: ChainHash, best_block: BestBlock, our_network_pubkey: PublicKey,
120		current_timestamp: u32, inbound_payment_key: inbound_payment::ExpandedKey,
121		receive_auth_key: ReceiveAuthKey, secp_ctx: Secp256k1<secp256k1::All>, message_router: MR,
122		logger: L,
123	) -> Self {
124		Self {
125			chain_hash,
126			best_block: RwLock::new(best_block),
127
128			our_network_pubkey,
129			highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
130			inbound_payment_key,
131
132			receive_auth_key,
133
134			secp_ctx,
135			message_router,
136
137			pending_offers_messages: Mutex::new(Vec::new()),
138			pending_async_payments_messages: Mutex::new(Vec::new()),
139
140			#[cfg(feature = "dnssec")]
141			hrn_resolver: OMNameResolver::new(current_timestamp, best_block.height),
142			#[cfg(feature = "dnssec")]
143			pending_dns_onion_messages: Mutex::new(Vec::new()),
144
145			async_receive_offer_cache: Mutex::new(AsyncReceiveOfferCache::new()),
146
147			logger,
148		}
149	}
150
151	/// If we are an async recipient, on startup we'll interactively build offers and static invoices
152	/// with an always-online node that will serve static invoices on our behalf. Once the offer is
153	/// built and the static invoice is confirmed as persisted by the server, the underlying
154	/// [`AsyncReceiveOfferCache`] should be persisted using
155	/// [`Self::writeable_async_receive_offer_cache`] so we remember the offers we've built.
156	pub fn with_async_payments_offers_cache(
157		mut self, async_receive_offer_cache: AsyncReceiveOfferCache,
158	) -> Self {
159		self.async_receive_offer_cache = Mutex::new(async_receive_offer_cache);
160		self
161	}
162
163	/// Sets the [`BlindedMessagePath`]s that we will use as an async recipient to interactively build
164	/// [`Offer`]s with a static invoice server, so the server can serve [`StaticInvoice`]s to payers
165	/// on our behalf when we're offline.
166	///
167	/// This method will also send out messages initiating async offer creation to the static invoice
168	/// server, if any peers are connected.
169	///
170	/// This method only needs to be called once when the server first takes on the recipient as a
171	/// client, or when the paths change, e.g. if the paths are set to expire at a particular time.
172	pub fn set_paths_to_static_invoice_server(
173		&self, paths_to_static_invoice_server: Vec<BlindedMessagePath>,
174		peers: Vec<MessageForwardNode>,
175	) -> Result<(), ()> {
176		let mut cache = self.async_receive_offer_cache.lock().unwrap();
177		cache.set_paths_to_static_invoice_server(paths_to_static_invoice_server.clone())?;
178		core::mem::drop(cache);
179
180		// We'll only fail here if no peers are connected yet for us to create reply paths to outbound
181		// offer_paths_requests, so ignore the error.
182		let _ = self.check_refresh_async_offers(peers, false);
183
184		Ok(())
185	}
186
187	/// Gets the node_id held by this [`OffersMessageFlow`]`
188	fn get_our_node_id(&self) -> PublicKey {
189		self.our_network_pubkey
190	}
191
192	fn get_receive_auth_key(&self) -> ReceiveAuthKey {
193		self.receive_auth_key
194	}
195
196	fn duration_since_epoch(&self) -> Duration {
197		#[cfg(not(feature = "std"))]
198		let now = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
199		#[cfg(feature = "std")]
200		let now = std::time::SystemTime::now()
201			.duration_since(std::time::SystemTime::UNIX_EPOCH)
202			.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
203		now
204	}
205
206	/// Notifies the [`OffersMessageFlow`] that a new block has been observed.
207	///
208	/// This allows the flow to keep in sync with the latest block timestamp,
209	/// which may be used for time-sensitive operations.
210	///
211	/// Must be called whenever a new chain tip becomes available. May be skipped
212	/// for intermediary blocks.
213	pub fn best_block_updated(&self, header: &Header, _height: u32) {
214		let timestamp = &self.highest_seen_timestamp;
215		let block_time = header.time as usize;
216
217		loop {
218			// Update timestamp to be the max of its current value and the block
219			// timestamp. This should keep us close to the current time without relying on
220			// having an explicit local time source.
221			// Just in case we end up in a race, we loop until we either successfully
222			// update timestamp or decide we don't need to.
223			let old_serial = timestamp.load(Ordering::Acquire);
224			if old_serial >= block_time {
225				break;
226			}
227			if timestamp
228				.compare_exchange(old_serial, block_time, Ordering::AcqRel, Ordering::Relaxed)
229				.is_ok()
230			{
231				break;
232			}
233		}
234
235		#[cfg(feature = "dnssec")]
236		{
237			let updated_time = timestamp.load(Ordering::Acquire) as u32;
238			self.hrn_resolver.new_best_block(_height, updated_time);
239		}
240	}
241}
242
243/// The maximum size of a received [`StaticInvoice`] before we'll fail verification in
244/// [`OffersMessageFlow::verify_serve_static_invoice_message].
245pub const MAX_STATIC_INVOICE_SIZE_BYTES: usize = 5 * 1024;
246
247/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
248/// along different paths.
249/// Sending multiple requests increases the chances of successful delivery in case some
250/// paths are unavailable. However, only one invoice for a given [`PaymentId`] will be paid,
251/// even if multiple invoices are received.
252const OFFERS_MESSAGE_REQUEST_LIMIT: usize = 10;
253
254#[cfg(test)]
255pub(crate) const TEST_OFFERS_MESSAGE_REQUEST_LIMIT: usize = OFFERS_MESSAGE_REQUEST_LIMIT;
256
257/// The default relative expiry for reply paths where a quick response is expected and the reply
258/// path is single-use.
259const TEMP_REPLY_PATH_RELATIVE_EXPIRY: Duration = Duration::from_secs(2 * 60 * 60);
260
261#[cfg(test)]
262pub(crate) const TEST_TEMP_REPLY_PATH_RELATIVE_EXPIRY: Duration = TEMP_REPLY_PATH_RELATIVE_EXPIRY;
263
264// Default to async receive offers and the paths used to update them lasting one year.
265const DEFAULT_ASYNC_RECEIVE_OFFER_EXPIRY: Duration = Duration::from_secs(365 * 24 * 60 * 60);
266
267#[cfg(test)]
268pub(crate) const TEST_DEFAULT_ASYNC_RECEIVE_OFFER_EXPIRY: Duration =
269	DEFAULT_ASYNC_RECEIVE_OFFER_EXPIRY;
270
271impl<MR: Deref, L: Deref> OffersMessageFlow<MR, L>
272where
273	MR::Target: MessageRouter,
274	L::Target: Logger,
275{
276	/// [`BlindedMessagePath`]s for an async recipient to communicate with this node and interactively
277	/// build [`Offer`]s and [`StaticInvoice`]s for receiving async payments.
278	///
279	/// If `relative_expiry` is unset, the [`BlindedMessagePath`]s will never expire.
280	///
281	/// Returns the paths that the recipient should be configured with via
282	/// [`Self::set_paths_to_static_invoice_server`].
283	///
284	/// Errors if blinded path creation fails or the provided `recipient_id` is larger than 1KiB.
285	pub fn blinded_paths_for_async_recipient(
286		&self, recipient_id: Vec<u8>, relative_expiry: Option<Duration>,
287		peers: Vec<MessageForwardNode>,
288	) -> Result<Vec<BlindedMessagePath>, ()> {
289		if recipient_id.len() > 1024 {
290			log_trace!(self.logger, "Async recipient ID exceeds 1024 bytes");
291			return Err(());
292		}
293
294		let path_absolute_expiry =
295			relative_expiry.map(|exp| exp.saturating_add(self.duration_since_epoch()));
296
297		let context = MessageContext::AsyncPayments(AsyncPaymentsContext::OfferPathsRequest {
298			recipient_id,
299			path_absolute_expiry,
300		});
301		self.create_blinded_paths(peers, context)
302	}
303
304	/// Creates a collection of blinded paths by delegating to
305	/// [`MessageRouter::create_blinded_paths`].
306	///
307	/// Errors if the `MessageRouter` errors.
308	fn create_blinded_paths(
309		&self, peers: Vec<MessageForwardNode>, context: MessageContext,
310	) -> Result<Vec<BlindedMessagePath>, ()> {
311		let recipient = self.get_our_node_id();
312		let receive_key = self.get_receive_auth_key();
313		let secp_ctx = &self.secp_ctx;
314
315		self.message_router
316			.create_blinded_paths(recipient, receive_key, context, peers, secp_ctx)
317			.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
318	}
319
320	/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
321	/// [`Router::create_blinded_payment_paths`].
322	fn create_blinded_payment_paths<ES: Deref, R: Deref>(
323		&self, router: &R, entropy_source: ES, usable_channels: Vec<ChannelDetails>,
324		amount_msats: Option<u64>, payment_secret: PaymentSecret, payment_context: PaymentContext,
325		relative_expiry_seconds: u32,
326	) -> Result<Vec<BlindedPaymentPath>, ()>
327	where
328		ES::Target: EntropySource,
329		R::Target: Router,
330	{
331		let expanded_key = &self.inbound_payment_key;
332		let entropy = &*entropy_source;
333		let secp_ctx = &self.secp_ctx;
334
335		let payee_node_id = self.get_our_node_id();
336
337		// Assume shorter than usual block times to avoid spuriously failing payments too early.
338		const SECONDS_PER_BLOCK: u32 = 9 * 60;
339		let relative_expiry_blocks = relative_expiry_seconds / SECONDS_PER_BLOCK;
340		let max_cltv_expiry = core::cmp::max(relative_expiry_blocks, CLTV_FAR_FAR_AWAY)
341			.saturating_add(LATENCY_GRACE_PERIOD_BLOCKS)
342			.saturating_add(self.best_block.read().unwrap().height);
343
344		let payee_tlvs = UnauthenticatedReceiveTlvs {
345			payment_secret,
346			payment_constraints: PaymentConstraints { max_cltv_expiry, htlc_minimum_msat: 1 },
347			payment_context,
348		};
349		let nonce = Nonce::from_entropy_source(entropy);
350		let payee_tlvs = payee_tlvs.authenticate(nonce, expanded_key);
351
352		router.create_blinded_payment_paths(
353			payee_node_id,
354			usable_channels,
355			payee_tlvs,
356			amount_msats,
357			secp_ctx,
358		)
359	}
360
361	#[cfg(test)]
362	/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
363	/// [`Router::create_blinded_payment_paths`].
364	pub(crate) fn test_create_blinded_payment_paths<ES: Deref, R: Deref>(
365		&self, router: &R, entropy_source: ES, usable_channels: Vec<ChannelDetails>,
366		amount_msats: Option<u64>, payment_secret: PaymentSecret, payment_context: PaymentContext,
367		relative_expiry_seconds: u32,
368	) -> Result<Vec<BlindedPaymentPath>, ()>
369	where
370		ES::Target: EntropySource,
371		R::Target: Router,
372	{
373		self.create_blinded_payment_paths(
374			router,
375			entropy_source,
376			usable_channels,
377			amount_msats,
378			payment_secret,
379			payment_context,
380			relative_expiry_seconds,
381		)
382	}
383}
384
385fn enqueue_onion_message_with_reply_paths<T: OnionMessageContents + Clone>(
386	message: T, message_paths: &[BlindedMessagePath], reply_paths: Vec<BlindedMessagePath>,
387	queue: &mut Vec<(T, MessageSendInstructions)>,
388) {
389	reply_paths
390		.iter()
391		.flat_map(|reply_path| message_paths.iter().map(move |path| (path, reply_path)))
392		.take(OFFERS_MESSAGE_REQUEST_LIMIT)
393		.for_each(|(path, reply_path)| {
394			let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
395				destination: Destination::BlindedPath(path.clone()),
396				reply_path: reply_path.clone(),
397			};
398			queue.push((message.clone(), instructions));
399		});
400}
401
402/// Instructions for how to respond to an `InvoiceRequest`.
403pub enum InvreqResponseInstructions {
404	/// We are the recipient of this payment, and a [`Bolt12Invoice`] should be sent in response to
405	/// the invoice request since it is now verified.
406	SendInvoice(VerifiedInvoiceRequest),
407	/// We are a static invoice server and should respond to this invoice request by retrieving the
408	/// [`StaticInvoice`] corresponding to the `recipient_id` and `invoice_slot` and calling
409	/// [`OffersMessageFlow::enqueue_static_invoice`].
410	///
411	/// [`StaticInvoice`]: crate::offers::static_invoice::StaticInvoice
412	SendStaticInvoice {
413		/// An identifier for the async recipient for whom we are serving [`StaticInvoice`]s.
414		///
415		/// [`StaticInvoice`]: crate::offers::static_invoice::StaticInvoice
416		recipient_id: Vec<u8>,
417		/// The slot number for the specific invoice being requested by the payer.
418		invoice_slot: u16,
419		/// The invoice request that should be forwarded to the async recipient in case the
420		/// recipient is online to respond. Should be forwarded by calling
421		/// [`OffersMessageFlow::enqueue_invoice_request_to_forward`].
422		invoice_request: InvoiceRequest,
423	},
424}
425
426/// Parameters for the reply path to a [`HeldHtlcAvailable`] onion message.
427pub enum HeldHtlcReplyPath {
428	/// The reply path to the [`HeldHtlcAvailable`] message should terminate at our node.
429	ToUs {
430		/// The id of the payment.
431		payment_id: PaymentId,
432		/// The peers to use when creating this reply path.
433		peers: Vec<MessageForwardNode>,
434	},
435	/// The reply path to the [`HeldHtlcAvailable`] message should terminate at our next-hop channel
436	/// counterparty, as they are holding our HTLC until they receive the corresponding
437	/// [`ReleaseHeldHtlc`] message.
438	///
439	/// [`ReleaseHeldHtlc`]: crate::onion_message::async_payments::ReleaseHeldHtlc
440	ToCounterparty {
441		/// The blinded path provided to us by our counterparty.
442		path: BlindedMessagePath,
443	},
444}
445
446impl<MR: Deref, L: Deref> OffersMessageFlow<MR, L>
447where
448	MR::Target: MessageRouter,
449	L::Target: Logger,
450{
451	/// Verifies an [`InvoiceRequest`] using the provided [`OffersContext`] or the [`InvoiceRequest::metadata`].
452	///
453	/// - If an [`OffersContext::InvoiceRequest`] with a `nonce` is provided, verification is performed using recipient context data.
454	/// - If no context is provided but the [`InvoiceRequest`] contains [`Offer`] metadata, verification is performed using that metadata.
455	/// - If neither is available, verification fails.
456	///
457	/// # Errors
458	///
459	/// Returns an error if:
460	/// - Both [`OffersContext`] and [`InvoiceRequest`] metadata are absent or invalid.
461	/// - The verification process (via recipient context data or metadata) fails.
462	pub fn verify_invoice_request(
463		&self, invoice_request: InvoiceRequest, context: Option<OffersContext>,
464	) -> Result<InvreqResponseInstructions, ()> {
465		let secp_ctx = &self.secp_ctx;
466		let expanded_key = &self.inbound_payment_key;
467
468		let nonce = match context {
469			None if invoice_request.metadata().is_some() => None,
470			Some(OffersContext::InvoiceRequest { nonce }) => Some(nonce),
471			Some(OffersContext::StaticInvoiceRequested {
472				recipient_id,
473				invoice_slot,
474				path_absolute_expiry,
475			}) => {
476				if path_absolute_expiry < self.duration_since_epoch() {
477					log_trace!(self.logger, "Static invoice request has expired");
478					return Err(());
479				}
480
481				return Ok(InvreqResponseInstructions::SendStaticInvoice {
482					recipient_id,
483					invoice_slot,
484					invoice_request,
485				});
486			},
487			_ => return Err(()),
488		};
489
490		let invoice_request = match nonce {
491			Some(nonce) => {
492				invoice_request.verify_using_recipient_data(nonce, expanded_key, secp_ctx)
493			},
494			None => invoice_request.verify_using_metadata(expanded_key, secp_ctx),
495		}?;
496
497		Ok(InvreqResponseInstructions::SendInvoice(invoice_request))
498	}
499
500	/// Verifies a [`Bolt12Invoice`] using the provided [`OffersContext`] or the invoice's payer metadata,
501	/// returning the corresponding [`PaymentId`] if successful.
502	///
503	/// - If an [`OffersContext::OutboundPayment`] with a `nonce` is provided, verification is performed
504	///   using this to form the payer metadata.
505	/// - If no context is provided and the invoice corresponds to a [`Refund`] without blinded paths,
506	///   verification is performed using the [`Bolt12Invoice::payer_metadata`].
507	/// - If neither condition is met, verification fails.
508	pub fn verify_bolt12_invoice(
509		&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
510	) -> Result<PaymentId, ()> {
511		let secp_ctx = &self.secp_ctx;
512		let expanded_key = &self.inbound_payment_key;
513
514		match context {
515			None if invoice.is_for_refund_without_paths() => {
516				invoice.verify_using_metadata(expanded_key, secp_ctx)
517			},
518			Some(&OffersContext::OutboundPayment { payment_id, nonce, .. }) => {
519				invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx)
520			},
521			_ => Err(()),
522		}
523	}
524
525	/// Verifies the provided [`AsyncPaymentsContext`] for an inbound [`HeldHtlcAvailable`] message.
526	///
527	/// Because blinded path contexts are verified as a part of onion message processing, this only
528	/// validates that the context is not yet expired based on `path_absolute_expiry`.
529	///
530	/// # Errors
531	///
532	/// Returns `Err(())` if:
533	/// - The inbound payment context has expired.
534	pub fn verify_inbound_async_payment_context(
535		&self, context: AsyncPaymentsContext,
536	) -> Result<(), ()> {
537		match context {
538			AsyncPaymentsContext::InboundPayment { path_absolute_expiry } => {
539				if self.duration_since_epoch() > path_absolute_expiry {
540					return Err(());
541				}
542				Ok(())
543			},
544			_ => Err(()),
545		}
546	}
547
548	fn create_offer_builder_intern<ES: Deref, PF, I>(
549		&self, entropy_source: ES, make_paths: PF,
550	) -> Result<(OfferBuilder<'_, DerivedMetadata, secp256k1::All>, Nonce), Bolt12SemanticError>
551	where
552		ES::Target: EntropySource,
553		PF: FnOnce(
554			PublicKey,
555			MessageContext,
556			&secp256k1::Secp256k1<secp256k1::All>,
557		) -> Result<I, Bolt12SemanticError>,
558		I: IntoIterator<Item = BlindedMessagePath>,
559	{
560		let node_id = self.get_our_node_id();
561		let expanded_key = &self.inbound_payment_key;
562		let entropy = entropy_source;
563		let secp_ctx = &self.secp_ctx;
564
565		let nonce = Nonce::from_entropy_source(entropy);
566		let context = MessageContext::Offers(OffersContext::InvoiceRequest { nonce });
567
568		let mut builder =
569			OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx)
570				.chain_hash(self.chain_hash);
571
572		for path in make_paths(node_id, context, secp_ctx)? {
573			builder = builder.path(path)
574		}
575
576		Ok((builder.into(), nonce))
577	}
578
579	/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
580	/// [`OffersMessageFlow`], and any corresponding [`InvoiceRequest`] can be verified using
581	/// [`Self::verify_invoice_request`]. The offer will expire at `absolute_expiry` if `Some`,
582	/// or will not expire if `None`.
583	///
584	/// # Privacy
585	///
586	/// Uses [`MessageRouter`] provided at construction to construct a [`BlindedMessagePath`] for
587	/// the offer. See the documentation of the selected [`MessageRouter`] for details on how it
588	/// selects blinded paths including privacy implications and reliability tradeoffs.
589	///
590	/// Also uses a derived signing pubkey in the offer for recipient privacy.
591	///
592	/// # Limitations
593	///
594	/// If [`DefaultMessageRouter`] is used to parameterize the [`OffersMessageFlow`], a direct
595	/// connection to the introduction node in the responding [`InvoiceRequest`]'s reply path is
596	/// required. See the [`DefaultMessageRouter`] documentation for more details.
597	///
598	/// # Errors
599	///
600	/// Returns an error if the parameterized [`Router`] is unable to create a blinded path for the offer.
601	///
602	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
603	///
604	/// [`DefaultMessageRouter`]: crate::onion_message::messenger::DefaultMessageRouter
605	pub fn create_offer_builder<ES: Deref>(
606		&self, entropy_source: ES, peers: Vec<MessageForwardNode>,
607	) -> Result<OfferBuilder<'_, DerivedMetadata, secp256k1::All>, Bolt12SemanticError>
608	where
609		ES::Target: EntropySource,
610	{
611		self.create_offer_builder_intern(&*entropy_source, |_, context, _| {
612			self.create_blinded_paths(peers, context)
613				.map(|paths| paths.into_iter().take(1))
614				.map_err(|_| Bolt12SemanticError::MissingPaths)
615		})
616		.map(|(builder, _)| builder)
617	}
618
619	/// Same as [`Self::create_offer_builder`], but allows specifying a custom [`MessageRouter`]
620	/// instead of using the one provided via the [`OffersMessageFlow`] parameterization.
621	///
622	/// This gives users full control over how the [`BlindedMessagePath`] is constructed,
623	/// including the option to omit it entirely.
624	///
625	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
626	///
627	/// See [`Self::create_offer_builder`] for more details on usage.
628	pub fn create_offer_builder_using_router<ME: Deref, ES: Deref>(
629		&self, router: ME, entropy_source: ES, peers: Vec<MessageForwardNode>,
630	) -> Result<OfferBuilder<'_, DerivedMetadata, secp256k1::All>, Bolt12SemanticError>
631	where
632		ME::Target: MessageRouter,
633		ES::Target: EntropySource,
634	{
635		let receive_key = self.get_receive_auth_key();
636		self.create_offer_builder_intern(&*entropy_source, |node_id, context, secp_ctx| {
637			router
638				.create_blinded_paths(node_id, receive_key, context, peers, secp_ctx)
639				.map(|paths| paths.into_iter().take(1))
640				.map_err(|_| Bolt12SemanticError::MissingPaths)
641		})
642		.map(|(builder, _)| builder)
643	}
644
645	/// Create an offer for receiving async payments as an often-offline recipient.
646	///
647	/// Because we may be offline when the payer attempts to request an invoice, you MUST:
648	/// 1. Provide at least 1 [`BlindedMessagePath`] terminating at an always-online node that will
649	///    serve the [`StaticInvoice`] created from this offer on our behalf.
650	/// 2. Use [`Self::create_static_invoice_builder`] to create a [`StaticInvoice`] from this
651	///    [`Offer`] plus the returned [`Nonce`], and provide the static invoice to the
652	///    aforementioned always-online node.
653	///
654	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
655	pub fn create_async_receive_offer_builder<ES: Deref>(
656		&self, entropy_source: ES, message_paths_to_always_online_node: Vec<BlindedMessagePath>,
657	) -> Result<(OfferBuilder<'_, DerivedMetadata, secp256k1::All>, Nonce), Bolt12SemanticError>
658	where
659		ES::Target: EntropySource,
660	{
661		self.create_offer_builder_intern(&*entropy_source, |_, _, _| {
662			Ok(message_paths_to_always_online_node)
663		})
664	}
665
666	fn create_refund_builder_intern<ES: Deref, PF, I>(
667		&self, entropy_source: ES, make_paths: PF, amount_msats: u64, absolute_expiry: Duration,
668		payment_id: PaymentId,
669	) -> Result<RefundBuilder<'_, secp256k1::All>, Bolt12SemanticError>
670	where
671		ES::Target: EntropySource,
672		PF: FnOnce(
673			PublicKey,
674			MessageContext,
675			&secp256k1::Secp256k1<secp256k1::All>,
676		) -> Result<I, Bolt12SemanticError>,
677		I: IntoIterator<Item = BlindedMessagePath>,
678	{
679		let node_id = self.get_our_node_id();
680		let expanded_key = &self.inbound_payment_key;
681		let entropy = &*entropy_source;
682		let secp_ctx = &self.secp_ctx;
683
684		let nonce = Nonce::from_entropy_source(entropy);
685		let context = MessageContext::Offers(OffersContext::OutboundPayment { payment_id, nonce });
686
687		// Create the base builder with common properties
688		let mut builder = RefundBuilder::deriving_signing_pubkey(
689			node_id,
690			expanded_key,
691			nonce,
692			secp_ctx,
693			amount_msats,
694			payment_id,
695		)?
696		.chain_hash(self.chain_hash)
697		.absolute_expiry(absolute_expiry);
698
699		for path in make_paths(node_id, context, secp_ctx)? {
700			builder = builder.path(path);
701		}
702
703		Ok(builder.into())
704	}
705
706	/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
707	/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
708	/// can be verified using [`Self::verify_bolt12_invoice`].
709	///
710	/// # Privacy
711	///
712	/// Uses [`MessageRouter`] provided at construction to construct a [`BlindedMessagePath`] for
713	/// the refund. See the documentation of the selected [`MessageRouter`] for details on how it
714	/// selects blinded paths including privacy implications and reliability tradeoffs.
715	///
716	/// The builder will have the provided expiration set. Any changes to the expiration on the
717	/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
718	/// block time minus two hours is used for the current time when determining if the refund has
719	/// expired.
720	///
721	/// The refund can be revoked by the user prior to receiving the invoice.
722	/// If abandoned, or if an invoice is not received before expiration, the payment will fail
723	/// with an [`Event::PaymentFailed`].
724	///
725	/// If `max_total_routing_fee_msat` is not specified, the default from
726	/// [`RouteParameters::from_payment_params_and_value`] is applied.
727	///
728	/// Also uses a derived payer id in the refund for payer privacy.
729	///
730	/// # Errors
731	///
732	/// Returns an error if:
733	/// - A duplicate `payment_id` is provided, given the caveats in the aforementioned link.
734	/// - `amount_msats` is invalid, or
735	/// - The parameterized [`Router`] is unable to create a blinded path for the refund.
736	///
737	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
738	///
739	/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
740	/// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
741	pub fn create_refund_builder<ES: Deref>(
742		&self, entropy_source: ES, amount_msats: u64, absolute_expiry: Duration,
743		payment_id: PaymentId, peers: Vec<MessageForwardNode>,
744	) -> Result<RefundBuilder<'_, secp256k1::All>, Bolt12SemanticError>
745	where
746		ES::Target: EntropySource,
747	{
748		self.create_refund_builder_intern(
749			&*entropy_source,
750			|_, context, _| {
751				self.create_blinded_paths(peers, context)
752					.map(|paths| paths.into_iter().take(1))
753					.map_err(|_| Bolt12SemanticError::MissingPaths)
754			},
755			amount_msats,
756			absolute_expiry,
757			payment_id,
758		)
759	}
760
761	/// Same as [`Self::create_refund_builder`] but allows specifying a custom [`MessageRouter`]
762	/// instead of using the one provided via the [`OffersMessageFlow`] parameterization.
763	///
764	/// This gives users full control over how the [`BlindedMessagePath`] is constructed,
765	/// including the option to omit it entirely.
766	///
767	/// See [`Self::create_refund_builder`] for more details on usage.
768	///
769	/// # Errors
770	///
771	/// In addition to the errors documented in [`Self::create_refund_builder`], this method will
772	/// return an error if the provided [`MessageRouter`] fails to construct a valid
773	/// [`BlindedMessagePath`] for the refund.
774	///
775	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
776	///
777	/// [`Refund`]: crate::offers::refund::Refund
778	/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
779	/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
780	/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
781	/// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
782	pub fn create_refund_builder_using_router<ES: Deref, ME: Deref>(
783		&self, router: ME, entropy_source: ES, amount_msats: u64, absolute_expiry: Duration,
784		payment_id: PaymentId, peers: Vec<MessageForwardNode>,
785	) -> Result<RefundBuilder<'_, secp256k1::All>, Bolt12SemanticError>
786	where
787		ME::Target: MessageRouter,
788		ES::Target: EntropySource,
789	{
790		let receive_key = self.get_receive_auth_key();
791		self.create_refund_builder_intern(
792			&*entropy_source,
793			|node_id, context, secp_ctx| {
794				router
795					.create_blinded_paths(node_id, receive_key, context, peers, secp_ctx)
796					.map(|paths| paths.into_iter().take(1))
797					.map_err(|_| Bolt12SemanticError::MissingPaths)
798			},
799			amount_msats,
800			absolute_expiry,
801			payment_id,
802		)
803	}
804
805	/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized
806	/// by the [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received in response
807	/// can be verified using [`Self::verify_bolt12_invoice`].
808	///
809	/// # Nonce
810	/// The nonce is used to create a unique [`InvoiceRequest::payer_metadata`] for the invoice request.
811	/// These will be used to verify the corresponding [`Bolt12Invoice`] when it is received.
812	///
813	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
814	pub fn create_invoice_request_builder<'a>(
815		&'a self, offer: &'a Offer, nonce: Nonce, payment_id: PaymentId,
816	) -> Result<InvoiceRequestBuilder<'a, 'a, secp256k1::All>, Bolt12SemanticError> {
817		let expanded_key = &self.inbound_payment_key;
818		let secp_ctx = &self.secp_ctx;
819
820		let builder: InvoiceRequestBuilder<secp256k1::All> =
821			offer.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?.into();
822		let builder = builder.chain_hash(self.chain_hash)?;
823
824		Ok(builder)
825	}
826
827	/// Creates a [`StaticInvoiceBuilder`] from the corresponding [`Offer`] and [`Nonce`] that were
828	/// created via [`Self::create_async_receive_offer_builder`].
829	///
830	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
831	pub fn create_static_invoice_builder<'a, ES: Deref, R: Deref>(
832		&self, router: &R, entropy_source: ES, offer: &'a Offer, offer_nonce: Nonce,
833		payment_secret: PaymentSecret, relative_expiry_secs: u32,
834		usable_channels: Vec<ChannelDetails>, peers: Vec<MessageForwardNode>,
835	) -> Result<StaticInvoiceBuilder<'a>, Bolt12SemanticError>
836	where
837		ES::Target: EntropySource,
838		R::Target: Router,
839	{
840		let expanded_key = &self.inbound_payment_key;
841		let entropy = &*entropy_source;
842		let secp_ctx = &self.secp_ctx;
843
844		let payment_context =
845			PaymentContext::AsyncBolt12Offer(AsyncBolt12OfferContext { offer_nonce });
846
847		let amount_msat = offer.amount().and_then(|amount| match amount {
848			Amount::Bitcoin { amount_msats } => Some(amount_msats),
849			Amount::Currency { .. } => None,
850		});
851
852		let created_at = self.duration_since_epoch();
853
854		let payment_paths = self
855			.create_blinded_payment_paths(
856				router,
857				entropy,
858				usable_channels,
859				amount_msat,
860				payment_secret,
861				payment_context,
862				relative_expiry_secs,
863			)
864			.map_err(|()| Bolt12SemanticError::MissingPaths)?;
865
866		let path_absolute_expiry = Duration::from_secs(inbound_payment::calculate_absolute_expiry(
867			created_at.as_secs(),
868			relative_expiry_secs,
869		));
870
871		let context = MessageContext::AsyncPayments(AsyncPaymentsContext::InboundPayment {
872			path_absolute_expiry,
873		});
874
875		let async_receive_message_paths = self
876			.create_blinded_paths(peers, context)
877			.map_err(|()| Bolt12SemanticError::MissingPaths)?;
878
879		StaticInvoiceBuilder::for_offer_using_derived_keys(
880			offer,
881			payment_paths,
882			async_receive_message_paths,
883			created_at,
884			expanded_key,
885			offer_nonce,
886			secp_ctx,
887		)
888		.map(|inv| inv.allow_mpp().relative_expiry(relative_expiry_secs))
889	}
890
891	/// Creates an [`InvoiceBuilder`] using the provided [`Refund`].
892	///
893	/// This method is used when a node wishes to construct an [`InvoiceBuilder`]
894	/// in response to a [`Refund`] request as part of a BOLT 12 flow.
895	///
896	/// Returns an `InvoiceBuilder` configured with:
897	/// - Blinded payment paths created using the parameterized [`Router`], with the provided
898	///   `payment_secret` included in the path payloads.
899	/// - The given `payment_hash` and `payment_secret`, enabling secure claim verification.
900	///
901	/// Returns an error if the refund targets a different chain or if no valid
902	/// blinded path can be constructed.
903	///
904	/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
905	pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref>(
906		&'a self, router: &R, entropy_source: ES, refund: &'a Refund, payment_hash: PaymentHash,
907		payment_secret: PaymentSecret, usable_channels: Vec<ChannelDetails>,
908	) -> Result<InvoiceBuilder<'a, DerivedSigningPubkey>, Bolt12SemanticError>
909	where
910		ES::Target: EntropySource,
911		R::Target: Router,
912	{
913		if refund.chain() != self.chain_hash {
914			return Err(Bolt12SemanticError::UnsupportedChain);
915		}
916
917		let expanded_key = &self.inbound_payment_key;
918		let entropy = &*entropy_source;
919
920		let amount_msats = refund.amount_msats();
921		let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
922
923		let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
924		let payment_paths = self
925			.create_blinded_payment_paths(
926				router,
927				entropy,
928				usable_channels,
929				Some(amount_msats),
930				payment_secret,
931				payment_context,
932				relative_expiry,
933			)
934			.map_err(|_| Bolt12SemanticError::MissingPaths)?;
935
936		#[cfg(feature = "std")]
937		let builder = refund.respond_using_derived_keys(
938			payment_paths,
939			payment_hash,
940			expanded_key,
941			entropy,
942		)?;
943
944		#[cfg(not(feature = "std"))]
945		let created_at = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
946		#[cfg(not(feature = "std"))]
947		let builder = refund.respond_using_derived_keys_no_std(
948			payment_paths,
949			payment_hash,
950			created_at,
951			expanded_key,
952			entropy,
953		)?;
954
955		Ok(builder.into())
956	}
957
958	/// Creates a response for the provided [`VerifiedInvoiceRequest`].
959	///
960	/// A response can be either an [`OffersMessage::Invoice`] with additional [`MessageContext`],
961	/// or an [`OffersMessage::InvoiceError`], depending on the [`InvoiceRequest`].
962	///
963	/// An [`OffersMessage::InvoiceError`] will be generated if:
964	/// - We fail to generate valid payment paths to include in the [`Bolt12Invoice`].
965	/// - We fail to generate a valid signed [`Bolt12Invoice`] for the [`InvoiceRequest`].
966	pub fn create_response_for_invoice_request<ES: Deref, NS: Deref, R: Deref>(
967		&self, signer: &NS, router: &R, entropy_source: ES,
968		invoice_request: VerifiedInvoiceRequest, amount_msats: u64, payment_hash: PaymentHash,
969		payment_secret: PaymentSecret, usable_channels: Vec<ChannelDetails>,
970	) -> (OffersMessage, Option<MessageContext>)
971	where
972		ES::Target: EntropySource,
973		NS::Target: NodeSigner,
974		R::Target: Router,
975	{
976		let entropy = &*entropy_source;
977		let secp_ctx = &self.secp_ctx;
978
979		let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
980
981		let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
982			offer_id: invoice_request.offer_id,
983			invoice_request: invoice_request.fields(),
984		});
985
986		let payment_paths = match self.create_blinded_payment_paths(
987			router,
988			entropy,
989			usable_channels,
990			Some(amount_msats),
991			payment_secret,
992			context,
993			relative_expiry,
994		) {
995			Ok(paths) => paths,
996			Err(_) => {
997				let error = InvoiceError::from(Bolt12SemanticError::MissingPaths);
998				return (OffersMessage::InvoiceError(error.into()), None);
999			},
1000		};
1001
1002		#[cfg(not(feature = "std"))]
1003		let created_at = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
1004
1005		let response = if invoice_request.keys.is_some() {
1006			#[cfg(feature = "std")]
1007			let builder = invoice_request.respond_using_derived_keys(payment_paths, payment_hash);
1008			#[cfg(not(feature = "std"))]
1009			let builder = invoice_request.respond_using_derived_keys_no_std(
1010				payment_paths,
1011				payment_hash,
1012				created_at,
1013			);
1014			builder
1015				.map(InvoiceBuilder::<DerivedSigningPubkey>::from)
1016				.and_then(|builder| builder.allow_mpp().build_and_sign(secp_ctx))
1017				.map_err(InvoiceError::from)
1018		} else {
1019			#[cfg(feature = "std")]
1020			let builder = invoice_request.respond_with(payment_paths, payment_hash);
1021			#[cfg(not(feature = "std"))]
1022			let builder = invoice_request.respond_with_no_std(payment_paths, payment_hash, created_at);
1023			builder
1024				.map(InvoiceBuilder::<ExplicitSigningPubkey>::from)
1025				.and_then(|builder| builder.allow_mpp().build())
1026				.map_err(InvoiceError::from)
1027				.and_then(|invoice| {
1028					#[cfg(c_bindings)]
1029					let mut invoice = invoice;
1030					invoice
1031						.sign(|invoice: &UnsignedBolt12Invoice| signer.sign_bolt12_invoice(invoice))
1032						.map_err(InvoiceError::from)
1033				})
1034		};
1035
1036		match response {
1037			Ok(invoice) => {
1038				let context =
1039					MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
1040
1041				(OffersMessage::Invoice(invoice), Some(context))
1042			},
1043			Err(error) => (OffersMessage::InvoiceError(error.into()), None),
1044		}
1045	}
1046
1047	/// Enqueues the created [`InvoiceRequest`] to be sent to the counterparty.
1048	///
1049	/// # Payment
1050	///
1051	/// The provided `payment_id` is used to create a unique [`MessageContext`] for the
1052	/// blinded paths sent to the counterparty. This allows them to respond with an invoice,
1053	/// over those blinded paths, which can be verified against the intended outbound payment,
1054	/// ensuring the invoice corresponds to a payment we actually want to make.
1055	///
1056	/// # Nonce
1057	/// The nonce is used to create a unique [`MessageContext`] for the reply paths.
1058	/// These will be used to verify the corresponding [`Bolt12Invoice`] when it is received.
1059	///
1060	/// Note: The provided [`Nonce`] MUST be the same as the [`Nonce`] used for creating the
1061	/// [`InvoiceRequest`] to ensure correct verification of the corresponding [`Bolt12Invoice`].
1062	///
1063	/// See [`OffersMessageFlow::create_invoice_request_builder`] for more details.
1064	///
1065	/// # Peers
1066	///
1067	/// The user must provide a list of [`MessageForwardNode`] that will be used to generate
1068	/// valid reply paths for the counterparty to send back the corresponding [`Bolt12Invoice`]
1069	/// or [`InvoiceError`].
1070	///
1071	/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1072	pub fn enqueue_invoice_request(
1073		&self, invoice_request: InvoiceRequest, payment_id: PaymentId, nonce: Nonce,
1074		peers: Vec<MessageForwardNode>,
1075	) -> Result<(), Bolt12SemanticError> {
1076		let context = MessageContext::Offers(OffersContext::OutboundPayment { payment_id, nonce });
1077		let reply_paths = self
1078			.create_blinded_paths(peers, context)
1079			.map_err(|_| Bolt12SemanticError::MissingPaths)?;
1080
1081		let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1082		if !invoice_request.paths().is_empty() {
1083			let message = OffersMessage::InvoiceRequest(invoice_request.clone());
1084			enqueue_onion_message_with_reply_paths(
1085				message,
1086				invoice_request.paths(),
1087				reply_paths,
1088				&mut pending_offers_messages,
1089			);
1090		} else if let Some(node_id) = invoice_request.issuer_signing_pubkey() {
1091			for reply_path in reply_paths {
1092				let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1093					destination: Destination::Node(node_id),
1094					reply_path,
1095				};
1096				let message = OffersMessage::InvoiceRequest(invoice_request.clone());
1097				pending_offers_messages.push((message, instructions));
1098			}
1099		} else {
1100			debug_assert!(false);
1101			return Err(Bolt12SemanticError::MissingIssuerSigningPubkey);
1102		}
1103
1104		Ok(())
1105	}
1106
1107	/// Enqueues the created [`Bolt12Invoice`] corresponding to a [`Refund`] to be sent
1108	/// to the counterparty.
1109	///
1110	/// # Peers
1111	///
1112	/// The user must provide a list of [`MessageForwardNode`] that will be used to generate valid
1113	/// reply paths for the counterparty to send back the corresponding [`InvoiceError`] if we fail
1114	/// to create blinded reply paths
1115	///
1116	/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1117	pub fn enqueue_invoice(
1118		&self, invoice: Bolt12Invoice, refund: &Refund, peers: Vec<MessageForwardNode>,
1119	) -> Result<(), Bolt12SemanticError> {
1120		let payment_hash = invoice.payment_hash();
1121
1122		let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
1123
1124		let reply_paths = self
1125			.create_blinded_paths(peers, context)
1126			.map_err(|_| Bolt12SemanticError::MissingPaths)?;
1127
1128		let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1129
1130		if refund.paths().is_empty() {
1131			for reply_path in reply_paths {
1132				let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1133					destination: Destination::Node(refund.payer_signing_pubkey()),
1134					reply_path,
1135				};
1136				let message = OffersMessage::Invoice(invoice.clone());
1137				pending_offers_messages.push((message, instructions));
1138			}
1139		} else {
1140			let message = OffersMessage::Invoice(invoice);
1141			enqueue_onion_message_with_reply_paths(
1142				message,
1143				refund.paths(),
1144				reply_paths,
1145				&mut pending_offers_messages,
1146			);
1147		}
1148
1149		Ok(())
1150	}
1151
1152	/// Forwards a [`StaticInvoice`] over the provided [`Responder`] in response to an
1153	/// [`InvoiceRequest`] that we as a static invoice server received on behalf of an often-offline
1154	/// recipient.
1155	pub fn enqueue_static_invoice(
1156		&self, invoice: StaticInvoice, responder: Responder,
1157	) -> Result<(), Bolt12SemanticError> {
1158		let duration_since_epoch = self.duration_since_epoch();
1159		if invoice.is_expired_no_std(duration_since_epoch) {
1160			return Err(Bolt12SemanticError::AlreadyExpired);
1161		}
1162		if invoice.is_offer_expired_no_std(duration_since_epoch) {
1163			return Err(Bolt12SemanticError::AlreadyExpired);
1164		}
1165
1166		let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1167		let message = OffersMessage::StaticInvoice(invoice);
1168		pending_offers_messages.push((message, responder.respond().into_instructions()));
1169
1170		Ok(())
1171	}
1172
1173	/// Forwards an [`InvoiceRequest`] to the specified [`BlindedMessagePath`]. If we receive an
1174	/// invoice request as a static invoice server on behalf of an often-offline recipient this
1175	/// can be used to forward the request to give the recipient a chance to provide an
1176	/// invoice if the recipient is online. The reply_path [`Responder`] provided is the path to
1177	/// the sender where the recipient can send the invoice.
1178	///
1179	/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
1180	/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
1181	/// [`Responder`]: crate::onion_message::messenger::Responder
1182	pub fn enqueue_invoice_request_to_forward(
1183		&self, invoice_request: InvoiceRequest, destination: BlindedMessagePath,
1184		reply_path: Responder,
1185	) {
1186		let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1187		let message = OffersMessage::InvoiceRequest(invoice_request);
1188		let instructions = MessageSendInstructions::ForwardedMessage {
1189			destination: Destination::BlindedPath(destination),
1190			reply_path: Some(reply_path.into_blinded_path()),
1191		};
1192		pending_offers_messages.push((message, instructions));
1193	}
1194
1195	/// Enqueues `held_htlc_available` onion messages to be sent to the payee via the reply paths
1196	/// contained within the provided [`StaticInvoice`].
1197	///
1198	/// [`ReleaseHeldHtlc`]: crate::onion_message::async_payments::ReleaseHeldHtlc
1199	/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1200	pub fn enqueue_held_htlc_available(
1201		&self, invoice: &StaticInvoice, reply_path_params: HeldHtlcReplyPath,
1202	) -> Result<(), Bolt12SemanticError> {
1203		let reply_path_terminates_at_us =
1204			matches!(reply_path_params, HeldHtlcReplyPath::ToUs { .. });
1205
1206		let reply_paths = match reply_path_params {
1207			HeldHtlcReplyPath::ToUs { payment_id, peers } => {
1208				let context =
1209					MessageContext::AsyncPayments(AsyncPaymentsContext::OutboundPayment {
1210						payment_id,
1211					});
1212				self.create_blinded_paths(peers, context)
1213					.map_err(|_| {
1214						log_trace!(self.logger, "Failed to create blinded paths when enqueueing held_htlc_available message");
1215						Bolt12SemanticError::MissingPaths
1216					})?
1217			},
1218			HeldHtlcReplyPath::ToCounterparty { path } => vec![path],
1219		};
1220
1221		log_trace!(
1222			self.logger,
1223			"Sending held_htlc_available message for async HTLC, with reply_path terminating at {}",
1224			if reply_path_terminates_at_us { "our node" } else { "our always-online counterparty" }
1225		);
1226		let mut pending_async_payments_messages =
1227			self.pending_async_payments_messages.lock().unwrap();
1228		let message = AsyncPaymentsMessage::HeldHtlcAvailable(HeldHtlcAvailable {});
1229		enqueue_onion_message_with_reply_paths(
1230			message,
1231			invoice.message_paths(),
1232			reply_paths,
1233			&mut pending_async_payments_messages,
1234		);
1235
1236		Ok(())
1237	}
1238
1239	/// If we are holding an HTLC on behalf of an often-offline sender, this method allows us to
1240	/// create a path for the sender to use as the reply path when they send the recipient a
1241	/// [`HeldHtlcAvailable`] onion message, so the recipient's [`ReleaseHeldHtlc`] response will be
1242	/// received to our node.
1243	///
1244	/// [`ReleaseHeldHtlc`]: crate::onion_message::async_payments::ReleaseHeldHtlc
1245	pub fn path_for_release_held_htlc<ES: Deref>(
1246		&self, intercept_id: InterceptId, prev_outbound_scid_alias: u64, htlc_id: u64, entropy: ES,
1247	) -> BlindedMessagePath
1248	where
1249		ES::Target: EntropySource,
1250	{
1251		// In the future, we should support multi-hop paths here.
1252		let context = MessageContext::AsyncPayments(AsyncPaymentsContext::ReleaseHeldHtlc {
1253			intercept_id,
1254			prev_outbound_scid_alias,
1255			htlc_id,
1256		});
1257		let num_dummy_hops = PADDED_PATH_LENGTH.saturating_sub(1);
1258		BlindedMessagePath::new_with_dummy_hops(
1259			&[],
1260			self.get_our_node_id(),
1261			num_dummy_hops,
1262			self.receive_auth_key,
1263			context,
1264			&*entropy,
1265			&self.secp_ctx,
1266		)
1267	}
1268
1269	/// Enqueues the created [`DNSSECQuery`] to be sent to the counterparty.
1270	///
1271	/// # Peers
1272	///
1273	/// The user must provide a list of [`MessageForwardNode`] that will be used to generate
1274	/// valid reply paths for the counterparty to send back the corresponding response for
1275	/// the [`DNSSECQuery`] message.
1276	///
1277	/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1278	#[cfg(feature = "dnssec")]
1279	pub fn enqueue_dns_onion_message(
1280		&self, message: DNSSECQuery, context: DNSResolverContext, dns_resolvers: Vec<Destination>,
1281		peers: Vec<MessageForwardNode>,
1282	) -> Result<(), Bolt12SemanticError> {
1283		let reply_paths = self
1284			.create_blinded_paths(peers, MessageContext::DNSResolver(context))
1285			.map_err(|_| Bolt12SemanticError::MissingPaths)?;
1286
1287		let message_params = dns_resolvers
1288			.iter()
1289			.flat_map(|destination| reply_paths.iter().map(move |path| (path, destination)))
1290			.take(OFFERS_MESSAGE_REQUEST_LIMIT);
1291		for (reply_path, destination) in message_params {
1292			self.pending_dns_onion_messages.lock().unwrap().push((
1293				DNSResolverMessage::DNSSECQuery(message.clone()),
1294				MessageSendInstructions::WithSpecifiedReplyPath {
1295					destination: destination.clone(),
1296					reply_path: reply_path.clone(),
1297				},
1298			));
1299		}
1300
1301		Ok(())
1302	}
1303
1304	/// Gets the enqueued [`OffersMessage`] with their corresponding [`MessageSendInstructions`].
1305	pub fn release_pending_offers_messages(&self) -> Vec<(OffersMessage, MessageSendInstructions)> {
1306		core::mem::take(&mut self.pending_offers_messages.lock().unwrap())
1307	}
1308
1309	/// Gets the enqueued [`AsyncPaymentsMessage`] with their corresponding [`MessageSendInstructions`].
1310	pub fn release_pending_async_messages(
1311		&self,
1312	) -> Vec<(AsyncPaymentsMessage, MessageSendInstructions)> {
1313		core::mem::take(&mut self.pending_async_payments_messages.lock().unwrap())
1314	}
1315
1316	/// Gets the enqueued [`DNSResolverMessage`] with their corresponding [`MessageSendInstructions`].
1317	#[cfg(feature = "dnssec")]
1318	pub fn release_pending_dns_messages(
1319		&self,
1320	) -> Vec<(DNSResolverMessage, MessageSendInstructions)> {
1321		core::mem::take(&mut self.pending_dns_onion_messages.lock().unwrap())
1322	}
1323
1324	/// Retrieve an [`Offer`] for receiving async payments as an often-offline recipient. Will only
1325	/// return an offer if [`Self::set_paths_to_static_invoice_server`] was called and we succeeded in
1326	/// interactively building a [`StaticInvoice`] with the static invoice server.
1327	///
1328	/// Returns the requested offer as well as a bool indicating whether the cache needs to be
1329	/// persisted using [`Self::writeable_async_receive_offer_cache`].
1330	pub fn get_async_receive_offer(&self) -> Result<(Offer, bool), ()> {
1331		let mut cache = self.async_receive_offer_cache.lock().unwrap();
1332		cache.get_async_receive_offer(self.duration_since_epoch())
1333	}
1334
1335	#[cfg(test)]
1336	pub(crate) fn test_get_async_receive_offers(&self) -> Vec<Offer> {
1337		self.async_receive_offer_cache.lock().unwrap().test_get_payable_offers()
1338	}
1339
1340	/// Sends out [`OfferPathsRequest`] and [`ServeStaticInvoice`] onion messages if we are an
1341	/// often-offline recipient and are configured to interactively build offers and static invoices
1342	/// with a static invoice server.
1343	///
1344	/// # Usage
1345	///
1346	/// This method should be called on peer connection and once per minute or so, to keep the offers
1347	/// cache updated. When calling this method once per minute, SHOULD set `timer_tick_occurred` so
1348	/// the cache can self-regulate the number of messages sent out.
1349	///
1350	/// Errors if we failed to create blinded reply paths when sending an [`OfferPathsRequest`] message.
1351	pub fn check_refresh_async_receive_offer_cache<ES: Deref, R: Deref>(
1352		&self, peers: Vec<MessageForwardNode>, usable_channels: Vec<ChannelDetails>, entropy: ES,
1353		router: R, timer_tick_occurred: bool,
1354	) -> Result<(), ()>
1355	where
1356		ES::Target: EntropySource,
1357		R::Target: Router,
1358	{
1359		// Terminate early if this node does not intend to receive async payments.
1360		{
1361			let cache = self.async_receive_offer_cache.lock().unwrap();
1362			if cache.paths_to_static_invoice_server().is_empty() {
1363				return Ok(());
1364			}
1365		}
1366
1367		self.check_refresh_async_offers(peers.clone(), timer_tick_occurred)?;
1368
1369		if timer_tick_occurred {
1370			self.check_refresh_static_invoices(peers, usable_channels, entropy, router);
1371		}
1372
1373		Ok(())
1374	}
1375
1376	fn check_refresh_async_offers(
1377		&self, peers: Vec<MessageForwardNode>, timer_tick_occurred: bool,
1378	) -> Result<(), ()> {
1379		let duration_since_epoch = self.duration_since_epoch();
1380		let mut cache = self.async_receive_offer_cache.lock().unwrap();
1381
1382		// Update the cache to remove expired offers, and check to see whether we need new offers to be
1383		// interactively built with the static invoice server.
1384		let needs_new_offer_slot =
1385			match cache.prune_expired_offers(duration_since_epoch, timer_tick_occurred) {
1386				Some(idx) => idx,
1387				None => return Ok(()),
1388			};
1389
1390		// If we need new offers, send out offer paths request messages to the static invoice server.
1391		let context = MessageContext::AsyncPayments(AsyncPaymentsContext::OfferPaths {
1392			path_absolute_expiry: duration_since_epoch
1393				.saturating_add(TEMP_REPLY_PATH_RELATIVE_EXPIRY),
1394			invoice_slot: needs_new_offer_slot,
1395		});
1396		let reply_paths = match self.create_blinded_paths(peers, context) {
1397			Ok(paths) => paths,
1398			Err(()) => {
1399				log_error!(
1400					self.logger,
1401					"Failed to create blinded paths for OfferPathsRequest message"
1402				);
1403				return Err(());
1404			},
1405		};
1406
1407		// We can't fail past this point, so indicate to the cache that we've requested new offers.
1408		cache.new_offers_requested();
1409
1410		let mut pending_async_payments_messages =
1411			self.pending_async_payments_messages.lock().unwrap();
1412		let message = AsyncPaymentsMessage::OfferPathsRequest(OfferPathsRequest {
1413			invoice_slot: needs_new_offer_slot,
1414		});
1415		enqueue_onion_message_with_reply_paths(
1416			message,
1417			cache.paths_to_static_invoice_server(),
1418			reply_paths,
1419			&mut pending_async_payments_messages,
1420		);
1421
1422		Ok(())
1423	}
1424
1425	/// Enqueue onion messages that will used to request invoice refresh from the static invoice
1426	/// server, based on the offers provided by the cache.
1427	fn check_refresh_static_invoices<ES: Deref, R: Deref>(
1428		&self, peers: Vec<MessageForwardNode>, usable_channels: Vec<ChannelDetails>, entropy: ES,
1429		router: R,
1430	) where
1431		ES::Target: EntropySource,
1432		R::Target: Router,
1433	{
1434		let mut serve_static_invoice_msgs = Vec::new();
1435		{
1436			let duration_since_epoch = self.duration_since_epoch();
1437			let cache = self.async_receive_offer_cache.lock().unwrap();
1438			for offer_and_metadata in cache.offers_needing_invoice_refresh(duration_since_epoch) {
1439				let (offer, offer_nonce, update_static_invoice_path) = offer_and_metadata;
1440
1441				let (invoice, forward_invreq_path) = match self.create_static_invoice_for_server(
1442					offer,
1443					offer_nonce,
1444					peers.clone(),
1445					usable_channels.clone(),
1446					&*entropy,
1447					&*router,
1448				) {
1449					Ok((invoice, path)) => (invoice, path),
1450					Err(()) => continue,
1451				};
1452
1453				let reply_path_context = {
1454					MessageContext::AsyncPayments(AsyncPaymentsContext::StaticInvoicePersisted {
1455						invoice_created_at: invoice.created_at(),
1456						offer_id: offer.id(),
1457					})
1458				};
1459
1460				let serve_invoice_message = ServeStaticInvoice {
1461					invoice,
1462					forward_invoice_request_path: forward_invreq_path,
1463				};
1464				serve_static_invoice_msgs.push((
1465					serve_invoice_message,
1466					update_static_invoice_path.clone(),
1467					reply_path_context,
1468				));
1469			}
1470		}
1471
1472		// Enqueue the new serve_static_invoice messages in a separate loop to avoid holding the offer
1473		// cache lock and the pending_async_payments_messages lock at the same time.
1474		for (serve_invoice_msg, serve_invoice_path, reply_path_ctx) in serve_static_invoice_msgs {
1475			let reply_paths = match self.create_blinded_paths(peers.clone(), reply_path_ctx) {
1476				Ok(paths) => paths,
1477				Err(()) => continue,
1478			};
1479
1480			let message = AsyncPaymentsMessage::ServeStaticInvoice(serve_invoice_msg);
1481			enqueue_onion_message_with_reply_paths(
1482				message,
1483				&[serve_invoice_path.into_blinded_path()],
1484				reply_paths,
1485				&mut self.pending_async_payments_messages.lock().unwrap(),
1486			);
1487		}
1488	}
1489
1490	/// Handles an incoming [`OfferPathsRequest`] onion message from an often-offline recipient who
1491	/// wants us (the static invoice server) to serve [`StaticInvoice`]s to payers on their behalf.
1492	/// Sends out [`OfferPaths`] onion messages in response.
1493	pub fn handle_offer_paths_request(
1494		&self, request: &OfferPathsRequest, context: AsyncPaymentsContext,
1495		peers: Vec<MessageForwardNode>,
1496	) -> Option<(OfferPaths, MessageContext)> {
1497		let duration_since_epoch = self.duration_since_epoch();
1498
1499		let recipient_id = match context {
1500			AsyncPaymentsContext::OfferPathsRequest { recipient_id, path_absolute_expiry } => {
1501				if duration_since_epoch > path_absolute_expiry.unwrap_or(Duration::MAX) {
1502					return None;
1503				}
1504				recipient_id
1505			},
1506			_ => return None,
1507		};
1508
1509		// Create the blinded paths that will be included in the async recipient's offer.
1510		let (offer_paths, paths_expiry) = {
1511			let path_absolute_expiry =
1512				duration_since_epoch.saturating_add(DEFAULT_ASYNC_RECEIVE_OFFER_EXPIRY);
1513			let context = MessageContext::Offers(OffersContext::StaticInvoiceRequested {
1514				recipient_id: recipient_id.clone(),
1515				path_absolute_expiry,
1516				invoice_slot: request.invoice_slot,
1517			});
1518
1519			match self.create_blinded_paths(peers, context) {
1520				Ok(paths) => (paths, path_absolute_expiry),
1521				Err(()) => {
1522					log_error!(
1523						self.logger,
1524						"Failed to create blinded paths for OfferPaths message"
1525					);
1526					return None;
1527				},
1528			}
1529		};
1530
1531		// Create a reply path so that the recipient can respond to our offer_paths message with the
1532		// static invoice that they create. This path will also be used by the recipient to update said
1533		// invoice.
1534		let reply_path_context = {
1535			let path_absolute_expiry =
1536				duration_since_epoch.saturating_add(DEFAULT_ASYNC_RECEIVE_OFFER_EXPIRY);
1537			MessageContext::AsyncPayments(AsyncPaymentsContext::ServeStaticInvoice {
1538				recipient_id,
1539				invoice_slot: request.invoice_slot,
1540				path_absolute_expiry,
1541			})
1542		};
1543
1544		let offer_paths_om =
1545			OfferPaths { paths: offer_paths, paths_absolute_expiry: Some(paths_expiry.as_secs()) };
1546		return Some((offer_paths_om, reply_path_context));
1547	}
1548
1549	/// Handles an incoming [`OfferPaths`] message from the static invoice server, sending out
1550	/// [`ServeStaticInvoice`] onion messages in response if we've built a new async receive offer and
1551	/// need the corresponding [`StaticInvoice`] to be persisted by the static invoice server.
1552	///
1553	/// Returns `None` if we have enough offers cached already, verification of `message` fails, or we
1554	/// fail to create blinded paths.
1555	pub fn handle_offer_paths<ES: Deref, R: Deref>(
1556		&self, message: OfferPaths, context: AsyncPaymentsContext, responder: Responder,
1557		peers: Vec<MessageForwardNode>, usable_channels: Vec<ChannelDetails>, entropy: ES,
1558		router: R,
1559	) -> Option<(ServeStaticInvoice, MessageContext)>
1560	where
1561		ES::Target: EntropySource,
1562		R::Target: Router,
1563	{
1564		let duration_since_epoch = self.duration_since_epoch();
1565		let invoice_slot = match context {
1566			AsyncPaymentsContext::OfferPaths { invoice_slot, path_absolute_expiry } => {
1567				if duration_since_epoch > path_absolute_expiry {
1568					return None;
1569				}
1570				invoice_slot
1571			},
1572			_ => return None,
1573		};
1574
1575		{
1576			// Only respond with `ServeStaticInvoice` if we actually need a new offer built.
1577			let mut cache = self.async_receive_offer_cache.lock().unwrap();
1578			cache.prune_expired_offers(duration_since_epoch, false);
1579			if !cache.should_build_offer_with_paths(
1580				&message.paths[..],
1581				message.paths_absolute_expiry,
1582				invoice_slot,
1583				duration_since_epoch,
1584			) {
1585				return None;
1586			}
1587		}
1588
1589		let (mut offer_builder, offer_nonce) =
1590			match self.create_async_receive_offer_builder(&*entropy, message.paths) {
1591				Ok((builder, nonce)) => (builder, nonce),
1592				Err(_) => return None, // Only reachable if OfferPaths::paths is empty
1593			};
1594		if let Some(paths_absolute_expiry) = message.paths_absolute_expiry {
1595			offer_builder =
1596				offer_builder.absolute_expiry(Duration::from_secs(paths_absolute_expiry));
1597		}
1598		let (offer_id, offer) = match offer_builder.build() {
1599			Ok(offer) => (offer.id(), offer),
1600			Err(_) => {
1601				log_error!(self.logger, "Failed to build async receive offer");
1602				debug_assert!(false);
1603				return None;
1604			},
1605		};
1606
1607		let (invoice, forward_invoice_request_path) = match self.create_static_invoice_for_server(
1608			&offer,
1609			offer_nonce,
1610			peers,
1611			usable_channels,
1612			&*entropy,
1613			router,
1614		) {
1615			Ok(res) => res,
1616			Err(()) => {
1617				log_error!(self.logger, "Failed to create static invoice for server");
1618				return None;
1619			},
1620		};
1621
1622		if let Err(()) = self.async_receive_offer_cache.lock().unwrap().cache_pending_offer(
1623			offer,
1624			message.paths_absolute_expiry,
1625			offer_nonce,
1626			responder,
1627			duration_since_epoch,
1628			invoice_slot,
1629		) {
1630			log_error!(self.logger, "Failed to cache pending offer");
1631			return None;
1632		}
1633
1634		let reply_path_context = {
1635			MessageContext::AsyncPayments(AsyncPaymentsContext::StaticInvoicePersisted {
1636				offer_id,
1637				invoice_created_at: invoice.created_at(),
1638			})
1639		};
1640
1641		let serve_invoice_message = ServeStaticInvoice { invoice, forward_invoice_request_path };
1642		Some((serve_invoice_message, reply_path_context))
1643	}
1644
1645	/// Creates a [`StaticInvoice`] and a blinded path for the server to forward invoice requests from
1646	/// payers to our node.
1647	fn create_static_invoice_for_server<ES: Deref, R: Deref>(
1648		&self, offer: &Offer, offer_nonce: Nonce, peers: Vec<MessageForwardNode>,
1649		usable_channels: Vec<ChannelDetails>, entropy: ES, router: R,
1650	) -> Result<(StaticInvoice, BlindedMessagePath), ()>
1651	where
1652		ES::Target: EntropySource,
1653		R::Target: Router,
1654	{
1655		let expanded_key = &self.inbound_payment_key;
1656		let duration_since_epoch = self.duration_since_epoch();
1657		let secp_ctx = &self.secp_ctx;
1658
1659		let offer_relative_expiry = offer
1660			.absolute_expiry()
1661			.map(|exp| exp.saturating_sub(duration_since_epoch).as_secs())
1662			.map(|exp_u64| exp_u64.try_into().unwrap_or(u32::MAX))
1663			.unwrap_or(u32::MAX);
1664
1665		// Set the invoice to expire at the same time as the offer. We aim to update this invoice as
1666		// often as possible, so there shouldn't be any reason to have it expire earlier than the
1667		// offer.
1668		let payment_secret = inbound_payment::create_for_spontaneous_payment(
1669			expanded_key,
1670			None, // The async receive offers we create are always amount-less
1671			offer_relative_expiry,
1672			duration_since_epoch.as_secs(),
1673			None,
1674		)?;
1675
1676		let invoice = self
1677			.create_static_invoice_builder(
1678				&router,
1679				&*entropy,
1680				&offer,
1681				offer_nonce,
1682				payment_secret,
1683				offer_relative_expiry,
1684				usable_channels,
1685				peers.clone(),
1686			)
1687			.and_then(|builder| builder.build_and_sign(secp_ctx))
1688			.map_err(|_| ())?;
1689
1690		let context = MessageContext::Offers(OffersContext::InvoiceRequest { nonce: offer_nonce });
1691		let forward_invoice_request_path = self
1692			.create_blinded_paths(peers, context)
1693			.and_then(|paths| paths.into_iter().next().ok_or(()))?;
1694
1695		Ok((invoice, forward_invoice_request_path))
1696	}
1697
1698	/// Verifies an incoming [`ServeStaticInvoice`] onion message from an often-offline recipient who
1699	/// wants us as a static invoice server to serve the [`ServeStaticInvoice::invoice`] to payers on
1700	/// their behalf.
1701	///
1702	/// On success, returns `(recipient_id, invoice_slot)` for use in persisting and later retrieving
1703	/// the static invoice from the database.
1704	///
1705	/// Errors if the [`ServeStaticInvoice::invoice`] is expired or larger than
1706	/// [`MAX_STATIC_INVOICE_SIZE_BYTES`].
1707	///
1708	/// [`ServeStaticInvoice::invoice`]: crate::onion_message::async_payments::ServeStaticInvoice::invoice
1709	pub fn verify_serve_static_invoice_message(
1710		&self, message: &ServeStaticInvoice, context: AsyncPaymentsContext,
1711	) -> Result<(Vec<u8>, u16), ()> {
1712		if message.invoice.is_expired_no_std(self.duration_since_epoch()) {
1713			log_trace!(self.logger, "Received expired StaticInvoice");
1714			return Err(());
1715		}
1716		if message.invoice.serialized_length() > MAX_STATIC_INVOICE_SIZE_BYTES {
1717			return Err(());
1718		}
1719		match context {
1720			AsyncPaymentsContext::ServeStaticInvoice {
1721				recipient_id,
1722				invoice_slot,
1723				path_absolute_expiry,
1724			} => {
1725				if self.duration_since_epoch() > path_absolute_expiry {
1726					log_trace!(self.logger, "Received expired StaticInvoice path");
1727					return Err(());
1728				}
1729
1730				return Ok((recipient_id, invoice_slot));
1731			},
1732			_ => return Err(()),
1733		};
1734	}
1735
1736	/// Indicates that a [`ServeStaticInvoice::invoice`] has been persisted and is ready to be served
1737	/// to payers on behalf of an often-offline recipient. This method must be called after persisting
1738	/// a [`StaticInvoice`] to confirm to the recipient that their corresponding [`Offer`] is ready to
1739	/// receive async payments.
1740	pub fn static_invoice_persisted(&self, responder: Responder) {
1741		let mut pending_async_payments_messages =
1742			self.pending_async_payments_messages.lock().unwrap();
1743		let message = AsyncPaymentsMessage::StaticInvoicePersisted(StaticInvoicePersisted {});
1744		pending_async_payments_messages.push((message, responder.respond().into_instructions()));
1745	}
1746
1747	/// Handles an incoming [`StaticInvoicePersisted`] onion message from the static invoice server.
1748	/// Returns a bool indicating whether the async receive offer cache needs to be re-persisted using
1749	/// [`Self::writeable_async_receive_offer_cache`].
1750	///
1751	/// [`StaticInvoicePersisted`]: crate::onion_message::async_payments::StaticInvoicePersisted
1752	pub fn handle_static_invoice_persisted(&self, context: AsyncPaymentsContext) -> bool {
1753		let mut cache = self.async_receive_offer_cache.lock().unwrap();
1754		cache.static_invoice_persisted(context)
1755	}
1756
1757	/// Get the encoded [`AsyncReceiveOfferCache`] for persistence.
1758	pub fn writeable_async_receive_offer_cache(&self) -> Vec<u8> {
1759		self.async_receive_offer_cache.encode()
1760	}
1761}