Skip to content

Commit ff8ddfc

Browse files
committed
fixup! Add support for sending to human-readable names that resolve to Bolt12 Offers
1 parent 2581e03 commit ff8ddfc

File tree

5 files changed

+98
-18
lines changed

5 files changed

+98
-18
lines changed

bindings/ldk_node.udl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ interface Bolt12Payment {
200200
[Throws=NodeError]
201201
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note);
202202
[Throws=NodeError]
203-
PaymentId send_to_human_readable_name([ByRef]string name, u64 amount_msat);
203+
PaymentId send_to_human_readable_name(HumanReadableName hrn, u64 amount_msat);
204204
[Throws=NodeError]
205205
Offer receive(u64 amount_msat, [ByRef]string description, u32? expiry_secs, u64? quantity);
206206
[Throws=NodeError]
@@ -253,6 +253,13 @@ interface LSPS1Liquidity {
253253
LSPS1OrderStatus check_order_status(OrderId order_id);
254254
};
255255

256+
interface HumanReadableName {
257+
[Name=from_encoded]
258+
constructor([ByRef] string encoded);
259+
string user();
260+
string domain();
261+
};
262+
256263
[Error]
257264
enum NodeError {
258265
"AlreadyRunning",

src/event.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,8 +1417,20 @@ where
14171417
);
14181418
}
14191419
},
1420-
LdkEvent::InvoiceReceived { .. } => {
1421-
debug_assert!(false, "We currently don't handle BOLT12 invoices manually, so this event should never be emitted.");
1420+
LdkEvent::InvoiceReceived { payment_id, invoice, context: _, responder: _ } => {
1421+
let update = PaymentDetailsUpdate {
1422+
hash: Some(Some(invoice.payment_hash())),
1423+
quantity: invoice.quantity(),
1424+
..PaymentDetailsUpdate::new(payment_id)
1425+
};
1426+
1427+
match self.payment_store.update(&update) {
1428+
Ok(_) => {},
1429+
Err(e) => {
1430+
log_error!(self.logger, "Failed to access payment store: {}", e);
1431+
return Err(ReplayEvent());
1432+
},
1433+
};
14221434
},
14231435
LdkEvent::ConnectionNeeded { node_id, addresses } => {
14241436
let runtime_lock = self.runtime.read().unwrap();

src/payment/bolt12.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use lightning::ln::channelmanager::{PaymentId, Retry};
2020
use lightning::offers::offer::{Amount, Offer as LdkOffer, Quantity};
2121
use lightning::offers::parse::Bolt12SemanticError;
2222
use lightning::offers::refund::Refund;
23-
use lightning::onion_message::dns_resolution::HumanReadableName;
23+
use lightning::onion_message::dns_resolution::HumanReadableName as LdkHumanReadableName;
2424
use lightning::onion_message::messenger::Destination;
2525
use lightning::util::string::UntrustedString;
2626

@@ -44,6 +44,18 @@ type Offer = Arc<crate::ffi::Offer>;
4444
type Refund = lightning::offers::refund::Refund;
4545
#[cfg(feature = "uniffi")]
4646
type Refund = Arc<crate::ffi::Refund>;
47+
type HumanReadableName = LdkHumanReadableName;
48+
#[cfg(feature = "uniffi")]
49+
type HumanReadableName = Arc<crate::uniffi_types::HumanReadableName>;
50+
51+
#[cfg(not(feature = "uniffi"))]
52+
pub fn maybe_convert_hrn(hrn: HumanReadableName) -> LdkHumanReadableName {
53+
hrn
54+
}
55+
#[cfg(feature = "uniffi")]
56+
pub fn maybe_convert_hrn(hrn: HumanReadableName) -> LdkHumanReadableName {
57+
hrn.inner.clone()
58+
}
4759

4860
/// A payment handler allowing to create and pay [BOLT 12] offers and refunds.
4961
///
@@ -282,30 +294,30 @@ impl Bolt12Payment {
282294
/// This can be used to pay so-called "zero-amount" offers, i.e., an offer that leaves the
283295
/// amount paid to be determined by the user.
284296
///
285-
/// If `dns_resolvers_node_ids` in Config is set to `None`, this operation will fail.
297+
/// If `dns_resolvers_node_ids` in [`Config.hrn_config`] is empty, this operation will fail.
286298
pub fn send_to_human_readable_name(
287-
&self, name: &str, amount_msat: u64,
299+
&self, hrn: HumanReadableName, amount_msat: u64,
288300
) -> Result<PaymentId, Error> {
289301
let rt_lock = self.runtime.read().unwrap();
290302
if rt_lock.is_none() {
291303
return Err(Error::NotRunning);
292304
}
293305

294-
let hrn = HumanReadableName::from_encoded(&name).map_err(|_| Error::HrnParsingFailed)?;
295-
296306
let mut random_bytes = [0u8; 32];
297307
rand::thread_rng().fill_bytes(&mut random_bytes);
298308
let payment_id = PaymentId(random_bytes);
299309
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
300310
let max_total_routing_fee_msat = None;
301311

302-
let dns_resolvers = match &self.config.dns_resolvers_node_ids {
303-
Some(dns_resolvers) => Ok(dns_resolvers.clone()),
304-
None => Err(Error::DnsResolversNotConfigured),
305-
}?;
312+
let destinations: Vec<Destination> = self
313+
.config
314+
.hrn_config
315+
.dns_resolvers_node_ids
316+
.iter()
317+
.map(|node_id| Destination::Node(*node_id))
318+
.collect();
306319

307-
let destinations: Vec<Destination> =
308-
dns_resolvers.into_iter().map(|public_key| Destination::Node(public_key)).collect();
320+
let hrn = maybe_convert_hrn(hrn);
309321

310322
match self.channel_manager.pay_for_offer_from_human_readable_name(
311323
hrn.clone(),
@@ -316,7 +328,7 @@ impl Bolt12Payment {
316328
destinations,
317329
) {
318330
Ok(()) => {
319-
log_info!(self.logger, "Initiated sending {} msats to {}", amount_msat, name);
331+
log_info!(self.logger, "Initiated sending {} msats to {:?}", amount_msat, hrn);
320332
let kind = PaymentKind::Bolt12Offer {
321333
hash: None,
322334
preimage: None,
@@ -337,7 +349,7 @@ impl Bolt12Payment {
337349
Ok(payment_id)
338350
},
339351
Err(()) => {
340-
log_error!(self.logger, "Failed to send payment to {}", name);
352+
log_error!(self.logger, "Failed to send payment to {:?}", hrn);
341353
let kind = PaymentKind::Bolt12Offer {
342354
hash: None,
343355
preimage: None,
@@ -352,7 +364,7 @@ impl Bolt12Payment {
352364
Some(amount_msat),
353365
None,
354366
PaymentDirection::Outbound,
355-
PaymentStatus::Pending,
367+
PaymentStatus::Failed,
356368
);
357369
self.payment_store.insert(payment)?;
358370
Err(Error::PaymentSendingFailed)

src/payment/store.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ impl_writeable_tlv_based_enum!(PaymentKind,
470470
(2, preimage, option),
471471
(3, quantity, option),
472472
(4, secret, option),
473-
(6, offer_id, required),
473+
(6, offer_id, option),
474474
},
475475
(8, Spontaneous) => {
476476
(0, hash, required),
@@ -542,6 +542,7 @@ pub(crate) struct PaymentDetailsUpdate {
542542
pub direction: Option<PaymentDirection>,
543543
pub status: Option<PaymentStatus>,
544544
pub confirmation_status: Option<ConfirmationStatus>,
545+
pub quantity: Option<u64>,
545546
}
546547

547548
impl PaymentDetailsUpdate {
@@ -557,6 +558,7 @@ impl PaymentDetailsUpdate {
557558
direction: None,
558559
status: None,
559560
confirmation_status: None,
561+
quantity: None,
560562
}
561563
}
562564
}
@@ -584,6 +586,11 @@ impl From<&PaymentDetails> for PaymentDetailsUpdate {
584586
_ => None,
585587
};
586588

589+
let quantity = match value.kind {
590+
PaymentKind::Bolt12Offer { quantity, .. } => quantity,
591+
_ => None,
592+
};
593+
587594
Self {
588595
id: value.id,
589596
hash: Some(hash),
@@ -595,6 +602,7 @@ impl From<&PaymentDetails> for PaymentDetailsUpdate {
595602
direction: Some(value.direction),
596603
status: Some(value.status),
597604
confirmation_status,
605+
quantity,
598606
}
599607
}
600608
}

src/uniffi_types.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub use lightning::ln::types::ChannelId;
2828
pub use lightning::offers::invoice::Bolt12Invoice;
2929
pub use lightning::offers::offer::{Offer, OfferId};
3030
pub use lightning::offers::refund::Refund;
31+
pub use lightning::onion_message::dns_resolution::HumanReadableName as LdkHumanReadableName;
3132
pub use lightning::routing::gossip::{NodeAlias, NodeId, RoutingFees};
3233
pub use lightning::util::string::UntrustedString;
3334

@@ -656,6 +657,46 @@ impl UniffiCustomTypeConverter for DateTime {
656657
}
657658
}
658659

660+
pub struct HumanReadableName {
661+
pub inner: LdkHumanReadableName,
662+
}
663+
664+
impl HumanReadableName {
665+
/// Returns the underlying HumanReadableName [`LdkHumanReadableName`]
666+
pub fn into_inner(&self) -> LdkHumanReadableName {
667+
self.inner.clone()
668+
}
669+
670+
pub fn from_encoded(encoded: &str) -> Self {
671+
let hrn = match LdkHumanReadableName::from_encoded(encoded) {
672+
Ok(hrn) => Ok(hrn),
673+
Err(e) => Err(format!("Error creating HRN {:?}", e)),
674+
};
675+
676+
Self { inner: hrn.expect("Error creating HRN") }
677+
}
678+
679+
pub fn user(&self) -> String {
680+
self.inner.user().to_string()
681+
}
682+
683+
pub fn domain(&self) -> String {
684+
self.inner.domain().to_string()
685+
}
686+
}
687+
688+
impl From<LdkHumanReadableName> for HumanReadableName {
689+
fn from(ldk_hrn: LdkHumanReadableName) -> Self {
690+
HumanReadableName { inner: ldk_hrn }
691+
}
692+
}
693+
694+
impl From<HumanReadableName> for LdkHumanReadableName {
695+
fn from(wrapper: HumanReadableName) -> Self {
696+
wrapper.into_inner()
697+
}
698+
}
699+
659700
#[cfg(test)]
660701
mod tests {
661702
use super::*;

0 commit comments

Comments
 (0)