@@ -572,28 +572,70 @@ where
572
572
} )
573
573
}
574
574
575
+ fn create_refund_builder_intern < PF , ES : Deref > (
576
+ & self , make_paths : PF , entropy_source : ES , amount_msats : u64 , absolute_expiry : Duration ,
577
+ payment_id : PaymentId ,
578
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
579
+ where
580
+ PF : FnOnce (
581
+ PublicKey ,
582
+ MessageContext ,
583
+ & secp256k1:: Secp256k1 < secp256k1:: All > ,
584
+ ) -> Result < Vec < BlindedMessagePath > , Bolt12SemanticError > ,
585
+ ES :: Target : EntropySource ,
586
+ {
587
+ let node_id = self . get_our_node_id ( ) ;
588
+ let expanded_key = & self . inbound_payment_key ;
589
+ let entropy = & * entropy_source;
590
+ let secp_ctx = & self . secp_ctx ;
591
+
592
+ let nonce = Nonce :: from_entropy_source ( entropy) ;
593
+ let context = MessageContext :: Offers ( OffersContext :: OutboundPayment {
594
+ payment_id,
595
+ nonce,
596
+ hmac : None ,
597
+ } ) ;
598
+
599
+ // Create the base builder with common properties
600
+ let mut builder = RefundBuilder :: deriving_signing_pubkey (
601
+ node_id,
602
+ expanded_key,
603
+ nonce,
604
+ secp_ctx,
605
+ amount_msats,
606
+ payment_id,
607
+ ) ?
608
+ . chain_hash ( self . chain_hash )
609
+ . absolute_expiry ( absolute_expiry) ;
610
+
611
+ for path in make_paths ( node_id, context, secp_ctx) ? {
612
+ builder = builder. path ( path) ;
613
+ }
614
+
615
+ Ok ( builder. into ( ) )
616
+ }
617
+
575
618
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
576
619
/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
577
620
/// can be verified using [`Self::verify_bolt12_invoice`].
578
621
///
622
+ /// # Privacy
623
+ ///
624
+ /// Uses the [`OffersMessageFlow`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`]
625
+ /// for the offer. See those docs for privacy implications.
626
+ ///
579
627
/// The builder will have the provided expiration set. Any changes to the expiration on the
580
628
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
581
629
/// block time minus two hours is used for the current time when determining if the refund has
582
630
/// expired.
583
631
///
584
- /// To refund can be revoked by the user prior to receiving the invoice.
632
+ /// The refund can be revoked by the user prior to receiving the invoice.
585
633
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
586
634
/// with an [`Event::PaymentFailed`].
587
635
///
588
636
/// If `max_total_routing_fee_msat` is not specified, the default from
589
637
/// [`RouteParameters::from_payment_params_and_value`] is applied.
590
638
///
591
- /// # Privacy
592
- ///
593
- /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
594
- /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
595
- /// privacy implications.
596
- ///
597
639
/// Also uses a derived payer id in the refund for payer privacy.
598
640
///
599
641
/// # Errors
@@ -612,32 +654,76 @@ where
612
654
where
613
655
ES :: Target : EntropySource ,
614
656
{
615
- let node_id = self . get_our_node_id ( ) ;
616
- let expanded_key = & self . inbound_payment_key ;
617
- let entropy = & * entropy_source;
618
- let secp_ctx = & self . secp_ctx ;
619
-
620
- let nonce = Nonce :: from_entropy_source ( entropy) ;
621
- let context = OffersContext :: OutboundPayment { payment_id, nonce, hmac : None } ;
622
-
623
- let path = self
624
- . create_blinded_paths_using_absolute_expiry ( context, Some ( absolute_expiry) , peers)
625
- . and_then ( |paths| paths. into_iter ( ) . next ( ) . ok_or ( ( ) ) )
626
- . map_err ( |_| Bolt12SemanticError :: MissingPaths ) ?;
627
-
628
- let builder = RefundBuilder :: deriving_signing_pubkey (
629
- node_id,
630
- expanded_key,
631
- nonce,
632
- secp_ctx,
657
+ self . create_refund_builder_intern (
658
+ |_, context, _| {
659
+ self . create_blinded_paths ( peers, context)
660
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) . collect ( ) )
661
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
662
+ } ,
663
+ & * entropy_source,
633
664
amount_msats,
665
+ absolute_expiry,
634
666
payment_id,
635
- ) ?
636
- . chain_hash ( self . chain_hash )
637
- . absolute_expiry ( absolute_expiry)
638
- . path ( path) ;
667
+ )
668
+ }
639
669
640
- Ok ( builder)
670
+ /// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
671
+ /// [`OffersMessageFlow`] when handling [`Bolt12Invoice`] messages for the refund.
672
+ ///
673
+ /// # Privacy
674
+ ///
675
+ /// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
676
+ /// Users can implement a custom [`MessageRouter`] to define properties of the
677
+ /// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
678
+ ///
679
+ /// # Payment
680
+ ///
681
+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
682
+ /// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
683
+ ///
684
+ /// The builder will have the provided expiration set. Any changes to the expiration on the
685
+ /// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
686
+ /// block time minus two hours is used for the current time when determining if the refund has
687
+ /// expired.
688
+ ///
689
+ /// The refund can be revoked by the user prior to receiving the invoice.
690
+ /// If abandoned, or if an invoice is not received before expiration, the payment will fail
691
+ /// with an [`Event::PaymentFailed`].
692
+ ///
693
+ /// If `max_total_routing_fee_msat` is not specified, The default from
694
+ /// [`RouteParameters::from_payment_params_and_value`] is applied.
695
+ ///
696
+ /// Also, uses a derived payer id in the refund for payer privacy.
697
+ ///
698
+ /// # Errors
699
+ ///
700
+ /// Errors if:
701
+ /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
702
+ /// - `amount_msats` is invalid, or
703
+ /// - the provided [`MessageRouter`] is unable to create a blinded path for the refund.
704
+ ///
705
+ /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
706
+ /// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value
707
+ pub fn create_refund_builder_using_router < ES : Deref , ME : Deref > (
708
+ & self , router : ME , entropy_source : ES , amount_msats : u64 , absolute_expiry : Duration ,
709
+ payment_id : PaymentId , peers : Vec < MessageForwardNode > ,
710
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
711
+ where
712
+ ME :: Target : MessageRouter ,
713
+ ES :: Target : EntropySource ,
714
+ {
715
+ self . create_refund_builder_intern (
716
+ |node_id, context, secp_ctx| {
717
+ router
718
+ . create_blinded_paths ( node_id, context, peers, secp_ctx)
719
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) . collect ( ) )
720
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
721
+ } ,
722
+ & * entropy_source,
723
+ amount_msats,
724
+ absolute_expiry,
725
+ payment_id,
726
+ )
641
727
}
642
728
643
729
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized
0 commit comments