ldk_node/balance.rs
1// This file is Copyright its original authors, visible in version control history.
2//
3// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
6// accordance with one or both of these licenses.
7
8use bitcoin::secp256k1::PublicKey;
9use bitcoin::{Amount, BlockHash, Txid};
10use lightning::chain::channelmonitor::{Balance as LdkBalance, BalanceSource};
11use lightning::ln::types::ChannelId;
12use lightning::sign::SpendableOutputDescriptor;
13use lightning::util::sweep::{OutputSpendStatus, TrackedSpendableOutput};
14use lightning_types::payment::{PaymentHash, PaymentPreimage};
15
16/// Details of the known available balances returned by [`Node::list_balances`].
17///
18/// [`Node::list_balances`]: crate::Node::list_balances
19#[derive(Debug, Clone)]
20pub struct BalanceDetails {
21 /// The total balance of our on-chain wallet.
22 pub total_onchain_balance_sats: u64,
23 /// The currently spendable balance of our on-chain wallet.
24 ///
25 /// This includes any sufficiently confirmed funds, minus
26 /// [`total_anchor_channels_reserve_sats`].
27 ///
28 /// [`total_anchor_channels_reserve_sats`]: Self::total_anchor_channels_reserve_sats
29 pub spendable_onchain_balance_sats: u64,
30 /// The share of our total balance that we retain as an emergency reserve to (hopefully) be
31 /// able to spend the Anchor outputs when one of our channels is closed.
32 pub total_anchor_channels_reserve_sats: u64,
33 /// The total balance that we would be able to claim across all our Lightning channels.
34 ///
35 /// Note this excludes balances that we are unsure if we are able to claim (e.g., as we are
36 /// waiting for a preimage or for a timeout to expire). These balances will however be included
37 /// as [`MaybePreimageClaimableHTLC`] and
38 /// [`MaybeTimeoutClaimableHTLC`] in [`lightning_balances`].
39 ///
40 /// [`MaybePreimageClaimableHTLC`]: LightningBalance::MaybePreimageClaimableHTLC
41 /// [`MaybeTimeoutClaimableHTLC`]: LightningBalance::MaybeTimeoutClaimableHTLC
42 /// [`lightning_balances`]: Self::lightning_balances
43 pub total_lightning_balance_sats: u64,
44 /// A detailed list of all known Lightning balances that would be claimable on channel closure.
45 ///
46 /// Note that less than the listed amounts are spendable over lightning as further reserve
47 /// restrictions apply. Please refer to [`ChannelDetails::outbound_capacity_msat`] and
48 /// [`ChannelDetails::next_outbound_htlc_limit_msat`] as returned by [`Node::list_channels`]
49 /// for a better approximation of the spendable amounts.
50 ///
51 /// [`ChannelDetails::outbound_capacity_msat`]: crate::ChannelDetails::outbound_capacity_msat
52 /// [`ChannelDetails::next_outbound_htlc_limit_msat`]: crate::ChannelDetails::next_outbound_htlc_limit_msat
53 /// [`Node::list_channels`]: crate::Node::list_channels
54 pub lightning_balances: Vec<LightningBalance>,
55 /// A detailed list of balances currently being swept from the Lightning to the on-chain
56 /// wallet.
57 ///
58 /// These are balances resulting from channel closures that may have been encumbered by a
59 /// delay, but are now being claimed and useable once sufficiently confirmed on-chain.
60 ///
61 /// Note that, depending on the sync status of the wallets, swept balances listed here might or
62 /// might not already be accounted for in [`total_onchain_balance_sats`].
63 ///
64 /// [`total_onchain_balance_sats`]: Self::total_onchain_balance_sats
65 pub pending_balances_from_channel_closures: Vec<PendingSweepBalance>,
66}
67
68/// Details about the status of a known Lightning balance.
69#[derive(Debug, Clone)]
70pub enum LightningBalance {
71 /// The channel is not yet closed (or the commitment or closing transaction has not yet
72 /// appeared in a block). The given balance is claimable (less on-chain fees) if the channel is
73 /// force-closed now. Values do not take into account any pending splices and are only based
74 /// on the confirmed state of the channel.
75 ClaimableOnChannelClose {
76 /// The identifier of the channel this balance belongs to.
77 channel_id: ChannelId,
78 /// The identifier of our channel counterparty.
79 counterparty_node_id: PublicKey,
80 /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
81 /// required to do so.
82 amount_satoshis: u64,
83 /// The transaction fee we pay for the closing commitment transaction. This amount is not
84 /// included in the `amount_satoshis` value.
85 ///
86 /// Note that if this channel is inbound (and thus our counterparty pays the commitment
87 /// transaction fee) this value will be zero. For channels created prior to LDK Node 0.4
88 /// the channel is always treated as outbound (and thus this value is never zero).
89 transaction_fee_satoshis: u64,
90 /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
91 /// from us and are related to a payment which was sent by us. This is the sum of the
92 /// millisatoshis part of all HTLCs which are otherwise represented by
93 /// [`LightningBalance::MaybeTimeoutClaimableHTLC`] with their
94 /// [`LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag set, as well as
95 /// any dust HTLCs which would otherwise be represented the same.
96 ///
97 /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`.
98 outbound_payment_htlc_rounded_msat: u64,
99 /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound
100 /// from us and are related to a forwarded HTLC. This is the sum of the millisatoshis part
101 /// of all HTLCs which are otherwise represented by
102 /// [`LightningBalance::MaybeTimeoutClaimableHTLC`] with their
103 /// [`LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment`] flag *not* set, as
104 /// well as any dust HTLCs which would otherwise be represented the same.
105 ///
106 /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`.
107 outbound_forwarded_htlc_rounded_msat: u64,
108 /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
109 /// to us and for which we know the preimage. This is the sum of the millisatoshis part of
110 /// all HTLCs which would be represented by [`LightningBalance::ContentiousClaimable`] on
111 /// channel close, but whose current value is included in `amount_satoshis`, as well as any
112 /// dust HTLCs which would otherwise be represented the same.
113 ///
114 /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's
115 /// `amount_satoshis`.
116 inbound_claiming_htlc_rounded_msat: u64,
117 /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound
118 /// to us and for which we do not know the preimage. This is the sum of the millisatoshis
119 /// part of all HTLCs which would be represented by
120 /// [`LightningBalance::MaybePreimageClaimableHTLC`] on channel close, as well as any dust
121 /// HTLCs which would otherwise be represented the same.
122 ///
123 /// This amount (rounded up to a whole satoshi value) will not be included in the
124 /// counterparty's `amount_satoshis`.
125 inbound_htlc_rounded_msat: u64,
126 },
127 /// The channel has been closed, and the given balance is ours but awaiting confirmations until
128 /// we consider it spendable.
129 ClaimableAwaitingConfirmations {
130 /// The identifier of the channel this balance belongs to.
131 channel_id: ChannelId,
132 /// The identifier of our channel counterparty.
133 counterparty_node_id: PublicKey,
134 /// The amount available to claim, in satoshis, possibly excluding the on-chain fees which
135 /// were spent in broadcasting the transaction.
136 amount_satoshis: u64,
137 /// The height at which an [`Event::SpendableOutputs`] event will be generated for this
138 /// amount.
139 ///
140 /// [`Event::SpendableOutputs`]: lightning::events::Event::SpendableOutputs
141 confirmation_height: u32,
142 /// Whether this balance is a result of cooperative close, a force-close, or an HTLC.
143 source: BalanceSource,
144 },
145 /// The channel has been closed, and the given balance should be ours but awaiting spending
146 /// transaction confirmation. If the spending transaction does not confirm in time, it is
147 /// possible our counterparty can take the funds by broadcasting an HTLC timeout on-chain.
148 ///
149 /// Once the spending transaction confirms, before it has reached enough confirmations to be
150 /// considered safe from chain reorganizations, the balance will instead be provided via
151 /// [`LightningBalance::ClaimableAwaitingConfirmations`].
152 ContentiousClaimable {
153 /// The identifier of the channel this balance belongs to.
154 channel_id: ChannelId,
155 /// The identifier of our channel counterparty.
156 counterparty_node_id: PublicKey,
157 /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
158 /// required to do so.
159 amount_satoshis: u64,
160 /// The height at which the counterparty may be able to claim the balance if we have not
161 /// done so.
162 timeout_height: u32,
163 /// The payment hash that locks this HTLC.
164 payment_hash: PaymentHash,
165 /// The preimage that can be used to claim this HTLC.
166 payment_preimage: PaymentPreimage,
167 },
168 /// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain
169 /// fees) if the counterparty does not know the preimage for the HTLCs. These are somewhat
170 /// likely to be claimed by our counterparty before we do.
171 MaybeTimeoutClaimableHTLC {
172 /// The identifier of the channel this balance belongs to.
173 channel_id: ChannelId,
174 /// The identifier of our channel counterparty.
175 counterparty_node_id: PublicKey,
176 /// The amount potentially available to claim, in satoshis, excluding the on-chain fees
177 /// which will be required to do so.
178 amount_satoshis: u64,
179 /// The height at which we will be able to claim the balance if our counterparty has not
180 /// done so.
181 claimable_height: u32,
182 /// The payment hash whose preimage our counterparty needs to claim this HTLC.
183 payment_hash: PaymentHash,
184 /// Indicates whether this HTLC represents a payment which was sent outbound from us.
185 outbound_payment: bool,
186 },
187 /// HTLCs which we received from our counterparty which are claimable with a preimage which we
188 /// do not currently have. This will only be claimable if we receive the preimage from the node
189 /// to which we forwarded this HTLC before the timeout.
190 MaybePreimageClaimableHTLC {
191 /// The identifier of the channel this balance belongs to.
192 channel_id: ChannelId,
193 /// The identifier of our channel counterparty.
194 counterparty_node_id: PublicKey,
195 /// The amount potentially available to claim, in satoshis, excluding the on-chain fees
196 /// which will be required to do so.
197 amount_satoshis: u64,
198 /// The height at which our counterparty will be able to claim the balance if we have not
199 /// yet received the preimage and claimed it ourselves.
200 expiry_height: u32,
201 /// The payment hash whose preimage we need to claim this HTLC.
202 payment_hash: PaymentHash,
203 },
204 /// The channel has been closed, and our counterparty broadcasted a revoked commitment
205 /// transaction.
206 ///
207 /// Thus, we're able to claim all outputs in the commitment transaction, one of which has the
208 /// following amount.
209 CounterpartyRevokedOutputClaimable {
210 /// The identifier of the channel this balance belongs to.
211 channel_id: ChannelId,
212 /// The identifier of our channel counterparty.
213 counterparty_node_id: PublicKey,
214 /// The amount, in satoshis, of the output which we can claim.
215 amount_satoshis: u64,
216 },
217}
218
219impl LightningBalance {
220 pub(crate) fn from_ldk_balance(
221 channel_id: ChannelId, counterparty_node_id: PublicKey, balance: LdkBalance,
222 ) -> Self {
223 match balance {
224 LdkBalance::ClaimableOnChannelClose {
225 balance_candidates,
226 confirmed_balance_candidate_index,
227 outbound_payment_htlc_rounded_msat,
228 outbound_forwarded_htlc_rounded_msat,
229 inbound_claiming_htlc_rounded_msat,
230 inbound_htlc_rounded_msat,
231 } => {
232 // unwrap safety: confirmed_balance_candidate_index is guaranteed to index into balance_candidates
233 let balance = balance_candidates.get(confirmed_balance_candidate_index).unwrap();
234
235 Self::ClaimableOnChannelClose {
236 channel_id,
237 counterparty_node_id,
238 amount_satoshis: balance.amount_satoshis,
239 transaction_fee_satoshis: balance.transaction_fee_satoshis,
240 outbound_payment_htlc_rounded_msat,
241 outbound_forwarded_htlc_rounded_msat,
242 inbound_claiming_htlc_rounded_msat,
243 inbound_htlc_rounded_msat,
244 }
245 },
246 LdkBalance::ClaimableAwaitingConfirmations {
247 amount_satoshis,
248 confirmation_height,
249 source,
250 } => Self::ClaimableAwaitingConfirmations {
251 channel_id,
252 counterparty_node_id,
253 amount_satoshis,
254 confirmation_height,
255 source,
256 },
257 LdkBalance::ContentiousClaimable {
258 amount_satoshis,
259 timeout_height,
260 payment_hash,
261 payment_preimage,
262 } => Self::ContentiousClaimable {
263 channel_id,
264 counterparty_node_id,
265 amount_satoshis,
266 timeout_height,
267 payment_hash,
268 payment_preimage,
269 },
270 LdkBalance::MaybeTimeoutClaimableHTLC {
271 amount_satoshis,
272 claimable_height,
273 payment_hash,
274 outbound_payment,
275 } => Self::MaybeTimeoutClaimableHTLC {
276 channel_id,
277 counterparty_node_id,
278 amount_satoshis,
279 claimable_height,
280 payment_hash,
281 outbound_payment,
282 },
283 LdkBalance::MaybePreimageClaimableHTLC {
284 amount_satoshis,
285 expiry_height,
286 payment_hash,
287 } => Self::MaybePreimageClaimableHTLC {
288 channel_id,
289 counterparty_node_id,
290 amount_satoshis,
291 expiry_height,
292 payment_hash,
293 },
294 LdkBalance::CounterpartyRevokedOutputClaimable { amount_satoshis } => {
295 Self::CounterpartyRevokedOutputClaimable {
296 channel_id,
297 counterparty_node_id,
298 amount_satoshis,
299 }
300 },
301 }
302 }
303}
304
305/// Details about the status of a known balance currently being swept to our on-chain wallet.
306#[derive(Debug, Clone)]
307pub enum PendingSweepBalance {
308 /// The spendable output is about to be swept, but a spending transaction has yet to be generated and
309 /// broadcast.
310 PendingBroadcast {
311 /// The identifier of the channel this balance belongs to.
312 channel_id: Option<ChannelId>,
313 /// The amount, in satoshis, of the output being swept.
314 amount_satoshis: u64,
315 },
316 /// A spending transaction has been generated and broadcast and is awaiting confirmation
317 /// on-chain.
318 BroadcastAwaitingConfirmation {
319 /// The identifier of the channel this balance belongs to.
320 channel_id: Option<ChannelId>,
321 /// The best height when we last broadcast a transaction spending the output being swept.
322 latest_broadcast_height: u32,
323 /// The identifier of the transaction spending the swept output we last broadcast.
324 latest_spending_txid: Txid,
325 /// The amount, in satoshis, of the output being swept.
326 amount_satoshis: u64,
327 },
328 /// A spending transaction has been confirmed on-chain and is awaiting threshold confirmations.
329 ///
330 /// It will be pruned after reaching [`PRUNE_DELAY_BLOCKS`] confirmations.
331 ///
332 /// [`PRUNE_DELAY_BLOCKS`]: lightning::util::sweep::PRUNE_DELAY_BLOCKS
333 AwaitingThresholdConfirmations {
334 /// The identifier of the channel this balance belongs to.
335 channel_id: Option<ChannelId>,
336 /// The identifier of the confirmed transaction spending the swept output.
337 latest_spending_txid: Txid,
338 /// The hash of the block in which the spending transaction was confirmed.
339 confirmation_hash: BlockHash,
340 /// The height at which the spending transaction was confirmed.
341 confirmation_height: u32,
342 /// The amount, in satoshis, of the output being swept.
343 amount_satoshis: u64,
344 },
345}
346
347impl PendingSweepBalance {
348 pub(crate) fn from_tracked_spendable_output(output_info: TrackedSpendableOutput) -> Self {
349 match output_info.status {
350 OutputSpendStatus::PendingInitialBroadcast { .. } => {
351 let channel_id = output_info.channel_id;
352 let amount_satoshis = value_from_descriptor(&output_info.descriptor).to_sat();
353 Self::PendingBroadcast { channel_id, amount_satoshis }
354 },
355 OutputSpendStatus::PendingFirstConfirmation {
356 latest_broadcast_height,
357 latest_spending_tx,
358 ..
359 } => {
360 let channel_id = output_info.channel_id;
361 let amount_satoshis = value_from_descriptor(&output_info.descriptor).to_sat();
362 let latest_spending_txid = latest_spending_tx.compute_txid();
363 Self::BroadcastAwaitingConfirmation {
364 channel_id,
365 latest_broadcast_height,
366 latest_spending_txid,
367 amount_satoshis,
368 }
369 },
370 OutputSpendStatus::PendingThresholdConfirmations {
371 latest_spending_tx,
372 confirmation_height,
373 confirmation_hash,
374 ..
375 } => {
376 let channel_id = output_info.channel_id;
377 let amount_satoshis = value_from_descriptor(&output_info.descriptor).to_sat();
378 let latest_spending_txid = latest_spending_tx.compute_txid();
379 Self::AwaitingThresholdConfirmations {
380 channel_id,
381 latest_spending_txid,
382 confirmation_hash,
383 confirmation_height,
384 amount_satoshis,
385 }
386 },
387 }
388 }
389}
390
391fn value_from_descriptor(descriptor: &SpendableOutputDescriptor) -> Amount {
392 match &descriptor {
393 SpendableOutputDescriptor::StaticOutput { output, .. } => output.value,
394 SpendableOutputDescriptor::DelayedPaymentOutput(output) => output.output.value,
395 SpendableOutputDescriptor::StaticPaymentOutput(output) => output.output.value,
396 }
397}