@@ -677,28 +677,67 @@ where
677
677
} )
678
678
}
679
679
680
+ fn create_refund_builder_intern < ES : Deref , PF , I > (
681
+ & self , entropy_source : ES , make_paths : PF , amount_msats : u64 , absolute_expiry : Duration ,
682
+ payment_id : PaymentId ,
683
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
684
+ where
685
+ ES :: Target : EntropySource ,
686
+ PF : FnOnce (
687
+ PublicKey ,
688
+ MessageContext ,
689
+ & secp256k1:: Secp256k1 < secp256k1:: All > ,
690
+ ) -> Result < I , Bolt12SemanticError > ,
691
+ I : IntoIterator < Item = BlindedMessagePath > ,
692
+ {
693
+ let node_id = self . get_our_node_id ( ) ;
694
+ let expanded_key = & self . inbound_payment_key ;
695
+ let entropy = & * entropy_source;
696
+ let secp_ctx = & self . secp_ctx ;
697
+
698
+ let nonce = Nonce :: from_entropy_source ( entropy) ;
699
+ let context = MessageContext :: Offers ( OffersContext :: OutboundPayment { payment_id, nonce } ) ;
700
+
701
+ // Create the base builder with common properties
702
+ let mut builder = RefundBuilder :: deriving_signing_pubkey (
703
+ node_id,
704
+ expanded_key,
705
+ nonce,
706
+ secp_ctx,
707
+ amount_msats,
708
+ payment_id,
709
+ ) ?
710
+ . chain_hash ( self . chain_hash )
711
+ . absolute_expiry ( absolute_expiry) ;
712
+
713
+ for path in make_paths ( node_id, context, secp_ctx) ? {
714
+ builder = builder. path ( path) ;
715
+ }
716
+
717
+ Ok ( builder. into ( ) )
718
+ }
719
+
680
720
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
681
721
/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
682
722
/// can be verified using [`Self::verify_bolt12_invoice`].
683
723
///
724
+ /// # Privacy
725
+ ///
726
+ /// Uses the [`OffersMessageFlow`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`]
727
+ /// for the offer. See those docs for privacy implications.
728
+ ///
684
729
/// The builder will have the provided expiration set. Any changes to the expiration on the
685
730
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
686
731
/// block time minus two hours is used for the current time when determining if the refund has
687
732
/// expired.
688
733
///
689
- /// To refund can be revoked by the user prior to receiving the invoice.
734
+ /// The refund can be revoked by the user prior to receiving the invoice.
690
735
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
691
736
/// with an [`Event::PaymentFailed`].
692
737
///
693
738
/// If `max_total_routing_fee_msat` is not specified, the default from
694
739
/// [`RouteParameters::from_payment_params_and_value`] is applied.
695
740
///
696
- /// # Privacy
697
- ///
698
- /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
699
- /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
700
- /// privacy implications.
701
- ///
702
741
/// Also uses a derived payer id in the refund for payer privacy.
703
742
///
704
743
/// # Errors
@@ -717,32 +756,63 @@ where
717
756
where
718
757
ES :: Target : EntropySource ,
719
758
{
720
- let node_id = self . get_our_node_id ( ) ;
721
- let expanded_key = & self . inbound_payment_key ;
722
- let entropy = & * entropy_source;
723
- let secp_ctx = & self . secp_ctx ;
724
-
725
- let nonce = Nonce :: from_entropy_source ( entropy) ;
726
- let context = OffersContext :: OutboundPayment { payment_id, nonce } ;
727
-
728
- let path = self
729
- . create_blinded_paths_using_absolute_expiry ( context, Some ( absolute_expiry) , peers)
730
- . and_then ( |paths| paths. into_iter ( ) . next ( ) . ok_or ( ( ) ) )
731
- . map_err ( |_| Bolt12SemanticError :: MissingPaths ) ?;
732
-
733
- let builder = RefundBuilder :: deriving_signing_pubkey (
734
- node_id,
735
- expanded_key,
736
- nonce,
737
- secp_ctx,
759
+ self . create_refund_builder_intern (
760
+ & * entropy_source,
761
+ |_, context, _| {
762
+ self . create_blinded_paths ( peers, context)
763
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
764
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
765
+ } ,
738
766
amount_msats,
767
+ absolute_expiry,
739
768
payment_id,
740
- ) ?
741
- . chain_hash ( self . chain_hash )
742
- . absolute_expiry ( absolute_expiry)
743
- . path ( path) ;
769
+ )
770
+ }
744
771
745
- Ok ( builder)
772
+ /// Same as [`Self::create_refund_builder`] but allows specifying a custom [`MessageRouter`]
773
+ /// instead of using the one provided via the [`OffersMessageFlow`] parameterization.
774
+ ///
775
+ /// This gives users full control over how the [`BlindedMessagePath`] is constructed,
776
+ /// including the option to omit it entirely.
777
+ ///
778
+ /// See [`Self::create_refund_builder`] for:
779
+ /// - how the resulting [`Refund`] is recognized by [`OffersMessageFlow`] and verified via [`Self::verify_bolt12_invoice`],
780
+ /// - refund expiration handling,
781
+ /// - rules around revocation and [`Event::PaymentFailed`] behavior,
782
+ /// - and defaulting logic for `max_total_routing_fee_msat`.
783
+ ///
784
+ /// # Errors
785
+ ///
786
+ /// In addition to the errors documented in [`Self::create_refund_builder`], this method will
787
+ /// return an error if the provided [`MessageRouter`] fails to construct a valid
788
+ /// [`BlindedMessagePath`] for the refund.
789
+ ///
790
+ /// [`Refund`]: crate::offers::refund::Refund
791
+ /// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
792
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
793
+ /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
794
+ /// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
795
+ pub fn create_refund_builder_using_router < ES : Deref , ME : Deref > (
796
+ & self , router : ME , entropy_source : ES , amount_msats : u64 , absolute_expiry : Duration ,
797
+ payment_id : PaymentId , peers : Vec < MessageForwardNode > ,
798
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
799
+ where
800
+ ME :: Target : MessageRouter ,
801
+ ES :: Target : EntropySource ,
802
+ {
803
+ let receive_key = self . get_receive_auth_key ( ) ;
804
+ self . create_refund_builder_intern (
805
+ & * entropy_source,
806
+ |node_id, context, secp_ctx| {
807
+ router
808
+ . create_blinded_paths ( node_id, receive_key, context, peers, secp_ctx)
809
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
810
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
811
+ } ,
812
+ amount_msats,
813
+ absolute_expiry,
814
+ payment_id,
815
+ )
746
816
}
747
817
748
818
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized
0 commit comments