Indexers provide an easy solution to query on-chain data. They process smart contract events in the background and store them in a database, which you can query using GraphQL.
This enables efficient access to all smart contract events and allows for filtering the data as needed.
Prerequisites
- Node.js 20.x or later is installed.
- Docker is installed, and you have basic knowledge of using it.
Instructions
Install Subquid
Create a Squid: Follow the instructions for creating a Squid.
- During setup, create a new Squid with a name of your choice. This will be used later.
Create the Indexer
Initialize the JavaScript environment
Install required packages
npm i dotenv typeorm @subsquid/evm-processor @subsquid/typeorm-store @subsquid/typeorm-migration @subsquid/graphql-server @subsquid/evm-abi
npm i typescript @subsquid/typeorm-codegen @subsquid/evm-typegen --save-dev
Add tsconfig.json
Create a tsconfig.json
file in your project root with the following configuration:
{
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
"module": "commonjs",
"target": "es2020",
"esModuleInterop": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Define the schema
Create a schema.graphql
file and define the database schema. For example:
type Transfer @entity {
id: ID!
from: String! @index
to: String! @index
value: BigInt!
}
This schema represents the structure of the events you want to store in your database.
Generate TypeORM entities
Run the following command to generate TypeORM entities based on the schema:
npx squid-typeorm-codegen
Create a .env
file
Define the database credentials in a .env
file:
DB_NAME=peaq
DB_PORT=23798
Create docker-compose.yaml
Create a docker-compose.yaml
file to set up a PostgreSQL database:
version: "3"
services:
db:
image: postgres:15
environment:
POSTGRES_DB: "${DB_NAME}"
POSTGRES_PASSWORD: postgres
ports:
- "${DB_PORT}:5432"
Start the database container:
Compile TypeORM classes
Compile the generated TypeORM classes:
Generate and apply migrations
- Generate the migration file:
npx squid-typeorm-migration generate
npx squid-typeorm-migration apply
Tie the code together
Create a src/main.ts
file and add the following code:
import { EvmBatchProcessor } from '@subsquid/evm-processor';
import { TypeormDatabase } from '@subsquid/typeorm-store';
import { DataStoredEvent } from './model';
const DataStoredEventTopic = '0x9455957c3b77d1d4ed071e2b469dd77e37fc5dfd3b4d44dc8a997cc97c7b3d49';
const CONTRACT_ADDRESS = '0xdbdac2ef52681230f996624a5fa2624b06972671';
const processor = new EvmBatchProcessor()
.setRpcEndpoint({
url: 'https://rpcpc1-qa.agung.peaq.network',
})
.setFinalityConfirmation(5)
.setBlockRange({ from: 3564900 })
.addLog({
address: [CONTRACT_ADDRESS]
})
.setFields({
log: {
transactionHash: true,
},
});
const db = new TypeormDatabase();
processor.run(db, async (ctx) => {
const events: DataStoredEvent[] = [];
for (let block of ctx.blocks) {
for (let log of block.logs) {
if (log.topics[0] === DataStoredEventTopic) {
const data = BigInt(log.data);
console.log("ID: ", log.id);
console.log("DATA: ", data);
console.log("BLOCK_NUMBER: ", block.header.height);
console.log("TX_HASH: ", log.block.hash);
events.push(new DataStoredEvent({
id: log.id,
data: Number(data),
blockNumber: block.header.height,
transactionHash: log.block.hash,
}));
}
}
}
await ctx.store.insert(events);
});
Compile and start the processor
node -r dotenv/config lib/main.js
Start the GraphQL server
In a separate terminal, start the GraphQL server: