feat(providers): surface revert reason from failed RPC sends#1473
Open
droplet-rl wants to merge 1 commit into
Open
feat(providers): surface revert reason from failed RPC sends#1473droplet-rl wants to merge 1 commit into
droplet-rl wants to merge 1 commit into
Conversation
When a required provider fails a send (e.g. an eth_estimateGas that
reverts on-chain), RetryProvider throws a generic "Not enough providers
succeeded" error. For a deterministic revert the underlying JSON-RPC
error - including the ABI-encoded custom error selector - is buried in
the raw response body, so callers and logs can't easily tell that the
tx simply reverted (e.g. RelayFilled / 0x8f260c60) versus a real
provider-availability problem.
Add `getRevertReason()`, a thin wrapper over the existing
`parseJsonRpcError()`, and use it to:
- prepend a decoded "Revert reason: <message> (<selector>)" line to the
wrapper error message, and
- preserve the original rejection on the thrown error's `cause`, so
callers can recover the structured `{ code, message, data }` via
`parseJsonRpcError(err.cause)`.
Add unit tests demonstrating reliable extraction from the exact ethers
v5 SERVER_ERROR ("processing response error") shape seen in production.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Context
From a Slack thread: the relayer logged a confusing error on an
eth_estimateGasforfillRelay:Two issues were raised:
On (1): that string is
RetryProvider.send's unconditional failure wrapper — it fires whenever the required-quorum providers don't all succeed, regardless of cause. Foreth_estimateGas/eth_call-at-latest the quorum is 1, so it really means "the one provider we needed reverted." It did fail fast (failImmediateshort-circuits on revert keywords), the wording just doesn't reflect that — and the decoded revert (0x8f260c60= SpokePoolRelayFilled(), a benign already-filled race) is left buried in the raw response body.On (2): yes — the structured error is already parseable via the existing
parseJsonRpcError(). This PR demonstrates that and wires it into the failure path.Change
getRevertReason()insrc/providers/utils.ts— a thin wrapper overparseJsonRpcError()that returns e.g."execution reverted (0x8f260c60)".RetryProvider.send(), when the required providers fail:Revert reason: <message> (<selector>)line to the wrapper message, andcause, so callers can recover the structured{ code, message, data }viaparseJsonRpcError(err.cause)instead of scraping the message string.No behavioural change to control flow (retries/quorum/fail-fast all unchanged) — this only enriches the error surface.
Tests
Added unit tests in
test/providers/utils.test.tsthat reconstruct the exact ethers v5 SERVER_ERROR ("processing response error") shape from the report and assert reliable extraction:parseJsonRpcErrorreturns{ code: 3, message: "execution reverted", data: "0x8f260c60" }(andundefinedfor non-JSON-RPC errors / null data handled).getRevertReasonreturns"execution reverted (0x8f260c60)".createSendErrorWithMessage(...)wrapper viaparseJsonRpcError(err.cause).Follow-ups (not in this PR)
0x8f260c60→RelayFilled) against the SpokePool interface for even friendlier logs — the relayer already maps known selectors.MultiCallerClient.knownRevertReasonsalready listsRelayFilled; preserving the structuredcausehere lets that filtering work even when the error is wrapped by estimateGas/UNPREDICTABLE_GAS_LIMIT.🤖 Generated with Claude Code