DAO-2226 When 1 feeTier from available ones doesn't have liquidity "auto" fails#2081
Open
TravellerOnTheRun wants to merge 6 commits intomainfrom
Open
DAO-2226 When 1 feeTier from available ones doesn't have liquidity "auto" fails#2081TravellerOnTheRun wants to merge 6 commits intomainfrom
TravellerOnTheRun wants to merge 6 commits intomainfrom
Conversation
When viem multicall throws (e.g. EVM OutOfGas on strict eth_call envelopes), retry once with batchSize 1 so each Quoter read uses a smaller aggregate3 chunk.
Route decimals reads through multicallWithGasEnvelopeRetry, dedupe addresses, skip RPC for empty input, and align fork test setup with one batch read.
Align local fork with heavier Multicall3 eth_call envelopes so batch quotes do not fail the whole call with OutOfGas under default limits.
Use the same high block gas limit as local fork:anvil so CI eth_call multicall batches behave like developer machines.
Document inner vs outer multicall failures, why Anvil can differ from public RPC, the fork:anvil and CI gas flags, app-level batch retry, and how to inspect eth_call traffic in the browser.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
viem maps a rejected aggregate3 eth_call to one failure row per contract instead of throwing; detect shared envelope-style errors and retry with batchSize 1. Consolidate fingerprint substrings; use the wrapper in fork multihop test helper so expectations match production.
cybervoid0
reviewed
Apr 14, 2026
| export function isLikelyOuterMulticallRpcFailure(err: unknown): boolean { | ||
| const fp = errorFingerprint(err) | ||
| return fingerprintMatchesChunkEnvelope(fp) || fp.includes('evm error') | ||
| } |
Contributor
There was a problem hiding this comment.
Using a broad evm error match for retry could mask legitimate reverts; consider narrowing to known RPC/gas envelope errors (or at least logging before retry).
cybervoid0
approved these changes
Apr 14, 2026
Ken-li-iov
approved these changes
Apr 14, 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.
Why this exists
The swap stack talks to Rootstock through normal JSON-RPC
eth_call. When we ask Uniswap V3 for quotes across several fee tiers, we do not fire one HTTP request per contract call if we can avoid it: we batch those reads through Multicall3, so a singleeth_callruns many small view calls inside one on-chain aggregate. That is the usual pattern on public RPCs and keeps latency and load down.The problem: that outer
eth_callis still one EVM execution with a single gas budget (the block gas limit the node applies to the call). A batch that is fine on a forgiving public endpoint can fail on Anvil or other strict setups with an Out of gas style error for the whole multicall. From the app’s perspective that looks like the entire quote path failed, even though each inner quoter read might succeed if sent separately. So fork-based development and CI can disagree with “it works on mainnet RPC” without any change to pool math or business logic.What we changed conceptually
Graceful degradation on outer failures — If the batched multicall fails in a way that matches this class of RPC / envelope errors, we retry once with a smaller multicall shape (effectively one inner call per batch chunk) so the same logic still runs, just with more round trips when the node is tight on gas.
Same idea for token decimals — Decimals are also read on-chain; batching and the same retry path keeps behavior consistent and avoids redundant calls (duplicate addresses are collapsed).
Align fork and CI with real gas headroom — Local fork and the workflow that starts Anvil use a higher block gas limit so developers and CI are not randomly blocked by default limits that do not match how public RPCs behave. This does not remove the need for the retry; it reduces noise when comparing fork vs production.
Documentation — There is a short, onboarding-oriented explanation of Multicall3, why one fat
eth_callcan fail as a unit, and how to inspect RPC traffic in the browser when debugging. No extra tooling is required for that.Together, this is about robustness and parity: quotes and decimals should behave predictably whether you are on a public RPC, a local fork, or CI, without giving up batching when the environment allows it.