Skip to content

Moonbeam RPC Significant Gas Underestimation in UniswapInterfaceMulticall Static Calls #3398

@mshakeg

Description

@mshakeg

Problem Description

When using UniswapInterfaceMulticall.callStatic.multicall() for gas estimation on Moonbeam mainnet, RPC nodes consistently underestimate the actual gas requirements, causing transactions to fail with out-of-gas errors.

Technical Details

Chain Affected: Moonbeam Mainnet (Chain ID: 1284)

Root Cause:

  • callStatic.multicall() returns gasUsed values that are lower than actual execution requirements
  • The internal gas accounting in UniswapInterfaceMulticall appears to be simulated incorrectly by Moonbeam RPC nodes
  • Other EVM chains simulate this correctly

Reproduction Steps

Method 1: Direct Contract Interaction

  1. Deploy or use existing UniswapInterfaceMulticall contract on Moonbeam
  2. Create multiple (permissionless/open) calls that consume significant gas (e.g., complex DeFi operations, state changes)
  3. Use callStatic.multicall(calls) to get gas estimates
  4. Execute actual multicall(calls) transaction using the estimated gas
  5. Observe transaction failure due to insufficient gas

Method 2: Synthetic Test Case

// Deploy a gas-consuming test contract
contract GasConsumer {
    mapping(uint256 => uint256) public data;

    function consumeGas(uint256 iterations) external {
        for(uint256 i = 0; i < iterations; i++) {
            data[i] = i * 2;
        }
    }
}

Then test with multicall:

// assuming the actual gas limit is guaranteed to be < 500000 we allocate at most that for each call
const calls = [
  { target: gasConsumer.address, gasLimit: 500000, callData: gasConsumer.interface.encodeFunctionData('consumeGas', [100]) },
  { target: gasConsumer.address, gasLimit: 500000, callData: gasConsumer.interface.encodeFunctionData('consumeGas', [150]) }
];

// This will underestimate
const staticResult = await multicall.callStatic.multicall(calls);
console.log('Estimated gas:', staticResult.returnData.map(r => r.gasUsed));

// This may fail
const tx = await multicall.multicall(calls);

Error Pattern

Transaction Status: 0 (reverted)
Gas Used: [Full gas limit] (indicating out-of-gas)
Error: CALL_EXCEPTION

Impact

  • Applications relying on accurate gas estimation face transaction failures
  • Gas fees are wasted on failed transactions
  • Automated systems (keepers, bots) cannot operate reliably

Current Workarounds

  1. Disable gas estimation and use static gas limits
  2. Apply significant gas buffers (50%+ markup)
  3. Use alternative gas estimation methods

Chain Comparison

  • Working chains: Ethereum, Polygon, Arbitrum, Base, and many other EVM chains
  • Problematic: Moonbeam mainnet specifically
  • Note: This issue is unique to Moonbeam's RPC gas simulation, the issue is on a few Moonbeam RPCs such as https://1rpc.io/glmr and https://moonbeam.unitedbloc.com

UniswapInterfaceMulticall Contract

The issue occurs in the internal gas accounting:

uint256 gasLeftBefore = gasleft();
(bool success, bytes memory ret) = target.call{gas: gasLimit}(callData);
uint256 gasUsed = gasLeftBefore - gasleft();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions