fix: guard advanced transfer against unaffordable capacity - #1180
Open
jvsena42 wants to merge 12 commits into
Open
fix: guard advanced transfer against unaffordable capacity#1180jvsena42 wants to merge 12 commits into
jvsena42 wants to merge 12 commits into
Conversation
jvsena42
force-pushed
the
fix/advanced-transfer-affordability
branch
2 times, most recently
from
August 25, 2026 16:08
542700f to
a006370
Compare
jvsena42
marked this pull request as ready for review
August 26, 2026 12:49
Greptile SummaryThe PR makes advanced transfer capacity affordability-aware, refreshes the selected funding source before order creation, and prevents cancelled fee quotes from updating the displayed estimate.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt | Adds affordability settling, live software and hardware budget refreshes, and cancellation of superseded receiving-fee quote jobs without leaving a blocking failure. |
| app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt | Integrates the settled range and affordability state while disabling amount controls during initialization. |
| app/src/test/java/to/bitkit/viewmodels/TransferViewModelTest.kt | Adds regression coverage for affordable capacity limits, drained funding sources, hardware-wallet selection, loading state, and stale quote ordering. |
| app/src/main/res/values/strings.xml | Adds localized messaging for advanced-transfer affordability rejection. |
| changelog.d/next/1180.fixed.md | Documents that advanced transfers now expose a maximum receiving capacity the selected balance can fund. |
Sequence Diagram
sequenceDiagram
participant User
participant UI as Advanced transfer UI
participant VM as TransferViewModel
participant Wallet as Selected funding source
participant LSP as Blocktank LSP
User->>UI: Open advanced transfer
UI->>VM: updateAdvancedTransferValues(order)
VM->>Wallet: Load current funding budget
VM->>LSP: Quote min/max receiving capacity
LSP-->>VM: Capacity-dependent fees
VM-->>UI: Affordable capacity range
User->>UI: Select capacity and continue
UI->>VM: onSpendingAdvancedContinue(capacity)
VM->>Wallet: Refresh selected funding budget
VM->>LSP: Re-quote selected capacity
alt Affordable
VM->>LSP: Create order
VM-->>UI: Navigate to confirmation
else Unaffordable
VM-->>UI: Show balance error
end
Reviews (4): Last reviewed commit: "fix: re-read device budget before placin..." | Re-trigger Greptile
jvsena42
marked this pull request as draft
August 26, 2026 12:58
jvsena42
marked this pull request as ready for review
August 26, 2026 14:13
jvsena42
marked this pull request as draft
August 26, 2026 14:34
This comment was marked as resolved.
This comment was marked as resolved.
jvsena42
marked this pull request as ready for review
August 26, 2026 16:18
jvsena42
marked this pull request as draft
August 26, 2026 16:25
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
force-pushed
the
fix/advanced-transfer-affordability
branch
from
August 26, 2026 16:49
5d171aa to
5a0288f
Compare
jvsena42
marked this pull request as ready for review
August 26, 2026 16:50
9 tasks
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.
This PR:
Description
The advanced screen lets the receiving capacity be chosen independently of the client balance, and the Min, Default and Max buttons set it straight from the LSP's liquidity options. Those bounds describe the LSP's channel size limits — nothing in them knows what the wallet can afford. Since the LSP prices both sides of the channel, raising the receiving capacity raises the order fee, so tapping Max on a transfer already sized near the balance produced an order costing more than the user had. The order was created regardless, and the failure only surfaced on the confirm screen, which throws while preparing the funding plan and leaves the swipe control stuck loading.
The max is now settled on an affordable capacity before it is offered, so Max lands on something that can be ordered rather than something that fails later. Finding that ceiling does not need a long search: the LSP fee is close to linear in the capacity, so pricing the min and the max brackets the answer and re-pricing through the rate those two quotes imply lands on it in a round or two. Every capacity offered has been quoted and found affordable. The screen shows a loading state while this settles, so the amount buttons cannot act on a range still being worked out.
The affordability check in the view model stays as a backstop for what moves after that, and both it and the confirm check now resolve the budget at the moment of the decision rather than reading the copy cached on screen entry. A hardware transfer keeps its cached budget, since those funds sit on the device and a fresh on-chain read would reject every one of them.
Separately, the fee quote behind the liquidity fee display was racing itself: each amount change started an uncancelled request, so a slow quote could land after a faster one and leave the display pinned to an amount the user had already left.
If the node will not report a balance at all, or the LSP will not give a quote, the user is deliberately not blocked and the confirm step stays the authority — blocking there would lock people out of the flow whenever the node is briefly unready. Those cases are logged separately so support logs show why a check was skipped.
Preview
Screen_recording_20260826_133538.mp4
QA Notes
Needs a transfer sized at or near Max — at smaller amounts there is enough headroom that raising the receiving capacity never crosses the balance, and the settling correctly does nothing.
Manual Tests
regression:Same screen → tap Default: Continue advances and the order is created.regression:Same screen → tap Min: Continue advances normally.regression:Spending Confirm → Advanced → Default returns to the default order and confirm still swipes through.Automated Checks
TransferViewModelTest.kt: settling the max on an affordable capacity, leaving an already-affordable max untouched, and holding the loading state while it settles.TransferViewModelTest.kt: rejecting an unaffordable capacity, accepting an affordable one, and proceeding when no budget was sized or the fee quote fails.TransferViewModelTest.kt: rejecting an order once the balance drains after the limits were sized, both on confirm and on the advanced screen, and funding a hardware transfer from the device balance rather than empty on-chain savings.TransferViewModelTest.kt: discarding a slower fee quote for a capacity the user has already left.just compile,just test, andjust lintall pass, with only pre-existing detekt findings in untouched files.