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

events · indexed topics · log decoding

SoliaVSThe Reentrancy Reaper
Solia saysEvents compile to LOG opcodes: up to four topics (first is the event signature hash, others are indexed args) plus non-indexed data — searchable on-chain, never readable by contracts.

Solidity events are syntactic sugar for the EVM LOG opcodes. Each event becomes a log entry with up to four 32-byte topics and a variable-length data blob. Topic 0 is always keccak256(eventSignature). Up to three more topics carry the indexed arguments. Everything else goes ABI-encoded into the data field.

Indexed topics are searchable: an indexer can ask "all Transfer events where from = 0xAlice" by topic. Non-indexed data is cheaper but not searchable. Critically, contracts CANNOT read their own events back — events are for off-chain observers only. The demo lays out a Transfer event into its topic and data structure.

Power-ups you unlock

The Reentrancy Reaper attacks — common mistakes

Boss battleLay out the topics and data for a Transfer(from, to, value) event with from and to indexed.

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>
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(64,'0'); };
const sig = 'Transfer(address,address,uint256)';
const from = '0xaaa...alice';
const to   = '0xbbb...bob';
const value = 100;
const evt = {
  topic0: H(sig),
  topic1: '0x' + from.slice(2).padStart(64, '0'),
  topic2: '0x' + to.slice(2).padStart(64, '0'),
  data:   '0x' + value.toString(16).padStart(64, '0')
};
document.getElementById('o').textContent = [
  'event Transfer(address indexed from, address indexed to, uint256 value)',
  '',
  '  topic0 (sig hash): ' + evt.topic0,
  '  topic1 (from):     ' + evt.topic1,
  '  topic2 (to):       ' + evt.topic2,
  '  data (value):      ' + evt.data,
  '',
  'indexer query "Transfer where from = 0xAlice" → filter by topic0 + topic1',
  'contracts CANNOT read their own logs — events are for off-chain observers only'
].join('\n');
</script></body></html>
▶ Open the interactive comic issue
‹ Fallback · Receive · Low-Level CallsStorage Layout · Slots · Mappings · Arrays ›