mevlog-rs - explore EVM chains from your terminal

Rust-based CLI tool for querying Ethereum (or any EVM-compatible chain) transactions, with flexible filtering and EVM tracing capabilities.
When working on an MEV bot, I could not find a simple way to search for specific transactions. I wrote one-off query scripts, and wanted to generalize them in an easy to reuse tool. So I started building mevlog to work as an "SQL for blockchain".
mevlog allows you to find and analyze transaction details via a simple CLI interface. It currently offers the following features:
- regexp search by emitted event names
- search by ENS domain names
- filter txs based on their position in a block
- search by root and internal method calls
- track smart contract storage changes
- detect validator bribes
- filter by the amount of a specific ERC20 token sent
- filter txs by value and real (including bribe) gas prices and cost
- colored human-readable, and JSON output formats
- ChainList integration to automatically select RPC endpoints
- TUI dashboard - browse and analyze EVM chains through a terminal-native visual interface (powered by ratatui.rs)
It works on public RPCs thanks to leveraging EVM tracing via Revm.
You can check out this article for technical details on how this project is implemented.
There's also a beta web version available.
Getting started
⚠️ Note
This README reflects the latest development on themainbranch. For documentation matching the current release, see crates.io — it stays in sync with the published crate.
Mevlog uses cryo CLI for fetching data. Please install it first by running:
and then:
or install from the crates.io:
TUI mode
For a more interactive experience, you can use the TUI (Terminal User Interface) mode:
Visit mevlog.rs/tui for more information.
Connection options
You can connect to chains using either a direct RPC URL or by specifying a chain ID:
Using RPC URL:
Using Chain ID:
When using --chain-id, mevlog automatically fetches available RPC URLs from ChainList, benchmarks them, and selects the fastest responding endpoint. Please remember that --trace rpc will likely not work with public RPC endpoints. And --trace revm could be throttled.
To discover available chain IDs, use the chains command:
On initial run mevlog downloads ~80mb openchain.xyz signatures, and ChainList data database to ~/.mevlog. Signatures data allows displaying human readable info instead of hex blobs.
To avoid throttling on public endpoints watch mode displays only the top 5 transactions from each block.
You can change it using the --position argument:
## display the top 20 txs from each new block
Filtering options
Here's a complete list of currently supported filters:
Options:
--limit <LIMIT>
Limit the number of transactions returned
--sort <SORT>
Sort transactions by field (gas-price, gas-used, tx-cost, full-tx-cost, erc20Transfer|<token_address>)
--sort-dir <SORT_DIR>
Sort direction (desc, asc) [default: desc]
-f, --from <FROM>
Filter by tx source address or ENS name
--to <TO>
Filter by tx target address or ENS name, or CREATE transactions
-t, --touching <TOUCHING>
Filter by contracts with storage changed by the transaction
--rpc-url <RPC_URL>
The URL of the HTTP provider
--chain-id <CHAIN_ID>
Chain ID to automatically select best RPC URL
--event <EVENT>
Include txs by event names matching the provided regex or signature and optionally an address
--not-event <NOT_EVENT>
Exclude txs by event names matching the provided regex or signature and optionally an address
--method <METHOD>
Include txs with root method names matching the provided regex, signature or signature hash
--calls <CALLS>
Include txs by subcalls method names matching the provided regex, signature or signature hash
--show-calls
Show detailed tx calls info
--ops
Display EVM opcodes executed by the transaction (requires --trace)
--tx-cost <TX_COST>
Filter by tx cost (e.g., 'le0.001ether', 'ge0.01ether')
--real-tx-cost <REAL_TX_COST>
Filter by real (including coinbase bribe) tx cost (e.g., 'le0.001ether', 'ge0.01ether')
--gas-price <GAS_PRICE>
Filter by effective gas price (e.g., 'ge2gwei', 'le1gwei')
--real-gas-price <REAL_GAS_PRICE>
Filter by real (including coinbase bribe) effective gas price (e.g., 'ge3gwei', 'le2gwei')
--value <VALUE>
Filter by transaction value (e.g., 'ge1ether', 'le0.1ether')
--erc20-transfer <TRANSFER>
Filter by Transfer events with specific address and optionally amount (e.g., '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' or '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48|ge1000gwei')
--erc20-transfer-amount
Display transfer amounts in ERC20 Transfer event logs
--ens
Enable ENS name resolution for addresses (increases RPC calls)
--erc20-symbols
Enable ERC20 token symbol resolution (increases RPC calls)
--failed
Show only txs which failed to execute
--format <FORMAT>
Output format ('text', 'json', 'json-pretty', 'json-stream', 'json-pretty-stream')
--batch-size <SIZE>
Batch size for data fetching (default: 100)
Both search and watch support the same filtering options.
A few examples of currently supported queries:
- find
jaredfromsubway.ethtransactions from the last 20 blocks that landed in positions 0-5:
- unknown method signature contract call in a top position (likely an MEV bot):
- query the last 50 blocks for transaction that transferred PEPE token:
- blocks between 22034300 and 22034320, position 0 transaction that did not emit any
Swapevents:
- blocks range for events containing
rebaseandTransferkeywords:
- query by transactions that created a new smart contract:
- find transactions that transferred more than 1 ETH:
- find transactions that transferred over 100k USDC
- find transactions that emitted any Transfer events for USDC and display amounts:
- find the top 10 transactions from the last 20 blocks sorted by gas price:
- find the 5 most expensive transactions by total cost from recent blocks:
- find the 10 cheapest transactions by gas price (ascending order):
- find transaction that transferred the most USDC in the last 50 blocks:
Event filters
The --event and --not-event options allow filtering transactions based on emitted events. The filter criteria can be:
- a contract address matching on any emitted events
0x6982508145454ce325ddbe47a25d4ec3d2311933 - a full event signature
Transfer(address,uint256) - a regular expression pattern
/(?i)(rebase).+/ - a combination of an event signature and a contract address
Transfer(address,uint256)|0x6982508145454ce325ddbe47a25d4ec3d2311933
You can supply mutiple --event and --not-event flags for precise control over which transactions are included or excluded.
Transfer filters
The --erc20-transfer option allows filtering transactions that emitted ERC20 Transfer events. The filter criteria can be:
- a contract address matching any transfer amount:
0xa0b86a33e6ba3bc6c2c5ed1b4b29b5473fd5d2de - a contract address with amount filtering:
0xa0b86a33e6ba3bc6c2c5ed1b4b29b5473fd5d2de|ge1000(transfers >= 1000 tokens) - amount operators:
ge(greater or equal),le(less or equal) - amount units: raw numbers,
ether,gwei, etc.
You can supply multiple --erc20-transfer flags to match transfers from different tokens or with different amount criteria.
By default, transfer amounts are not displayed in the logs. Use the --erc20-transfer-amount flag to show transfer amounts alongside the Transfer events.
ENS and ERC20 token symbols resolution
You can enable ENS name resolution and ERC20 token symbol lookup for transfers and Uniswap swaps using the --ens and --erc20-symbols flags:
# Enable ENS name display for addresses
# Enable ERC20 token symbols display
# Enable both ENS and token symbols
Performance considerations:
⚠️ Warning: Enabling these flags increases RPC calls and may cause throttling on public endpoints.
Recommended usage pattern:
- Initial cache population: Enable flags for a small range of recent blocks to cache popular ENS names and ERC20 symbols:
# Cache popular symbols and ENS names from recent blocks
- Regular usage: Disable flags to use only cached values, reducing RPC calls:
# Use cached ENS/symbol data only (no additional RPC calls)
The tool maintains persistent caches in ~/.mevlog/.ens-cache and ~/.mevlog/.symbols-cache. Once populated, cached values are used automatically even when the flags are disabled.
EVM tracing filters
All the above queries use only standard block and logs input. By enabling --trace [rpc|revm] flag you can query by more conditions:
- query last 5 blocks for a top transaction that paid over 0.02 ETH total (including coinbase bribe) transaction cost:
- find txs that changed storage slots of the Balancer vault contract:
mevlog search -b 10:latest --touching 0xba12222222228d8ba445958a75a0704d566bf2c8 --trace rpc
You can also filter by real (including bribe) gas price:
It's possible to search txs by their sub method calls:
Output formats
Mevlog supports different output formats via the --format option:
text(default): Human-readable colored output, displays results block by block as they are processedjson: Compact, oneline JSON output, displays all results at once after processing all blocksjson-pretty: Pretty-printed JSON output, displays all results at once after processing all blocksjson-stream: Compact, oneline JSON output, displays results block by block as they are processedjson-pretty-stream: Pretty-printed JSON output, displays results block by block as they are processed
Streaming vs Batch behavior:
- Streaming formats (
text,json-stream,json-pretty-stream): Display results block by block as they are processed, useful for real-time monitoring and large block ranges - Batch formats (
json,json-pretty): Collect all results in memory and display them at once after processing all blocks, useful for piping to other tools or when you need all results in a single JSON array
Examples:
# Default human-readable output (streaming)
# Compact JSON, all results at once
# Pretty JSON, streaming block by block
EVM tracing modes
--trace rpc
This mode uses the debug_traceTransaction method. It's usually not available on public endpoints.
--trace revm
This mode leverages Revm tracing by downloading all the relevant storage slots and running simulations locally. If you want to trace a transaction at position 10, Revm must first simulate all the previous transactions from this block. It can be slow and cause throttling from public endpoints.
Subsequent revm simulations for the same block and transaction range use cached data and should be significantly faster.
Analyzing a single transaction data
This command displays info for a single target transaction. By adding --before --after arguments you can include surrounding transactions:
You can reverse the display order by adding the --reverse flag.
EVM Opcodes tracing
You can trace the EVM opcodes executed by a transaction using the --ops flag. This requires enabling tracing with either --trace rpc or --trace revm:
# Trace opcodes using Revm (works on public RPCs)
# Trace opcodes using RPC (requires debug API access)
Plain text output:
PC OP COST GAS_LEFT
0 PUSH1 3 545253
2 PUSH1 3 545250
4 MSTORE 3 545247
5 CALLVALUE 2 545244
...
JSON output:
The opcode trace shows:
- PC: Program counter (position in bytecode)
- OP: Opcode name (e.g., PUSH1, MSTORE, CALL)
- COST: Gas cost of this opcode execution
- GAS_LEFT: Remaining gas after this opcode executes
Listing available chains
Sample text output:
Available chains (7 total):
# Chain ID Name
------------------------------------------------------------
1 1 Ethereum Mainnet
2 61 Ethereum Classic
3 1617 Ethereum Inscription Mainnet
4 52226 Cytonic Ethereum Testnet
5 513100 EthereumFair
6 560048 Ethereum Hoodi
7 11155111 Ethereum Sepolia
Sample JSON output:
Options:
--filter <TEXT>: Filter chains by name (case-insensitive substring match)--chain-id <ID>: Filter by specific chain IDs (can be used multiple times)--limit <NUMBER>: Limit the number of chains returned--format <FORMAT>: Output format ('text', 'json', 'json-pretty')
Getting chain information
Sample output:
Chain Information
================
Chain ID: 1
Name: Ethereum Mainnet
Currency: ETH
Explorer URL: https://etherscan.io
RPC Timeout: 1s
This command displays detailed information about a specific chain, including current token price and RPC endpoint benchmarks. You can also get JSON output:
By default, the command filters RPC endpoints responding under 1000ms (1 second). You can adjust this timeout for networks with slower connections:
You can limit the number of RPC URLs returned (default is 5):
If you only need basic chain information without RPC URL benchmarking (which is faster), use the --skip-urls flag:
This will display only the core chain information:
Chain Information
================
Chain ID: 1
Name: Ethereum Mainnet
Currency: ETH
Explorer URL: https://etherscan.io
Checking debug tracing support
Before using --trace rpc mode, you can check if an RPC endpoint supports debug tracing:
# Output: false
# Output: true
This command tests the debug_traceTransaction RPC method by fetching a recent transaction and attempting to trace it. Returns true if debug tracing is supported, false otherwise.
Supported EVM chains
The project currently supports over 2k EVM chains by reading the metadata from ChainList. But only a few chains display $USD txs prices from integrated ChainLink oracles. I'm planning to work on improving the coverage.
If you use it with an unsupported chain, explorer URL and currency symbol is not displayed.
Development
tokio-console feature adds support for tokio-console:
RUSTFLAGS="--cfg tokio_unstable"
seed-db feature enables action to populate signatures and chains metadata SQLite database:
Benchmark
Benchmark using hotpath lib:
Time:
QUIET=1 cargo run --features 'hotpath' --release --bin mevlog search -b 23263469:23263489 --chain-id 1 --skip-verify-chain-id --native-token-price 5000 --rpc-url https://eth.merkle.io
Run once to cache all relevant data. Subsequent invocations won't trigger any RPC calls, so you can profile performance without network overhead. Annotate more methods with [cfg_attr(feature = "hotpath", hotpath::measure)] if needed.

Allocations:
QUIET=1 cargo run --features 'hotpath,hotpath-alloc' --release --bin mevlog search -b 23263469:23263489 --chain-id 1 --skip-verify-chain-id --native-token-price 5000 --rpc-url https://eth.merkle.io
Live profiling:
QUIET=1
In another terminal: