How Solidity function selectors work
A technical guide about how function selectors work in Solidity
Table of Contents for How Solidity function selectors work
How selectors work
When you write Solidity code, you will write contracts with functions
contract Example {
function funcA() public {
}
function funcB(uint256 someNum) public {
}
}
When this gets compiled, the original names (funcA
, funcB
in the above example) do not get stored.
Instead each function is changed to a selector. Instead the first four bytes of a hash of the function (and arguments) are stored, and these are used when the functions are called.
In psuedocode, it looks like this:
var $funcANameAndArgs = 'funcA()';
var $funcBNameAndArgs = 'funcB(uint256)';
var $funcAHash = keccack256(funcANameAndArgs);
var $funcBHash = keccack256(funcBNameAndArgs);
var $selectorFuncA = firstFourBytes($funcAHash);
var $selectorFuncB = firstFourBytes($funcBHash);
It hashes the function name, and the types of any arguements (but not the names), and takes the first 4 bytes (8 characters in hex).
Note: If you define a function as function something(uint aNumber)
, then you have to hash something(uint256)
(note the full uint256
is used, not just uint
).
How to call another contract’s function, using a selector
You can use abi.encodeWithSignature
addr.call(abi.encodeWithSignature("transfer(address,uint256)", yourAddressVariable, yourAmountVariable))
Selectors for library functions
If you have a library, with a function that has a struct then the selector is generated in a different way.
Normally if you have a function that has a param that is a struct, the selector will be the first 4 bytes of the keccak256 hash of each variable type within a struct.
e.g.
struct CoolStruct {
uint256 coolValue;
uint256 otherCoolValue;
}
function getHash(CoolStruct memory self) public pure returns (bytes32 hash) {
hash = keccak256(abi.encodePacked(
self.coolValue
));
}
You’d expect the selector to be keccak256("getHash((uint256,uint256))")
, which is 0x31183ed7
but in a library it is the first four bytes of keccak256("getHash(LibStructTest.CoolStruct)")
(0x54d08d7a
)
For more info about this (and also the source that I found / copied examples from) is https://github.com/ethereum/solidity/issues/6420
Spotted a typo or have a suggestion to make this crypto dev article better? Please let me know!
Previous post
📙 Solidity Auditing online quiz
Learn how to audit smart contracts by looking at some example code and trying to find the bugs
⛽ Solidity Gas Optimizations Guide
How to optimize and reduce gas usage in your smart contracts in Solidity
🧪 Guide to testing with Foundry
Guide to adding testing for your Solidity contracts, using the Foundry and Forge tools
📌 Guide to UTXO
UTXO and the UTXO set (used by blockchains such as Bitcoin) explained
📐 Solidity Assembly Guide
Introduction guide to using assembly in your Solidity smart contracts
📦 Ethereum EOF format explained
Information explaining what the upcoming Ethereum EOF format is all about