freecoding.school100% FREE · NO SIGNUP
The EVM CoreISSUE #27 of 48

function selectors · 4-byte clashing

SoliaVSThe Reentrancy Reaper
Solia saysA function selector is the first 4 bytes of keccak256 of its canonical signature; with only 2³² possible selectors, real-world collisions exist and the compiler has to detect them.

When you call transfer(address,uint256), the calldata starts with a 4-byte selector: the first 4 bytes of keccak256("transfer(address,uint256)"). The contract jumps to the matching function based on those 4 bytes. With only 2³² possible selectors and millions of function names in the wild, collisions do exist — the compiler refuses to deploy a contract with two clashing selectors.

Knowing how selectors are computed lets you debug malformed calldata, write low-level dispatchers, and read raw transactions. The demo computes selectors for four standard ERC-20 functions using a toy hash; the same rule holds under real keccak256.

Power-ups you unlock

The Reentrancy Reaper attacks — common mistakes

Boss battleCompute the (toy-hash) selectors for four ERC-20 functions and verify they do not collide.

Example code

<!doctype html><html><head><meta charset="utf-8"></head>
<body style="background:#06040d;color:#e6e0ff;font-family:monospace;padding:20px"><pre id="o"></pre>
<script>
// real selector = keccak256(signature)[0:4]; toy hash here for runnability.  determinism property is identical.
const H = (s) => { let h=2166136261>>>0; for(const c of s){ h^=c.charCodeAt(0); h=Math.imul(h,16777619); } return '0x' + (h>>>0).toString(16).padStart(8,'0'); };
const sigs = [
  'transfer(address,uint256)',
  'transferFrom(address,address,uint256)',
  'approve(address,uint256)',
  'balanceOf(address)'
];
const rows = sigs.map(s => '  ' + H(s) + '   ' + s);
const selectors = sigs.map(H);
const collisions = selectors.length - new Set(selectors).size;
document.getElementById('o').textContent = [
  'function selector = first 4 bytes of keccak256(signature)',
  '',
  ...rows,
  '',
  'collisions in this set: ' + collisions + '   (compiler refuses to deploy clashing selectors)',
  '',
  'famous real-world clash: burn(uint256) vs burn(int256) → different selectors despite same intent'
].join('\n');
</script></body></html>
▶ Open the interactive comic issue
‹ Abi Encoding · Encode · EncodePacked · DecodeCustom Errors · Revert Data ›