Skip to content

Improve Fee UX: Bidirectional Fee/Rate Input & Better Rebalance Button#447

Open
Legend101Zz wants to merge 14 commits intocaravan-bitcoin:mainfrom
Legend101Zz:feat/fees-based-change-in-tx
Open

Improve Fee UX: Bidirectional Fee/Rate Input & Better Rebalance Button#447
Legend101Zz wants to merge 14 commits intocaravan-bitcoin:mainfrom
Legend101Zz:feat/fees-based-change-in-tx

Conversation

@Legend101Zz
Copy link
Copy Markdown
Contributor

Problem

Users reported two major UX issues when building transactions:

  1. No way to specify exact fee amounts: Users could only set a fee rate and had to use trial-and-error, repeatedly adjusting the rate (4 → 5 → 4.5 → 4.6 sats/vB) until they achieved the desired total fee. This was frustrating when trying to pay exactly X satoshis in fees.

  2. Unintuitive rebalance button: The output amount rebalance feature used a small gray +/- icon button that users found difficult to discover and unclear in its purpose.

  3. Auto-spend mode limitations: In wallet auto-spend mode, the fee amount field was completely hidden, preventing any fee customization beyond the rate.

Changes Made

Screenshot 2026-01-13 at 20 39 03

Testing

Manual Testing Checklist:

  • Fee Rate → Fee Amount sync

    • Enter fee rate with inputs selected → fee amount updates
    • Enter fee rate without inputs → fee amount stays "0.0000"
    • Change fee rate → fee amount recalculates
  • Fee Amount → Fee Rate sync

    • Enter fee amount with inputs selected → rate updates
    • Enter fee amount without inputs → rate stays same
    • Helper text shows "Effective rate: X sats/vB"
  • Rebalance button

    • Button is visible and prominent (blue, labeled "Rebalance")
    • Shows correct action ("Increase to..." or "Decrease to...")
    • Clicking button adjusts output amount correctly
    • Only appears when balance error exists and is fixable
  • Auto-spend mode

    • Fee amount field is visible
    • Can enter exact fee amount
    • Auto coin selection uses exact fee when specified
    • Error shown if specified fee is too low
    • Effective fee rate updates correctly
  • Edge cases

    • Empty fee amount → graceful handling
    • Zero fee rate → no errors
    • Very large fees → validation works
    • Add/remove outputs → fee recalculates correctly

Test Transactions:

  1. Script Explorer (manual mode)
  2. Wallet spend (auto-spend mode)
  3. Multi-output transactions
  4. Transactions requiring change

Related Issues

Fixes #443


@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 13, 2026

🦋 Changeset detected

Latest commit: a62473c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
caravan-coordinator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented Jan 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
caravan-coordinator Ready Ready Preview, Comment Apr 27, 2026 6:27pm

Request Review

@Legend101Zz
Copy link
Copy Markdown
Contributor Author

@bucko13 let me know if we want to make the fees field editable in auto mode too , not a big change , just wanted to confirm once :)

@Legend101Zz Legend101Zz requested a review from bucko13 January 13, 2026 15:53
Comment thread apps/coordinator/src/components/ScriptExplorer/OutputsForm.jsx Outdated
Copy link
Copy Markdown
Contributor

@bucko13 bucko13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a couple of console.logs to cleanup. will validate functionality as well.

Comment thread apps/coordinator/src/components/ScriptExplorer/OutputsForm.jsx Outdated
@bucko13
Copy link
Copy Markdown
Contributor

bucko13 commented Jan 21, 2026

The UX still feels a little funny to me and I wonder if maybe there are some regressions. First, to be clear, this is just in the manual mode right?

Screenshot 2026-01-21 at 4 34 26 PM

Second, there's some weird state management thing going on. When i clicked back and forth on the manual toggle. I got stuck with this error that inputs must be positive. Toggling the input on and off fixed that.

Screenshot 2026-01-21 at 4 35 38 PM

Lastly the "rebalance" is missing now for the change. Note in the second screenshot below when I add a second output for change the grey + shows up, but I don't see that in the new version for some reason.
Screenshot 2026-01-21 at 4 36 53 PM

Screenshot 2026-01-21 at 4 37 26 PM

Last thought: I wonder if fees should be in sats. The fee rate is of course in sats and I feel like thinking in sats for fees is a little more intuitive. It's certainly easier to type in with the number field.

@Legend101Zz
Copy link
Copy Markdown
Contributor Author

@bucko13 sorry for the huge delay on this , finally I have fixed all the issues and also I decided not have the fees edit field on auto mode as it was getting far to complicated and logic was being fragile and inaccurate to calculate the fees before hand without knowing the inputs , can you check the UI , I am happy to iterate as we are taking time so any new fresh and better UX would be very nice

Screenshot 2026-03-17 at 22 59 19

@Legend101Zz
Copy link
Copy Markdown
Contributor Author

@bucko13 @tomunchained how do these look ?
Screenshot 2026-03-17 at 23 10 48

Screenshot 2026-03-17 at 23 10 30

@bucko13
Copy link
Copy Markdown
Contributor

bucko13 commented Mar 17, 2026

@bucko13
Copy link
Copy Markdown
Contributor

bucko13 commented Mar 17, 2026

Ah, i think this is a legitimate e2e failure!

    1 failed
      [mutate-wallet] › e2e/tests/mutate/transaction-flow.spec.ts:84:3 › Transaction Creation and Signing › manual coin selection: create, sign, broadcast 

)
rate = "0";
setFeeRate(rate);
setFeeRate(rate === "" ? "0" : rate); // Reducer handles fee calculation and validation
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can also do:

Math.round(num * 100) / 100

Copy link
Copy Markdown
Contributor

@bucko13 bucko13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple small questions/comments. Need to fix e2e as well. I'll test functionally next but the screenshots look good

let feeRateString = action.value;

// Limit to 2 decimal places
if (feeRateString && feeRateString.includes(".")) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Math.round((num + Number.EPSILON) * 100) / 100

(or similar)

@bucko13
Copy link
Copy Markdown
Contributor

bucko13 commented Mar 17, 2026

UX Feedback:

I don't love that the up arrow increments by a hundredth of a sat/vbyte when doing the up arrow. that's a very small unit of change that I don't think has much value

Screenshot 2026-03-17 at 4 48 10 PM

It looks like the fee rate is not updating with the fee amount

Screenshot 2026-03-17 at 4 51 43 PM Screenshot 2026-03-17 at 4 51 58 PM Screenshot 2026-03-17 at 4 52 09 PM

Got some weird UI juping around when I added a change. There was a

Screenshot 2026-03-17 at 4 53 14 PM

And this was funky too. When i changed the fee amount, rebalance was only available on the recipient output, rather than the change one which is where I would expect it
Screenshot 2026-03-17 at 4 53 38 PM

@Legend101Zz
Copy link
Copy Markdown
Contributor Author

Ah, i think this is a legitimate e2e failure!

    1 failed
      [mutate-wallet] › e2e/tests/mutate/transaction-flow.spec.ts:84:3 › Transaction Creation and Signing › manual coin selection: create, sign, broadcast 

I yes I suspected that as I made changes to the transcation creation flow so would need to make changes to selectors in the Page model in. e2e , glad it's working fine :)

@github-actions
Copy link
Copy Markdown
Contributor

This pull request has been inactive for 30 days and has been marked as stale. It will be closed in 7 days if no further activity occurs. To keep this PR open, add the "long-lived" label or comment on it.

@github-actions github-actions Bot added the stale label Apr 21, 2026
Address Buck's review feedback: only show the Rebalance button on the
change output (or on recipients when no change output is set), and use
Math.round((n + Number.EPSILON) * 100) / 100 for fee-rate rounding so
floating-point artifacts don't leak into the input.
Buck noted ↑/↓ on the fee rate input bumping by 0.01 sat/vB has no
practical value. Switch the step to 1 (manual decimal entry still works,
reducer still rounds to 2 places).

Also fix the row jumping when a change output is added: the rebalance
column (xs=2) plus delete column (xs=1) was overflowing past 12, causing
the row to wrap. Address column shrunk to xs=6 and both action slots are
now always rendered (empty when inactive) so columns stay stable. Helper
text under the Rebalance button is clipped with an ellipsis instead of
wrapping to a second line.
Buck reported the fee rate field staying stale while editing the fee
amount. updateFee was guarded by !feeError, so any non-fatal validation
hiccup (intermediate typing, fee-too-high) suppressed the back-calc and
left the rate showing the previous value.

Drop the !feeError guard. As long as inputs are known and feeSats > 0,
recompute the rate from the typed fee. Use the same EPSILON-based
rounding as updateFeeRate so display values stay consistent.
The IconButton wrapping AddCircle was replaced by a labelled Button, so
locating it via the auto-generated AddCircleIcon test id is brittle and
only matches the "Increase" variant. Tag the button with
data-testid="rebalance-button" and have the manual-coin-selection flow
look it up directly.
…c runs

bitcoinsToSatoshis returns a string, not a BigNumber. updateFee was
storing that string in feeSats and then guarding the back-calculation
with BigNumber.isBigNumber(feeSats), which always returned false. The
fee field updated, but feeRate silently stayed at its previous value —
the symptom Buck and the maintainer both saw in the form and Preview
modal.

Wrap the result in new BigNumber(...) so the guards behave like numbers
and the back-calc actually fires.

Add a regression test that mirrors the reported scenario (1 input of
6.25 BTC, two outputs, fee=0.001 BTC) and asserts the rate climbs well
above the previous value of 1 sat/vB.
…nge-in-tx

# Conflicts:
#	apps/coordinator/e2e/tests/03-transaction_flow.spec.ts
@Legend101Zz Legend101Zz force-pushed the feat/fees-based-change-in-tx branch from bf1b0f3 to c2a983a Compare April 27, 2026 18:19
@Legend101Zz
Copy link
Copy Markdown
Contributor Author

UX Feedback:

I don't love that the up arrow increments by a hundredth of a sat/vbyte when doing the up arrow. that's a very small unit of change that I don't think has much value

Screenshot 2026-03-17 at 4 48 10 PM It looks like the fee rate is not updating with the fee amount

Screenshot 2026-03-17 at 4 51 43 PM Screenshot 2026-03-17 at 4 51 58 PM Screenshot 2026-03-17 at 4 52 09 PM
Got some weird UI juping around when I added a change. There was a

Screenshot 2026-03-17 at 4 53 14 PM And this was funky too. When i changed the fee amount, rebalance was only available on the recipient output, rather than the change one which is where I would expect it Screenshot 2026-03-17 at 4 53 38 PM

Thank you for all the testing ... I have resolved all these bugs and flaky behaviour on my end , can you please test it out again :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Alternative way of choosing fees when building transactions

2 participants