Skip to content

Conversation

@gustavo-grieco
Copy link
Collaborator

@gustavo-grieco gustavo-grieco commented Sep 11, 2025

This PR add an experimental feature that allows to automatically encode valid callback data in any bytes argument using non-view/non-pure functions to call. For instance, now echidna can automatically solve this:

pragma solidity ^0.8.0;

contract MultiDelegatecall {
   
    function multicall(bytes[] memory data)
        external
        payable
        returns (bytes[] memory results)
    {
        results = new bytes[](data.length);

        for (uint256 i; i < data.length; i++) {
            (bool ok, bytes memory res) = address(this).delegatecall(data[i]);
            results[i] = res;
            if (!ok) {
               return results;
            }
        }
    }
}

contract TestMultiDelegatecall is MultiDelegatecall {
    event Log(address caller, string func, uint256 i);

    function func1(uint256 x, uint256 y) external {
        emit Log(msg.sender, "func1", x + y);
    }

    function func2() external returns (uint256) {
        emit Log(msg.sender, "func2", 2);
        return 111;
    }

    mapping(address => uint256) public balanceOf;
    function mint() external payable {
        balanceOf[msg.sender] += msg.value;
    }
}

contract Test {
  TestMultiDelegatecall c = new TestMultiDelegatecall();
  bool once = false;

  function testMultiDelegatecall(bytes[] memory data)
        external
        payable
    { 
      require(!once);
      once = true;
      c.multicall{value: msg.value}(data);
      assert(c.balanceOf(address(this)) <= msg.value);
    }
}

With this PR, echidna will try to use possible callbacks encoded in the bytes[] argument from testMultiDelegatecall. It will immediately found a way to break the invariant:

testMultiDelegatecall(bytes[]): failed!💥  
  Call sequence:
    Test.testMultiDelegatecall(["\DC2I\197\139", "\DC2I\197\139"]) Value: 0x1

Traces: 
call TestMultiDelegatecall::multicall(bytes[])([0x1249c58b, 0x1249c58b]) (/Users/g/Code/echidna/multicall.sol:50)
 ├╴call TestMultiDelegatecall::mint()() (/Users/g/Code/echidna/multicall.sol:13)
 │  └╴← 0x
 ├╴call TestMultiDelegatecall::mint()() (/Users/g/Code/echidna/multicall.sol:13)
 │  └╴← 0x
 └╴← ([0x, 0x])
call TestMultiDelegatecall::balanceOf(address)(Test) (/Users/g/Code/echidna/multicall.sol:51)
 └╴← (2)

@gustavo-grieco gustavo-grieco changed the title [RFC] Support for specifying calldata/callback using kaitai structures Support for encoding valid calls for callbacks Sep 13, 2025
@gustavo-grieco gustavo-grieco marked this pull request as ready for review September 13, 2025 17:39
@elopez elopez added this to the Echidna 2.3.0 milestone Sep 15, 2025
@elopez elopez merged commit 80ceeda into crytic:master Sep 26, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants