71
71
crate :: offers:: refund:: RefundMaybeWithDerivedMetadataBuilder ,
72
72
} ;
73
73
74
+ #[ cfg( feature = "dnssec" ) ]
75
+ use crate :: onion_message:: dns_resolution:: { DNSResolverMessage , OMNameResolver } ;
76
+
74
77
/// Functions commonly shared in usage between [`ChannelManager`] & `OffersMessageFlow`
75
78
///
76
79
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
@@ -80,6 +83,16 @@ pub trait OffersMessageCommons {
80
83
& self ,
81
84
) -> MutexGuard < ' _ , Vec < ( OffersMessage , MessageSendInstructions ) > > ;
82
85
86
+ #[ cfg( feature = "dnssec" ) ]
87
+ /// Get pending DNS onion messages
88
+ fn get_pending_dns_onion_messages (
89
+ & self ,
90
+ ) -> MutexGuard < ' _ , Vec < ( DNSResolverMessage , MessageSendInstructions ) > > ;
91
+
92
+ #[ cfg( feature = "dnssec" ) ]
93
+ /// Get hrn resolver
94
+ fn get_hrn_resolver ( & self ) -> & OMNameResolver ;
95
+
83
96
/// Signs the [`TaggedHash`] of a BOLT 12 invoice.
84
97
///
85
98
/// May be called by a function passed to [`UnsignedBolt12Invoice::sign`] where `invoice` is the
@@ -202,6 +215,13 @@ pub trait OffersMessageCommons {
202
215
/// Get the approximate current time using the highest seen timestamp
203
216
fn get_highest_seen_timestamp ( & self ) -> Duration ;
204
217
218
+ #[ cfg( feature = "dnssec" ) ]
219
+ /// Add new awaiting offer
220
+ fn add_new_awaiting_offer (
221
+ & self , payment_id : PaymentId , expiration : StaleExpiration , retry_strategy : Retry ,
222
+ max_total_routing_fee_msat : Option < u64 > , amount_msats : u64 ,
223
+ ) -> Result < ( ) , ( ) > ;
224
+
205
225
/// Internal pay_for_offer
206
226
fn pay_for_offer_intern <
207
227
CPP : FnOnce ( & InvoiceRequest , Nonce ) -> Result < ( ) , Bolt12SemanticError > ,
@@ -1383,4 +1403,81 @@ where
1383
1403
Err ( ( ) ) => Err ( Bolt12SemanticError :: InvalidAmount ) ,
1384
1404
}
1385
1405
}
1406
+
1407
+ /// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
1408
+ /// resolver(s) at `dns_resolvers` which resolve names according to bLIP 32.
1409
+ ///
1410
+ /// If the wallet supports paying on-chain schemes, you should instead use
1411
+ /// [`OMNameResolver::resolve_name`] and [`OMNameResolver::handle_dnssec_proof_for_uri`] (by
1412
+ /// implementing [`DNSResolverMessageHandler`]) directly to look up a URI and then delegate to
1413
+ /// your normal URI handling.
1414
+ ///
1415
+ /// If `max_total_routing_fee_msat` is not specified, the default from
1416
+ /// [`RouteParameters::from_payment_params_and_value`] is applied.
1417
+ ///
1418
+ /// # Payment
1419
+ ///
1420
+ /// The provided `payment_id` is used to ensure that only one invoice is paid for the request
1421
+ /// when received. See [Avoiding Duplicate Payments] for other requirements once the payment has
1422
+ /// been sent.
1423
+ ///
1424
+ /// To revoke the request, use [`ChannelManager::abandon_payment`] prior to receiving the
1425
+ /// invoice. If abandoned, or an invoice isn't received in a reasonable amount of time, the
1426
+ /// payment will fail with an [`Event::InvoiceRequestFailed`].
1427
+ ///
1428
+ /// # Privacy
1429
+ ///
1430
+ /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
1431
+ /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
1432
+ /// docs of the parameterized [`Router`], which implements [`MessageRouter`].
1433
+ ///
1434
+ /// # Limitations
1435
+ ///
1436
+ /// Requires a direct connection to the given [`Destination`] as well as an introduction node in
1437
+ /// [`Offer::paths`] or to [`Offer::signing_pubkey`], if empty. A similar restriction applies to
1438
+ /// the responding [`Bolt12Invoice::payment_paths`].
1439
+ ///
1440
+ /// # Errors
1441
+ ///
1442
+ /// Errors if:
1443
+ /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
1444
+ ///
1445
+ /// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
1446
+ /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
1447
+ #[ cfg( feature = "dnssec" ) ]
1448
+ pub fn pay_for_offer_from_human_readable_name (
1449
+ & self , name : HumanReadableName , amount_msats : u64 , payment_id : PaymentId ,
1450
+ retry_strategy : Retry , max_total_routing_fee_msat : Option < u64 > ,
1451
+ dns_resolvers : Vec < Destination > ,
1452
+ ) -> Result < ( ) , ( ) > {
1453
+ let ( onion_message, context) = self . commons . get_hrn_resolver ( ) . resolve_name (
1454
+ payment_id,
1455
+ name,
1456
+ & * self . entropy_source ,
1457
+ ) ?;
1458
+ let reply_paths =
1459
+ self . commons . create_blinded_paths ( MessageContext :: DNSResolver ( context) ) ?;
1460
+ let expiration = StaleExpiration :: TimerTicks ( 1 ) ;
1461
+ self . commons . add_new_awaiting_offer (
1462
+ payment_id,
1463
+ expiration,
1464
+ retry_strategy,
1465
+ max_total_routing_fee_msat,
1466
+ amount_msats,
1467
+ ) ?;
1468
+ let message_params = dns_resolvers
1469
+ . iter ( )
1470
+ . flat_map ( |destination| reply_paths. iter ( ) . map ( move |path| ( path, destination) ) )
1471
+ . take ( OFFERS_MESSAGE_REQUEST_LIMIT ) ;
1472
+ for ( reply_path, destination) in message_params {
1473
+ self . commons . get_pending_dns_onion_messages ( ) . push ( (
1474
+ DNSResolverMessage :: DNSSECQuery ( onion_message. clone ( ) ) ,
1475
+ MessageSendInstructions :: WithSpecifiedReplyPath {
1476
+ destination : destination. clone ( ) ,
1477
+ reply_path : reply_path. clone ( ) ,
1478
+ } ,
1479
+ ) ) ;
1480
+ }
1481
+ Ok ( ( ) )
1482
+ }
1386
1483
}
0 commit comments