web3-indexer-demo-2.mp4
- Simple user dashboard -> contract address, abi, on-chain events to fetch
- React-hook-form
- Displaying live on-chain event + past events
- Directly talk to an RPC provider (Alchemy)
- Fetch past logs in batch mode (e.g., 10k blocks at once).
- Store results in PostgreSQL(Prisma ORM).
we will display only the latest 1000 block limit- Live Listener – WebSocket subscription for new events.
- Queue/Buffer – Store events as pending until N confirmations.
- Reorg Handler – Detect chain reorg → rollback and re-fetch.
- DB Writer – Write finalized events into Postgres.
- PostgreSQL with Prisma ORM + Dockerized PostgreSQL
# Define your database schema
schema.prisma
# Apply migrations
npx prisma migrate dev --name init
# Manage your data
npx prisma studio- We need a flexible schema, since events differ by contract
- define model
Contract,Event,Chain
-
When event listener/indexer runs:
- Connects to RPC (Alchemy/Infura).
- Fetches past logs in batches.
- Listens for real-time events (eth_subscribe).
- Decodes logs using ABI → JSON { from, to, value }.
- Saves into Event table.
-
GraphQL Layer:
- Queries Event table by filters (block range, eventName, contract, indexedParams).
-
Queue + Retry (for reorgs):
- If a block gets reorged, update blockHash & re-fetch logs from replaced block range.
- Store events with blockHash for consistency.
- Apollo Server -> Indexer + Database + API:
- Fetches/stores blockchain events in DB.
- Exposes them via GraphQL schema.
- Example query a user can run:
1. define graphql schema
2. define data set (db, rest-api, another server)
3. define resolver
start 2. Apollo Client -> Query Builder UI:
- Users don’t directly write GraphQL manually (unless you give them that option).
- Instead, they use a visual query builder UI (dropdowns, filters, date pickers, event types, etc.).
- Your query builder generates GraphQL queries under the hood →
Apollo Client sends them to Apollo Server→ shows results nicely in UI (tables, charts, etc.)
1. init ApolloClient
2. Connect your client to react
3. fetch data with 'useQuery'
- we will use
GraphiQLopensourced query IDE by Apollo Community
https://github.com/graphql/graphiql
demo 1:
Contract sepolia: 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238
Contract mainnet: 0xA0b86a33E6441956f6ed9f27c6eB6e5d22c02893
From Block: 6700000
To Block: 6701000
Events: Transfer,Approvalabi
[
{
"anonymous": false,
"inputs": [
{"indexed": true, "name": "from", "type": "address"},
{"indexed": true, "name": "to", "type": "address"},
{"indexed": false, "name": "value", "type": "uint256"}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{"indexed": true, "name": "owner", "type": "address"},
{"indexed": true, "name": "spender", "type": "address"},
{"indexed": false, "name": "value", "type": "uint256"}
],
"name": "Approval",
"type": "event"
}
]demo 2:
Contract mainnet: 0x1fA9Ed83350f32747478E77564Ab21c453524B29
From Block: ?
To Block: ?query example:
- This are the function that are queryable
type Query {
getContracts(network: String): [Contract!]!
getContract(address: String!, network: String!): Contract
getEvents(filters: EventFilters, pagination: PaginationInput): EventsResponse!
getEventsByContract(contractAddress: String!, network: String!, eventName: String, pagination: PaginationInput): EventsResponse!
getIndexingStatus(contractAddress: String, network: String): [IndexingStatus!]!
getEventTypes(contractAddress: String!, network: String!): [String!]!
}- This is the example of query user can put to get response (indexer+db):
query Test($address: String!, $network: String!){
getContract(address: $address, network: $network) {
address,
name
}
getEvents {
totalCount,
events {
contractAddress,
eventName,
contract {
network
},
eventSignature
}
}
}- POST
/api/indexer- Start indexing with contract details - GET
/api/indexer- Health check
{
"contractAddress": "0x...",
"contractABI": "[{...}]",
"eventsToTrack": ["Transfer", "Approval"],
"network": "sepolia",
"fromBlock": "earliest",
"toBlock": "latest"
}- Next version of the project will focus on building sdk, do that other Dapps can directly integrate our indexer and query directly to their Dapp.