| name | Subgraph Migration |
| description | This skill should be used when the user asks to "migrate from subgraph", "convert subgraph to hyperindex", "migrate from thegraph", "port subgraph", "convert subgraph handlers", "migrate assemblyscript to typescript", or mentions TheGraph, subgraph migration, subgraph.yaml conversion, or converting from TheGraph to Envio. For core HyperIndex development patterns, refer to the hyperindex-development skill. |
| version | 1.0.0 |
Subgraph to HyperIndex Migration
Migrate from TheGraph subgraphs to Envio HyperIndex. HyperIndex delivers up to 100x faster indexing with a developer-friendly TypeScript API.
Migration Overview
Three major steps:
subgraph.yaml → config.yaml
- Schema migration (near copy-paste)
- Event handler migration (AssemblyScript → TypeScript)
Step 1: Config Migration
subgraph.yaml → config.yaml
TheGraph:
specVersion: 0.0.4
dataSources:
- kind: ethereum/contract
name: Factory
network: mainnet
source:
address: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"
startBlock: 10000835
abi: Factory
mapping:
eventHandlers:
- event: PairCreated(indexed address,indexed address,address,uint256)
handler: handlePairCreated
templates:
- name: Pair
source:
abi: Pair
HyperIndex:
name: my-indexer
networks:
- id: 1
start_block: 10000835
contracts:
- name: Factory
address: 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
handler: src/factory.ts
events:
- event: PairCreated(address indexed token0, address indexed token1, address pair, uint256)
- name: Pair
handler: src/pair.ts
events:
- event: Swap(...)
Key differences:
- Remove
dataSources, templates, mapping nesting
- Use
networks → contracts structure
- Event signatures include parameter names
- Dynamic contracts have no address field
Step 2: Schema Migration
Remove @entity decorator
type Token @entity {
id: ID!
symbol: String!
}
type Token {
id: ID!
symbol: String!
}
Convert Bytes to String
address: Bytes!
address: String!
Entity Relationships
type Transfer @entity {
token: Token!
}
type Transfer {
token_id: String!
}
Entity Arrays MUST have @derivedFrom
type Token @entity {
transfers: [Transfer!]!
}
type Token {
transfers: [Transfer!]! @derivedFrom(field: "token")
}
type Transfer {
token_id: String!
}
Critical: Arrays without @derivedFrom cause codegen error EE211.
Step 3: Handler Migration
Basic Pattern
TheGraph (AssemblyScript):
export function handleTransfer(event: TransferEvent): void {
let entity = new Transfer(event.transaction.hash.toHexString());
entity.from = event.params.from;
entity.to = event.params.to;
entity.amount = event.params.value;
entity.save();
}
HyperIndex (TypeScript):
import { MyContract } from "generated";
MyContract.Transfer.handler(async ({ event, context }) => {
const entity = {
id: `${event.chainId}-${event.transaction.hash}-${event.logIndex}`,
from: event.params.from,
to: event.params.to,
amount: event.params.value,
blockNumber: BigInt(event.block.number),
};
context.Transfer.set(entity);
});
Entity Loading
TheGraph:
let token = Token.load(id);
if (token == null) {
token = new Token(id);
}
HyperIndex:
let token = await context.Token.get(id);
if (!token) {
token = { id, name: "Unknown", };
}
Entity Updates
TheGraph:
token.totalSupply = newSupply;
token.save();
HyperIndex (use spread - entities are immutable):
context.Token.set({
...token,
totalSupply: newSupply,
});
Dynamic Contract Registration
TheGraph:
import { Pair as PairTemplate } from "../generated/templates";
PairTemplate.create(event.params.pair);
HyperIndex:
Factory.PairCreated.contractRegister(({ event, context }) => {
context.addPair(event.params.pair);
});
Factory.PairCreated.handler(async ({ event, context }) => {
});
Contract State (RPC Calls)
TheGraph:
let contract = ERC20.bind(address);
let name = contract.name();
HyperIndex (use Effect API):
import { createEffect, S } from "envio";
export const getTokenName = createEffect({
name: "getTokenName",
input: S.string,
output: S.string,
cache: true,
}, async ({ input: address }) => {
const name = await client.readContract({
address: address as `0x${string}`,
abi: ERC20_ABI,
functionName: "name",
});
return name;
});
const name = await context.effect(getTokenName, address);
Common Migration Issues
Missing async/await
const token = context.Token.get(id);
const token = await context.Token.get(id);
Field Selection for Transaction Data
events:
- event: Transfer(...)
field_selection:
transaction_fields:
- hash
Multichain ID Prefixes
const id = `${event.chainId}-${originalId}`;
BigDecimal Precision
Maintain precision from original subgraph:
import { BigDecimal } from "generated";
const ZERO_BD = new BigDecimal(0);
const ONE_BD = new BigDecimal(1);
Migration Checklist
Additional Resources
Reference Files
For detailed migration patterns:
references/migration-patterns.md - Complete pattern reference
references/common-mistakes.md - Pitfalls and solutions
External Resources