Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,14 @@ interface Bolt11Payment {
[Throws=NodeError]
Bolt11Invoice receive_for_hash(u64 amount_msat, [ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, PaymentHash payment_hash);
[Throws=NodeError]
Bolt11Invoice receive_for_hash_with_min_cltv_expiry_delta(u64 amount_msat, [ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, PaymentHash payment_hash, u16 min_cltv_expiry_delta);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount_for_hash([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, PaymentHash payment_hash);
[Throws=NodeError]
Bolt11Invoice receive_variable_amount_for_hash_with_min_cltv_expiry_delta([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, PaymentHash payment_hash, u16 min_cltv_expiry_delta);
[Throws=NodeError]
Bolt11Invoice receive_via_jit_channel(u64 amount_msat, [ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_lsp_fee_limit_msat);
[Throws=NodeError]
Bolt11Invoice receive_via_jit_channel_for_hash(u64 amount_msat, [ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_lsp_fee_limit_msat, PaymentHash payment_hash);
Expand Down
81 changes: 76 additions & 5 deletions src/payment/bolt11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,8 @@ impl Bolt11Payment {
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(Some(amount_msat), &description, expiry_secs, None)?;
let invoice =
self.receive_inner(Some(amount_msat), &description, expiry_secs, None, None)?;
Ok(maybe_wrap(invoice))
}

Expand All @@ -435,8 +436,44 @@ impl Bolt11Payment {
payment_hash: PaymentHash,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice =
self.receive_inner(Some(amount_msat), &description, expiry_secs, Some(payment_hash))?;
let invoice = self.receive_inner(
Some(amount_msat),
&description,
expiry_secs,
Some(payment_hash),
None,
)?;
Ok(maybe_wrap(invoice))
}

/// Returns a payable invoice that can be used to request a payment of the amount
/// given for the given payment hash.
///
/// We will register the given payment hash and emit a [`PaymentClaimable`] event once
/// the inbound payment arrives.
///
/// `min_cltv_expiry_delta` sets the minimum CLTV delta to use for the final hop.
///
/// **Note:** users *MUST* handle this event and claim the payment manually via
/// [`claim_for_hash`] as soon as they have obtained access to the preimage of the given
/// payment hash. If they're unable to obtain the preimage, they *MUST* immediately fail the payment via
/// [`fail_for_hash`].
///
/// [`PaymentClaimable`]: crate::Event::PaymentClaimable
/// [`claim_for_hash`]: Self::claim_for_hash
/// [`fail_for_hash`]: Self::fail_for_hash
pub fn receive_for_hash_with_min_cltv_expiry_delta(
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
payment_hash: PaymentHash, min_cltv_expiry_delta: u16,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(
Some(amount_msat),
&description,
expiry_secs,
Some(payment_hash),
Some(min_cltv_expiry_delta),
)?;
Ok(maybe_wrap(invoice))
}

Expand All @@ -448,7 +485,7 @@ impl Bolt11Payment {
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(None, &description, expiry_secs, None)?;
let invoice = self.receive_inner(None, &description, expiry_secs, None, None)?;
Ok(maybe_wrap(invoice))
}

Expand All @@ -470,19 +507,53 @@ impl Bolt11Payment {
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(None, &description, expiry_secs, Some(payment_hash))?;
let invoice =
self.receive_inner(None, &description, expiry_secs, Some(payment_hash), None)?;
Ok(maybe_wrap(invoice))
}

/// Returns a payable invoice that can be used to request a payment for the given payment hash
/// and the amount to be determined by the user, also known as a "zero-amount" invoice.
///
/// We will register the given payment hash and emit a [`PaymentClaimable`] event once
/// the inbound payment arrives.
///
/// `min_cltv_expiry_delta` sets the minimum CLTV delta to use for the final hop.
///
/// **Note:** users *MUST* handle this event and claim the payment manually via
/// [`claim_for_hash`] as soon as they have obtained access to the preimage of the given
/// payment hash. If they're unable to obtain the preimage, they *MUST* immediately fail the payment via
/// [`fail_for_hash`].
///
/// [`PaymentClaimable`]: crate::Event::PaymentClaimable
/// [`claim_for_hash`]: Self::claim_for_hash
/// [`fail_for_hash`]: Self::fail_for_hash
pub fn receive_variable_amount_for_hash_with_min_cltv_expiry_delta(
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
min_cltv_expiry_delta: u16,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(
None,
&description,
expiry_secs,
Some(payment_hash),
Some(min_cltv_expiry_delta),
)?;
Ok(maybe_wrap(invoice))
}

pub(crate) fn receive_inner(
&self, amount_msat: Option<u64>, invoice_description: &LdkBolt11InvoiceDescription,
expiry_secs: u32, manual_claim_payment_hash: Option<PaymentHash>,
min_cltv_expiry_delta: Option<u16>,
) -> Result<LdkBolt11Invoice, Error> {
let invoice = {
let invoice_params = Bolt11InvoiceParameters {
amount_msats: amount_msat,
description: invoice_description.clone(),
invoice_expiry_delta_secs: Some(expiry_secs),
min_final_cltv_expiry_delta: min_cltv_expiry_delta,
payment_hash: manual_claim_payment_hash,
..Default::default()
};
Expand Down
1 change: 1 addition & 0 deletions src/payment/unified_qr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ impl UnifiedQrPayment {
&invoice_description,
expiry_sec,
None,
None,
) {
Ok(invoice) => Some(invoice),
Err(e) => {
Expand Down
35 changes: 35 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,41 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
manual_payment_hash,
)
.unwrap();
let min_cltv_expiry_delta = 100;
let manual_preimage_with_min_cltv = PaymentPreimage([44u8; 32]);
let manual_payment_hash_with_min_cltv =
PaymentHash(Sha256::hash(&manual_preimage_with_min_cltv.0).to_byte_array());
let manual_invoice_with_min_cltv = node_b
.bolt11_payment()
.receive_for_hash_with_min_cltv_expiry_delta(
invoice_amount_3_msat,
&invoice_description.clone().into(),
9217,
manual_payment_hash_with_min_cltv,
min_cltv_expiry_delta,
)
.unwrap();
let expected_min_final_cltv_expiry_delta = u64::from(min_cltv_expiry_delta) + 3;
assert_eq!(
manual_invoice_with_min_cltv.min_final_cltv_expiry_delta(),
expected_min_final_cltv_expiry_delta
);
let manual_variable_preimage_with_min_cltv = PaymentPreimage([45u8; 32]);
let manual_variable_payment_hash_with_min_cltv =
PaymentHash(Sha256::hash(&manual_variable_preimage_with_min_cltv.0).to_byte_array());
let manual_variable_invoice_with_min_cltv = node_b
.bolt11_payment()
.receive_variable_amount_for_hash_with_min_cltv_expiry_delta(
&invoice_description.clone().into(),
9217,
manual_variable_payment_hash_with_min_cltv,
min_cltv_expiry_delta,
)
.unwrap();
assert_eq!(
manual_variable_invoice_with_min_cltv.min_final_cltv_expiry_delta(),
expected_min_final_cltv_expiry_delta
);
let manual_payment_id = node_a.bolt11_payment().send(&manual_invoice, None).unwrap();

let claimable_amount_msat = expect_payment_claimable_event!(
Expand Down
Loading