1

When the function has parameters, Solidity generates its signature by adding the parameter types after the function name, in between brackets, and taking a keccak256 hash of the resulting string. As an example:

sendMessage(string,address)

The signature of this function is 0xc48d6d5e.

However, what if the "string" and "address" parameters do not exist? Would Solidity take the keccak256 hash of sendMessage, sendMessage(), or something else?

1

1 Answer 1

1

A simple test to show that the answer is "sendMessage()".

Solidity Contract:

pragma solidity 0.6.12;

contract MyContract {
    uint256 private constant SUCCESS = 42;
    uint256 private constant FAILURE = 84;

    function sendMessage() external pure returns (uint256) {
        return SUCCESS;
    }

    function test(bytes4 funcSelector) external view returns (uint256) {
        bytes memory data = abi.encodeWithSelector(funcSelector);
        (bool success, bytes memory returnData) = address(this).staticcall(data);

        if (success && returnData.length == 32)
            return abi.decode(returnData, (uint256));

        return FAILURE;
    }
}

Truffle 5.x Script:

contract("MyContract", () => {
    it("test", async () => {
        const myContract = await artifacts.require("MyContract").new();
        const success = await myContract.test(web3.utils.keccak256("sendMessage()"));
        const failure = await myContract.test(web3.utils.keccak256("sendMessage"));
        console.log(success.toString()); // prints 42
        console.log(failure.toString()); // prints 84
    });
});

Here is a simpler way to do it, without even interacting with a contract:

const Web3 = require("web3");

const web3 = new Web3();

const abi = [{
    "inputs":[],
    "name":"sendMessage",
    "outputs":[],
    "stateMutability":"pure",
    "type":"function"
}];

const contract = new web3.eth.Contract(abi);

console.log(Web3.utils.keccak256("sendMessage").slice(0, 10));
console.log(Web3.utils.keccak256("sendMessage()").slice(0, 10));

for (const method of contract._jsonInterface)
    if (method.name == "sendMessage")
        console.log(method.signature);

The printout is:

0x736c24a9
0xe5aed28a
0xe5aed28a
3
  • Does this also work when "sendMessage" is marked as payable? Dec 2, 2020 at 21:02
  • @PaulRazvanBerg: No reason why it shouldn't. The function selector is computed based on only the function name along with the input parameter types. Any other part in the function signature (public/private/internal/external, pure/view/payable and even the return-value type) has no impact on that. Dec 2, 2020 at 21:05
  • 1
    @PaulRazvanBerg: See my update on how to do it without even interacting with a contract. Dec 3, 2020 at 4:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.