Handle BTC fee fallback without raw transaction#6188
Handle BTC fee fallback without raw transaction#6188SeniorZhai wants to merge 1 commit intomasterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a BTC-specific fee estimation fallback path so the UI can still display a fee when building a raw BTC transaction fails (e.g., missing/invalid UTXOs), by allowing fee-rate estimation without providing a raw transaction.
Changes:
- Add a BTC fallback flow in
InputFragment.refreshGasto estimate/display fee even when the raw transaction cannot be built. - Introduce
applyFallbackBtcFeeWithoutRawTransactionto apply the fallback fee/rate/minFee to UI/state. - Update
Web3ViewModel.estimateBtcFeeRateto accept an optional raw transaction hex.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| app/src/main/java/one/mixin/android/ui/wallet/InputFragment.kt | Adds BTC fallback fee estimation path when raw tx build or fee calc fails; updates UI accordingly. |
| app/src/main/java/one/mixin/android/ui/home/web3/Web3ViewModel.kt | Allows BTC fee estimation API call with rawTransactionHex omitted/empty. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (handledByBtcFallback) { | ||
| binding.iconImageView.isVisible = false | ||
| binding.contentTextView.isVisible = true | ||
| binding.loadingProgressBar.isVisible = false | ||
| applyFeeUi() | ||
| return |
There was a problem hiding this comment.
The fallback handling repeats the same UI state toggles (iconImageView/contentTextView/loadingProgressBar + applyFeeUi()) in multiple branches. This duplication makes it easy for the branches to drift (e.g., one path missing a UI update). Consider extracting a small helper to apply the common UI state for "fee resolved" and call it from all branches.
| val estimate = web3ViewModel.estimateBtcFeeRate(currentRate = rate?.toPlainString()) ?: return false | ||
| rate = estimate.feeRate?.toBigDecimalOrNull() ?: rate | ||
| miniFee = estimate.minFee ?: miniFee | ||
| val fallbackFee: BigDecimal = estimate.minFee?.toBigDecimalOrNull()?.movePointLeft(1) ?: return false |
There was a problem hiding this comment.
fallbackFee is derived from estimate.minFee by doing movePointLeft(1), which changes the unit/scale (÷10) compared to how minFee is treated elsewhere (e.g., Web3ViewModel.calcFee compares minFee directly against a BTC-denominated estimatedFee). This is likely to under-estimate the BTC fee and can produce invalid/underfunded transactions. Consider using estimate.minFee directly (same unit as calcFee) or clearly converting based on documented API units, but keep it consistent across the codepaths.
| val fallbackFee: BigDecimal = estimate.minFee?.toBigDecimalOrNull()?.movePointLeft(1) ?: return false | |
| val fallbackFee: BigDecimal = estimate.minFee?.toBigDecimalOrNull() ?: return false |
| delay(3000) | ||
| refreshGas(t) | ||
| return |
There was a problem hiding this comment.
refreshGas retries by calling itself after delay(3000) (both when transaction == null and when gas == null). If the underlying condition never resolves (e.g., persistent BTC UTXO/build failures), this creates unbounded recursion and can eventually overflow the stack. Prefer an iterative retry loop (or a bounded retry with backoff) and ensure it stops when the coroutine is cancelled / fragment is no longer active.
No description provided.