@@ -102,6 +102,8 @@ use {
102102 crate::offers::refund::RefundMaybeWithDerivedMetadataBuilder,
103103};
104104
105+ use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, CreationError, Currency, Description, InvoiceBuilder as Bolt11InvoiceBuilder, SignOrCreationError, DEFAULT_EXPIRY_TIME};
106+
105107use alloc::collections::{btree_map, BTreeMap};
106108
107109use crate::io;
@@ -9093,6 +9095,152 @@ where
90939095 self.finish_close_channel(failure);
90949096 }
90959097 }
9098+
9099+ /// Utility for creating a BOLT11 invoice that can be verified by [`ChannelManager`] without
9100+ /// storing any additional state. It achieves this by including a [`PaymentSecret`] in the
9101+ /// invoice which it uses to verify that the invoice has not expired and the payment amount is
9102+ /// sufficient, reproducing the [`PaymentPreimage`] if applicable.
9103+ pub fn create_bolt11_invoice(
9104+ &self, params: Bolt11InvoiceParameters,
9105+ ) -> Result<Bolt11Invoice, SignOrCreationError<()>> {
9106+ let Bolt11InvoiceParameters {
9107+ currency, amount_msats, description, invoice_expiry_delta_secs,
9108+ min_final_cltv_expiry_delta, payment_hash,
9109+ } = params;
9110+
9111+ let currency = match currency {
9112+ Some(currency) => currency,
9113+ None => Network::from_chain_hash(self.chain_hash).map(Into::into).unwrap_or(Currency::Bitcoin),
9114+ };
9115+
9116+ #[cfg(feature = "std")]
9117+ let duration_since_epoch = {
9118+ use std::time::SystemTime;
9119+ SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
9120+ .expect("for the foreseeable future this shouldn't happen")
9121+ };
9122+ #[cfg(not(feature = "std"))]
9123+ let duration_since_epoch =
9124+ Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
9125+
9126+ if let Some(min_final_cltv_expiry_delta) = min_final_cltv_expiry_delta {
9127+ if min_final_cltv_expiry_delta.saturating_add(3) < MIN_FINAL_CLTV_EXPIRY_DELTA {
9128+ return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
9129+ }
9130+ }
9131+
9132+ let (payment_hash, payment_secret) = match payment_hash {
9133+ Some(payment_hash) => {
9134+ let payment_secret = self
9135+ .create_inbound_payment_for_hash(
9136+ payment_hash, amount_msats,
9137+ invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32),
9138+ min_final_cltv_expiry_delta,
9139+ )
9140+ .map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
9141+ (payment_hash, payment_secret)
9142+ },
9143+ None => {
9144+ self
9145+ .create_inbound_payment(
9146+ amount_msats, invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32),
9147+ min_final_cltv_expiry_delta,
9148+ )
9149+ .map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?
9150+ },
9151+ };
9152+
9153+ log_trace!(self.logger, "Creating invoice with payment hash {}", &payment_hash);
9154+
9155+ let invoice = Bolt11InvoiceBuilder::new(currency);
9156+ let invoice = match description {
9157+ Bolt11InvoiceDescription::Direct(description) => invoice.description(description.into_inner().0),
9158+ Bolt11InvoiceDescription::Hash(hash) => invoice.description_hash(hash.0),
9159+ };
9160+
9161+ let mut invoice = invoice
9162+ .duration_since_epoch(duration_since_epoch)
9163+ .payee_pub_key(self.get_our_node_id())
9164+ .payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
9165+ .payment_secret(payment_secret)
9166+ .basic_mpp()
9167+ .min_final_cltv_expiry_delta(
9168+ // Add a buffer of 3 to the delta if present, otherwise use LDK's minimum.
9169+ min_final_cltv_expiry_delta.map(|x| x.saturating_add(3)).unwrap_or(MIN_FINAL_CLTV_EXPIRY_DELTA).into()
9170+ );
9171+
9172+ if let Some(invoice_expiry_delta_secs) = invoice_expiry_delta_secs{
9173+ invoice = invoice.expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
9174+ }
9175+
9176+ if let Some(amount_msats) = amount_msats {
9177+ invoice = invoice.amount_milli_satoshis(amount_msats);
9178+ }
9179+
9180+ let channels = self.list_channels();
9181+ let route_hints = super::invoice_utils::sort_and_filter_channels(channels, amount_msats, &self.logger);
9182+ for hint in route_hints {
9183+ invoice = invoice.private_route(hint);
9184+ }
9185+
9186+ let raw_invoice = invoice.build_raw().map_err(|e| SignOrCreationError::CreationError(e))?;
9187+ let signature = self.node_signer.sign_invoice(&raw_invoice, Recipient::Node);
9188+
9189+ raw_invoice
9190+ .sign(|_| signature)
9191+ .map(|invoice| Bolt11Invoice::from_signed(invoice).unwrap())
9192+ .map_err(|e| SignOrCreationError::SignError(e))
9193+ }
9194+ }
9195+
9196+ /// Parameters used with [`create_bolt11_invoice`].
9197+ ///
9198+ /// [`create_bolt11_invoice`]: ChannelManager::create_bolt11_invoice
9199+ pub struct Bolt11InvoiceParameters {
9200+ /// A BIP-0173 currency. If not set, uses the [`Currency`] for the [`Network`] used when
9201+ /// initializing [`ChannelManager`]. See [`ChainParameters::network`].
9202+ pub currency: Option<Currency>,
9203+
9204+ /// The amount for the invoice, if any.
9205+ pub amount_msats: Option<u64>,
9206+
9207+ /// The description for what the invoice is for, or hash of such description.
9208+ pub description: Bolt11InvoiceDescription,
9209+
9210+ /// The invoice expiration relative to its creation time. If not set, the invoice will expire in
9211+ /// [`DEFAULT_EXPIRY_TIME`] by default.
9212+ ///
9213+ /// The creation time used is the duration since the Unix epoch for `std` builds. For non-`std`
9214+ /// builds, the highest block timestamp seen is used instead.
9215+ pub invoice_expiry_delta_secs: Option<u32>,
9216+
9217+ /// The minimum `cltv_expiry` for the last HTLC in the route. If not set, will use
9218+ /// [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
9219+ ///
9220+ /// If set, must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`], and a three-block buffer will be
9221+ /// added as well to allow for up to a few new block confirmations during routing.
9222+ pub min_final_cltv_expiry_delta: Option<u16>,
9223+
9224+ /// The payment hash used in the invoice. If not set, a payment hash will be generated using a
9225+ /// preimage that can be reproduced by [`ChannelManager`] without storing any state.
9226+ ///
9227+ /// Uses the payment hash if set. This may be useful if you're building an on-chain swap or
9228+ /// involving another protocol where the payment hash is also involved outside the scope of
9229+ /// lightning.
9230+ pub payment_hash: Option<PaymentHash>,
9231+ }
9232+
9233+ impl Default for Bolt11InvoiceParameters {
9234+ fn default() -> Self {
9235+ Self {
9236+ currency: None,
9237+ amount_msats: None,
9238+ description: Bolt11InvoiceDescription::Direct(Description::empty()),
9239+ invoice_expiry_delta_secs: None,
9240+ min_final_cltv_expiry_delta: None,
9241+ payment_hash: None,
9242+ }
9243+ }
90969244}
90979245
90989246macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
0 commit comments