fix(ark): let users see and fund the exit-fee reserve during an exit - #183
Closed
CypherBoxLLC wants to merge 2 commits into
Closed
CypherBoxLLC wants to merge 2 commits into
CypherBoxLLC wants to merge 2 commits into
Conversation
Two bugs found while running a real unilateral exit, both of which made the exit harder to complete at the exact moment it mattered. 1. THE FUNDING UI DISAPPEARED DURING AN EXIT. Settings.tsx replaced the whole exit section with an "Emergency exit in progress" panel, so the reserve could be neither seen nor topped up while an exit ran. That panel also promises funds sweep automatically once the timelock expires, while removing the means to make that true: every exit branch needs a CPFP broadcast and every claim needs a fee. Observed live on 2026-08-18. A five-capsule exit ran the reserve down from 3654 to 699 sats with four claims still owed, and there was no way to add more from that screen. The capsules would have sat exited-but-unclaimed indefinitely. The panel now shows the on-chain reserve balance and offers a top-up that opens the existing funding sheet. The Convert tab is hidden mid-exit because it is a cooperative offboard, ASP-gated by assertNoActiveArkExit, so it cannot work there; Receive and From-a-wallet both can, since they are ASP-independent, which matters because an exit is often running precisely when the server is unreachable. A user sitting on Convert when an exit begins is moved to Receive, otherwise the sheet would render nothing at all. 2. A LOCKED WALLET LEFT THE RECEIVE SHEET SPINNING FOREVER. ReceivedListNew fetched the Ark address and the on-chain address with Promise.all, so a failure in either discarded BOTH. The Ark address needs the Ark wallet; the on-chain address is a local BDK call and is the ASP-independent way to fund an exit. With the wallet locked the Ark fetch threw "Ark wallet not initialized" and took the perfectly obtainable on-chain address down with it, leaving null state and a spinner that never resolved, with only a three-second toast saying "Failed to fetch Ark addresses". Now allSettled, so each address stands on its own, and the message names the actual cause: a locked vault says so and tells the user to open it.
…is stuck Reported from device: the Fund exit fees confirm screen sat on a spinner captioned "Please wait" with no amount, no fee and no explanation. Two separate defects, both of which produce that. SwipeButton exposes only `isLoading`, and when true it renders a spinner captioned "Please wait". This screen was passing `!plan.ok`, `indeterminate` and `sourceId !== 'coinos'` into it. None of those are busy states, they are permanent ones, so the screen told the user it was working on something that was never going to happen. `planExitFunding` had already computed exactly why (the reserve is already funded, or the balance cannot cover the fee plus a useful top-up) and that reason was rendered as small print inside the card while the call to action contradicted it. A blocked state is now rendered as a blocked state, carrying the reason, and the swipe only appears when swiping can achieve something. Second, the preparation step could hang forever. It calls getArkOnchainAddress, which goes through ensureArkOnchainHandle to spawn bark's on-chain BDK wallet against an esplora endpoint, and nothing on that path has a timeout. A provider that accepts the connection and then never answers leaves `loading` true for the lifetime of the screen, because it is only cleared in the `finally`. That is not hypothetical on this device: the same launch logged `onchain spawn failed via blockstream.info` with a 338 byte body where a 64 character blockhash belongs, while both explorers answered a desktop on the same LAN correctly. Both awaits are now bounded at 20s, and a failure renders on screen with the likely cause rather than a toast that vanishes before it can be read. The deposit address depends on a reachable chain source, so changing network usually clears it. Follow-up once #184 merges: that error should go through arkNetworkFaultMessage, which names whether the chain source or the Ark server is at fault. It is on a separate branch, so wiring it here would make this change unmergeable on its own.
This was referenced Aug 19, 2026
Owner
Author
|
Landed in This PR did not auto-close because its base was another feature branch rather than Closing as merged. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #182. Base is
fix/coinos-withdraw-idempotency, so the diff here is the single commit54bfd1e. GitHub will retarget this tomainautomatically when #182 merges.The bug
While an exit was running, the red "Emergency exit in progress" panel REPLACED the exit-funding UI.
The fee reserve could be neither seen nor topped up at the exact moment it matters, which is the
moment the exit is spending it. If the reserve ran dry mid-exit there was no in-app way to refill it.
The panel and the funding section now coexist.
Also here
Promise.allbecomesPromise.allSettledin the receive sheet. A failing Ark address wasdiscarding a perfectly good on-chain address alongside it and leaving a permanent spinner, so a
half-down backend took out the whole receive screen.
Verification
tscerror set byte-identical toorigin/main(405 errors, 19 TS2304)