Skip to content

Commit 19f4e2c

Browse files
committed
Add counterparty_skimmed_fee_msat field to PaymentKind::Bolt11Jit
.. we add a field describing exactly how much the LSP withheld.
1 parent f0338d1 commit 19f4e2c

File tree

5 files changed

+76
-4
lines changed

5 files changed

+76
-4
lines changed

bindings/ldk_node.udl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ interface ClosureReason {
385385
interface PaymentKind {
386386
Onchain(Txid txid, ConfirmationStatus status);
387387
Bolt11(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret);
388-
Bolt11Jit(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, LSPFeeLimits lsp_fee_limits);
388+
Bolt11Jit(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, u64? counterparty_skimmed_fee_msat, LSPFeeLimits lsp_fee_limits);
389389
Bolt12Offer(PaymentHash? hash, PaymentPreimage? preimage, PaymentSecret? secret, OfferId offer_id, UntrustedString? payer_note, u64? quantity);
390390
Bolt12Refund(PaymentHash? hash, PaymentPreimage? preimage, PaymentSecret? secret, UntrustedString? payer_note, u64? quantity);
391391
Spontaneous(PaymentHash hash, PaymentPreimage? preimage);

src/event.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,26 @@ where
659659
};
660660
}
661661

662+
// If the LSP skimmed anything, update our stored payment.
663+
if counterparty_skimmed_fee_msat > 0 {
664+
match info.kind {
665+
PaymentKind::Bolt11Jit { .. } => {
666+
let update = PaymentDetailsUpdate {
667+
counterparty_skimmed_fee_msat: Some(Some(counterparty_skimmed_fee_msat)),
668+
..PaymentDetailsUpdate::new(payment_id)
669+
};
670+
match self.payment_store.update(&update) {
671+
Ok(_) => (),
672+
Err(e) => {
673+
log_error!(self.logger, "Failed to access payment store: {}", e);
674+
return Err(ReplayEvent());
675+
},
676+
};
677+
}
678+
_ => debug_assert!(false, "We only expect the counterparty to get away with withholding fees for JIT payments."),
679+
}
680+
}
681+
662682
// If this is known by the store but ChannelManager doesn't know the preimage,
663683
// the payment has been registered via `_for_hash` variants and needs to be manually claimed via
664684
// user interaction.

src/payment/bolt11.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ impl Bolt11Payment {
664664
hash: payment_hash,
665665
preimage,
666666
secret: Some(payment_secret.clone()),
667+
counterparty_skimmed_fee_msat: None,
667668
lsp_fee_limits,
668669
};
669670
let payment = PaymentDetails::new(

src/payment/store.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ impl PaymentDetails {
165165
update_if_necessary!(self.fee_paid_msat, fee_paid_msat_opt);
166166
}
167167

168+
if let Some(skimmed_fee_msat) = update.counterparty_skimmed_fee_msat {
169+
match self.kind {
170+
PaymentKind::Bolt11Jit { ref mut counterparty_skimmed_fee_msat, .. } => {
171+
update_if_necessary!(*counterparty_skimmed_fee_msat, skimmed_fee_msat);
172+
},
173+
_ => debug_assert!(
174+
false,
175+
"We should only ever override counterparty_skimmed_fee_msat for JIT payments"
176+
),
177+
}
178+
}
179+
168180
if let Some(status) = update.status {
169181
update_if_necessary!(self.status, status);
170182
}
@@ -257,7 +269,14 @@ impl Readable for PaymentDetails {
257269

258270
if secret.is_some() {
259271
if let Some(lsp_fee_limits) = lsp_fee_limits {
260-
PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits }
272+
let counterparty_skimmed_fee_msat = None;
273+
PaymentKind::Bolt11Jit {
274+
hash,
275+
preimage,
276+
secret,
277+
counterparty_skimmed_fee_msat,
278+
lsp_fee_limits,
279+
}
261280
} else {
262281
PaymentKind::Bolt11 { hash, preimage, secret }
263282
}
@@ -346,6 +365,12 @@ pub enum PaymentKind {
346365
preimage: Option<PaymentPreimage>,
347366
/// The secret used by the payment.
348367
secret: Option<PaymentSecret>,
368+
/// The value, in thousands of a satoshi, that was deducted from this payment as an extra
369+
/// fee taken by our channel counterparty.
370+
///
371+
/// Will only be `Some` once we received the payment. Will always be `None` for LDK Node
372+
/// v0.4 and prior.
373+
counterparty_skimmed_fee_msat: Option<u64>,
349374
/// Limits applying to how much fee we allow an LSP to deduct from the payment amount.
350375
///
351376
/// Allowing them to deduct this fee from the first inbound payment will pay for the LSP's
@@ -423,6 +448,7 @@ impl_writeable_tlv_based_enum!(PaymentKind,
423448
},
424449
(4, Bolt11Jit) => {
425450
(0, hash, required),
451+
(1, counterparty_skimmed_fee_msat, option),
426452
(2, preimage, option),
427453
(4, secret, option),
428454
(6, lsp_fee_limits, required),
@@ -501,6 +527,7 @@ pub(crate) struct PaymentDetailsUpdate {
501527
pub secret: Option<Option<PaymentSecret>>,
502528
pub amount_msat: Option<Option<u64>>,
503529
pub fee_paid_msat: Option<Option<u64>>,
530+
pub counterparty_skimmed_fee_msat: Option<Option<u64>>,
504531
pub direction: Option<PaymentDirection>,
505532
pub status: Option<PaymentStatus>,
506533
pub confirmation_status: Option<ConfirmationStatus>,
@@ -515,6 +542,7 @@ impl PaymentDetailsUpdate {
515542
secret: None,
516543
amount_msat: None,
517544
fee_paid_msat: None,
545+
counterparty_skimmed_fee_msat: None,
518546
direction: None,
519547
status: None,
520548
confirmation_status: None,
@@ -538,13 +566,21 @@ impl From<&PaymentDetails> for PaymentDetailsUpdate {
538566
_ => None,
539567
};
540568

569+
let counterparty_skimmed_fee_msat = match value.kind {
570+
PaymentKind::Bolt11Jit { counterparty_skimmed_fee_msat, .. } => {
571+
Some(counterparty_skimmed_fee_msat)
572+
},
573+
_ => None,
574+
};
575+
541576
Self {
542577
id: value.id,
543578
hash: Some(hash),
544579
preimage: Some(preimage),
545580
secret: Some(secret),
546581
amount_msat: Some(value.amount_msat),
547582
fee_paid_msat: Some(value.fee_paid_msat),
583+
counterparty_skimmed_fee_msat,
548584
direction: Some(value.direction),
549585
status: Some(value.status),
550586
confirmation_status,
@@ -841,10 +877,17 @@ mod tests {
841877
);
842878

843879
match bolt11_jit_decoded.kind {
844-
PaymentKind::Bolt11Jit { hash: h, preimage: p, secret: s, lsp_fee_limits: l } => {
880+
PaymentKind::Bolt11Jit {
881+
hash: h,
882+
preimage: p,
883+
secret: s,
884+
counterparty_skimmed_fee_msat: c,
885+
lsp_fee_limits: l,
886+
} => {
845887
assert_eq!(hash, h);
846888
assert_eq!(preimage, p);
847889
assert_eq!(secret, s);
890+
assert_eq!(None, c);
848891
assert_eq!(lsp_fee_limits, Some(l));
849892
},
850893
_ => {

tests/integration_tests_rust.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,15 @@ fn lsps2_client_service_integration() {
11371137
let service_fee_msat = (jit_amount_msat * channel_opening_fee_ppm as u64) / 1_000_000;
11381138
let expected_received_amount_msat = jit_amount_msat - service_fee_msat;
11391139
expect_payment_successful_event!(payer_node, Some(payment_id), None);
1140-
expect_payment_received_event!(client_node, expected_received_amount_msat);
1140+
let client_payment_id =
1141+
expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap();
1142+
let client_payment = client_node.payment(&client_payment_id).unwrap();
1143+
match client_payment.kind {
1144+
PaymentKind::Bolt11Jit { counterparty_skimmed_fee_msat, .. } => {
1145+
assert_eq!(counterparty_skimmed_fee_msat, Some(service_fee_msat));
1146+
},
1147+
_ => panic!("Unexpected payment kind"),
1148+
}
11411149

11421150
let expected_channel_overprovisioning_msat =
11431151
(expected_received_amount_msat * channel_over_provisioning_ppm as u64) / 1_000_000;

0 commit comments

Comments
 (0)