feat(transaction-pay-controller): validate relay quotes#9143
Open
matthewwalsh0 wants to merge 23 commits into
Open
feat(transaction-pay-controller): validate relay quotes#9143matthewwalsh0 wants to merge 23 commits into
matthewwalsh0 wants to merge 23 commits into
Conversation
matthewwalsh0
force-pushed
the
feat/pay-quote-validation
branch
from
June 16, 2026 11:29
4c879f1 to
c8d67d2
Compare
matthewwalsh0
force-pushed
the
feat/pay-quote-validation
branch
4 times, most recently
from
June 17, 2026 20:38
8d2856d to
38a7453
Compare
10 tasks
matthewwalsh0
force-pushed
the
feat/pay-quote-validation
branch
2 times, most recently
from
July 15, 2026 11:13
2d16a71 to
70adf3b
Compare
|
No dependency changes detected. Learn more about Socket for GitHub. 👍 No dependency changes detected in pull request |
matthewwalsh0
force-pushed
the
feat/pay-quote-validation
branch
from
July 18, 2026 18:40
316de97 to
3f1ff46
Compare
Member
Author
|
@metamaskbot publish-preview |
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
matthewwalsh0
marked this pull request as ready for review
July 20, 2026 12:53
matthewwalsh0
temporarily deployed
to
default-branch
July 20, 2026 12:53 — with
GitHub Actions
Inactive
jpuri
previously approved these changes
Jul 21, 2026
…de amounts in error messages
…with human-formatted details
- Change QuoteValidationError from flat string to structured QuoteValidationErrorInfo
{ message, reason, detail? } across types, validation, relay-validation, quotes
- Add formatBalanceShortfall/formatTokenAmount helpers: shift by source token
decimals via getTokenInfo, append symbol (e.g. 'Required: 1.5 USDC'),
raw atomic fallback when token info unavailable
- Add 'no-quotes' QuoteValidationReason; capture strategy getQuotes() errors
as validationError so genuine no-route failures surface in the UI
- Rename simulation error message to 'Quote simulation failed'
- Export QuoteValidationErrorInfo and QuoteValidationReason from index
- 1269 tests pass, 100% coverage, ESLint clean
…d move relay validation into getRelayQuotes
…coder in relay-submit Remove the dependency on generateEIP7702BatchTransaction exported from transaction-controller. Restore the local buildEip7702BatchTransaction function and ERC-7821 constants/interface so transaction-controller needs no changes for this PR.
…ith SentinelApiService messenger action - Add @metamask-previews/sentinel-api-service dependency - Rewrite simulation.ts to call SentinelApiService:simulateTransactions via messenger - Add SentinelApiServiceActions to TransactionPayControllerMessenger AllowedActions - Delete sentinel.ts and sentinel.test.ts (local client removed) - Rewrite simulation.test.ts and relay-validation.test.ts to use messenger mock - Add BREAKING changelog entry for new messenger action requirement - Re-export generateEIP7702BatchTransaction from transaction-controller (rebase fix)
…validation - Revert TC CHANGELOG diff (no changes to transaction-controller source) - Revert PayStrategyQuoteSupportResult: checkQuoteSupport returns boolean - Slim relay-submit.ts: remove manual EIP-7702 encoder, un-export helpers - Simplify simulation.ts: trust Sentinel transaction.error directly - Fix exported function ordering (exported before private helpers) - Delete relay-validation.ts: inline validateRelayQuotes into relay-quotes.ts - Rename QuoteValidation* -> Quote* (QuoteError, QuoteErrorInfo, QuoteErrorReason, isQuoteError, QuoteSimulation, QuoteExecutionRequest) - Add validation.test.ts with 100% coverage of all validation branches
…simulation builders, rename quoteError
…e balances - Log the selected simulation type (execute / 7702-batch / normal) in relay validation. - getLiveTokenBalance now falls back to the 'latest' block when the 'pending' query throws, with a warning log, for both native and ERC-20 paths.
matthewwalsh0
force-pushed
the
feat/pay-quote-validation
branch
from
July 21, 2026 14:50
51750aa to
1e8a1f7
Compare
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 1e8a1f7. Configure here.
matthewwalsh0
enabled auto-merge
July 21, 2026 16:39
jpuri
approved these changes
Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Explanation
Transaction Pay surfaces Relay quotes without checking that their execution path is still executable, so clients can end up with quotes that only fail later at submission or simulation.
This PR validates Relay quotes while they are being fetched, before they are surfaced as executable. Each quote is converted into normalized execution transactions, then shared validation utilities check:
@metamask/sentinel-api-service)When validation fails, no executable quote is surfaced and
TransactionDatacarries a structuredquoteError: QuoteErrorInfodescribing why.message/detailare display-ready copy andreasonis a machine-readable discriminant ('simulation-failed' | 'insufficient-source-balance' | 'insufficient-transfer-balance' | 'balance-unavailable' | 'no-quotes') for analytics and for conditionally surfacing alerts in clients.Simulation and validation live in generic utilities so other strategies can opt in, and the Relay execute-request building is unified into a single
getRelayExecuteRequesthelper shared by the validation and submit paths.BREAKING:
TransactionPayControllerMessengernow requires theSentinelApiService:simulateTransactionsaction. Consumers must includeSentinelApiServiceActionsin theAllowedActionstype passed to theTransactionPayControllermessenger.References
Checklist
Note
High Risk
Breaking messenger contract and changes when Relay quotes are shown; misconfigured Sentinel or validation could block pay flows, though validation defaults off via feature flag.
Overview
Adds pre-surface validation for Relay quotes: after fetch, quotes can be checked for live source balance, decoded ERC-20 transfer amounts, and Sentinel transaction simulation before clients treat them as executable. Validation is gated by
payStrategies.relay.validationEnabledinconfirmations_pay_extended(off by default as a kill switch).When quote loading fails or yields no executable quotes,
TransactionData.quoteError(QuoteErrorInfowith display copy plus machine-readablereason) is set; it clears when a new quote fetch starts.QuoteError/ sharedvalidateQuoteExecutionandsimulateQuoteTransactionsare exported for reuse by other strategies.Relay paths are refactored so validation and submit share
getRelaySubmitCalls,buildRelaySubmitParams, andgetRelayExecuteRequest(optionalregenerateBatchParamsfor execute). Relay fetch errors are re-thrown without the previousFailed to fetch Relay quoteswrapper.BREAKING:
TransactionPayControllerMessengermust allowSentinelApiService:simulateTransactions(@metamask/sentinel-api-servicedependency). Live balance RPC usespendingwithlatestfallback whenpendingis unsupported.Reviewed by Cursor Bugbot for commit 1e8a1f7. Bugbot is set up for automated code reviews on this repo. Configure here.