feat(transaction-controller): extract revert reason for failed transactions#8589
Draft
matthewwalsh0 wants to merge 1 commit intomainfrom
Draft
feat(transaction-controller): extract revert reason for failed transactions#8589matthewwalsh0 wants to merge 1 commit intomainfrom
matthewwalsh0 wants to merge 1 commit intomainfrom
Conversation
eff0b70 to
f5196a9
Compare
4 tasks
f5196a9 to
988450c
Compare
…ctions When a transaction fails on-chain (status 0x0) or is predicted to fail during gas estimation, decode and surface the revert reason instead of just "Transaction failed on-chain". - Add extractRevertReason util that decodes Error(string), Panic(uint256) with named codes, custom error selectors, and empty reverts; falls back to the provider error message when no revert data is surfaced - Add revertReason?: string on TransactionMeta, populated when an on-chain receipt has a failure status (replays via eth_estimateGas) - Add gasRevertReason?: string on TransactionMeta, populated when eth_estimateGas reverts during transaction creation, allowing UI to warn the user before they confirm a tx that's predicted to fail - Append the on-chain reason to the existing 'Transaction failed on-chain' error message via a new OnChainFailureError subclass eth_estimateGas is used (instead of eth_call) for the on-chain replay path as a workaround for a bug in eth-json-rpc-middleware's RetryOnEmptyMiddleware: its isExecutionRevertedError check fails to recognise EIP-1474 / Infura-style revert errors (code 3, suffixed message), causing it to retry reverted calls 10 times and discard the original error data. eth_estimateGas returns the same revert payload but bypasses that middleware. A separate upstream PR fixes the underlying bug.
988450c to
fcfa427
Compare
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
When a transaction fails — either on-chain after broadcast, or up-front during gas estimation — MetaMask currently records a generic "Transaction failed on-chain" with no information about why it failed. The actual revert reason — `ERC20: transfer amount exceeds balance`, `Panic: arithmetic overflow`, etc. — is recoverable from any standard JSON-RPC endpoint.
This PR extracts the human-readable revert reason at both points and surfaces it on `TransactionMeta`:
The on-chain failure path also appends the decoded reason to the existing error message: `"Transaction failed on-chain: ERC20: transfer amount exceeds balance"`.
Decoding
The shared `decodeRevertReasonFromError` util handles:
Always wrapped in try/catch — never throws, safe to run on every failure path.
Why `eth_estimateGas` (not `eth_call`)
The on-chain replay path uses `eth_estimateGas` rather than `eth_call` to work around a bug in `@metamask/eth-json-rpc-middleware`'s `RetryOnEmptyMiddleware` (fixed separately in #8597). That middleware's `isExecutionRevertedError` check rejects EIP-1474 / Infura-style revert errors (`code: 3`, suffixed message), causing reverted `eth_call`s to be retried 10 times and the original error data to be discarded. `eth_estimateGas` returns the same revert payload but isn't routed through that middleware.
When #8597 lands and is consumed, we could revisit and switch back to `eth_call` if there's value in the block-tag precision. For now `eth_estimateGas` produces the same reasons in practice.
References
Changelog
```
Added
```
Checklist