Skip to content

Commit 2c8c06b

Browse files
committed
Use the pay_for_offer_from_hrn method from LDK upstream
This commit ensures that when using the unified API to send to a HRN, we use pay_for_offer_from_hrn
1 parent ed2afda commit 2c8c06b

File tree

6 files changed

+89
-7
lines changed

6 files changed

+89
-7
lines changed

bindings/ldk_node.udl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ interface Bolt12Payment {
202202
[Throws=NodeError]
203203
PaymentId send([ByRef]Offer offer, u64? quantity, string? payer_note);
204204
[Throws=NodeError]
205-
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note);
205+
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note, HumanReadableName? hrn);
206206
[Throws=NodeError]
207207
Offer receive(u64 amount_msat, [ByRef]string description, u32? expiry_secs, u64? quantity);
208208
[Throws=NodeError]
@@ -321,6 +321,7 @@ enum NodeError {
321321
"LiquidityFeeTooHigh",
322322
"InvalidBlindedPaths",
323323
"AsyncPaymentServicesDisabled",
324+
"HrnParsingFailed",
324325
};
325326

326327
dictionary NodeStatus {
@@ -781,6 +782,13 @@ interface Offer {
781782
PublicKey? issuer_signing_pubkey();
782783
};
783784

785+
interface HumanReadableName {
786+
[Throws=NodeError, Name=from_encoded]
787+
constructor([ByRef] string encoded);
788+
string user();
789+
string domain();
790+
};
791+
784792
[Traits=(Debug, Display, Eq)]
785793
interface Refund {
786794
[Throws=NodeError, Name=from_str]

src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ pub enum Error {
125125
InvalidBlindedPaths,
126126
/// Asynchronous payment services are disabled.
127127
AsyncPaymentServicesDisabled,
128+
/// Parsing a Human-Readable Name has failed.
129+
HrnParsingFailed,
128130
}
129131

130132
impl fmt::Display for Error {
@@ -202,6 +204,9 @@ impl fmt::Display for Error {
202204
Self::AsyncPaymentServicesDisabled => {
203205
write!(f, "Asynchronous payment services are disabled.")
204206
},
207+
Self::HrnParsingFailed => {
208+
write!(f, "Failed to parse a human-readable name.")
209+
},
205210
}
206211
}
207212
}

src/ffi/types.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub use lightning::chain::channelmonitor::BalanceSource;
6060
pub use lightning::events::{ClosureReason, PaymentFailureReason};
6161
pub use lightning::ln::types::ChannelId;
6262
pub use lightning::offers::offer::OfferId;
63+
pub use lightning::onion_message::dns_resolution::HumanReadableName as LdkHumanReadableName;
6364
pub use lightning::routing::gossip::{NodeAlias, NodeId, RoutingFees};
6465
pub use lightning::routing::router::RouteParametersConfig;
6566
pub use lightning_types::string::UntrustedString;
@@ -309,6 +310,58 @@ impl std::fmt::Display for Offer {
309310
}
310311
}
311312

313+
pub struct HumanReadableName {
314+
pub(crate) inner: LdkHumanReadableName,
315+
}
316+
317+
impl HumanReadableName {
318+
pub fn into_inner(&self) -> LdkHumanReadableName {
319+
self.inner.clone()
320+
}
321+
322+
pub fn from_encoded(encoded: &str) -> Result<Self, Error> {
323+
let hrn = match LdkHumanReadableName::from_encoded(encoded) {
324+
Ok(hrn) => Ok(hrn),
325+
Err(_) => Err(Error::HrnParsingFailed),
326+
}?;
327+
328+
Ok(Self { inner: hrn })
329+
}
330+
331+
pub fn user(&self) -> String {
332+
self.inner.user().to_string()
333+
}
334+
335+
pub fn domain(&self) -> String {
336+
self.inner.domain().to_string()
337+
}
338+
}
339+
340+
impl From<LdkHumanReadableName> for HumanReadableName {
341+
fn from(ldk_hrn: LdkHumanReadableName) -> Self {
342+
HumanReadableName { inner: ldk_hrn }
343+
}
344+
}
345+
346+
impl From<HumanReadableName> for LdkHumanReadableName {
347+
fn from(wrapper: HumanReadableName) -> Self {
348+
wrapper.into_inner()
349+
}
350+
}
351+
352+
impl Deref for HumanReadableName {
353+
type Target = LdkHumanReadableName;
354+
fn deref(&self) -> &Self::Target {
355+
&self.inner
356+
}
357+
}
358+
359+
impl AsRef<LdkHumanReadableName> for HumanReadableName {
360+
fn as_ref(&self) -> &LdkHumanReadableName {
361+
self.deref()
362+
}
363+
}
364+
312365
/// A `Refund` is a request to send an [`Bolt12Invoice`] without a preceding [`Offer`].
313366
///
314367
/// Typically, after an invoice is paid, the recipient may publish a refund allowing the sender to

src/payment/bolt12.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
1515

1616
use lightning::blinded_path::message::BlindedMessagePath;
1717
use lightning::ln::channelmanager::{OptionalOfferPaymentParams, PaymentId, Retry};
18-
use lightning::offers::offer::{Amount, Offer as LdkOffer, Quantity};
18+
use lightning::offers::offer::{Amount, Offer as LdkOffer, OfferFromHrn, Quantity};
1919
use lightning::offers::parse::Bolt12SemanticError;
2020
use lightning::routing::router::RouteParametersConfig;
2121
#[cfg(feature = "uniffi")]
@@ -45,6 +45,11 @@ type Refund = lightning::offers::refund::Refund;
4545
#[cfg(feature = "uniffi")]
4646
type Refund = Arc<crate::ffi::Refund>;
4747

48+
#[cfg(not(feature = "uniffi"))]
49+
type HumanReadableName = lightning::onion_message::dns_resolution::HumanReadableName;
50+
#[cfg(feature = "uniffi")]
51+
type HumanReadableName = Arc<crate::ffi::HumanReadableName>;
52+
4853
/// A payment handler allowing to create and pay [BOLT 12] offers and refunds.
4954
///
5055
/// Should be retrieved by calling [`Node::bolt12_payment`].
@@ -183,6 +188,7 @@ impl Bolt12Payment {
183188
/// response.
184189
pub fn send_using_amount(
185190
&self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>,
191+
hrn: Option<HumanReadableName>,
186192
) -> Result<PaymentId, Error> {
187193
if !*self.is_running.read().unwrap() {
188194
return Err(Error::NotRunning);
@@ -217,7 +223,11 @@ impl Bolt12Payment {
217223
retry_strategy,
218224
route_params_config,
219225
};
220-
let res = if let Some(quantity) = quantity {
226+
let res = if let Some(hrn) = hrn {
227+
let hrn = maybe_deref(&hrn);
228+
let offer = OfferFromHrn { offer: offer.clone(), hrn: *hrn };
229+
self.channel_manager.pay_for_offer_from_hrn(&offer, amount_msat, payment_id, params)
230+
} else if let Some(quantity) = quantity {
221231
self.channel_manager.pay_for_offer_with_quantity(
222232
&offer,
223233
Some(amount_msat),

src/payment/unified.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::Config;
2525

2626
use lightning::ln::channelmanager::PaymentId;
2727
use lightning::offers::offer::Offer;
28+
use lightning::onion_message::dns_resolution::HumanReadableName;
2829
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
2930

3031
use bip21::de::ParamKind;
@@ -198,8 +199,12 @@ impl UnifiedPayment {
198199
resolved.methods().iter().find(|m| matches!(m, PaymentMethod::LightningBolt12(_)))
199200
{
200201
let offer = maybe_wrap(offer.clone());
201-
let payment_result = if let Some(amount_msat) = amount_msat {
202-
self.bolt12_payment.send_using_amount(&offer, amount_msat, None, None)
202+
203+
let payment_result = if let Ok(hrn) = HumanReadableName::from_encoded(uri_str) {
204+
let hrn = maybe_wrap(hrn.clone());
205+
self.bolt12_payment.send_using_amount(&offer, amount_msat.unwrap_or(0), None, None, Some(hrn))
206+
} else if let Some(amount_msat) = amount_msat {
207+
self.bolt12_payment.send_using_amount(&offer, amount_msat, None, None, None)
203208
} else {
204209
self.bolt12_payment.send(&offer, None, None)
205210
}

tests/integration_tests_rust.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ fn simple_bolt12_send_receive() {
10071007
let expected_payer_note = Some("Test".to_string());
10081008
assert!(node_a
10091009
.bolt12_payment()
1010-
.send_using_amount(&offer, less_than_offer_amount, None, None)
1010+
.send_using_amount(&offer, less_than_offer_amount, None, None, None)
10111011
.is_err());
10121012
let payment_id = node_a
10131013
.bolt12_payment()
@@ -1016,6 +1016,7 @@ fn simple_bolt12_send_receive() {
10161016
expected_amount_msat,
10171017
expected_quantity,
10181018
expected_payer_note.clone(),
1019+
None,
10191020
)
10201021
.unwrap();
10211022

@@ -1257,7 +1258,7 @@ fn async_payment() {
12571258
node_receiver.stop().unwrap();
12581259

12591260
let payment_id =
1260-
node_sender.bolt12_payment().send_using_amount(&offer, 5_000, None, None).unwrap();
1261+
node_sender.bolt12_payment().send_using_amount(&offer, 5_000, None, None, None).unwrap();
12611262

12621263
// Sleep to allow the payment reach a state where the htlc is held and waiting for the receiver to come online.
12631264
std::thread::sleep(std::time::Duration::from_millis(3000));

0 commit comments

Comments
 (0)