Skip to content

feat: retry failed quote loads and surface quote errors in TransactionPayController - #9837

Open
dan437 wants to merge 10 commits into
mainfrom
feat/transaction-pay-retry-failed-quote-loads
Open

feat: retry failed quote loads and surface quote errors in TransactionPayController#9837
dan437 wants to merge 10 commits into
mainfrom
feat/transaction-pay-retry-failed-quote-loads

Conversation

@dan437

@dan437 dan437 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Explanation

When a quote load in TransactionPayController failed unexpectedly, the error was swallowed (.catch(noop)), nothing was written to state, and the refresh loop skipped transactions with no quotes — so they were never retried. One failed fetch left the transaction permanently without quotes: clients showed no fees, and submission was blocked by the publish guard ("MetaMask Pay: Cannot submit without quote").

This change makes failed quote loads recoverable:

  • refreshQuotes now also retries transactions that should have quotes but have none, on the default refresh interval. One transaction's failure no longer stops the others from refreshing.
  • QuoteRefresher keeps the refresh loop alive while such a transaction exists.
  • Unexpected failures are persisted to quoteError (reason no-quotes) instead of being swallowed — but only when quotes are needed and none are usable. Existing executable quotes stay usable until a refresh replaces them, and direct routes stay silent because they need no quotes. Stale no-op quotes from a previous direct route are dropped so the retry loop picks the transaction up.
  • Every failed or skipped attempt stamps quotesLastUpdated, so retries wait a full interval instead of running every tick, and late writes cannot recreate pay state that cleanup already removed.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Touches core quote fetch, refresh, and error state for pay submission; behavior is well-tested but affects when users see errors and when submit is allowed.

Overview
Fixes MetaMask Pay transactions that could stay permanently without quotes after a single failed or empty quote fetch, which blocked fees display and submit.

Quote retry and refresh loop: refreshQuotes now retries transactions that should have quotes but have none (failed load, empty result, fiat payment selected, etc.), respecting the normal refresh interval via quotesLastUpdated. QuoteRefresher keeps polling while isQuoteRetryPending is true, not only when executable quotes already exist. Per-transaction failures are isolated so one bad transaction does not stop others from refreshing.

Failure persistence: Unexpected quote pipeline errors call persistQuoteLoadFailure, which stamps quotesLastUpdated, sets quoteError (no-quotes) only when quotes are needed and none are usable, drops stale no-op quotes so retries can run, and skips writes if pay state was removed. Refresh paths that skip or throw still stamp attempt time so retries do not hammer every tick.

Controller: updateQuotes rejections are logged instead of swallowed with noop, without changing the fire-and-forget call pattern.

Reviewed by Cursor Bugbot for commit b94dcdd. Bugbot is set up for automated code reviews on this repo. Configure here.

@dan437
dan437 marked this pull request as ready for review August 14, 2026 09:16
@dan437
dan437 requested review from a team as code owners August 14, 2026 09:16
@dan437
dan437 deployed to default-branch August 14, 2026 09:16 — with GitHub Actions Active
@matthewwalsh0
matthewwalsh0 self-requested a review August 14, 2026 10:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant