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
Events compile to LOG0-LOG4 opcodes
Topic 0 = keccak256(event signature)
Up to 3 indexed args become topics 1-3
Non-indexed args go ABI-encoded into the data blob
Contracts cannot read their own events — off-chain only
The Reentrancy Reaper attacks — common mistakes
Trying to read a past event from a contract function
Indexing more than 3 args (compiler error)
Indexing a large dynamic type (only the hash gets stored)
Forgetting events are essential for indexers, frontends, and analytics
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>