Skip to content

Commit a8ed274

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 e0e1386 commit a8ed274

File tree

6 files changed

+91
-9
lines changed

6 files changed

+91
-9
lines changed

bindings/ldk_node.udl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ interface Bolt12Payment {
203203
[Throws=NodeError]
204204
PaymentId send([ByRef]Offer offer, u64? quantity, string? payer_note, RouteParametersConfig? route_parameters);
205205
[Throws=NodeError]
206-
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note, RouteParametersConfig? route_parameters);
206+
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note, RouteParametersConfig? route_parameters, HumanReadableName? hrn);
207207
[Throws=NodeError]
208208
Offer receive(u64 amount_msat, [ByRef]string description, u32? expiry_secs, u64? quantity);
209209
[Throws=NodeError]
@@ -322,6 +322,7 @@ enum NodeError {
322322
"LiquidityFeeTooHigh",
323323
"InvalidBlindedPaths",
324324
"AsyncPaymentServicesDisabled",
325+
"HrnParsingFailed",
325326
};
326327

327328
dictionary NodeStatus {
@@ -783,6 +784,13 @@ interface Offer {
783784
PublicKey? issuer_signing_pubkey();
784785
};
785786

787+
interface HumanReadableName {
788+
[Throws=NodeError, Name=from_encoded]
789+
constructor([ByRef] string encoded);
790+
string user();
791+
string domain();
792+
};
793+
786794
[Traits=(Debug, Display, Eq)]
787795
interface Refund {
788796
[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: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,58 @@ impl std::fmt::Display for Offer {
270270
}
271271
}
272272

273+
pub struct HumanReadableName {
274+
pub(crate) inner: LdkHumanReadableName,
275+
}
276+
277+
impl HumanReadableName {
278+
pub fn into_inner(&self) -> LdkHumanReadableName {
279+
self.inner.clone()
280+
}
281+
282+
pub fn from_encoded(encoded: &str) -> Result<Self, Error> {
283+
let hrn = match LdkHumanReadableName::from_encoded(encoded) {
284+
Ok(hrn) => Ok(hrn),
285+
Err(_) => Err(Error::HrnParsingFailed),
286+
}?;
287+
288+
Ok(Self { inner: hrn })
289+
}
290+
291+
pub fn user(&self) -> String {
292+
self.inner.user().to_string()
293+
}
294+
295+
pub fn domain(&self) -> String {
296+
self.inner.domain().to_string()
297+
}
298+
}
299+
300+
impl From<LdkHumanReadableName> for HumanReadableName {
301+
fn from(ldk_hrn: LdkHumanReadableName) -> Self {
302+
HumanReadableName { inner: ldk_hrn }
303+
}
304+
}
305+
306+
impl From<HumanReadableName> for LdkHumanReadableName {
307+
fn from(wrapper: HumanReadableName) -> Self {
308+
wrapper.into_inner()
309+
}
310+
}
311+
312+
impl Deref for HumanReadableName {
313+
type Target = LdkHumanReadableName;
314+
fn deref(&self) -> &Self::Target {
315+
&self.inner
316+
}
317+
}
318+
319+
impl AsRef<LdkHumanReadableName> for HumanReadableName {
320+
fn as_ref(&self) -> &LdkHumanReadableName {
321+
self.deref()
322+
}
323+
}
324+
273325
/// A `Refund` is a request to send an [`Bolt12Invoice`] without a preceding [`Offer`].
274326
///
275327
/// Typically, after an invoice is paid, the recipient may publish a refund allowing the sender to

src/payment/bolt12.rs

Lines changed: 12 additions & 3 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`].
@@ -192,7 +197,7 @@ impl Bolt12Payment {
192197
/// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis.
193198
pub fn send_using_amount(
194199
&self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>,
195-
route_parameters: Option<RouteParametersConfig>,
200+
route_parameters: Option<RouteParametersConfig>, hrn: Option<HumanReadableName>,
196201
) -> Result<PaymentId, Error> {
197202
if !*self.is_running.read().unwrap() {
198203
return Err(Error::NotRunning);
@@ -228,7 +233,11 @@ impl Bolt12Payment {
228233
retry_strategy,
229234
route_params_config: route_parameters,
230235
};
231-
let res = if let Some(quantity) = quantity {
236+
let res = if let Some(hrn) = hrn {
237+
let hrn = maybe_deref(&hrn);
238+
let offer = OfferFromHrn { offer: offer.clone(), hrn: *hrn };
239+
self.channel_manager.pay_for_offer_from_hrn(&offer, amount_msat, payment_id, params)
240+
} else if let Some(quantity) = quantity {
232241
self.channel_manager.pay_for_offer_with_quantity(
233242
&offer,
234243
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 std::vec::IntoIter;
2525

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

@@ -203,8 +204,12 @@ impl UnifiedPayment {
203204
resolved.methods().iter().find(|m| matches!(m, PaymentMethod::LightningBolt12(_)))
204205
{
205206
let offer = maybe_wrap(offer.clone());
206-
let payment_result = if let Some(amount_msat) = amount_msat {
207-
self.bolt12_payment.send_using_amount(&offer, amount_msat, None, None, route_parameters)
207+
208+
let payment_result = if let Ok(hrn) = HumanReadableName::from_encoded(uri_str) {
209+
let hrn = maybe_wrap(hrn.clone());
210+
self.bolt12_payment.send_using_amount(&offer, amount_msat.unwrap_or(0), None, None, route_parameters, Some(hrn))
211+
} else if let Some(amount_msat) = amount_msat {
212+
self.bolt12_payment.send_using_amount(&offer, amount_msat, None, None, route_parameters, None)
208213
} else {
209214
self.bolt12_payment.send(&offer, None, None, route_parameters)
210215
}

tests/integration_tests_rust.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ async fn simple_bolt12_send_receive() {
10231023
let expected_payer_note = Some("Test".to_string());
10241024
assert!(node_a
10251025
.bolt12_payment()
1026-
.send_using_amount(&offer, less_than_offer_amount, None, None, None)
1026+
.send_using_amount(&offer, less_than_offer_amount, None, None, None, None)
10271027
.is_err());
10281028
let payment_id = node_a
10291029
.bolt12_payment()
@@ -1033,6 +1033,7 @@ async fn simple_bolt12_send_receive() {
10331033
expected_quantity,
10341034
expected_payer_note.clone(),
10351035
None,
1036+
None,
10361037
)
10371038
.unwrap();
10381039

@@ -1281,8 +1282,10 @@ async fn async_payment() {
12811282

12821283
node_receiver.stop().unwrap();
12831284

1284-
let payment_id =
1285-
node_sender.bolt12_payment().send_using_amount(&offer, 5_000, None, None, None).unwrap();
1285+
let payment_id = node_sender
1286+
.bolt12_payment()
1287+
.send_using_amount(&offer, 5_000, None, None, None, None)
1288+
.unwrap();
12861289

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

0 commit comments

Comments
 (0)