@@ -22,6 +22,8 @@ use lightning::offers::invoice::Bolt12Invoice;
2222use lightning:: offers:: offer:: { Amount , Offer , Quantity } ;
2323use lightning:: offers:: parse:: Bolt12SemanticError ;
2424use lightning:: offers:: refund:: Refund ;
25+ use lightning:: onion_message:: dns_resolution:: HumanReadableName ;
26+ use lightning:: onion_message:: messenger:: Destination ;
2527use lightning:: util:: string:: UntrustedString ;
2628
2729use rand:: RngCore ;
@@ -256,6 +258,72 @@ impl Bolt12Payment {
256258 }
257259 }
258260
261+ /// Send a payment to an offer resolved from a human-readable name [BIP 353].
262+ ///
263+ /// Paying to human-readable names makes it more intuitive to make payments for offers
264+ /// as users can simply send payments to HRNs such as `[email protected] `. 265+ ///
266+ /// This can be used to pay so-called "zero-amount" offers, i.e., an offer that leaves the
267+ /// amount paid to be determined by the user.
268+ ///
269+ /// `dns_resolvers` should be a list of node Destinations that are configured for dns resolution (as outlined in bLIP 32).
270+ /// These nodes can be found by running a search through the `NetworkGraph` to find nodes that announce the
271+ /// `dns_resolver` feature flag.
272+ pub fn send_to_human_readable_name (
273+ & self , name : & str , amount_msat : u64 , dns_resolvers : Vec < Destination > ,
274+ ) -> Result < PaymentId , Error > {
275+ let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
276+ if rt_lock. is_none ( ) {
277+ return Err ( Error :: NotRunning ) ;
278+ }
279+
280+ let hrn = HumanReadableName :: from_encoded ( & name) . map_err ( |_| Error :: HrnParsingFailed ) ?;
281+
282+ let mut random_bytes = [ 0u8 ; 32 ] ;
283+ rand:: thread_rng ( ) . fill_bytes ( & mut random_bytes) ;
284+ let payment_id = PaymentId ( random_bytes) ;
285+ let retry_strategy = Retry :: Timeout ( LDK_PAYMENT_RETRY_TIMEOUT ) ;
286+ let max_total_routing_fee_msat = None ;
287+
288+ match self . channel_manager . pay_for_offer_from_human_readable_name (
289+ hrn. clone ( ) ,
290+ amount_msat,
291+ payment_id,
292+ retry_strategy,
293+ max_total_routing_fee_msat,
294+ dns_resolvers,
295+ ) {
296+ Ok ( ( ) ) => {
297+ log_info ! ( self . logger, "Initiated sending {} msats to {}" , amount_msat, name) ;
298+ let kind = PaymentKind :: HrnBolt12Offer { hrn } ;
299+ let payment = PaymentDetails :: new (
300+ payment_id,
301+ kind,
302+ Some ( amount_msat) ,
303+ None ,
304+ PaymentDirection :: Outbound ,
305+ PaymentStatus :: Pending ,
306+ ) ;
307+ self . payment_store . insert ( payment) ?;
308+ Ok ( payment_id)
309+ } ,
310+ Err ( ( ) ) => {
311+ log_error ! ( self . logger, "Failed to send payment to {}" , name) ;
312+ let kind = PaymentKind :: HrnBolt12Offer { hrn } ;
313+ let payment = PaymentDetails :: new (
314+ payment_id,
315+ kind,
316+ Some ( amount_msat) ,
317+ None ,
318+ PaymentDirection :: Outbound ,
319+ PaymentStatus :: Pending ,
320+ ) ;
321+ self . payment_store . insert ( payment) ?;
322+ Err ( Error :: PaymentSendingFailed )
323+ } ,
324+ }
325+ }
326+
259327 /// Returns a payable offer that can be used to request and receive a payment of the amount
260328 /// given.
261329 pub fn receive (
0 commit comments