6

I'm trying to understand what .selector means when appended to logic wrapped up inside of functions definitions. I've tried to read the section in soliditydocs, but it doesn't seem to answer my question?

1 Answer 1

13

From the docs:

.selector returns the ABI function selector.

The first four bytes of the call data for a function call specifies the function to be called. It is the first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3) hash of the signature of the function. The signature is defined as the canonical expression of the basic prototype without data location specifier, i.e. the function name with the parenthesised list of parameter types. Parameter types are split by a single comma - no spaces are used.

So, you can identify a function by hashing the name with the parameter types.

Example:

pragma solidity ^0.5.0;

contract Contract {

    MyContract contract1 = new MyContract();

    function getSelector() public view returns (bytes4, bytes4) {
        return (contract1.function1.selector, contract1.getBalance.selector);
    }

    function callGetValue(uint _x) public view returns (uint) {

        bytes4 selector = contract1.getValue.selector;

        bytes memory data = abi.encodeWithSelector(selector, _x);
        (bool success, bytes memory returnedData) = address(contract1).staticcall(data);
        require(success);

        return abi.decode(returnedData, (uint256));
    }
}

contract MyContract {

    function function1() public {}

    function getBalance(address _address) public view returns (uint256){}

    function getValue (uint _value) public pure returns (uint) {
        return _value;
    }

}

Output of getSelector():

decoded output  
{
    "0": "bytes4: 0x29a71964",
    "1": "bytes4: 0xf8b2cb4f"
}

Check with keccak256 function:

truffle(development)> web3.utils.keccak256("function1()")
'0x29a7196481fcfcc8167dc71995324289246256364d7384313ac6b8432377ea3a'

truffle(development)> web3.utils.keccak256("getBalance(address)")
'0xf8b2cb4f3943230388faeee074f1503714bff212640051caba01411868d14ae3'

But let's see the first four bytes:

0x29a71964
0xf8b2cb4f

You can verify that you can obtain the function selector from .selector directly in Solidity or using the keccak256 function.

Calling a function using .selector (See: ABI Encoding and Decoding Functions):

In the contract above, the function callGetValue(uint _x) call the function getValue(uint _value) using the selector:

If you pass a value (for example: 3), you will get:

decoded input
{
    "uint256 _x": "3"
}

decoded output
{
    "0": "uint256: 3"
}
5
  • 4
    Note that the .selector will not work for functions declared as internal and private, so only available for public and external functions.
    – CJ42
    Oct 27, 2019 at 14:47
  • Can't find that in the docs... Did you find out by trying or looking at the source? Sep 20, 2020 at 12:17
  • @MarkusKottländer Check this: solidity.readthedocs.io/en/latest/…
    – alberto
    Sep 20, 2020 at 12:25
  • I did. I just quickly searched for "internal" or "public" etc. Can't find anything but I'll read carefully. Sep 20, 2020 at 12:28
  • 1
    @MarkusKottländer In case you haven't found: solidity.readthedocs.io/en/latest/contracts.html#libraries (third paragraph) is related to what you want (calls to internal function) says that JUMP is used instead of DELEGATECALL. selector is not used.
    – alberto
    Oct 3, 2020 at 9:00

Your Answer

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

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