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
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"
}
-
4Note that the
.selector
will not work for functions declared asinternal
andprivate
, so only available forpublic
andexternal
functions.– CJ42Oct 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
-
-
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 ofDELEGATECALL
.selector
is not used.– albertoOct 3, 2020 at 9:00