contract::rwread · write workbench →

function selectors explained

a function selector is how the EVM knows which function a transaction is calling: the first 4 bytes of the keccak-256 hash of the function's canonical signature.

how a selector is derived

take the function's canonical signature — its name followed by parameter types in parentheses — hash it with keccak-256, and keep the first 4 bytes. for transfer(address,uint256), that hash begins a9059cbb…, so the selector is 0xa9059cbb. every call to that function starts its calldata with those four bytes; the contract's dispatcher compares them to decide which code to run.

why signatures must be canonical

the hash is taken over an exact string, so the signature must be in canonical form: parameter types only, no parameter names, and no spaces. transfer(address,uint256) and transfer(address to, uint256 amount) are different strings and would hash to different selectors — only the first is correct. types use their canonical spelling too (uint256, not uint), and tuples are written as parenthesized type lists, e.g. swap((address,uint256),bool).

errors and events

custom errors use the same 4-byte selector scheme as functions — that's how revert data is decoded back into a named error. events are different: their topic is the full 32-byte keccak-256 hash of the signature, not just the first four bytes.

collisions

four bytes is only 2³² possibilities, so different signatures can collide on the same selector. it's uncommon but real, and occasionally abused. this is why decoding is done against a specific ABI: the selector narrows the candidates, and the argument types confirm the match.

try it

compute a selector from any signature with the function selector calculator, or decode a full transaction with the calldata decoder.