Skip to content

Commit 4dcfe1b

Browse files
committed
Introduce create_{offer,refund}_builder_using_router
Introduced two new builder functions that accept a custom `MessageRouter` as input. This gives users the flexibility to plug in their own router implementation, enabling custom logic for blinded path creation when building Offers or Refunds. It’s a step toward greater extensibility and control in how paths are constructed.
1 parent 408c89c commit 4dcfe1b

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10221,6 +10221,56 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
1022110221

1022210222
Ok(builder.into())
1022310223
}
10224+
10225+
/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
10226+
/// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer.
10227+
///
10228+
/// # Privacy
10229+
///
10230+
/// Constructs a [`BlindedMessagePath`] for the offer using a custom [`MessageRouter`].
10231+
/// Users can implement a custom [`MessageRouter`] to define properties of the
10232+
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
10233+
///
10234+
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
10235+
///
10236+
/// # Limitations
10237+
///
10238+
/// Requires a direct connection to the introduction node in the responding [`InvoiceRequest`]'s
10239+
/// reply path.
10240+
///
10241+
/// # Errors
10242+
///
10243+
/// Errors if the provided [`Router`] is unable to create a blinded path for the offer.
10244+
///
10245+
/// [`Offer`]: crate::offers::offer::Offer
10246+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
10247+
pub fn create_offer_builder_using_router<ME: MessageRouter>(
10248+
&$self,
10249+
router: ME,
10250+
) -> Result<$builder, Bolt12SemanticError> {
10251+
let node_id = $self.get_our_node_id();
10252+
let expanded_key = &$self.inbound_payment_key;
10253+
let entropy = &*$self.entropy_source;
10254+
let secp_ctx = &$self.secp_ctx;
10255+
10256+
let nonce = Nonce::from_entropy_source(entropy);
10257+
let context = MessageContext::Offers(OffersContext::InvoiceRequest { nonce });
10258+
10259+
let peers = $self.get_peers_for_blinded_path();
10260+
10261+
let path = router.create_blinded_paths(node_id, context, peers, secp_ctx)
10262+
.map_err(|_| Bolt12SemanticError::MissingPaths)?
10263+
.into_iter().next();
10264+
10265+
let mut builder = OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx)
10266+
.chain_hash($self.chain_hash);
10267+
10268+
if let Some(path) = path {
10269+
builder = builder.path(path)
10270+
}
10271+
10272+
Ok(builder.into())
10273+
}
1022410274
} }
1022510275

1022610276
macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
@@ -10302,6 +10352,91 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1030210352

1030310353
Ok(builder.into())
1030410354
}
10355+
10356+
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
10357+
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
10358+
///
10359+
/// # Payment
10360+
///
10361+
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
10362+
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
10363+
///
10364+
/// The builder will have the provided expiration set. Any changes to the expiration on the
10365+
/// returned builder will not be honored by [`ChannelManager`]. For non-`std`, the highest seen
10366+
/// block time minus two hours is used for the current time when determining if the refund has
10367+
/// expired.
10368+
///
10369+
/// To revoke the refund, use [`ChannelManager::abandon_payment`] prior to receiving the
10370+
/// invoice. If abandoned, or an invoice isn't received before expiration, the payment will fail
10371+
/// with an [`Event::PaymentFailed`].
10372+
///
10373+
/// If `max_total_routing_fee_msat` is not specified, The default from
10374+
/// [`RouteParameters::from_payment_params_and_value`] is applied.
10375+
///
10376+
/// # Privacy
10377+
///
10378+
/// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
10379+
/// Users can implement a custom [`MessageRouter`] to define properties of the
10380+
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
10381+
///
10382+
/// Also, uses a derived payer id in the refund for payer privacy.
10383+
///
10384+
/// # Limitations
10385+
///
10386+
/// Requires a direct connection to an introduction node in the responding
10387+
/// [`Bolt12Invoice::payment_paths`].
10388+
///
10389+
/// # Errors
10390+
///
10391+
/// Errors if:
10392+
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
10393+
/// - `amount_msats` is invalid, or
10394+
/// - the provided [`Router`] is unable to create a blinded path for the refund.
10395+
///
10396+
/// [`Refund`]: crate::offers::refund::Refund
10397+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
10398+
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
10399+
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
10400+
pub fn create_refund_builder_using_router<ME: MessageRouter>(
10401+
&$self, router: ME, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
10402+
retry_strategy: Retry, route_params_config: RouteParametersConfig
10403+
) -> Result<$builder, Bolt12SemanticError> {
10404+
let node_id = $self.get_our_node_id();
10405+
let expanded_key = &$self.inbound_payment_key;
10406+
let entropy = &*$self.entropy_source;
10407+
let secp_ctx = &$self.secp_ctx;
10408+
10409+
let nonce = Nonce::from_entropy_source(entropy);
10410+
let context = MessageContext::Offers(
10411+
OffersContext::OutboundPayment { payment_id, nonce, hmac: None }
10412+
);
10413+
10414+
let peers = $self.get_peers_for_blinded_path();
10415+
let path = router.create_blinded_paths(node_id, context, peers, secp_ctx)
10416+
.map_err(|_| Bolt12SemanticError::MissingPaths)?
10417+
.into_iter().next();
10418+
10419+
let mut builder = RefundBuilder::deriving_signing_pubkey(
10420+
node_id, expanded_key, nonce, secp_ctx, amount_msats, payment_id
10421+
)?
10422+
.chain_hash($self.chain_hash)
10423+
.absolute_expiry(absolute_expiry);
10424+
10425+
if let Some(path) = path {
10426+
builder = builder.path(path)
10427+
}
10428+
10429+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
10430+
10431+
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
10432+
$self.pending_outbound_payments
10433+
.add_new_awaiting_invoice(
10434+
payment_id, expiration, retry_strategy, route_params_config, None,
10435+
)
10436+
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
10437+
10438+
Ok(builder.into())
10439+
}
1030510440
} }
1030610441

1030710442
/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent

0 commit comments

Comments
 (0)