Note: This is a reference implementation example for indexing the RMRK protocol. It is provided as-is for educational and development purposes. For production deployments, please review and customize the code according to your specific requirements.
A high-performance indexer for the RMRK protocol built on Subsquid. This indexer processes EVM blockchain data for RMRK's advanced NFT standards (nestable, multi-asset, and equippable NFTs) and exposes it via a GraphQL API.
- Multi-Chain Support: Index RMRK NFTs across multiple EVM chains (Moonbeam, Moonbase Alpha, etc.)
- Advanced NFT Standards:
- Nestable NFTs: NFTs that can own other NFTs
- Multi-Asset NFTs: NFTs with multiple asset representations
- Equippable NFTs: NFTs with equipable parts/slots
- High Performance: Utilizes Subsquid Archive for fast historical data sync
- GraphQL API: Auto-generated GraphQL API with subscription support
- Marketplace Integration: Indexes marketplace events (listings, bids, sales)
- Reindexing Support: Optimized reindexing from cached raw blockchain logs
- Rate Limiting: Configurable RPC rate limiting to work with various providers
This is a monorepo built with:
- Subsquid: EVM indexing framework
- TypeORM: Database ORM
- GraphQL: API layer
- Turborepo: Monorepo build system
- Yarn Workspaces: Package management
rmrk-indexer/
├── apps/
│ └── evm-indexer/ # Main indexer application
│ ├── src/
│ │ ├── mapping/ # Event handlers
│ │ ├── model/ # TypeORM entities
│ │ ├── abi/ # Contract ABIs
│ │ ├── services/ # Business logic
│ │ └── processor.ts # Main processor entry
│ ├── schema.graphql # GraphQL schema definition
│ ├── db/migrations/ # Database migrations
│ └── assets/ # Static assets
├── libs/
│ ├── utils/ # Shared utilities
│ ├── eslint-config-server/# ESLint configuration
│ ├── jest-presets/ # Jest testing configuration
│ └── tsconfig/ # TypeScript configurations
└── scripts/ # Build and deployment scripts
- Processor fetches blockchain logs from RPC endpoint or Subsquid Archive
- Event Handlers transform raw logs into structured data
- TypeORM Store persists data to PostgreSQL
- GraphQL Server exposes data via auto-generated API
- Node.js: v16 or higher
- Yarn: v1.22.19 (specified in package.json)
- Docker & Docker Compose: For local PostgreSQL database
- PostgreSQL: v12 or higher (via Docker or standalone)
git clone https://github.com/rmrk-team/rmrk-indexer.git
cd rmrk-indexer
yarn install
cd apps/evm-indexer
cp .env.dev .env
Edit .env
with your configuration:
# Chain Configuration
CHAIN=moonbase-alpha
CHAIN_WSS=wss://moonbeam-alpha.api.onfinality.io/ws?apikey=YOUR_API_KEY
FROM_BLOCK=4260920
# Contract Addresses
RMRK_REGISTRY_ADDRESS=0xCEd0e87a29A2570A5866f4a4F3e45fA1dd82FD53
RMRK_COLLECTION_UTILS_ADDRESS=0xad567e7Dd1DFEa4b7EB86E415C5E838c090c0a00
MARKETPLACE_CONTRACT_ADDRESS=0xc97FA8f2b52b95Cb88048910d7bc2BA44C067B4f
MARKETPLACE_CONTRACT_FROM_BLOCK=4472161
# Performance
RPC_RATE_LIMIT=400
RPC_MAX_BATCH_SIZE=100
# Features
RUN_EVENT_SYNC=true
IS_REINDEX_EVENT_FACADE_ENABLED=true
IS_SUBSQUID_ARCHIVE_ENABLED=true
# Database (Docker defaults)
DB_NAME=squid
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASS=postgres
# From project root
docker compose -f docker-compose.evm.yaml up -d db
# From project root
yarn build
# From project root
yarn db:migrate
# From project root
yarn processor:start
# From project root
yarn query-node:start
The GraphQL playground will be available at: http://localhost:4350/graphql
Variable | Description | Default | Required |
---|---|---|---|
CHAIN |
EVM network to index | - | ✅ |
CHAIN_WSS |
WebSocket RPC endpoint | - | ✅ |
FROM_BLOCK |
Starting block number | - | ✅ |
TO_BLOCK |
Ending block number | - | ❌ |
RMRK_REGISTRY_ADDRESS |
RMRK Registry contract | - | ✅ |
RMRK_COLLECTION_UTILS_ADDRESS |
Collection utils contract | - | ✅ |
MARKETPLACE_CONTRACT_ADDRESS |
Marketplace contract | - | ❌ |
MARKETPLACE_CONTRACT_FROM_BLOCK |
Marketplace start block | - | ❌ |
RPC_RATE_LIMIT |
Requests per second | 90 | ❌ |
RPC_MAX_BATCH_SIZE |
Max batch call size | 100 | ❌ |
IS_SUBSQUID_ARCHIVE_ENABLED |
Use Subsquid Archive | true | ❌ |
IS_REINDEX_EVENT_FACADE_ENABLED |
Enable reindexing mode | false | ❌ |
- Moonbeam
- Moonbase Alpha
- Moonriver
- Base
- Base Sepolia
- (Configurable for any EVM chain)
# Build all packages
yarn build
# Build specific app
yarn build:evm-indexer
# Run tests
yarn test
# Lint code
cd apps/evm-indexer && npm run lint
# Apply migrations
yarn db:migrate
# Reset processor state
yarn db:state-schema-reset
# Generate new migration (after schema changes)
cd apps/evm-indexer
make migration
- Edit
apps/evm-indexer/schema.graphql
- Generate TypeORM entities:
cd apps/evm-indexer make codegen
- Generate migration:
make migration
- Apply migration:
make migrate
- Add event ABI to
apps/evm-indexer/src/abi/
- Generate TypeScript types:
npx squid-evm-typegen --abi src/abi/YOUR_CONTRACT.json --output src/abi/yourContract.ts
- Add event topics to
apps/evm-indexer/src/topics.ts
- Update processor in
src/processorFactory.ts
- Create event handler in
src/mapping/
- Register handler in
src/mapping/contractHandler.ts
# Start all services
docker compose -f docker-compose.evm.yaml up
# Stop services
docker compose -f docker-compose.evm.yaml down
# View logs
docker compose -f docker-compose.evm.yaml logs -f
# Build image
docker compose -f docker-compose.evm.yaml build
# Run services
docker compose -f docker-compose.evm.yaml up -d
# Check status
docker compose -f docker-compose.evm.yaml ps
- Set environment variables for your target environment
- Build the project:
yarn build
- Run migrations:
yarn db:migrate
- Start processor:
yarn processor:start
- Start GraphQL server:
yarn query-node:start
- Processor Logs: Monitor block processing progress
- Database: Check
_processor_status
table for sync status - GraphQL: Access
/graphql
endpoint for API health
Access the interactive GraphQL playground at http://localhost:4350/graphql
query GetCollections {
collections(limit: 10, orderBy: id_ASC) {
id
name
symbol
owner
totalSupply
nfts {
id
tokenId
}
}
}
query GetNFT {
nftById(id: "YOUR_NFT_ID") {
id
tokenId
owner
collection {
name
}
assets {
id
metadata
priority
}
children {
id
tokenId
}
}
}
query GetListings {
listings(where: { status_eq: ACTIVE }, limit: 20) {
id
price
seller
nft {
id
tokenId
collection {
name
}
}
}
}
subscription NewEvents {
events(limit: 1) {
id
eventType
block {
number
timestamp
}
}
}
The indexer supports optimized reindexing from cached raw logs. See apps/evm-indexer/REINDEX.md for detailed instructions.
- Update
LAST_SYNC_VERSION
environment variable - Run:
yarn db:state-schema-reset
# Run all tests
yarn test
# Test specific block range
cd apps/evm-indexer
npm run testing 11525199 0x78642bde93e1d71087a1c3c842f9f5224d063ef1
Made with ❤️ by the RMRK team