FIX: include recovering funds in Arkade balance & guard sends against them#8747
FIX: include recovering funds in Arkade balance & guard sends against them#8747pietro909 wants to merge 4 commits into
Conversation
After a server signer-rotation cutoff, an imported Arkade wallet whose funds are all deprecated-signer VTXOs showed a balance of 0. SDK 0.4.35 puts such funds in the new WalletBalance.pendingRecovery bucket, which is excluded from `available`/`recoverable` but still counted in `total`. fetchBalance() (and the swap-event refresh handler) summed `available + recoverable`, dropping pendingRecovery. Switch both to `total - boarding.total`, which keeps boarding excluded (same double-count rationale) while including pendingRecovery — the user's money, pending the SDK's automatic migration.
The displayed Arkade balance includes `pendingRecovery` (deprecated-signer funds past their rotation cutoff), but the SDK's send coin-selection excludes those VTXOs until the Ark server sweeps them. Paying against a balance that is mostly pendingRecovery therefore failed with a bare "insufficient funds" that contradicts the on-screen amount. Detect that case in payInvoice and throw an honest message telling the user the funds are recovering and how many sats are spendable now.
When a send is blocked because the balance is mostly pendingRecovery,
surface a concrete ETA instead of open-ended wording. Each deprecated-
signer report carries `nextSweepEta` (ms epoch of the soonest batch
expiry = when the server sweeps those VTXOs and they become spendable);
take the earliest across signers and render it with the app's relative
time helper ("… should become available in 2 days"). Falls back to the
open-ended message when no future ETA is advertised.
Also add getBalance/getVtxoManager to the payInvoice test mock and cover
the recovering-funds guard (with and without an advertised ETA).
GladosBlueWallet
left a comment
There was a problem hiding this comment.
Bugfix PR: count pendingRecovery in Arkade headline balance and block LN pays with a clearer error. Balance math tracks the SDK story; the guard is sane on ScanLNDInvoice. Your test chamber skipped the actual balance regression and several guard edge cases — classic.
Inline findings (could not anchor on diff)
tests/unit/lightning-ark-wallet.test.ts:1240— [HIGH] You rewrote balance astotal − boardingto swallowpendingRecovery, then never tested it infetchBalance. Existing cases still pass withpendingRecovery: 0; the headline fix is theater until a wallet-full-of-recovering-sats case proves otherwise.class/wallets/lightning-ark-wallet.ts:645— [MEDIUM] Native ArksendBitcoinexits before your recovering-funds guard. Wallet shows recovery-inclusive balance; user pays anark1address with unspendable VTXOs and gets the same cryptic failure you claimed to eliminate. One door has a warning sign; the other is a pit.
| }); | ||
| }); | ||
|
|
||
| it('payInvoice blocks with a recovering-funds message when the balance is mostly pendingRecovery', async () => { |
There was a problem hiding this comment.
[HIGH] Guard tests only cover the zero-spendable horror show. No subject verifies mixed wallets (spendable covers invoice → swap proceeds), fee-boundary blocks with _feesLoaded, or past nextSweepEta falling back. You built a safety interlock and only photographed it engaged.
| // that case and surface an honest message instead. | ||
| const balance = await this._wallet.getBalance(); | ||
| const spendable = balance.available + balance.recoverable; | ||
| const estFee = this.getSubmarineFeeEstimate(invoiceDetails.amountSats) ?? 0; |
There was a problem hiding this comment.
[MEDIUM] Guard fee math uses getSubmarineFeeEstimate(...) ?? 0 but payInvoice never calls ensureLightningFeesLoaded. ScanLNDInvoice warms fees; lnurlPay does not — mixed spendable+recovery wallets can sail past your guard and die on a generic SDK insufficient-funds error. Congratulations on a partial fix.
Overtorment
left a comment
There was a problem hiding this comment.
so, whats the verdict on this one? do we need it?
i see glados is not happy with the code
|
Wake the fuck up samurai, we have PRs to merge [all PRs for @ncoelho] https://github.com/BlueWallet/BlueWallet/pulls/review-requested/ncoelho |
1 similar comment
|
Wake the fuck up samurai, we have PRs to merge [all PRs for @ncoelho] https://github.com/BlueWallet/BlueWallet/pulls/review-requested/ncoelho |

FIX: include recovering funds in Arkade balance & guard sends against them
Problem
After a signer-rotation cutoff, an imported Arkade wallet holding only deprecated-signer funds (
pendingRecovery) showed a balance of 0 — the headline wasavailable + recoverable, which omits that leg. But those funds also can't be spent until the server sweeps them, so simply displaying them would let a send fail with a bareinsufficient fundsthat contradicts the on-screen amount.Changes
total − boarding.total(includespendingRecovery), consistent acrossfetchBalance()and the swap-event refresh.pendingRecovery > 0,payInvoicethrows a clear "funds still recovering" message and skips the swap — with a concrete sweep ETA when the SDK advertises one.Screenshot
Testing
Added unit coverage for the guard and ETA rendering; 73 tests passing in
lightning-ark-wallet.test.ts.