Skip to content

Commit e36a2c0

Browse files
committed
add max_fee for payments
1 parent 1cf2906 commit e36a2c0

File tree

6 files changed

+31
-4
lines changed

6 files changed

+31
-4
lines changed

proto/lndkrpc.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ message PayOfferRequest {
1313
optional uint64 amount = 2;
1414
optional string payer_note = 3;
1515
optional uint32 response_invoice_timeout = 4;
16+
optional uint64 max_fee = 5;
1617
}
1718

1819
message PayOfferResponse {
@@ -38,6 +39,7 @@ message GetInvoiceResponse {
3839
message PayInvoiceRequest {
3940
string invoice = 1;
4041
optional uint64 amount = 2;
42+
optional uint64 max_fee = 3;
4143
}
4244

4345
message PayInvoiceResponse {

src/cli.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ async fn main() {
215215
amount,
216216
payer_note,
217217
response_invoice_timeout,
218+
max_fee: None,
218219
});
219220
add_metadata(&mut request, macaroon).unwrap_or_else(|_| exit(1));
220221

@@ -314,6 +315,7 @@ async fn main() {
314315
let mut request = Request::new(PayInvoiceRequest {
315316
invoice: invoice_string.to_owned(),
316317
amount,
318+
max_fee: None,
317319
});
318320
add_metadata(&mut request, macaroon).unwrap_or_else(|_| exit(1));
319321
match client.pay_invoice(request).await {

src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ pub struct PayOfferParams {
289289
/// The amount of time in seconds that we will wait for the offer creator to respond with
290290
/// an invoice. If not provided, we will use the default value of 15 seconds.
291291
pub response_invoice_timeout: Option<u32>,
292+
pub max_fee: Option<u64>,
292293
}
293294

294295
impl OfferHandler {
@@ -312,9 +313,9 @@ impl OfferHandler {
312313
/// offer.
313314
pub async fn pay_offer(&self, cfg: PayOfferParams) -> Result<Payment, OfferError> {
314315
let client_clone = cfg.client.clone();
316+
let max_fee: Option<u64> = cfg.max_fee.clone();
315317
let (invoice, validated_amount, payment_id) = self.get_invoice(cfg).await?;
316-
317-
self.pay_invoice(client_clone, validated_amount, &invoice, payment_id)
318+
self.pay_invoice(client_clone, validated_amount, &invoice, payment_id, max_fee)
318319
.await
319320
}
320321

@@ -385,6 +386,7 @@ impl OfferHandler {
385386
amount: u64,
386387
invoice: &Bolt12Invoice,
387388
payment_id: PaymentId,
389+
max_fee: Option<u64>,
388390
) -> Result<Payment, OfferError> {
389391
let payment_hash = invoice.payment_hash();
390392
let path_info = invoice.payment_paths()[0].clone();
@@ -397,6 +399,7 @@ impl OfferHandler {
397399
payment_hash: payment_hash.0,
398400
msats: amount,
399401
payment_id,
402+
max_fee,
400403
};
401404

402405
let intro_node_id = match params.path.introduction_node {

src/lndk_offers.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,18 @@ impl OfferHandler {
329329
.await
330330
.map_err(OfferError::RouteFailure)?;
331331

332+
let route: Route = resp.routes[0].clone();
333+
if let Some(max_fee) = params.max_fee {
334+
let route_fee = route.total_fees_msat as u64;
335+
if route_fee > max_fee {
336+
return Err(OfferError::RouteFailure(Status::unknown(
337+
"Route fee is greater than max fee",
338+
)));
339+
}
340+
}
341+
332342
let _ = payer
333-
.send_to_route(params.payment_hash, resp.routes[0].clone())
343+
.send_to_route(params.payment_hash, route)
334344
.await
335345
.map_err(OfferError::RouteFailure)?;
336346

@@ -357,6 +367,7 @@ pub struct SendPaymentParams {
357367
pub payment_hash: [u8; 32],
358368
pub msats: u64,
359369
pub payment_id: PaymentId,
370+
pub max_fee: Option<u64>,
360371
}
361372

362373
/// Checks that the user-provided amount matches the provided offer or invoice.
@@ -1239,6 +1250,7 @@ mod tests {
12391250
payment_hash: payment_hash,
12401251
msats: 2000,
12411252
payment_id,
1253+
max_fee: None,
12421254
};
12431255
assert!(handler.send_payment(payer_mock, params).await.is_ok());
12441256
}
@@ -1263,6 +1275,7 @@ mod tests {
12631275
payment_hash: payment_hash,
12641276
msats: 2000,
12651277
payment_id,
1278+
max_fee: None,
12661279
};
12671280
assert!(handler.send_payment(payer_mock, params).await.is_err());
12681281
}
@@ -1297,6 +1310,7 @@ mod tests {
12971310
payment_hash: payment_hash,
12981311
msats: 2000,
12991312
payment_id,
1313+
max_fee: None,
13001314
};
13011315
assert!(handler.send_payment(payer_mock, params).await.is_err());
13021316
}

src/server.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ impl Offers for LNDKServer {
114114
destination,
115115
reply_path: Some(reply_path),
116116
response_invoice_timeout: inner_request.response_invoice_timeout,
117+
max_fee: inner_request.max_fee,
117118
};
118119

119120
let payment = match self.offer_handler.pay_offer(cfg).await {
@@ -208,6 +209,7 @@ impl Offers for LNDKServer {
208209
destination,
209210
reply_path: Some(reply_path),
210211
response_invoice_timeout: inner_request.response_invoice_timeout,
212+
max_fee: None,
211213
};
212214

213215
let (invoice, _, payment_id) = match self.offer_handler.get_invoice(cfg).await {
@@ -270,9 +272,10 @@ impl Offers for LNDKServer {
270272
Err(e) => return Err(Status::invalid_argument(e.to_string())),
271273
};
272274
let payment_id = PaymentId(self.offer_handler.messenger_utils.get_secure_random_bytes());
275+
let max_fee: Option<u64> = inner_request.max_fee.into();
273276
let invoice = match self
274277
.offer_handler
275-
.pay_invoice(client, amount, &invoice, payment_id)
278+
.pay_invoice(client, amount, &invoice, payment_id, max_fee)
276279
.await
277280
{
278281
Ok(invoice) => {

tests/integration_tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ async fn create_offers(
5858
destination: Destination::BlindedPath(blinded_path),
5959
reply_path: Some(reply_path),
6060
response_invoice_timeout: None,
61+
max_fee: None,
6162
};
6263

6364
pay_cfgs.push(pay_cfg);
@@ -344,6 +345,7 @@ async fn test_lndk_pay_offer() {
344345
destination: Destination::BlindedPath(blinded_path.clone()),
345346
reply_path: Some(reply_path),
346347
response_invoice_timeout: None,
348+
max_fee: None
347349
};
348350
select! {
349351
val = messenger.run(lndk_cfg.clone(), Arc::clone(&handler)) => {
@@ -401,6 +403,7 @@ async fn test_lndk_pay_offer_concurrently() {
401403
destination: Destination::BlindedPath(blinded_path.clone()),
402404
reply_path: Some(reply_path),
403405
response_invoice_timeout: None,
406+
max_fee: None,
404407
};
405408
// Let's also try to pay the same offer multiple times concurrently.
406409
select! {

0 commit comments

Comments
 (0)