Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.

Commit ffa4f15

Browse files
bors[bot]luckysori
andauthored
Merge #509
509: Update on-chain balance immediately after channel closure r=luckysori a=luckysori Fixes #461. The coins are correctly moved to a pending state, like we do with any other on-chain transaction. The user is also informed about what to expect when closing the channel. It's important to note that if the user runs into a force-closure for some other reason, the coins will also go into a pending state and be reflected in the overall on-chain balance, but it will take _hundreds_ of confirmations for the coins to be confirmed. ![image](https://user-images.githubusercontent.com/9418575/205271194-a34a118e-2ac5-45d8-a6a7-b511e15f5528.png) Co-authored-by: Lucas Soriano del Pino <lucas_soriano@fastmail.com>
2 parents 310b2e5 + db7357a commit ffa4f15

File tree

5 files changed

+74
-13
lines changed

5 files changed

+74
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/main.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ Future<void> callGetBalances() async {
319319
try {
320320
final balance = await api.getBalance();
321321
bitcoinBalance.update(Amount(balance.onChain.confirmed), Amount(balance.onChain.trustedPending),
322-
Amount(balance.onChain.untrustedPending));
323-
lightningBalance.update(Amount(balance.offChain));
322+
Amount(balance.onChain.untrustedPending), Amount(balance.offChain.pendingClose));
323+
lightningBalance.update(Amount(balance.offChain.available));
324324
FLog.trace(text: 'Successfully retrieved wallet balances');
325325
} catch (error) {
326326
FLog.error(text: "Failed to get balances:" + error.toString());

lib/models/balance_model.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,22 @@ class BitcoinBalance extends ChangeNotifier {
1414
Amount confirmed = Amount.zero;
1515
Amount pendingInternal = Amount.zero;
1616
Amount pendingExternal = Amount.zero;
17+
Amount pendingChannelClose = Amount.zero;
1718

1819
Amount pending() {
19-
return Amount(pendingExternal.asSats + pendingInternal.asSats);
20+
return Amount(pendingExternal.asSats + pendingInternal.asSats + pendingChannelClose.asSats);
2021
}
2122

2223
Amount total() {
2324
return Amount(confirmed.asSats + pending().asSats);
2425
}
2526

26-
void update(Amount confirmed, Amount pendingInternal, Amount pendingExternal) {
27+
void update(Amount confirmed, Amount pendingInternal, Amount pendingExternal,
28+
Amount pendingChannelClose) {
2729
this.confirmed = confirmed;
2830
this.pendingInternal = pendingInternal;
2931
this.pendingExternal = pendingExternal;
32+
this.pendingChannelClose = pendingChannelClose;
3033

3134
super.notifyListeners();
3235
}

lib/wallet/close_channel.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class _CloseChannelState extends State<CloseChannel> {
5353
TextSpan(
5454
text:
5555
"Closing the channel will send ${closeAmount.value} sats to your 10101 on-chain wallet.\n\n"),
56+
const TextSpan(
57+
text:
58+
"It will take at least 2 blocks after the publication of the channel close transaction for your coins to be confirmed by your on-chain wallet.\n\n"),
5659
const TextSpan(
5760
text:
5861
"Once the channel is closed, you will have to open a new one if you want to continue using your wallet for Lightning payments and trading.")
@@ -90,7 +93,7 @@ class _CloseChannelState extends State<CloseChannel> {
9093
}
9194

9295
Future<void> closeChannel() async {
93-
FLog.info(text: "Closing channel with outbound liquidity of " + closeAmount.toString());
96+
FLog.info(text: "Closing channel with outbound liquidity of " + closeAmount.value.toString());
9497

9598
try {
9699
await api.closeChannel();

rust/src/wallet.rs

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub struct Wallet {
6363
#[derive(Debug, Clone, Serialize)]
6464
pub struct Balance {
6565
pub on_chain: OnChain,
66-
pub off_chain: u64,
66+
pub off_chain: OffChain,
6767
}
6868

6969
#[derive(Debug, Clone, Serialize)]
@@ -76,6 +76,12 @@ pub struct OnChain {
7676
pub confirmed: u64,
7777
}
7878

79+
#[derive(Debug, Clone, Serialize)]
80+
pub struct OffChain {
81+
pub available: u64,
82+
pub pending_close: u64,
83+
}
84+
7985
impl Wallet {
8086
pub fn new(data_dir: &Path) -> Result<Wallet> {
8187
let network = config::network();
@@ -140,7 +146,7 @@ impl Wallet {
140146

141147
pub fn get_balance(&self) -> Result<Balance> {
142148
let bdk_balance = self.get_bdk_balance()?;
143-
let ldk_balance = self.get_ldk_balance();
149+
let off_chain = self.get_ldk_balance()?;
144150
Ok(Balance {
145151
// subtract the ldk balance from the bdk balance as this balance is locked in the
146152
// off chain wallet.
@@ -149,7 +155,7 @@ impl Wallet {
149155
untrusted_pending: bdk_balance.untrusted_pending,
150156
confirmed: bdk_balance.confirmed,
151157
},
152-
off_chain: ldk_balance,
158+
off_chain,
153159
})
154160
}
155161

@@ -163,14 +169,63 @@ impl Wallet {
163169
Ok(balance)
164170
}
165171

166-
/// LDK balance is the total sum of money in all open channels
167-
fn get_ldk_balance(&self) -> u64 {
168-
self.lightning
172+
/// The LDK [`OffChain`] balance keeps track of:
173+
///
174+
/// - The total sum of money in all open channels.
175+
/// - The total sum of money in close transactions that do not yet pay to our on-chain wallet.
176+
fn get_ldk_balance(&self) -> Result<OffChain> {
177+
let open_channels = self.lightning.channel_manager.list_channels();
178+
179+
let claimable_channel_balances = {
180+
let ignored_channels = open_channels.iter().collect::<Vec<_>>();
181+
let ignored_channels = &ignored_channels.as_slice();
182+
self.lightning
183+
.chain_monitor
184+
.get_claimable_balances(ignored_channels)
185+
};
186+
187+
let pending_close = claimable_channel_balances.iter().fold(0, |acc, balance| {
188+
tracing::trace!("Pending on-chain balance from channel closure: {balance:?}");
189+
190+
use ::lightning::chain::channelmonitor::Balance::*;
191+
match balance {
192+
ClaimableOnChannelClose {
193+
claimable_amount_satoshis,
194+
}
195+
| ClaimableAwaitingConfirmations {
196+
claimable_amount_satoshis,
197+
..
198+
}
199+
| ContentiousClaimable {
200+
claimable_amount_satoshis,
201+
..
202+
}
203+
| MaybeTimeoutClaimableHTLC {
204+
claimable_amount_satoshis,
205+
..
206+
}
207+
| MaybePreimageClaimableHTLC {
208+
claimable_amount_satoshis,
209+
..
210+
}
211+
| CounterpartyRevokedOutputClaimable {
212+
claimable_amount_satoshis,
213+
} => acc + claimable_amount_satoshis,
214+
}
215+
});
216+
217+
let available = self
218+
.lightning
169219
.channel_manager
170220
.list_channels()
171221
.iter()
172222
.map(|details| details.balance_msat / 1000)
173-
.sum()
223+
.sum();
224+
225+
Ok(OffChain {
226+
available,
227+
pending_close,
228+
})
174229
}
175230

176231
fn get_channel_manager(&self) -> Arc<ChannelManager> {

0 commit comments

Comments
 (0)