Events and logging

Events are how your contract communicates with the outside world — and they're cheaper than storage.

What are events?

Events are a way for contracts to emit structured logs to the Ethereum transaction receipt. They don't live in contract storage — they're written to the transaction log, which is much cheaper. Frontends and indexers listen for events to update their state.

solidity
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);

The indexed keyword marks a parameter as searchable (filterable). You can have up to 3 indexed parameters per event. Non-indexed parameters are encoded in the log data and are cheaper but not filterable.

Emitting events

solidity
function transfer(address to, uint256 amount) public returns (bool) {
    require(balances[msg.sender] >= amount, 'Insufficient balance');
    balances[msg.sender] -= amount;
    balances[to] += amount;
    emit Transfer(msg.sender, to, amount);
    return true;
}

Listening to events on the frontend

With ethers.js, you can listen for events in real-time or query historical events.

javascript
// Listen for new Transfer events
contract.on('Transfer', (from, to, value) => {
  console.log('Transfer: ' + from + ' -> ' + to + ': ' + ethers.formatEther(value) + ' tokens');
});

// Query historical Transfer events
const filter = contract.filters.Transfer(null, userAddress);
const events = await contract.queryFilter(filter, fromBlock, toBlock);

Indexed vs. non-indexed

solidity
// Good: addresses are indexed for filtering, amount is not (just data)
event Swap(
    address indexed sender,
    address indexed tokenIn,
    address indexed tokenOut,
    uint256 amountIn,     // not indexed — just data
    uint256 amountOut     // not indexed — just data
);

Index fields you'll want to filter by — typically addresses and IDs. Large data values like amounts are better left non-indexed.

Events as an audit trail

In production DeFi applications, events form the authoritative audit trail. Every significant state change should emit an event. This is how block explorers, analytics dashboards, and indexers (like The Graph) reconstruct contract history. A contract with no events is effectively a black box to everyone outside the chain.

←   Structs and enumsModifiers   →