@@ -622,28 +622,71 @@ where
622
622
} )
623
623
}
624
624
625
+ fn create_refund_builder_intern < ES : Deref , PF , I > (
626
+ & self , entropy_source : ES , make_paths : PF , amount_msats : u64 , absolute_expiry : Duration ,
627
+ payment_id : PaymentId ,
628
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
629
+ where
630
+ ES :: Target : EntropySource ,
631
+ PF : FnOnce (
632
+ PublicKey ,
633
+ MessageContext ,
634
+ & secp256k1:: Secp256k1 < secp256k1:: All > ,
635
+ ) -> Result < I , Bolt12SemanticError > ,
636
+ I : IntoIterator < Item = BlindedMessagePath > ,
637
+ {
638
+ let node_id = self . get_our_node_id ( ) ;
639
+ let expanded_key = & self . inbound_payment_key ;
640
+ let entropy = & * entropy_source;
641
+ let secp_ctx = & self . secp_ctx ;
642
+
643
+ let nonce = Nonce :: from_entropy_source ( entropy) ;
644
+ let context = MessageContext :: Offers ( OffersContext :: OutboundPayment {
645
+ payment_id,
646
+ nonce,
647
+ hmac : None ,
648
+ } ) ;
649
+
650
+ // Create the base builder with common properties
651
+ let mut builder = RefundBuilder :: deriving_signing_pubkey (
652
+ node_id,
653
+ expanded_key,
654
+ nonce,
655
+ secp_ctx,
656
+ amount_msats,
657
+ payment_id,
658
+ ) ?
659
+ . chain_hash ( self . chain_hash )
660
+ . absolute_expiry ( absolute_expiry) ;
661
+
662
+ for path in make_paths ( node_id, context, secp_ctx) ? {
663
+ builder = builder. path ( path) ;
664
+ }
665
+
666
+ Ok ( builder. into ( ) )
667
+ }
668
+
625
669
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
626
670
/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
627
671
/// can be verified using [`Self::verify_bolt12_invoice`].
628
672
///
673
+ /// # Privacy
674
+ ///
675
+ /// Uses the [`OffersMessageFlow`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`]
676
+ /// for the offer. See those docs for privacy implications.
677
+ ///
629
678
/// The builder will have the provided expiration set. Any changes to the expiration on the
630
679
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
631
680
/// block time minus two hours is used for the current time when determining if the refund has
632
681
/// expired.
633
682
///
634
- /// To refund can be revoked by the user prior to receiving the invoice.
683
+ /// The refund can be revoked by the user prior to receiving the invoice.
635
684
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
636
685
/// with an [`Event::PaymentFailed`].
637
686
///
638
687
/// If `max_total_routing_fee_msat` is not specified, the default from
639
688
/// [`RouteParameters::from_payment_params_and_value`] is applied.
640
689
///
641
- /// # Privacy
642
- ///
643
- /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
644
- /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
645
- /// privacy implications.
646
- ///
647
690
/// Also uses a derived payer id in the refund for payer privacy.
648
691
///
649
692
/// # Errors
@@ -662,32 +705,76 @@ where
662
705
where
663
706
ES :: Target : EntropySource ,
664
707
{
665
- let node_id = self . get_our_node_id ( ) ;
666
- let expanded_key = & self . inbound_payment_key ;
667
- let entropy = & * entropy_source;
668
- let secp_ctx = & self . secp_ctx ;
669
-
670
- let nonce = Nonce :: from_entropy_source ( entropy) ;
671
- let context = OffersContext :: OutboundPayment { payment_id, nonce, hmac : None } ;
672
-
673
- let path = self
674
- . create_blinded_paths_using_absolute_expiry ( context, Some ( absolute_expiry) , peers)
675
- . and_then ( |paths| paths. into_iter ( ) . next ( ) . ok_or ( ( ) ) )
676
- . map_err ( |_| Bolt12SemanticError :: MissingPaths ) ?;
677
-
678
- let builder = RefundBuilder :: deriving_signing_pubkey (
679
- node_id,
680
- expanded_key,
681
- nonce,
682
- secp_ctx,
708
+ self . create_refund_builder_intern (
709
+ & * entropy_source,
710
+ |_, context, _| {
711
+ self . create_blinded_paths ( peers, context)
712
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
713
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
714
+ } ,
683
715
amount_msats,
716
+ absolute_expiry,
684
717
payment_id,
685
- ) ?
686
- . chain_hash ( self . chain_hash )
687
- . absolute_expiry ( absolute_expiry)
688
- . path ( path) ;
718
+ )
719
+ }
689
720
690
- Ok ( builder)
721
+ /// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
722
+ /// [`OffersMessageFlow`] when handling [`Bolt12Invoice`] messages for the refund.
723
+ ///
724
+ /// # Privacy
725
+ ///
726
+ /// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
727
+ /// Users can implement a custom [`MessageRouter`] to define properties of the
728
+ /// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
729
+ ///
730
+ /// # Payment
731
+ ///
732
+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
733
+ /// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
734
+ ///
735
+ /// The builder will have the provided expiration set. Any changes to the expiration on the
736
+ /// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
737
+ /// block time minus two hours is used for the current time when determining if the refund has
738
+ /// expired.
739
+ ///
740
+ /// The refund can be revoked by the user prior to receiving the invoice.
741
+ /// If abandoned, or if an invoice is not received before expiration, the payment will fail
742
+ /// with an [`Event::PaymentFailed`].
743
+ ///
744
+ /// If `max_total_routing_fee_msat` is not specified, The default from
745
+ /// [`RouteParameters::from_payment_params_and_value`] is applied.
746
+ ///
747
+ /// Also, uses a derived payer id in the refund for payer privacy.
748
+ ///
749
+ /// # Errors
750
+ ///
751
+ /// Errors if:
752
+ /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
753
+ /// - `amount_msats` is invalid, or
754
+ /// - the provided [`MessageRouter`] is unable to create a blinded path for the refund.
755
+ ///
756
+ /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
757
+ /// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
758
+ pub fn create_refund_builder_using_router < ES : Deref , ME : Deref > (
759
+ & self , router : ME , entropy_source : ES , amount_msats : u64 , absolute_expiry : Duration ,
760
+ payment_id : PaymentId , peers : Vec < MessageForwardNode > ,
761
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
762
+ where
763
+ ME :: Target : MessageRouter ,
764
+ ES :: Target : EntropySource ,
765
+ {
766
+ self . create_refund_builder_intern (
767
+ & * entropy_source,
768
+ |node_id, context, secp_ctx| {
769
+ router
770
+ . create_blinded_paths ( node_id, context, peers, secp_ctx)
771
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
772
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
773
+ } ,
774
+ amount_msats,
775
+ absolute_expiry,
776
+ payment_id,
777
+ )
691
778
}
692
779
693
780
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized
0 commit comments