/// transaction fee) this value will be zero. For [`ChannelMonitor`]s created prior to LDK
/// 0.0.117, the channel is always treated as outbound (and thus this value is never zero).
transaction_fee_satoshis: u64,
+ /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
+ /// from us and are related to a payment which was sent by us. This is the sum of the
+ /// millisatoshis part of all HTLCs which are otherwise represented by
+ /// [`Balance::MaybeTimeoutClaimableHTLC`] with their
+ /// [`Balance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag set, as well as any dust
+ /// HTLCs which would otherwise be represented the same.
+ outbound_payment_htlc_rounded_msat: u64,
+ /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
+ /// from us and are related to a forwarded HTLC. This is the sum of the millisatoshis part
+ /// of all HTLCs which are otherwise represented by [`Balance::MaybeTimeoutClaimableHTLC`]
+ /// with their [`Balance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag *not* set, as
+ /// well as any dust HTLCs which would otherwise be represented the same.
+ outbound_forwarded_htlc_rounded_msat: u64,
+ /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
+ /// to us and for which we know the preimage. This is the sum of the millisatoshis part of
+ /// all HTLCs which would be represented by [`Balance::ContentiousClaimable`] on channel
+ /// close, but who's current value is included in
+ /// [`Balance::ClaimableOnChannelClose::amount_satoshis`], as well as any dust HTLCs which
+ /// would otherwise be represented the same.
+ inbound_claiming_htlc_rounded_msat: u64,
+ /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
+ /// to us and for which we do not know the preimage. This is the sum of the millisatoshis
+ /// part of all HTLCs which would be represented by [`Balance::MaybePreimageClaimableHTLC`]
+ /// on channel close, as well as any dust HTLCs which would otherwise be represented the
+ /// same.
+ inbound_htlc_rounded_msat: u64,
},
/// The channel has been closed, and the given balance is ours but awaiting confirmations until
/// we consider it spendable.
} else {
let mut claimable_inbound_htlc_value_sat = 0;
let mut nondust_htlc_count = 0;
+ let mut outbound_payment_htlc_rounded_msat = 0;
+ let mut outbound_forwarded_htlc_rounded_msat = 0;
+ let mut inbound_claiming_htlc_rounded_msat = 0;
+ let mut inbound_htlc_rounded_msat = 0;
for (htlc, _, source) in us.current_holder_commitment_tx.htlc_outputs.iter() {
if htlc.transaction_output_index.is_some() {
nondust_htlc_count += 1;
- } else { continue; }
+ }
+ let rounded_value_msat = if htlc.transaction_output_index.is_none() {
+ htlc.amount_msat
+ } else { htlc.amount_msat % 1000 };
if htlc.offered {
let outbound_payment = match source {
None => {
Some(HTLCSource::PreviousHopData(_)) => false,
Some(HTLCSource::OutboundRoute { .. }) => true,
};
- res.push(Balance::MaybeTimeoutClaimableHTLC {
- amount_satoshis: htlc.amount_msat / 1000,
- claimable_height: htlc.cltv_expiry,
- payment_hash: htlc.payment_hash,
- outbound_payment,
- });
+ if outbound_payment {
+ outbound_payment_htlc_rounded_msat += rounded_value_msat;
+ } else {
+ outbound_forwarded_htlc_rounded_msat += rounded_value_msat;
+ }
+ if htlc.transaction_output_index.is_some() {
+ res.push(Balance::MaybeTimeoutClaimableHTLC {
+ amount_satoshis: htlc.amount_msat / 1000,
+ claimable_height: htlc.cltv_expiry,
+ payment_hash: htlc.payment_hash,
+ outbound_payment,
+ });
+ }
} else if us.payment_preimages.get(&htlc.payment_hash).is_some() {
- claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
+ inbound_claiming_htlc_rounded_msat += rounded_value_msat;
+ if htlc.transaction_output_index.is_some() {
+ claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
+ claimable_inbound_htlc_value_msat += htlc.amount_msat;
+ }
} else {
- // As long as the HTLC is still in our latest commitment state, treat
- // it as potentially claimable, even if it has long-since expired.
- res.push(Balance::MaybePreimageClaimableHTLC {
- amount_satoshis: htlc.amount_msat / 1000,
- expiry_height: htlc.cltv_expiry,
- payment_hash: htlc.payment_hash,
- });
+ inbound_htlc_rounded_msat += rounded_value_msat;
+ if htlc.transaction_output_index.is_some() {
+ // As long as the HTLC is still in our latest commitment state, treat
+ // it as potentially claimable, even if it has long-since expired.
+ res.push(Balance::MaybePreimageClaimableHTLC {
+ amount_satoshis: htlc.amount_msat / 1000,
+ expiry_height: htlc.cltv_expiry,
+ payment_hash: htlc.payment_hash,
+ });
+ }
}
}
res.push(Balance::ClaimableOnChannelClose {
us.current_holder_commitment_tx.feerate_per_kw, nondust_htlc_count,
us.onchain_tx_handler.channel_type_features())
} else { 0 },
+ outbound_payment_htlc_rounded_msat,
+ outbound_forwarded_htlc_rounded_msat,
+ inbound_claiming_htlc_rounded_msat,
+ inbound_htlc_rounded_msat,
});
}
assert_eq!(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000_000 - 1_000 - commitment_tx_fee - anchor_outputs_value,
transaction_fee_satoshis: commitment_tx_fee,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}],
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
- assert_eq!(vec![Balance::ClaimableOnChannelClose { amount_satoshis: 1_000, transaction_fee_satoshis: 0 }],
+ assert_eq!(vec![Balance::ClaimableOnChannelClose {
+ amount_satoshis: 1_000, transaction_fee_satoshis: 0,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
+ }],
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - commitment_tx_fee - anchor_outputs_value,
transaction_fee_satoshis: commitment_tx_fee,
+ outbound_payment_htlc_rounded_msat: 3000,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]),
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000,
transaction_fee_satoshis: 0,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 3000,
}, received_htlc_balance.clone(), received_htlc_timeout_balance.clone()]),
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
commitment_tx_fee - // The commitment transaction fee with two HTLC outputs
anchor_outputs_value, // The anchor outputs value in satoshis
transaction_fee_satoshis: commitment_tx_fee,
+ outbound_payment_htlc_rounded_msat: 3000,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}, sent_htlc_timeout_balance.clone()];
if !prev_commitment_tx {
a_expected_balances.push(sent_htlc_balance.clone());
assert_eq!(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000 + 3_000 + 4_000,
transaction_fee_satoshis: 0,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 3000,
+ inbound_htlc_rounded_msat: 0,
}],
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 1_000_000 - 500_000 - 10_000 - commitment_tx_fee,
transaction_fee_satoshis: commitment_tx_fee,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]),
sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 500_000 - 20_000,
transaction_fee_satoshis: 0,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}, b_received_htlc_balance.clone(), b_sent_htlc_balance.clone()]),
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 100_000 - 5_000 - 4_000 - 3 - 2_000 + 3_000,
transaction_fee_satoshis: 0,
+ outbound_payment_htlc_rounded_msat: 3000,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}, Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: 2_000,
claimable_height: missing_htlc_cltv_timeout,
assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose {
amount_satoshis: 100_000 - 4_000 - 3_000,
transaction_fee_satoshis: 0,
+ outbound_payment_htlc_rounded_msat: 0,
+ outbound_forwarded_htlc_rounded_msat: 0,
+ inbound_claiming_htlc_rounded_msat: 0,
+ inbound_htlc_rounded_msat: 0,
}, Balance::MaybeTimeoutClaimableHTLC {
amount_satoshis: 4_000,
claimable_height: htlc_cltv_timeout,