# Solidity Events Analysis

## Theory

Events in Solidity provide a structured mechanism for logging contract state changes and actions. Unlike storage variables that persist on-chain and cost gas to read, events are stored in transaction logs, a cheaper, append-only data structure designed specifically for external consumption and monitoring.

#### Event Structure and Anatomy

When a Solidity contract emits an event, it generates a log entry containing several key components. Each log entry includes the contract address that emitted it, the event data itself, and up to four indexed topics that enable efficient filtering and searching.

```solidity
event Transfer(address indexed from, address indexed to, uint256 value);
```

In this standard ERC-20 transfer event, `from` and `to` are marked as `indexed`, which means they become searchable topics. The `value` parameter remains in the data portion of the log since it's not indexed.

#### Topic System and Indexing

The topic system provides the backbone for efficient event querying across the blockchain. Topic\[0] always contains the event signature hash—computed as `keccak256("Transfer(address,address,uint256)")`—which uniquely identifies the event type. Topics\[1] through Topics\[3] contain the indexed parameters in the order they appear in the event declaration.

For the Transfer event above, the structure would be:

* **Topic\[0]**: `keccak256("Transfer(address,address,uint256)")`
* **Topic\[1]**: The `from` address (zero-padded to 32 bytes)
* **Topic\[2]**: The `to` address (zero-padded to 32 bytes)
* **Data**: ABI-encoded `value` parameter

This indexing architecture allows blockchain nodes to efficiently filter millions of transactions without scanning every log entry. When investigating on-chain activity, understanding this structure enables precise queries that retrieve only relevant events from massive datasets.

#### Why Events Matter for Analysis

Events serve as the primary audit trail for smart contract interactions. While contract storage tells you the current state, events reveal the complete history of how that state evolved. Security researchers use events to trace fund flows in DeFi protocols, identify exploit patterns, reconstruct attack timelines, and verify compliance with expected contract behavior.

Unlike calling view functions that return current state, event logs preserve historical data permanently. This immutability makes them invaluable for forensic analysis, regulatory compliance, and post-mortem investigations of security incidents. Even if a contract's storage is manipulated or destroyed, the event logs remain as an unchangeable record of what transpired.

#### Gas Considerations and Design Patterns

Emitting events consumes significantly less gas than storing equivalent data in contract storage. A storage write (SSTORE) costs 20,000 gas for a new slot or 5,000 gas for updates, while logging data through events costs approximately 375 gas plus 8 gas per byte of data. This makes events the optimal choice for recording information needed off-chain but not required for on-chain logic.

Smart contract developers often emit detailed events specifically to facilitate external monitoring and analysis, even when that data isn't needed by the contract itself. Critical actions like ownership transfers, large value movements, access control changes, and privilege escalations should always emit events to maintain transparency and enable security monitoring.

> **Note**: Once you've identified relevant transactions through event analysis, the next step is often to inspect and simulate those transactions to understand their execution flow and state changes. See the [ransactions Analysis](/smart-contracts-pentesting/on-chain-analysis/transactions-analysis.md) guide for detailed instructions on transaction analysis techniques.

## Practice

{% tabs %}
{% tab title="cast" %}
[Cast](https://getfoundry.sh/cast/overview/) provides a powerful command-line interface for querying blockchain events with precise filtering capabilities. The basic syntax accepts block ranges, contract addresses, event signatures, and topic filters to narrow results.

**Search by event name and contract address:**

This query retrieves all Transfer events from a specific contract across the blockchain history. The event signature must match exactly, including parameter types, for Cast to compute the correct topic hash.

```bash
# Search Transfer event emitted by $CONTRACT_ADDRESS
cast logs --from-block $START_BLOCK_NB 
  --to-block latest \
  --address $CONTRACT_ADDRESS \
  "Transfer(address,address,uint256)" \
  --rpc-url $RPC_URL \
  --json
```

**Search globally by event signature:**

Omitting the `--address` flag searches for the event across all contracts. This approach is useful when investigating widespread patterns or when tracking a specific event type across an entire ecosystem.

```bash
# Search for all Approval event (no emitter filter) 
cast logs \
  --from-block $START_BLOCK_NB \
  --to-block latest \
  "Approval(address,address,uint256)" \
  --rpc-url $RPC_URL \
  --json
```

**Search by raw topic hash:**

Using `raw topic hashes` bypasses signature parsing and directly filters on the keccak256 hash. This is particularly useful when working with non-standard events.

```bash
# Example topic hash for Transfer(address,address,uint256)
cast logs \
  --from-block $START_BLOCK_NB \
  --to-block latest \
  0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef \
  --rpc-url $RPC_URL \
  --json
```

**Filter events by indexed parameters:**

This combines Cast's event retrieval with `jq` post-processing to filter on specific indexed values. Here we're finding all transfers originating from a particular address by checking topic\[1], which contains the `from` parameter in a Transfer event.

```bash
cast logs \
  --from-block 0 \
  --to-block latest \
  --address $CONTRACT_ADDRESS \
  "Transfer(address,address,uint256)" \
  --rpc-url $RPC_URL \
  --json | \
jq '.[] | select(.topics[1] == "0x000000000000000000000000742d35Cc6634C0532925a3b844Bc9e7595f0bEb")'
```

{% endtab %}

{% tab title="mevlog-rs" %}
[mevlog-rs](https://github.com/pawurb/mevlog-rs) event filtering capabilities extend beyond simple pattern matching to support complex multi-condition queries with regular expressions and address-specific filtering.

**Search by event signature**

```bash
# Find all Uniswap V2 Swap events in the last 20 blocks (on ethereum)
mevlog search \
  --blocks 20:latest \
  --event "Swap(address,uint256,uint256,uint256,uint256,address)" \
  --chain-id 1
  
# Find all ERC20 Transfer events in the last 20 blocks, using custom RPC
mevlog search \
  --blocks 20:latest \
  --event "Transfer(address,address,uint256)" \
  --rpc-url $RPC_URL
```

**Filter by event name with contract address:**

```bash
# Find Transfer events specifically from USDC contract
mevlog search \
  --blocks 50:latest \
  --event "Transfer(address,address,uint256)|0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" \
  --chain-id 1
```

{% endtab %}
{% endtabs %}

## Resources

{% embed url="<https://docs.soliditylang.org/en/latest/contracts.html#events>" %}

{% embed url="<https://book.getfoundry.sh/reference/cast/cast-logs>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://red.infiltr8.io/smart-contracts-pentesting/on-chain-analysis/solidity-events-analysis.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
