foundry icon indicating copy to clipboard operation
foundry copied to clipboard

feat(`cheatcodes`): add `vm.getSelectors(name)` cheatcode to get a list of all selectors

Open dadadave80 opened this issue 3 months ago • 5 comments

Component

Other (please describe)

Describe the feature you would like

Current Workflow:

Currently, to retrieve function selectors from a contract name, I use the following helper function:

function getSelectors(string memory _contractName) internal returns (bytes4[] memory selectors_) {
    string[] memory cmd = new string[](5);
    cmd[0] = "forge";
    cmd[1] = "inspect";
    cmd[2] = _contractName;
    cmd[3] = "methodIdentifiers";
    cmd[4] = "--json";

    bytes memory res = vm.ffi(cmd);
    string memory output = string(res);

    string[] memory keys = vm.parseJsonKeys(output, "");
    uint256 keysLength = keys.length;

    // Initialize the selectors array with the selectorCount
    selectors_ = new bytes4[](keysLength);

    for (uint256 i; i < keysLength; ++i) {
        selectors_[i] = bytes4(bytes32(keccak256(bytes(keys[i]))));
    }
}

The issue:

  • This approach requires enabling ffi, which many developers may not be comfortable with for security reasons.
  • It introduces external command execution, which could slow down tests and create unnecessary complexity.
  • ffi usage reduces portability and reproducibility in some environments.

Proposed Solution

  • Add a native utility function to Vm.sol (or another appropriate cheatcode interface) for retrieving selectors directly from compiled contract data:
function getSelectors(string memory contractName) external returns (bytes4[] memory);

This function would:

  • Accept the contract name (or optionally, its bytecode).
  • Return an array of all function selectors derived from the contract’s ABI.
  • Eliminate the need for ffi and forge inspect calls during tests.

Additional Notes

  • I also noticed that no current Vm.sol function accepts string in memory, which may require adjustments or documentation.
  • This feature would be extremely useful for developers working with Diamond Standard (EIP-2535) or similar patterns where function selector management is critical.

Additional context

No response

dadadave80 avatar Aug 29 '25 21:08 dadadave80

Hi @dadadave80

Would it not be possible to use vm.readFile to read the artifact and then decode that with vm.parseJsonKeys?

forge inspect behind the scenes is simply just a way to call the methodIdentifiers field of the artifact JSON:

in out/Counter.sol/Counter.json:

  "methodIdentifiers": {
    "increment()": "d09de08a",
    "number()": "8381f58a",
    "setNumber(uint256)": "3fb5c1cb"
  },

zerosnacks avatar Oct 07 '25 09:10 zerosnacks

Thank you so much @zerosnacks. It works!

function getSelectors(string memory _contractName) internal view returns (bytes4[] memory selectors_) {
        string memory path = string.concat("out/", _contractName, ".sol/", _contractName, ".json");
        string memory artifact = vm.readFile(path);

        string[] memory funcSigs = vm.parseJsonKeys(artifact, "$.methodIdentifiers");
        uint256 funcSigsLength = funcSigs.length;

        selectors_ = new bytes4[](funcSigsLength);

        for (uint256 i; i < funcSigsLength; ++i) {
            selectors_[i] = bytes4(keccak256(bytes(funcSigs[i])));
        }
    }

dadadave80 avatar Oct 07 '25 12:10 dadadave80

Hi @zerosnacks, there is a "small issue":

Image

It dumps the contract's artifact (twice) when trying to debug tests.

dadadave80 avatar Oct 12 '25 10:10 dadadave80

This is expected, one is a debug log for the file content and the other for parsing the keys. If you require more control over what logs are displayed use console.log or run in --json mode and select with jq.

zerosnacks avatar Oct 13 '25 07:10 zerosnacks

Thank you, I realize my current issue wasn’t clearly expressed.

The main problem is that when I enable test traces, the terminal gets cluttered with all the artifact logs from the contracts I’m extracting methodIdentifiers from.

It would be great if this cheatcode (vm.getSelectors) could handle that internally and simply return the list of function signatures, without printing the artifacts to the console.

Also, I’d be happy if you could possibly put me through how to add this feature to Foundry — I’d love to contribute to it.

dadadave80 avatar Oct 13 '25 09:10 dadadave80