-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Force Close #207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat: Force Close #207
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements the force close UI and logic for Lightning channels that fail to cooperatively close. When cooperative channel closures fail after repeated retries (30 minutes), users are presented with a force transfer sheet that allows them to forcefully close the channels.
Key Changes:
- Added force transfer sheet UI component with user confirmation flow
- Implemented force close logic in TransferViewModel with proper error handling
- Extended LightningService to support both cooperative and force channel closures
- Integrated force transfer flow into the app's sheet management system
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| ForceTransferSheet.swift | New sheet component providing UI for force close confirmation with loading states and toast notifications |
| TransferViewModel.swift | Added force close functionality and sheet integration for failed cooperative closures |
| SheetViewModel.swift | Added force transfer sheet configuration and management |
| LightningService.swift | Extended closeChannel method to support force close with optional reason parameter |
| MainNavView.swift | Registered force transfer sheet in the app's sheet presentation system |
| AppScene.swift | Injected SheetViewModel dependency into TransferViewModel initialization |
|
Still trying to setup the test environment, but you can do the review already, if you want |
ovitrif
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code reviewed 🎉
LGTM, for test env please use setup described in my android PR:
synonymdev/bitkit-android#414
It was a reliable way to test this fully controllable for me, back then
Will also test tomorrow using same setup
|
to test we need to:
|
|
Added force close to individual channel close too |
To don't extend the PR too much, I commented the coop code to enforce the force flow. The disconnect peer feature will be added on node info screen polish |
Pull request was converted to draft
|
Test videos Updated |
|
The code looks good, but when testing after mining 144 block it still doesn't show the funds back in savings for me |
Found this when connected to Blocktank but it worked when connected to an external channel. l still couldn't find the reason. I'll test the android behavior, maybe block tank has a different lock time |
You should be able to see block height when funds are available in Settings > Advanced> Lightning Node > scroll to bottom to check Balances It's the number in parenthesis |
|
I mined many blocks but still the same. |
Then the channel didn't close at all ever :) |
|
Set as draft again to investigate |
|
What I got so far:
LDK has claimableHeight = 0, which means LDK is failing to calculate when this force-close output becomes spendable. This is why the funds are stuck indefinitely. External node channels are not on trusted list so they use a non-anchor channel format. That is why it worked on the tests Another strange this is that transactionName = 0 |
|
@ovitrif I suggest merge this branch, because it has the same behavior of android, and investigate the issue in another |
@jvsena42 If not, my plan was to test this myself before merging ;) |
Only tested with a Polar node, but if necessary I can add the disconnect channel feature to test with bitkit-docker |
Polar test is fine as well, but since this PR is about force close, we need someone else than the author to review force close :) I will do it, can't be that hard ^^ |



Description
This Pr implements force close UI and logic
Linked Issues/Tasks
Roadmap
Reference
Screenshot / Video
Test flow 1 - Close single channel:
Simulator.Screen.Recording.-.iPhone.16.-.2025-11-07.at.20.24.17.mp4
Test flow 2 - Close all channels:
TransferViewModel.swift:35-36use this to mock a total coop failure :And this to skip the retry process:
(OBS: tried to reproduce this with Bloktank but the force transaction hadn't been confirmed even after 200 blocks. It probably has a different lock time)
force.close.simulation.mp4