Introduction
The Graph est un protocole décentralisé qui indexe et organise les données des blockchains comme Ethereum, permettant des requêtes GraphQL ultra-rapides. Imaginez un Google pour la blockchain : au lieu de scanner des millions de blocs, vous queryez un subgraph optimisé.
Pourquoi l'utiliser en 2026 ? Avec l'essor des dApps DeFi et NFT, les données on-chain explosent. Les subgraphs évitent les nœuds RPC lents et coûteux, rendant vos apps scalables. Ce tutoriel beginner vous guide pas à pas pour créer un subgraph indexant les transferts d'un token ERC20 (ex: USDC). Vous obtiendrez un code 100% fonctionnel, déployable sur le Hosted Service de The Graph. À la fin, vous queryerez vos données en temps réel. Durée : 30 min. Prêt à booster vos projets Web3 ?
Prérequis
- Node.js 18+ et npm/yarn installés
- Compte gratuit sur The Graph Hosted Service
- Clé API subgraph (créez-en une après inscription)
- Connaissances basiques JavaScript/TypeScript
- MetaMask ou Infura pour ABI (optionnel, on utilisera un exemple public)
Installer Graph CLI
npm install -g @graphprotocol/graph-cli
npm install -g @graphprotocol/graph-node
npm install -g @graphprotocol/graph-tsGraph CLI est l'outil en ligne de commande officiel pour créer, build et déployer les subgraphs. L'installation globale permet d'exécuter graph partout. Vérifiez avec graph --version : doit afficher 0.38+. Évitez les versions anciennes pour compatibilité 2026.
Créer le projet subgraph
Créez un dossier projet et initialisez le squelette. Nous ciblerons les transferts ERC20 du contrat USDC (0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 sur Ethereum Mainnet). Cela indexera tous les événements Transfer.
Initialiser le subgraph
mkdir erc20-transfers-subgraph
cd erc20-transfers-subgraph
graph init --studio erc20-transfers
# Suivez les prompts :
# Network: mainnet
# Contract: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# ABI: Copiez depuis Etherscan ou fournissez un fichier local
# Start Block: 12287507 (premier bloc USDC)La commande graph init génère la structure : subgraph.yaml, schema.graphql, dossiers abis/ et src/. Spécifiez le contrat USDC pour auto-générer l'ABI. Le start block optimise l'indexation en ignorant les blocs vides. Piège : sans ABI valide, le build échoue.
Configurer subgraph.yaml
specVersion: 0.0.5
graphqlSchema: ./schema.graphql
schemaFile: ./schema.graphql
packageManager: npm
source:
abi: ERC20
address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
startBlock: 12287507
network: mainnet
dataSources:
- kind: ethereum/contract
name: ERC20
source:
abi: ERC20
address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
startBlock: 12287507
mapping:
entities:
- Transfer
abis:
- name: ERC20
file: ./abis/ERC20.json
eventHandlers:
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer
file: ./src/erc20.tsCe fichier YAML définit la source (contrat Ethereum), les événements à écouter (Transfer) et le mapping handler. specVersion: 0.0.5 est standard en 2026. Le startBlock accélère l'indexation. Piège : adresse en checksum (majuscules) pour éviter les erreurs de résolution.
Définir le schema GraphQL
Le schema décrit les entités à indexer, comme une DB relationnelle en GraphQL. Nous stockerons chaque Transfer avec from/to/value/block.
Écrire schema.graphql
type Transfer @entity {
id: ID!
from: Bytes! # address
to: Bytes! # address
value: BigInt!
blockNumber: BigInt!
blockTimestamp: BigInt!
transactionHash: Bytes!
}
type ERC20 @entity {
id: ID!
totalSupply: BigInt!
symbol: String!
name: String!
}Les types Transfer et ERC20 sont des entités persistantes. Bytes pour adresses/hex, BigInt pour uint256 (valeurs > JS Number). @entity active l'indexation. Après modification, relancez graph codegen. Piège : oubliez ! sur champs non-nullables, les queries planteront.
Générer code et ABI
graph codegen
graph buildgraph codegen génère les types TypeScript dans generated/ à partir du schema et ABI. graph build compile les mappings en WASM. Vérifiez build/subgraph.sol.json sans erreurs. Essentiel avant déploiement.
Implémenter les mappings
Les mappings en AssemblyScript traitent les événements blockchain. Comme des hooks : à chaque Transfer, on sauve l'entité.
Écrire le mapping erc20.ts
import { Transfer as TransferEvent } from "../generated/ERC20/ERC20";
import { Transfer, ERC20 } from "../generated/schema";
import { BigInt, Bytes } from "@graphprotocol/graph-ts";
export function handleTransfer(event: TransferEvent): void {
let transfer = new Transfer(event.transaction.hash.toHex() + "-" + event.logIndex.toString());
transfer.from = event.params.from;
transfer.to = event.params.to;
transfer.value = event.params.value;
transfer.blockNumber = event.block.number;
transfer.blockTimestamp = event.block.timestamp;
transfer.transactionHash = event.transaction.hash;
transfer.save();
// Update ERC20 entity
let token = ERC20.load("current");
if (token == null) {
token = new ERC20("current");
token.symbol = "USDC";
token.name = "USD Coin";
token.totalSupply = BigInt.fromI32(0);
}
token.save();
}À chaque événement Transfer, on crée une entité Transfer avec ID unique (tx hash + log index). On met à jour l'entité ERC20. save() persiste en IPFS/Indexeur. AssemblyScript est strict : utilisez BigInt pour les grands nombres. Piège : ID dupliqués causent des overwrites.
Télécharger ABI ERC20
{"abiVersion":2,"version":"erc20:1.0.0","types":{"TransferEvent":{"fields":[{"name":"from","type":"address","indexed":true},{"name":"to","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}]},"ApprovalEvent":{"fields":[{"name":"owner","type":"address","indexed":true},{"name":"spender","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}]},"TransferResult":{"type":"boolean"},"ApprovalResult":{"type":"boolean"},"TransferResultWithReturnData":{"data":{"type":"bytes"},"success":{"type":"boolean"}},"ApprovalResultWithReturnData":{"data":{"type":"bytes"},"success":{"type":"boolean"}}},"functions":[{"name":"allowance","inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"name":"approve","inputs":[{"name":"spender","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"TransferResult"}]},{"name":"balanceOf","inputs":[{"name":"account","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8"}]},{"name":"name","inputs":[],"outputs":[{"name":"","type":"string"}]},{"name":"symbol","inputs":[],"outputs":[{"name":"","type":"string"}]},{"name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"name":"transfer","inputs":[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"TransferResult"}]},{"name":"transferFrom","inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"TransferResult"}]}],
"events":["TransferEvent","ApprovalEvent"]}L'ABI définit les événements et fonctions du contrat ERC20. Téléchargez-le depuis Etherscan (USDC) et placez en abis/ERC20.json. Format JSON standard IPFS. Sans ça, les mappings ne reconnaissent pas les params. Piège : ABI tronqué = événements ignorés.
Déployer le subgraph
graph auth --studio YOUR_API_KEY
graph deploy --studio erc20-transfers
# Ou pour Hosted Service:
graph deploy --service-name mainnet YOUR_SUBGRAPH_ID --ipfs https://api.thegraph.com/ipfs/Authentifiez avec votre clé API. graph deploy build, upload sur IPFS et déploie sur Hosted Service. Remplacez YOUR_API_KEY et YOUR_SUBGRAPH_ID. Surveillez le dashboard pour sync. Temps : 5-10 min pour 1M+ transfers. Piège : oubli d'auth = 401 error.
Query le subgraph
Une fois déployé, queryez via GraphQL Playground : https://api.studio.thegraph.com/query/YOUR_ID/erc20-transfers/version/latest. Exemple query :
``graphql``
query {
transfers(first: 10, orderBy: blockTimestamp, orderDirection: desc) {
id
from
to
value
blockTimestamp
}
}
Résultat : JSON avec 10 derniers transfers USDC.
Bonnes pratiques
- Commencez par un startBlock récent : Réduit le temps d'indexation de jours à minutes.
- Utilisez des IDs composites : tx.hash + logIndex évite les doublons.
- Limitez les entités : Indexez seulement les events nécessaires pour scaler.
- Testez localement :
graph testavant deploy. - Migrez vers décentralisé : Après Hosted, passez à L2/Substreams en 2026.
Erreurs courantes à éviter
- ABI manquant/invalide :
graph codegenéchoue → Téléchargez toujours depuis source fiable. - BigInt vs Number : Overflow sur values > 2^53 → Toujours
BigInt.fromString(). - Pas de .save() : Entités non persistées → Vérifiez chaque handler.
- StartBlock trop bas : Indexation infinie → Visez > 10M pour mainnet.
Pour aller plus loin
- Docs officielles : The Graph Docs
- Exemple avancé : Subgraphs Uniswap V3
- Formations Learni Web3 : Maîtrisez Solidity + The Graph en 20h.
- Outils : SubQuery (alternative), Goldsky (hosted).