-
Notifications
You must be signed in to change notification settings - Fork 4
Send-max computed at the default fee speed, but the drain happens at the selected speed (#1144) #1147
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?
Send-max computed at the default fee speed, but the drain happens at the selected speed (#1144) #1147
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2879,17 +2879,43 @@ class AppViewModel @Inject constructor( | |
| amount: ULong, | ||
| tags: List<String> = emptyList(), | ||
| ): Result<Txid> { | ||
| val state = _sendUiState.value | ||
| return lightningRepo.sendOnChain( | ||
| address = address, | ||
| sats = amount, | ||
| speed = _sendUiState.value.speed, | ||
| utxosToSpend = _sendUiState.value.selectedUtxos, | ||
| isMaxAmount = _sendUiState.value.payMethod == SendMethod.ONCHAIN && | ||
| amount == walletRepo.balanceState.value.maxSendOnchainSats, | ||
| speed = state.speed, | ||
| utxosToSpend = state.selectedUtxos, | ||
| feeRates = state.feeRates, | ||
| isMaxAmount = state.payMethod == SendMethod.ONCHAIN && | ||
| shouldDrainOnchain(address, amount, state), | ||
| tags = tags, | ||
| ) | ||
| } | ||
|
|
||
| private suspend fun shouldDrainOnchain(address: String, amount: ULong, state: SendUiState): Boolean { | ||
| // cached max is computed at the default speed, so drain only if it still holds for the selected one | ||
| if (amount != walletRepo.balanceState.value.maxSendOnchainSats) return false | ||
|
|
||
| val maxAtSelectedSpeed = lightningRepo.estimateMaxSendOnchain( | ||
| address = address, | ||
| speed = state.speed, | ||
| feeRates = state.feeRates, | ||
|
Comment on lines
+2899
to
+2902
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address-type mismatch makes this comparison apples-to-oranges — max-send is broken for P2TR/P2SH/P2PKH recipients. This recomputes the max using the recipient Reproduced on regtest (balance 1,000,000 sats, default speed):
So MAX now fails for P2TR/P2SH/P2PKH recipients, and symmetrically for P2WPKH recipients once the user switches Suggest comparing like with like: either recompute with the same address the cached max used, or derive the MAX button amount from the recipient + selected rate. |
||
| ).onFailure { | ||
| Logger.warn("Failed to recompute max send amount for speed '${state.speed}'", it, context = TAG) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| }.getOrNull() ?: return false | ||
|
|
||
| if (amount != maxAtSelectedSpeed) { | ||
| Logger.info( | ||
| "Sending exact amount '$amount' instead of draining, " + | ||
| "max at speed '${state.speed}' is '$maxAtSelectedSpeed'", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here — |
||
| context = TAG, | ||
| ) | ||
| return false | ||
| } | ||
|
Comment on lines
+2907
to
+2914
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The intended "fall back to an exact-amount send" path can never succeed. Whenever Consider clamping |
||
|
|
||
| return true | ||
| } | ||
|
|
||
| private suspend fun sendLightning( | ||
| bolt11: String, | ||
| amount: ULong? = null, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Fixed max on-chain sends so the wallet no longer drains at a fee speed the confirmed amount did not account for. |
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.
This duplicates
DeriveBalanceStateUseCase.getMaxSendAmountwith different inputs, and the drain decision is exact equality between the two.getMaxSendAmount(~L214) computes the same quantity but fetches fee rates fresh viablocktank.getFees()and applies the 1%-of-balance fallback; this one takes the send-sheet snapshotstate.feeRates(captured inresetSendState) and has no fallback. SinceshouldDrainOnchainrequiresamount == maxAtSelectedSpeedexactly, any blocktank rate refresh between the last balance derivation and confirm silently disables drain — same failure mode as theAppViewModelcomments.Having the use case delegate to this new repo method (same address, same rates) would make the two agree by construction rather than by coincidence.