| name | subgraph-indexing |
| description | Subgraph development for The Graph protocol. Includes manifest configuration, GraphQL schema design, AssemblyScript handlers, entity relationships, and deployment to hosted and decentralized networks. |
| allowed-tools | Read, Grep, Write, Bash, Edit, Glob, WebFetch |
| graph | {"domains":["domain:security"],"specializations":["specialization:cryptography-blockchain"],"skillAreas":["skill-area:blockchain-analytics-explorer","skill-area:on-chain-data-oracle-integration","skill-area:graphql-schema-design"],"roles":["role:backend-engineer","role:data-engineer"]} |
Subgraph Indexing Skill
Subgraph development for The Graph protocol, enabling efficient blockchain data indexing and querying.
Capabilities
- Manifest Configuration: Write subgraph.yaml files
- Schema Design: Define GraphQL schemas for entities
- Event Handlers: Implement AssemblyScript handlers
- Entity Relationships: Handle derived fields and relations
- Local Testing: Test with Graph Node locally
- Deployment: Deploy to hosted and decentralized networks
- Performance: Optimize indexing performance
- Reorg Handling: Handle chain reorganizations
Installation
npm install -g @graphprotocol/graph-cli
graph --version
Project Setup
Initialize Subgraph
graph init --product subgraph-studio \
--from-contract 0x... \
--network mainnet \
--abi ./abi.json \
my-subgraph
cd my-subgraph
Project Structure
my-subgraph/
├── subgraph.yaml # Manifest
├── schema.graphql # GraphQL schema
├── src/
│ └── mapping.ts # Event handlers
├── abis/
│ └── Contract.json # Contract ABIs
├── tests/
│ └── contract.test.ts # Unit tests
└── package.json
Manifest (subgraph.yaml)
specVersion: 0.0.5
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum
name: Token
network: mainnet
source:
address: "0x..."
abi: Token
startBlock: 18000000
mapping:
kind: ethereum/events
apiVersion: 0.0.7
language: wasm/assemblyscript
entities:
- Transfer
- Account
abis:
- name: Token
file: ./abis/Token.json
eventHandlers:
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer
- event: Approval(indexed address,indexed address,uint256)
handler: handleApproval
GraphQL Schema
type Token @entity {
id: ID!
name: String!
symbol: String!
decimals: Int!
totalSupply: BigInt!
holders: [Account!]! @derivedFrom(field: "token")
}
type Account @entity {
id: ID!
token: Token!
balance: BigInt!
transfersFrom: [Transfer!]! @derivedFrom(field: "from")
transfersTo: Transfer
Transfer
ID
Account
Account
BigInt
BigInt
BigInt
Bytes
DailyVolume
ID
BigInt
BigInt
Int
AssemblyScript Handlers
import { Transfer as TransferEvent } from "../generated/Token/Token";
import { Token, Account, Transfer, DailyVolume } from "../generated/schema";
import { BigInt, Bytes, Address } from "@graphprotocol/graph-ts";
export function handleTransfer(event: TransferEvent): void {
let transfer = new Transfer(
event.transaction.hash.toHex() + "-" + event.logIndex.toString()
);
transfer.from = getOrCreateAccount(event.params.from).id;
transfer.to = getOrCreateAccount(event.params.to).id;
transfer.value = event.params.value;
transfer.timestamp = event..;
transfer. = event..;
transfer. = event..;
transfer.();
(event.., event...());
(event.., event..);
(event.., event..);
}
(): {
id = address.();
account = .(id);
(account == ) {
account = (id);
account. = ;
account. = .();
account.();
}
account;
}
(): {
account = (address);
account. = account..(delta);
account.();
}
(): {
dayId = timestamp.() / ;
id = dayId.();
volume = .(id);
(volume == ) {
volume = (id);
volume. = .(dayId * );
volume. = .();
volume. = ;
}
volume. = volume..(value);
volume. = volume. + ;
volume.();
}
Data Source Templates
templates:
- kind: ethereum
name: Pool
network: mainnet
source:
abi: Pool
mapping:
kind: ethereum/events
apiVersion: 0.0.7
language: wasm/assemblyscript
entities:
- Pool
- Swap
abis:
- name: Pool
file: ./abis/Pool.json
eventHandlers:
- event: Swap(indexed address,uint256,uint256)
handler: handleSwap
file: ./src/pool.ts
import { Pool as PoolTemplate } from "../generated/templates";
export function handlePoolCreated(event: PoolCreated): void {
PoolTemplate.create(event.params.pool);
let pool = new Pool(event.params.pool.toHex());
pool.save();
}
Build and Deploy
graph codegen
graph build
graph auth --studio <deploy-key>
graph deploy --studio my-subgraph
graph deploy --node https://api.thegraph.com/deploy/ \
--ipfs https://api.thegraph.com/ipfs/ \
username/my-subgraph
Querying
query RecentTransfers {
transfers(first: 10, orderBy: timestamp, orderDirection: desc) {
id
from {
id
balance
}
to {
id
balance
}
value
timestamp
}
}
query TopHolders {
accounts(first: 10, orderBy: balance, orderDirection: desc) {
id
balance
}
}
query DailyVolumes {
dailyVolumes(first: 30, orderBy: date, orderDirection: desc) {
date
volume
txCount
}
}
Testing
import { assert, test, clearStore } from "matchstick-as";
import { handleTransfer } from "../src/mapping";
import { createTransferEvent } from "./utils";
test("Creates Transfer entity", () => {
let event = createTransferEvent(
"0x1234...",
"0x5678...",
"1000000000000000000"
);
handleTransfer(event);
assert.entityCount("Transfer", 1);
clearStore();
});
Process Integration
| Process | Purpose |
|---|
subgraph-development.js | Subgraph development |
blockchain-indexer-development.js | Indexing pipelines |
dapp-frontend-development.js | Data integration |
Best Practices
- Use appropriate startBlock to avoid reindexing
- Implement efficient entity updates
- Handle reorgs with immutable entities
- Use derived fields for relations
- Test with Matchstick
- Monitor indexing performance
See Also
skills/wallet-integration/SKILL.md - dApp integration
agents/web3-frontend/AGENT.md - Frontend expert
- The Graph Documentation