@@ -571,28 +571,71 @@ where
571
571
} )
572
572
}
573
573
574
+ fn create_refund_builder_intern < ES : Deref , PF , I > (
575
+ & self , entropy_source : ES , make_paths : PF , amount_msats : u64 , absolute_expiry : Duration ,
576
+ payment_id : PaymentId ,
577
+ ) -> Result < RefundBuilder < secp256k1:: All > , Bolt12SemanticError >
578
+ where
579
+ ES :: Target : EntropySource ,
580
+ PF : FnOnce (
581
+ PublicKey ,
582
+ MessageContext ,
583
+ & secp256k1:: Secp256k1 < secp256k1:: All > ,
584
+ ) -> Result < I , Bolt12SemanticError > ,
585
+ I : IntoIterator < Item = BlindedMessagePath > ,
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
+
574
618
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
575
619
/// [`OffersMessageFlow`], and any corresponding [`Bolt12Invoice`] received for the refund
576
620
/// can be verified using [`Self::verify_bolt12_invoice`].
577
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
+ ///
578
627
/// The builder will have the provided expiration set. Any changes to the expiration on the
579
628
/// returned builder will not be honored by [`OffersMessageFlow`]. For non-`std`, the highest seen
580
629
/// block time minus two hours is used for the current time when determining if the refund has
581
630
/// expired.
582
631
///
583
- /// 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.
584
633
/// If abandoned, or if an invoice is not received before expiration, the payment will fail
585
634
/// with an [`Event::PaymentFailed`].
586
635
///
587
636
/// If `max_total_routing_fee_msat` is not specified, the default from
588
637
/// [`RouteParameters::from_payment_params_and_value`] is applied.
589
638
///
590
- /// # Privacy
591
- ///
592
- /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
593
- /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
594
- /// privacy implications.
595
- ///
596
639
/// Also uses a derived payer id in the refund for payer privacy.
597
640
///
598
641
/// # Errors
@@ -611,32 +654,76 @@ where
611
654
where
612
655
ES :: Target : EntropySource ,
613
656
{
614
- let node_id = self . get_our_node_id ( ) ;
615
- let expanded_key = & self . inbound_payment_key ;
616
- let entropy = & * entropy_source;
617
- let secp_ctx = & self . secp_ctx ;
618
-
619
- let nonce = Nonce :: from_entropy_source ( entropy) ;
620
- let context = OffersContext :: OutboundPayment { payment_id, nonce, hmac : None } ;
621
-
622
- let path = self
623
- . create_blinded_paths_using_absolute_expiry ( context, Some ( absolute_expiry) , peers)
624
- . and_then ( |paths| paths. into_iter ( ) . next ( ) . ok_or ( ( ) ) )
625
- . map_err ( |_| Bolt12SemanticError :: MissingPaths ) ?;
626
-
627
- let builder = RefundBuilder :: deriving_signing_pubkey (
628
- node_id,
629
- expanded_key,
630
- nonce,
631
- secp_ctx,
657
+ self . create_refund_builder_intern (
658
+ & * entropy_source,
659
+ |_, context, _| {
660
+ self . create_blinded_paths ( peers, context)
661
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
662
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
663
+ } ,
632
664
amount_msats,
665
+ absolute_expiry,
633
666
payment_id,
634
- ) ?
635
- . chain_hash ( self . chain_hash )
636
- . absolute_expiry ( absolute_expiry)
637
- . path ( path) ;
667
+ )
668
+ }
638
669
639
- 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
+ & * entropy_source,
717
+ |node_id, context, secp_ctx| {
718
+ router
719
+ . create_blinded_paths ( node_id, context, peers, secp_ctx)
720
+ . map ( |paths| paths. into_iter ( ) . take ( 1 ) )
721
+ . map_err ( |_| Bolt12SemanticError :: MissingPaths )
722
+ } ,
723
+ amount_msats,
724
+ absolute_expiry,
725
+ payment_id,
726
+ )
640
727
}
641
728
642
729
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is recognized
0 commit comments