Skip to content

Commit c34abe3

Browse files
committed
Add a supported_quantity during offer generation
Bolt12Payment receive is updated to handle and set a quantity. If the quantiy is Some and set to 0 the new error type InvalidQuantity is returned. Otherwise we convert the set quantity to Quantity::Bounded(). If quantity is None we use Quantity::Unbounded.
1 parent de31355 commit c34abe3

File tree

5 files changed

+48
-21
lines changed

5 files changed

+48
-21
lines changed

bindings/ldk_node.udl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ interface Bolt12Payment {
124124
[Throws=NodeError]
125125
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note);
126126
[Throws=NodeError]
127-
Offer receive(u64 amount_msat, [ByRef]string description);
127+
Offer receive(u64 amount_msat, [ByRef]string description, u64? quantity);
128128
[Throws=NodeError]
129129
Offer receive_variable_amount([ByRef]string description);
130130
[Throws=NodeError]
@@ -201,6 +201,7 @@ enum NodeError {
201201
"InvalidChannelId",
202202
"InvalidNetwork",
203203
"InvalidUri",
204+
"InvalidQuantity",
204205
"DuplicatePayment",
205206
"UnsupportedCurrency",
206207
"InsufficientFunds",

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ pub enum Error {
8989
InvalidNetwork,
9090
/// The given URI is invalid.
9191
InvalidUri,
92+
/// The given quantity is invalid.
93+
InvalidQuantity,
9294
/// A payment with the given hash has already been initiated.
9395
DuplicatePayment,
9496
/// The provided offer was denonminated in an unsupported currency.
@@ -153,6 +155,7 @@ impl fmt::Display for Error {
153155
Self::InvalidChannelId => write!(f, "The given channel ID is invalid."),
154156
Self::InvalidNetwork => write!(f, "The given network is invalid."),
155157
Self::InvalidUri => write!(f, "The given URI is invalid."),
158+
Self::InvalidQuantity => write!(f, "The given quantity is invalid."),
156159
Self::DuplicatePayment => {
157160
write!(f, "A payment with the given hash has already been initiated.")
158161
},

src/payment/bolt12.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ use crate::types::ChannelManager;
1212

1313
use lightning::ln::channelmanager::{PaymentId, Retry};
1414
use lightning::offers::invoice::Bolt12Invoice;
15-
use lightning::offers::offer::{Amount, Offer};
15+
use lightning::offers::offer::{Amount, Offer, Quantity};
1616
use lightning::offers::parse::Bolt12SemanticError;
1717
use lightning::offers::refund::Refund;
1818
use lightning::util::string::UntrustedString;
1919

2020
use rand::RngCore;
2121

22+
use std::num::NonZeroU64;
2223
use std::sync::{Arc, RwLock};
2324
use std::time::{Duration, SystemTime, UNIX_EPOCH};
2425

@@ -246,14 +247,28 @@ impl Bolt12Payment {
246247

247248
/// Returns a payable offer that can be used to request and receive a payment of the amount
248249
/// given.
249-
pub fn receive(&self, amount_msat: u64, description: &str) -> Result<Offer, Error> {
250+
pub fn receive(
251+
&self, amount_msat: u64, description: &str, quantity: Option<u64>,
252+
) -> Result<Offer, Error> {
250253
let offer_builder = self.channel_manager.create_offer_builder().map_err(|e| {
251254
log_error!(self.logger, "Failed to create offer builder: {:?}", e);
252255
Error::OfferCreationFailed
253256
})?;
257+
258+
let user_set_qty = if let Some(qty) = quantity {
259+
if qty == 0 {
260+
return Err(Error::InvalidQuantity);
261+
} else {
262+
Quantity::Bounded(NonZeroU64::new(qty).unwrap())
263+
}
264+
} else {
265+
Quantity::Unbounded
266+
};
267+
254268
let offer = offer_builder
255269
.amount_msats(amount_msat)
256270
.description(description.to_string())
271+
.supported_quantity(user_set_qty)
257272
.build()
258273
.map_err(|e| {
259274
log_error!(self.logger, "Failed to create offer: {:?}", e);

src/payment/unified_qr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl UnifiedQrPayment {
9292

9393
let amount_msats = amount_sats * 1_000;
9494

95-
let bolt12_offer = match self.bolt12_payment.receive(amount_msats, description) {
95+
let bolt12_offer = match self.bolt12_payment.receive(amount_msats, description, None) {
9696
Ok(offer) => Some(offer),
9797
Err(e) => {
9898
log_error!(self.logger, "Failed to create offer: {}", e);

tests/integration_tests_rust.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,13 @@ fn simple_bolt12_send_receive() {
424424
std::thread::sleep(std::time::Duration::from_secs(1));
425425

426426
let expected_amount_msat = 100_000_000;
427-
let offer = node_b.bolt12_payment().receive(expected_amount_msat, "asdf").unwrap();
428-
let quantity = Some(1);
429-
let payer_note = Some("Test".to_string());
430-
let payment_id = node_a.bolt12_payment().send(&offer, quantity, payer_note.clone()).unwrap();
427+
let offer = node_b.bolt12_payment().receive(expected_amount_msat, "asdf", None).unwrap();
428+
let expected_quantity = Some(1);
429+
let expected_payer_note = Some("Test".to_string());
430+
let payment_id = node_a
431+
.bolt12_payment()
432+
.send(&offer, expected_quantity, expected_payer_note.clone())
433+
.unwrap();
431434

432435
expect_payment_successful_event!(node_a, Some(payment_id), None);
433436
let node_a_payments = node_a.list_payments();
@@ -444,8 +447,8 @@ fn simple_bolt12_send_receive() {
444447
assert!(hash.is_some());
445448
assert!(preimage.is_some());
446449
assert_eq!(offer_id, offer.id());
447-
assert_eq!(&quantity, qty);
448-
assert_eq!(payer_note.unwrap(), note.clone().unwrap().0);
450+
assert_eq!(&expected_quantity, qty);
451+
assert_eq!(expected_payer_note.unwrap(), note.clone().unwrap().0);
449452
//TODO: We should eventually set and assert the secret sender-side, too, but the BOLT12
450453
//API currently doesn't allow to do that.
451454
},
@@ -475,16 +478,21 @@ fn simple_bolt12_send_receive() {
475478
let offer_amount_msat = 100_000_000;
476479
let less_than_offer_amount = offer_amount_msat - 10_000;
477480
let expected_amount_msat = offer_amount_msat + 10_000;
478-
let offer = node_b.bolt12_payment().receive(offer_amount_msat, "asdf").unwrap();
479-
let quantity = Some(1);
480-
let payer_note = Some("Test".to_string());
481+
let offer = node_b.bolt12_payment().receive(offer_amount_msat, "asdf", None).unwrap();
482+
let expected_quantity = Some(1);
483+
let expected_payer_note = Some("Test".to_string());
481484
assert!(node_a
482485
.bolt12_payment()
483486
.send_using_amount(&offer, less_than_offer_amount, None, None)
484487
.is_err());
485488
let payment_id = node_a
486489
.bolt12_payment()
487-
.send_using_amount(&offer, expected_amount_msat, quantity, payer_note.clone())
490+
.send_using_amount(
491+
&offer,
492+
expected_amount_msat,
493+
expected_quantity,
494+
expected_payer_note.clone(),
495+
)
488496
.unwrap();
489497

490498
expect_payment_successful_event!(node_a, Some(payment_id), None);
@@ -502,8 +510,8 @@ fn simple_bolt12_send_receive() {
502510
assert!(hash.is_some());
503511
assert!(preimage.is_some());
504512
assert_eq!(offer_id, offer.id());
505-
assert_eq!(&quantity, qty);
506-
assert_eq!(payer_note.unwrap(), note.clone().unwrap().0);
513+
assert_eq!(&expected_quantity, qty);
514+
assert_eq!(expected_payer_note.unwrap(), note.clone().unwrap().0);
507515
//TODO: We should eventually set and assert the secret sender-side, too, but the BOLT12
508516
//API currently doesn't allow to do that.
509517
hash.unwrap()
@@ -533,11 +541,11 @@ fn simple_bolt12_send_receive() {
533541

534542
// Now node_b refunds the amount node_a just overpaid.
535543
let overpaid_amount = expected_amount_msat - offer_amount_msat;
536-
let quantity = Some(1);
537-
let payer_note = Some("Test".to_string());
544+
let expected_quantity = Some(1);
545+
let expected_payer_note = Some("Test".to_string());
538546
let refund = node_b
539547
.bolt12_payment()
540-
.initiate_refund(overpaid_amount, 3600, quantity, payer_note.clone())
548+
.initiate_refund(overpaid_amount, 3600, expected_quantity, expected_payer_note.clone())
541549
.unwrap();
542550
let invoice = node_a.bolt12_payment().request_refund_payment(&refund).unwrap();
543551
expect_payment_received_event!(node_a, overpaid_amount);
@@ -561,8 +569,8 @@ fn simple_bolt12_send_receive() {
561569
} => {
562570
assert!(hash.is_some());
563571
assert!(preimage.is_some());
564-
assert_eq!(&quantity, qty);
565-
assert_eq!(payer_note.unwrap(), note.clone().unwrap().0)
572+
assert_eq!(&expected_quantity, qty);
573+
assert_eq!(expected_payer_note.unwrap(), note.clone().unwrap().0)
566574
//TODO: We should eventually set and assert the secret sender-side, too, but the BOLT12
567575
//API currently doesn't allow to do that.
568576
},

0 commit comments

Comments
 (0)