Skip to content

Commit 3ae60bf

Browse files
committed
Account for pending splice in claimable balances
There are two states in which a pending splice balance should be considered: 1. The channel has closed with a confirmed holder commitment transaction from a splice that did not become locked. The balance from this transaction is reported. 2. The channel is open and has multiple holder commitment transaction candidates that are valid based on the funding transaction that confirms. We want to report the pending splice balance to users while it has yet to become locked, such that they are able to see their funds have moved from their onchain wallet to the channel. We default to reporting the latest splice/RBF balance via `Balance::claimable_amount_satoshis` to mimic how an onchain wallet would behave when reporting unconfirmed balance.
1 parent b40dca0 commit 3ae60bf

File tree

2 files changed

+111
-53
lines changed

2 files changed

+111
-53
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,24 @@ pub enum BalanceSource {
777777
Htlc,
778778
}
779779

780+
/// The claimable balance of a holder commitment transaction that has yet to be broadcast.
781+
#[derive(Clone, Debug, PartialEq, Eq)]
782+
#[cfg_attr(test, derive(PartialOrd, Ord))]
783+
pub struct HolderCommitmentTransactionBalance {
784+
/// The amount available to claim, in satoshis, excluding the on-chain fees which will be
785+
/// required to do so.
786+
pub amount_satoshis: u64,
787+
/// The transaction fee we pay for the closing commitment transaction. This amount is not
788+
/// included in the [`HolderCommitmentTransaction::amount_satoshis`] value.
789+
/// This amount includes the sum of dust HTLCs on the commitment transaction, any elided anchors,
790+
/// as well as the sum of msat amounts rounded down from non-dust HTLCs.
791+
///
792+
/// Note that if this channel is inbound (and thus our counterparty pays the commitment
793+
/// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
794+
/// 0.0.124, the channel is always treated as outbound (and thus this value is never zero).
795+
pub transaction_fee_satoshis: u64,
796+
}
797+
780798
/// Details about the balance(s) available for spending once the channel appears on chain.
781799
///
782800
/// See [`ChannelMonitor::get_claimable_balances`] for more details on when these will or will not
@@ -785,21 +803,21 @@ pub enum BalanceSource {
785803
#[cfg_attr(test, derive(PartialOrd, Ord))]
786804
pub enum Balance {
787805
/// The channel is not yet closed (or the commitment or closing transaction has not yet
788-
/// appeared in a block). The given balance is claimable (less on-chain fees) if the channel is
789-
/// force-closed now.
806+
/// appeared in a block).
790807
ClaimableOnChannelClose {
791-
/// The amount available to claim, in satoshis, excluding the on-chain fees which will be
792-
/// required to do so.
793-
amount_satoshis: u64,
794-
/// The transaction fee we pay for the closing commitment transaction. This amount is not
795-
/// included in the [`Balance::ClaimableOnChannelClose::amount_satoshis`] value.
796-
/// This amount includes the sum of dust HTLCs on the commitment transaction, any elided anchors,
797-
/// as well as the sum of msat amounts rounded down from non-dust HTLCs.
808+
/// A list of balance candidates based on the latest set of valid holder commitment
809+
/// transactions that can hit the chain. Typically, a channel only has one valid holder
810+
/// commitment transaction that spends the current funding output. As soon as a channel is
811+
/// spliced, an alternative holder commitment transaction exists spending the new funding
812+
/// output. More alternative holder commitment transactions can exist as the splice remains
813+
/// pending and RBF attempts are made.
798814
///
799-
/// Note that if this channel is inbound (and thus our counterparty pays the commitment
800-
/// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
801-
/// 0.0.124, the channel is always treated as outbound (and thus this value is never zero).
802-
transaction_fee_satoshis: u64,
815+
/// The candidates are sorted by the order in which the holder commitment transactions were
816+
/// negotiated. When only one candidate exists, the channel does not have a splice pending.
817+
/// When multiple candidates exist, the last one reflects the balance of the
818+
/// latest splice/RBF attempt, while the first reflects the balance prior to the splice
819+
/// occurring.
820+
balance_candidates: Vec<HolderCommitmentTransactionBalance>,
803821
/// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
804822
/// from us and are related to a payment which was sent by us. This is the sum of the
805823
/// millisatoshis part of all HTLCs which are otherwise represented by
@@ -821,7 +839,7 @@ pub enum Balance {
821839
/// to us and for which we know the preimage. This is the sum of the millisatoshis part of
822840
/// all HTLCs which would be represented by [`Balance::ContentiousClaimable`] on channel
823841
/// close, but whose current value is included in
824-
/// [`Balance::ClaimableOnChannelClose::amount_satoshis`], as well as any dust HTLCs which
842+
/// [`HolderCommitmentTransactionBalance::amount_satoshis`], as well as any dust HTLCs which
825843
/// would otherwise be represented the same.
826844
///
827845
/// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's
@@ -928,7 +946,11 @@ impl Balance {
928946
#[rustfmt::skip]
929947
pub fn claimable_amount_satoshis(&self) -> u64 {
930948
match self {
931-
Balance::ClaimableOnChannelClose { amount_satoshis, .. }|
949+
Balance::ClaimableOnChannelClose { balance_candidates, .. } => {
950+
// FIXME: Should we report the balance for the currently confirmed splice
951+
// transaction before it has been locked?
952+
balance_candidates.last().map(|balance| balance.amount_satoshis).unwrap_or(0)
953+
},
932954
Balance::ClaimableAwaitingConfirmations { amount_satoshis, .. }|
933955
Balance::ContentiousClaimable { amount_satoshis, .. }|
934956
Balance::CounterpartyRevokedOutputClaimable { amount_satoshis, .. }
@@ -2671,7 +2693,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
26712693
debug_assert!(htlc_input_idx_opt.is_some());
26722694
BitcoinOutPoint::new(*txid, htlc_input_idx_opt.unwrap_or(0))
26732695
} else {
2674-
debug_assert!(!self.channel_type_features().supports_anchors_zero_fee_htlc_tx());
2696+
let funding = get_confirmed_funding_scope!(self);
2697+
debug_assert!(!funding.channel_type_features().supports_anchors_zero_fee_htlc_tx());
26752698
BitcoinOutPoint::new(*txid, 0)
26762699
}
26772700
} else {
@@ -2833,8 +2856,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
28332856
}
28342857

28352858
if let Some(txid) = confirmed_txid {
2859+
let funding_spent = get_confirmed_funding_scope!(us);
28362860
let mut found_commitment_tx = false;
2837-
if let Some(counterparty_tx_htlcs) = us.funding.counterparty_claimable_outpoints.get(&txid) {
2861+
if let Some(counterparty_tx_htlcs) = funding_spent.counterparty_claimable_outpoints.get(&txid) {
28382862
// First look for the to_remote output back to us.
28392863
if let Some(conf_thresh) = pending_commitment_tx_conf_thresh {
28402864
if let Some(value) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
@@ -2855,7 +2879,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
28552879
// confirmation with the same height or have never met our dust amount.
28562880
}
28572881
}
2858-
if Some(txid) == us.funding.current_counterparty_commitment_txid || Some(txid) == us.funding.prev_counterparty_commitment_txid {
2882+
if Some(txid) == funding_spent.current_counterparty_commitment_txid || Some(txid) == funding_spent.prev_counterparty_commitment_txid {
28592883
walk_htlcs!(false, false, counterparty_tx_htlcs.iter().map(|(a, b)| (a, b.as_ref().map(|b| &**b))));
28602884
} else {
28612885
walk_htlcs!(false, true, counterparty_tx_htlcs.iter().map(|(a, b)| (a, b.as_ref().map(|b| &**b))));
@@ -2898,17 +2922,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
28982922
}
28992923
}
29002924
found_commitment_tx = true;
2901-
} else if txid == us.funding.current_holder_commitment_tx.trust().txid() {
2925+
} else if txid == funding_spent.current_holder_commitment_tx.trust().txid() {
29022926
walk_htlcs!(true, false, holder_commitment_htlcs!(us, CURRENT_WITH_SOURCES));
29032927
if let Some(conf_thresh) = pending_commitment_tx_conf_thresh {
29042928
res.push(Balance::ClaimableAwaitingConfirmations {
2905-
amount_satoshis: us.funding.current_holder_commitment_tx.to_broadcaster_value_sat(),
2929+
amount_satoshis: funding_spent.current_holder_commitment_tx.to_broadcaster_value_sat(),
29062930
confirmation_height: conf_thresh,
29072931
source: BalanceSource::HolderForceClosed,
29082932
});
29092933
}
29102934
found_commitment_tx = true;
2911-
} else if let Some(prev_holder_commitment_tx) = &us.funding.prev_holder_commitment_tx {
2935+
} else if let Some(prev_holder_commitment_tx) = &funding_spent.prev_holder_commitment_tx {
29122936
if txid == prev_holder_commitment_tx.trust().txid() {
29132937
walk_htlcs!(true, false, holder_commitment_htlcs!(us, PREV_WITH_SOURCES).unwrap());
29142938
if let Some(conf_thresh) = pending_commitment_tx_conf_thresh {
@@ -2927,7 +2951,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29272951
// neither us nor our counterparty misbehaved. At worst we've under-estimated
29282952
// the amount we can claim as we'll punish a misbehaving counterparty.
29292953
res.push(Balance::ClaimableAwaitingConfirmations {
2930-
amount_satoshis: us.funding.current_holder_commitment_tx.to_broadcaster_value_sat(),
2954+
amount_satoshis: funding_spent.current_holder_commitment_tx.to_broadcaster_value_sat(),
29312955
confirmation_height: conf_thresh,
29322956
source: BalanceSource::CoopClose,
29332957
});
@@ -2939,6 +2963,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29392963
let mut outbound_forwarded_htlc_rounded_msat = 0;
29402964
let mut inbound_claiming_htlc_rounded_msat = 0;
29412965
let mut inbound_htlc_rounded_msat = 0;
2966+
// We share the same set of HTLCs across all scopes, so we don't need to check the other
2967+
// scopes as it'd be redundant.
29422968
for (htlc, source) in holder_commitment_htlcs!(us, CURRENT_WITH_SOURCES) {
29432969
let rounded_value_msat = if htlc.transaction_output_index.is_none() {
29442970
htlc.amount_msat
@@ -2980,16 +3006,27 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
29803006
}
29813007
}
29823008
}
2983-
let to_self_value_sat = us.funding.current_holder_commitment_tx.to_broadcaster_value_sat();
3009+
let balance_candidates = core::iter::once(&us.funding)
3010+
.chain(us.pending_funding.iter())
3011+
.map(|funding| {
3012+
let to_self_value_sat = funding.current_holder_commitment_tx.to_broadcaster_value_sat();
3013+
// In addition to `commit_tx_fee_sat`, this can also include dust HTLCs, any
3014+
// elided anchors, and the total msat amount rounded down from non-dust HTLCs.
3015+
let transaction_fee_satoshis = if us.holder_pays_commitment_tx_fee.unwrap_or(true) {
3016+
let transaction = &funding.current_holder_commitment_tx.trust().built_transaction().transaction;
3017+
let output_value_sat: u64 = transaction.output.iter().map(|txout| txout.value.to_sat()).sum();
3018+
funding.channel_parameters.channel_value_satoshis - output_value_sat
3019+
} else {
3020+
0
3021+
};
3022+
HolderCommitmentTransactionBalance {
3023+
amount_satoshis: to_self_value_sat + claimable_inbound_htlc_value_sat,
3024+
transaction_fee_satoshis,
3025+
}
3026+
})
3027+
.collect();
29843028
res.push(Balance::ClaimableOnChannelClose {
2985-
amount_satoshis: to_self_value_sat + claimable_inbound_htlc_value_sat,
2986-
// In addition to `commit_tx_fee_sat`, this can also include dust HTLCs, any elided anchors,
2987-
// and the total msat amount rounded down from non-dust HTLCs
2988-
transaction_fee_satoshis: if us.holder_pays_commitment_tx_fee.unwrap_or(true) {
2989-
let transaction = &us.funding.current_holder_commitment_tx.trust().built_transaction().transaction;
2990-
let output_value_sat: u64 = transaction.output.iter().map(|txout| txout.value.to_sat()).sum();
2991-
us.funding.channel_parameters.channel_value_satoshis - output_value_sat
2992-
} else { 0 },
3029+
balance_candidates,
29933030
outbound_payment_htlc_rounded_msat,
29943031
outbound_forwarded_htlc_rounded_msat,
29953032
inbound_claiming_htlc_rounded_msat,

lightning/src/ln/monitor_tests.rs

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
1414
use crate::sign::{ecdsa::EcdsaChannelSigner, OutputSpender, SignerProvider, SpendableOutputDescriptor};
1515
use crate::chain::Watch;
16-
use crate::chain::channelmonitor::{ANTI_REORG_DELAY, ARCHIVAL_DELAY_BLOCKS,LATENCY_GRACE_PERIOD_BLOCKS, COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE, Balance, BalanceSource, ChannelMonitorUpdateStep};
16+
use crate::chain::channelmonitor::{Balance, BalanceSource, ChannelMonitorUpdateStep, HolderCommitmentTransactionBalance, ANTI_REORG_DELAY, ARCHIVAL_DELAY_BLOCKS, COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE, LATENCY_GRACE_PERIOD_BLOCKS};
1717
use crate::chain::transaction::OutPoint;
1818
use crate::chain::chaininterface::{ConfirmationTarget, LowerBoundedFeeEstimator, compute_feerate_sat_per_1000_weight};
1919
use crate::events::bump_transaction::{BumpTransactionEvent};
@@ -334,16 +334,21 @@ fn do_chanmon_claim_value_coop_close(anchors: bool) {
334334
let commitment_tx_fee = chan_feerate * chan_utils::commitment_tx_base_weight(&channel_type_features) / 1000;
335335
let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
336336
assert_eq!(vec![Balance::ClaimableOnChannelClose {
337-
amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value,
338-
transaction_fee_satoshis: commitment_tx_fee,
337+
balance_candidates: vec![HolderCommitmentTransactionBalance {
338+
amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value,
339+
transaction_fee_satoshis: commitment_tx_fee,
340+
}],
339341
outbound_payment_htlc_rounded_msat: 0,
340342
outbound_forwarded_htlc_rounded_msat: 0,
341343
inbound_claiming_htlc_rounded_msat: 0,
342344
inbound_htlc_rounded_msat: 0,
343345
}],
344346
nodes[0].chain_monitor.chain_monitor.get_monitor(chan_id).unwrap().get_claimable_balances());
345347
assert_eq!(vec![Balance::ClaimableOnChannelClose {
346-
amount_satoshis: 1_000, transaction_fee_satoshis: 0,
348+
balance_candidates: vec![HolderCommitmentTransactionBalance {
349+
amount_satoshis: 1_000,
350+
transaction_fee_satoshis: 0,
351+
}],
347352
outbound_payment_htlc_rounded_msat: 0,
348353
outbound_forwarded_htlc_rounded_msat: 0,
349354
inbound_claiming_htlc_rounded_msat: 0,
@@ -530,18 +535,22 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
530535
let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 };
531536
let amount_satoshis = 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value - 1; /* msat amount that is burned to fees */
532537
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
533-
amount_satoshis,
534-
// In addition to `commitment_tx_fee`, this also includes the dust HTLC, and the total msat amount rounded down from non-dust HTLCs
535-
transaction_fee_satoshis: 1_000_000 - 4_000 - 3_000 - 1_000 - amount_satoshis - anchor_outputs_value,
538+
balance_candidates: vec![HolderCommitmentTransactionBalance {
539+
amount_satoshis,
540+
// In addition to `commitment_tx_fee`, this also includes the dust HTLC, and the total msat amount rounded down from non-dust HTLCs
541+
transaction_fee_satoshis: 1_000_000 - 4_000 - 3_000 - 1_000 - amount_satoshis - anchor_outputs_value,
542+
}],
536543
outbound_payment_htlc_rounded_msat: 3300,
537544
outbound_forwarded_htlc_rounded_msat: 0,
538545
inbound_claiming_htlc_rounded_msat: 0,
539546
inbound_htlc_rounded_msat: 0,
540547
}, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
541548
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(chan_id).unwrap().get_claimable_balances()));
542549
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
543-
amount_satoshis: 1_000,
544-
transaction_fee_satoshis: 0,
550+
balance_candidates: vec![HolderCommitmentTransactionBalance {
551+
amount_satoshis: 1_000,
552+
transaction_fee_satoshis: 0,
553+
}],
545554
outbound_payment_htlc_rounded_msat: 0,
546555
outbound_forwarded_htlc_rounded_msat: 0,
547556
inbound_claiming_htlc_rounded_msat: 0,
@@ -594,9 +603,11 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
594603
anchor_outputs_value - // The anchor outputs value in satoshis
595604
1; // The rounded up msat part of the one HTLC
596605
let mut a_expected_balances = vec![Balance::ClaimableOnChannelClose {
597-
amount_satoshis, // Channel funding value in satoshis
598-
// In addition to `commitment_tx_fee`, this also includes the dust HTLC, and the total msat amount rounded down from non-dust HTLCs
599-
transaction_fee_satoshis: 1_000_000 - 4_000 - 3_000 - 1_000 - amount_satoshis - anchor_outputs_value,
606+
balance_candidates: vec![HolderCommitmentTransactionBalance {
607+
amount_satoshis, // Channel funding value in satoshis
608+
// In addition to `commitment_tx_fee`, this also includes the dust HTLC, and the total msat amount rounded down from non-dust HTLCs
609+
transaction_fee_satoshis: 1_000_000 - 4_000 - 3_000 - 1_000 - amount_satoshis - anchor_outputs_value,
610+
}],
600611
outbound_payment_htlc_rounded_msat: 3000 + if prev_commitment_tx {
601612
200 /* 1 to-be-failed HTLC */ } else { 300 /* 2 HTLCs */ },
602613
outbound_forwarded_htlc_rounded_msat: 0,
@@ -609,8 +620,10 @@ fn do_test_claim_value_force_close(anchors: bool, prev_commitment_tx: bool) {
609620
assert_eq!(sorted_vec(a_expected_balances),
610621
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(chan_id).unwrap().get_claimable_balances()));
611622
assert_eq!(vec![Balance::ClaimableOnChannelClose {
612-
amount_satoshis: 1_000 + 3_000 + 4_000,
613-
transaction_fee_satoshis: 0,
623+
balance_candidates: vec![HolderCommitmentTransactionBalance {
624+
amount_satoshis: 1_000 + 3_000 + 4_000,
625+
transaction_fee_satoshis: 0,
626+
}],
614627
outbound_payment_htlc_rounded_msat: 0,
615628
outbound_forwarded_htlc_rounded_msat: 0,
616629
inbound_claiming_htlc_rounded_msat: 3000 + if prev_commitment_tx {
@@ -1126,8 +1139,10 @@ fn test_no_preimage_inbound_htlc_balances() {
11261139
let commitment_tx_fee = chan_feerate *
11271140
(chan_utils::commitment_tx_base_weight(&channel_type_features) + 2 * chan_utils::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
11281141
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
1129-
amount_satoshis: 1_000_000 - 500_000 - 10_000 - commitment_tx_fee,
1130-
transaction_fee_satoshis: commitment_tx_fee,
1142+
balance_candidates: vec![HolderCommitmentTransactionBalance {
1143+
amount_satoshis: 1_000_000 - 500_000 - 10_000 - commitment_tx_fee,
1144+
transaction_fee_satoshis: commitment_tx_fee,
1145+
}],
11311146
outbound_payment_htlc_rounded_msat: 0,
11321147
outbound_forwarded_htlc_rounded_msat: 0,
11331148
inbound_claiming_htlc_rounded_msat: 0,
@@ -1136,8 +1151,10 @@ fn test_no_preimage_inbound_htlc_balances() {
11361151
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(chan_id).unwrap().get_claimable_balances()));
11371152

11381153
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
1139-
amount_satoshis: 500_000 - 20_000,
1140-
transaction_fee_satoshis: 0,
1154+
balance_candidates: vec![HolderCommitmentTransactionBalance {
1155+
amount_satoshis: 500_000 - 20_000,
1156+
transaction_fee_satoshis: 0,
1157+
}],
11411158
outbound_payment_htlc_rounded_msat: 0,
11421159
outbound_forwarded_htlc_rounded_msat: 0,
11431160
inbound_claiming_htlc_rounded_msat: 0,
@@ -1430,8 +1447,10 @@ fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_
14301447
assert_eq!(
14311448
sorted_vec(vec![
14321449
Balance::ClaimableOnChannelClose {
1433-
amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000 - 1 /* rounded up msat parts of HTLCs */,
1434-
transaction_fee_satoshis: 0,
1450+
balance_candidates: vec![HolderCommitmentTransactionBalance {
1451+
amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000 - 1 /* rounded up msat parts of HTLCs */,
1452+
transaction_fee_satoshis: 0,
1453+
}],
14351454
outbound_payment_htlc_rounded_msat: 3200,
14361455
outbound_forwarded_htlc_rounded_msat: 0,
14371456
inbound_claiming_htlc_rounded_msat: 100,
@@ -1967,8 +1986,10 @@ fn do_test_revoked_counterparty_aggregated_claims(anchors: bool) {
19671986
let _a_htlc_msgs = get_htlc_update_msgs!(&nodes[0], nodes[1].node.get_our_node_id());
19681987

19691988
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
1970-
amount_satoshis: 100_000 - 4_000 - 3_000 - 1 /* rounded up msat parts of HTLCs */,
1971-
transaction_fee_satoshis: 0,
1989+
balance_candidates: vec![HolderCommitmentTransactionBalance {
1990+
amount_satoshis: 100_000 - 4_000 - 3_000 - 1 /* rounded up msat parts of HTLCs */,
1991+
transaction_fee_satoshis: 0,
1992+
}],
19721993
outbound_payment_htlc_rounded_msat: 100,
19731994
outbound_forwarded_htlc_rounded_msat: 0,
19741995
inbound_claiming_htlc_rounded_msat: 0,

0 commit comments

Comments
 (0)