fix: keep QuickBuy CTA live during background quote refresh#31059
Conversation
The CTA disable gate and amount-section spinner were wired to the raw isQuoteLoading flag, so the Buy/Sell button greyed out and the receive estimate was replaced by a spinner on every periodic quote refresh, even though the displayed quote stayed valid and submittable the whole time. Introduce isBlockingQuoteLoad (loading without a usable on-screen quote) and use it for the CTA, total, and amount spinner. The displayed quote now stays interactive during refresh and updates in place when the new quote lands. Genuine no-usable-quote cases (first load, amount/token change, mid-drag, error) remain blocked via existing guards. Co-authored-by: Cursor <cursoragent@cursor.com>
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 06b5620. Configure here.
This update adds an `isQuoteRequestStale` flag to the Quick Buy functionality, which indicates when request-only inputs (like slippage and destination address) have changed since the last quote was fetched. This ensures that the displayed quotes are not treated as submittable when they no longer match the current request. The flag is integrated into the `useQuickBuyController` and `useQuickBuyQuotes` hooks, affecting the UI behavior of the Quick Buy CTA and loading states. Additionally, tests have been added to verify the correct behavior when inputs change and quotes are refetched. Co-authored-by: Tyler Chong <tyler.chong@consensys.net>
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
No E2E test files reference QuickBuy, SocialLeaderboard, or TraderPositionView directly. The changes are purely internal hook/component refinements with no shared infrastructure impact (no controllers, Engine, navigation, or shared components modified). Tag selection rationale:
Risk is low because: (1) changes are isolated to a single feature area, (2) no shared infrastructure is modified, (3) the logic change is a refinement (background refresh no longer blocks CTA), (4) comprehensive unit tests cover the new behavior. Performance Test Selection: |

Description
Screen.Recording.2026-06-04.at.11.04.52.mov
In QuickBuy, quotes auto-refresh on a fixed interval. The data layer already keeps the displayed quote live during a refresh (
useQuickBuyQuotesonly flipsisQuoteLoading = trueand atomically swapsrawQuoteson success — it never clears the existing quote). However, the controller wired the rawisQuoteLoadingflag into the CTA disable gate and the amount-section spinner.As a result, on every refresh tick the Buy/Sell button greyed out and the receive estimate was replaced by a spinner, even though the on-screen quote stayed valid and submittable the entire time. This produced a visible, recurring flicker.
This PR introduces
isBlockingQuoteLoad— loading that has no usable on-screen quote yet (first load, or an input change where the current quote no longer matches). A plain background refresh is excluded, so the CTA stays enabled and the receive estimate stays visible, then updates in place when the new quote arrives.The genuine "no usable quote for what's displayed" cases remain blocked via the existing, more precise guards:
isAmountUncommittedisPendingQuoteRefreshhasQuoteMismatch!activeQuote,hasErrorThe all-quotes select screen keeps consuming raw
isQuoteLoading, where reflecting refresh activity is desirable.Key changes
useQuickBuyController.ts: derivehasUsableQuoteOnScreen+isBlockingQuoteLoad; use the latter inisConfirmDisabledandisTotalLoading; expose it on the result type.QuickBuyAmount.tsx: feedisBlockingQuoteLoadto the amount section so the receive estimate persists during refresh.Changelog
CHANGELOG entry: null
Related issues
Fixes:
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Performance checks (if applicable)
Pre-merge reviewer checklist
Made with Cursor
Note
Medium Risk
Changes quote gating and submit-disable logic for trades; incorrect stale/usable detection could allow or block submission at the wrong time, though new flags and tests target those cases.
Overview
QuickBuy was treating every quote fetch as a full UI block: the Buy/Sell CTA and receive estimate reacted to raw
isQuoteLoading, so periodic auto-refresh caused flicker even when the on-screen quote stayed valid.The controller now derives
isBlockingQuoteLoad(loading only when there is no usable quote for the current amount, token pair, and committed inputs) and wires that into confirm disable, total loading, and the amount section spinner.useQuickBuyQuotesaddsisQuoteRequestStalewhen hidden request inputs (slippage, destination address, gas flags) change after the last settled fetch, so the CTA cannot stay enabled on a quote that no longer matches the active request.Initial load and real input changes still block as before; benign background refreshes keep the CTA enabled and the estimate visible until the new quote lands.
Reviewed by Cursor Bugbot for commit bc095ab. Bugbot is set up for automated code reviews on this repo. Configure here.