@@ -31,6 +31,7 @@ use bitcoin::secp256k1::Secp256k1;
31
31
use bitcoin::{LockTime, secp256k1, Sequence};
32
32
33
33
use crate::blinded_path::BlindedPath;
34
+ use crate::blinded_path::payment::{PaymentConstraints, ReceiveTlvs};
34
35
use crate::chain;
35
36
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
36
37
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@@ -56,9 +57,10 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
56
57
use crate::ln::outbound_payment;
57
58
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration};
58
59
use crate::ln::wire::Encode;
60
+ use crate::offers::invoice::{BlindedPayInfo, DEFAULT_RELATIVE_EXPIRY};
59
61
use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
60
62
use crate::offers::parse::Bolt12SemanticError;
61
- use crate::offers::refund::RefundBuilder;
63
+ use crate::offers::refund::{Refund, RefundBuilder} ;
62
64
use crate::onion_message::{Destination, OffersMessage, PendingOnionMessage};
63
65
use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, WriteableEcdsaChannelSigner};
64
66
use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
@@ -7445,6 +7447,67 @@ where
7445
7447
Ok(())
7446
7448
}
7447
7449
7450
+ /// Creates a [`Bolt12Invoice`] for a [`Refund`] and enqueues it to be sent via an onion
7451
+ /// message.
7452
+ ///
7453
+ /// The resulting invoice uses a [`PaymentHash`] recognized by the [`ChannelManager`] and a
7454
+ /// [`BlindedPath`] containing the [`PaymentSecret`] needed to reconstruct the corresponding
7455
+ /// [`PaymentPreimage`].
7456
+ ///
7457
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
7458
+ pub fn request_refund_payment(&self, refund: &Refund) -> Result<(), Bolt12SemanticError> {
7459
+ let expanded_key = &self.inbound_payment_key;
7460
+ let entropy = &*self.entropy_source;
7461
+ let secp_ctx = &self.secp_ctx;
7462
+
7463
+ let amount_msats = refund.amount_msats();
7464
+ let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
7465
+
7466
+ match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
7467
+ Ok((payment_hash, payment_secret)) => {
7468
+ let payment_paths = vec![
7469
+ self.create_one_hop_blinded_payment_path(payment_secret),
7470
+ ];
7471
+ #[cfg(not(feature = "no-std"))]
7472
+ let builder = refund.respond_using_derived_keys(
7473
+ payment_paths, payment_hash, expanded_key, entropy
7474
+ )?;
7475
+ #[cfg(feature = "no-std")]
7476
+ let created_at = Duration::from_secs(
7477
+ self.highest_seen_timestamp.load(Ordering::Acquire) as u64
7478
+ );
7479
+ #[cfg(feature = "no-std")]
7480
+ let builder = refund.respond_using_derived_keys_no_std(
7481
+ payment_paths, payment_hash, created_at, expanded_key, entropy
7482
+ )?;
7483
+ let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
7484
+ let reply_path = self.create_one_hop_blinded_path();
7485
+
7486
+ let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
7487
+ if refund.paths().is_empty() {
7488
+ let message = PendingOnionMessage {
7489
+ contents: OffersMessage::Invoice(invoice),
7490
+ destination: Destination::Node(refund.payer_id()),
7491
+ reply_path: Some(reply_path),
7492
+ };
7493
+ pending_offers_messages.push(message);
7494
+ } else {
7495
+ for path in refund.paths() {
7496
+ let message = PendingOnionMessage {
7497
+ contents: OffersMessage::Invoice(invoice.clone()),
7498
+ destination: Destination::BlindedPath(path.clone()),
7499
+ reply_path: Some(reply_path.clone()),
7500
+ };
7501
+ pending_offers_messages.push(message);
7502
+ }
7503
+ }
7504
+
7505
+ Ok(())
7506
+ },
7507
+ Err(()) => Err(Bolt12SemanticError::InvalidAmount),
7508
+ }
7509
+ }
7510
+
7448
7511
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
7449
7512
/// to pay us.
7450
7513
///
@@ -7553,6 +7616,29 @@ where
7553
7616
BlindedPath::one_hop_for_message(self.get_our_node_id(), entropy_source, secp_ctx).unwrap()
7554
7617
}
7555
7618
7619
+ /// Creates a one-hop blinded path with [`ChannelManager::get_our_node_id`] as the introduction
7620
+ /// node.
7621
+ fn create_one_hop_blinded_payment_path(
7622
+ &self, payment_secret: PaymentSecret
7623
+ ) -> (BlindedPayInfo, BlindedPath) {
7624
+ let entropy_source = self.entropy_source.deref();
7625
+ let secp_ctx = &self.secp_ctx;
7626
+
7627
+ let payee_node_id = self.get_our_node_id();
7628
+ let max_cltv_expiry = self.best_block.read().unwrap().height() + LATENCY_GRACE_PERIOD_BLOCKS;
7629
+ let payee_tlvs = ReceiveTlvs {
7630
+ payment_secret,
7631
+ payment_constraints: PaymentConstraints {
7632
+ max_cltv_expiry,
7633
+ htlc_minimum_msat: 1,
7634
+ },
7635
+ };
7636
+ // TODO: Err for overflow?
7637
+ BlindedPath::one_hop_for_payment(
7638
+ payee_node_id, payee_tlvs, entropy_source, secp_ctx
7639
+ ).unwrap()
7640
+ }
7641
+
7556
7642
/// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids
7557
7643
/// are used when constructing the phantom invoice's route hints.
7558
7644
///
0 commit comments