A minimal Rust-based on-chain indexer that extracts ERC20 Transfer events from an Ethereum RPC endpoint and stores them in a local SQLite database.
src/
├── main.rs # Entry point & orchestration (tokio tasks)
├── config.rs # Environment configuration (.env)
├── indexer.rs # Core indexing logic (fetch + parse)
└── storage.rs # Database operations using Diesel
- Connect to an Ethereum-compatible RPC (
HTTPorWS) - Fetch and decode ERC20
Transferlogs - Persist decoded events into SQLite
- Automatically resume from the last indexed block (state checkpoint)
- Basic error handling & retry logic
- REST API or query layer
- Real-time subscriptions (WebSocket)
- Multi-chain or multi-token indexing
- Reorg or confirmation-depth handling
-
Copy
.env.exampleand configure environment variables:cp .env.example .env
Example:
RPC_URL=http://127.0.0.1:8545 START_BLOCK=0 DB_PATH=indexer.db CHAIN_ID=31337 TOKEN_ADDRESS=0x0000000000000000000000000000000000000000
-
Build and run:
cargo build --release cargo run
CREATE TABLE sync (
chain_id INTEGER NOT NULL,
block_number INTEGER NOT NULL,
PRIMARY KEY (chain_id)
);
CREATE TABLE transfers (
chain_id INTEGER NOT NULL,
block_number INTEGER NOT NULL,
tx_hash CHAR(66) NOT NULL,
token_address CHAR(42) NOT NULL,
from_addr CHAR(42) NOT NULL,
to_addr CHAR(42) NOT NULL,
value NUMERIC NOT NULL,
log_index INTEGER NOT NULL,
PRIMARY KEY (chain_id, tx_hash, log_index)
);
CREATE INDEX idx_block ON transfers(chain_id, block_number);
CREATE INDEX idx_token ON transfers(chain_id, token_address);
CREATE INDEX idx_from ON transfers(from_addr);
CREATE INDEX idx_to ON transfers(to_addr);tokio— async runtimealloy— Ethereum RPC clientdiesel— ORM / SQLite layerdotenvy— environment configurationhex— hex encoding / decoding
┌────────────┐ ┌──────────────┐ ┌────────────┐
│ Fetcher │────→──▶│ Parser │────→──▶│ Storage │
│ (RPC logs) │ │ (ABI decode) │ │ (SQLite) │
└────────────┘ └──────────────┘ └────────────┘
Sequential processing: fetch logs from RPC, decode Transfer events, and store in SQLite. Each block range is processed in order to maintain consistency.
-
.envconfiguration & project skeleton - SQLite schema migration
- Fetch
Transferlogs viaalloy - Decode topics into structured events
- Insert into DB with Diesel
- Log progress and exit
- Add
/healthand/transfers?addr=REST API withaxum - Reorg handling (
CONFIRMATIONS) - Batched inserts for performance
- Multi-token or multi-chain support
- Prometheus metrics (QPS, block height)
- Optional Postgres backend
- Async task orchestration with
tokio::spawnandmpscchannels - Practical use of
alloyRPC APIs for Ethereum interaction - Clean modular design leveraging Rust's ownership model
- Extensible architecture for production-grade indexers