Function selector is how we tell them smart contract which function to run. It is the first 4 bytes which we get from the functions name and it is used when calling low level functions like call
on a contract and asking it to run a function.
For example function foo(){ }
has selector 0xc2985578
Side Note: The function selector is most probably unique for a contract. It is just 4 bytes and that is not a lot of data and thus there can exist another function which has a totally different name but same selector. But that is neither here nor there, so let's move on.
To build a selector in solidity:
- convert the function name to bytes
- then get its keccak256. this gives us a 1 way hash which has fixed size
- now take the first 4 bytes of that hash.
bytes4(keccak256(bytes("foo()")))
Now, this is good, but most likely the function also takes input params and the values of the input also need to be encoded in to bytes and added to the selector.
So let's say we have a function like foo(uint256)
which we want to call with value of 1
. then we can get the encoded value like this
bytes4 prefix = bytes4(keccak256(bytes("foo(uint256)")))
uint a = 1;
bytes32 suffix = bytes32(a);
bytes memory ans = abi.encodePacked(prefix, suffix);
and this gives us 0x2fbebd380000000000000000000000000000000000000000000000000000000000000001
So this worked, but there is abi.encodeWithSignature
which is an easier way to get the selector with values all encoded in bytes for us to use.
And there is another helper function abi.encodeWithSelector
which takes the selector from us and just encodes and appends the inputs for us.
And finally the same can be done in javascript using ethers.js
. We can build an interface
with just the function whose selector we want and call getSigHash
to get the selector
Ethers also supports encoding input values as well
So thats it. now you know how to encode & build function selectors with & without inputs, from solidity & from the frontend.
Top comments (0)