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