@@ -611,28 +611,71 @@ where
611
611
} )
612
612
}
613
613
614
+ fn create_refund_builder_intern < ES : Deref , PF , I > (
615
+ & self , entropy_source : ES , make_paths : PF , amount_msats : u64 , absolute_expiry : Duration ,
616
+ payment_id : PaymentId ,
617
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
618
+ where
619
+ ES :: Target : EntropySource ,
620
+ PF : FnOnce (
621
+ PublicKey ,
622
+ MessageContext ,
623
+ & secp256k1:: Secp256k1 < secp256k1:: All > ,
624
+ ) -> Result < I , Bolt12SemanticError > ,
625
+ I : IntoIterator < Item = BlindedMessagePath > ,
626
+ {
627
+ let node_id = self . get_our_node_id ( ) ;
628
+ let expanded_key = & self . inbound_payment_key ;
629
+ let entropy = & * entropy_source;
630
+ let secp_ctx = & self . secp_ctx ;
631
+
632
+ let nonce = Nonce :: from_entropy_source ( entropy) ;
633
+ let context = MessageContext :: Offers ( OffersContext :: OutboundPayment {
634
+ payment_id,
635
+ nonce,
636
+ hmac : None ,
637
+ } ) ;
638
+
639
+ // Create the base builder with common properties
640
+ let mut builder = RefundBuilder :: deriving_signing_pubkey (
641
+ node_id,
642
+ expanded_key,
643
+ nonce,
644
+ secp_ctx,
645
+ amount_msats,
646
+ payment_id,
647
+ ) ?
648
+ . chain_hash ( self . chain_hash )
649
+ . absolute_expiry ( absolute_expiry) ;
650
+
651
+ for path in make_paths ( node_id, context, secp_ctx) ? {
652
+ builder = builder. path ( path) ;
653
+ }
654
+
655
+ Ok ( builder. into ( ) )
656
+ }
657
+
614
658
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
615
659
/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
616
660
/// can be verified using [`Self::verify_bolt12_invoice`].
617
661
///
662
+ /// # Privacy
663
+ ///
664
+ /// Uses the [`OffersMessageFlow`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`]
665
+ /// for the offer. See those docs for privacy implications.
666
+ ///
618
667
/// The builder will have the provided expiration set. Any changes to the expiration on the
619
668
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
620
669
/// block time minus two hours is used for the current time when determining if the refund has
621
670
/// expired.
622
671
///
623
- /// To refund can be revoked by the user prior to receiving the invoice.
672
+ /// The refund can be revoked by the user prior to receiving the invoice.
624
673
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
625
674
/// with an [`Event::PaymentFailed`].
626
675
///
627
676
/// If `max_total_routing_fee_msat` is not specified, the default from
628
677
/// [`RouteParameters::from_payment_params_and_value`] is applied.
629
678
///
630
- /// # Privacy
631
- ///
632
- /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
633
- /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
634
- /// privacy implications.
635
- ///
636
679
/// Also uses a derived payer id in the refund for payer privacy.
637
680
///
638
681
/// # Errors
@@ -651,32 +694,62 @@ where
651
694
where
652
695
ES :: Target : EntropySource ,
653
696
{
654
- let node_id = self . get_our_node_id ( ) ;
655
- let expanded_key = & self . inbound_payment_key ;
656
- let entropy = & * entropy_source;
657
- let secp_ctx = & self . secp_ctx ;
658
-
659
- let nonce = Nonce :: from_entropy_source ( entropy) ;
660
- let context = OffersContext :: OutboundPayment { payment_id, nonce, hmac : None } ;
661
-
662
- let path = self
663
- . create_blinded_paths_using_absolute_expiry ( context, Some ( absolute_expiry) , peers)
664
- . and_then ( |paths| paths. into_iter ( ) . next ( ) . ok_or ( ( ) ) )
665
- . map_err ( |_| Bolt12SemanticError :: MissingPaths ) ?;
666
-
667
- let builder = RefundBuilder :: deriving_signing_pubkey (
668
- node_id,
669
- expanded_key,
670
- nonce,
671
- secp_ctx,
697
+ self . create_refund_builder_intern (
698
+ & * entropy_source,
699
+ |_, context, _| {
700
+ self . create_blinded_paths ( peers, context)
701
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
702
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
703
+ } ,
672
704
amount_msats,
705
+ absolute_expiry,
673
706
payment_id,
674
- ) ?
675
- . chain_hash ( self . chain_hash )
676
- . absolute_expiry ( absolute_expiry)
677
- . path ( path) ;
707
+ )
708
+ }
678
709
679
- Ok ( builder)
710
+ /// Same as [`Self::create_refund_builder`] but allows specifying a custom [`MessageRouter`]
711
+ /// instead of using the one provided via the [`OffersMessageFlow`] parameterization.
712
+ ///
713
+ /// This gives users full control over how the [`BlindedMessagePath`] is constructed,
714
+ /// including the option to omit it entirely.
715
+ ///
716
+ /// See [`Self::create_refund_builder`] for:
717
+ /// - how the resulting [`Refund`] is recognized by [`OffersMessageFlow`] and verified via [`Self::verify_bolt12_invoice`],
718
+ /// - refund expiration handling,
719
+ /// - rules around revocation and [`Event::PaymentFailed`] behavior,
720
+ /// - and defaulting logic for `max_total_routing_fee_msat`.
721
+ ///
722
+ /// # Errors
723
+ ///
724
+ /// In addition to the errors documented in [`Self::create_refund_builder`], this method will
725
+ /// return an error if the provided [`MessageRouter`] fails to construct a valid
726
+ /// [`BlindedMessagePath`] for the refund.
727
+ ///
728
+ /// [`Refund`]: crate::offers::refund::Refund
729
+ /// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
730
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
731
+ /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
732
+ /// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
733
+ pub fn create_refund_builder_using_router < ES : Deref , ME : Deref > (
734
+ & self , router : ME , entropy_source : ES , amount_msats : u64 , absolute_expiry : Duration ,
735
+ payment_id : PaymentId , peers : Vec < MessageForwardNode > ,
736
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
737
+ where
738
+ ME :: Target : MessageRouter ,
739
+ ES :: Target : EntropySource ,
740
+ {
741
+ self . create_refund_builder_intern (
742
+ & * entropy_source,
743
+ |node_id, context, secp_ctx| {
744
+ router
745
+ . create_blinded_paths ( node_id, context, peers, secp_ctx)
746
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
747
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
748
+ } ,
749
+ amount_msats,
750
+ absolute_expiry,
751
+ payment_id,
752
+ )
680
753
}
681
754
682
755
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized
0 commit comments