Skip to content
Learni
Voir tous les tutoriels
Blockchain

Comment déployer un subgraph The Graph en 2026

Read in English

Introduction

The Graph est le protocole d'indexation décentralisé incontournable pour les dApps Web3 en 2026. Il permet de query des données blockchain via GraphQL, surpassant les RPC lents pour des requêtes complexes comme les swaps Uniswap ou transfers ERC20. Pourquoi l'utiliser ? Imaginez interroger 1M+ événements en millisecondes au lieu d'heures de scanning.

Ce tutoriel avancé vous guide pas à pas pour indexer les événements Transfer d'un token ERC20 sur Sepolia (adresse : 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238). On couvre l'installation CLI, schema GraphQL, mappings en AssemblyScript, build local avec Docker, queries playground, et déploiement sur Subgraph Studio. Résultat : un endpoint GraphQL queryable en production. Idéal pour dashboards DeFi ou NFT analytics. Durée estimée : 2h pour un dev expérimenté.

Prérequis

  • Node.js 20+ et Yarn 1.22+
  • Docker et Docker Compose (pour graph-node local)
  • Clé API Alchemy ou Infura (RPC Sepolia)
  • Compte Subgraph Studio (gratuit sur thegraph.com/studio)
  • Connaissances avancées en Solidity, GraphQL et TypeScript
  • Git installé

Installation de la CLI The Graph

terminal
npm install -g @graphprotocol/graph-cli
yarn global add @graphprotocol/graph-cli
graph --version

Installez la CLI officielle via npm ou Yarn pour gérer init, codegen et deploy. Vérifiez avec graph --version (doit afficher 0.38+ en 2026). Évitez les versions globales obsolètes ; utilisez npx si conflits.

Initialisation du projet subgraph

Créez un nouveau répertoire et initialisez le boilerplate. Cela génère subgraph.yaml, schema.graphql et src/mapping.ts. On cible Sepolia (chainId 11155111) et notre ERC20 à 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238.

Initialiser le subgraph

terminal
mkdir erc20-subgraph && cd erc20-subgraph
graph init --studio erc20-subgraph
# Suivez les prompts :
# - Subgraph name: erc20-sepolia
# - Directory: .
# - Ethereum network: sepolia
# - Contract address: 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238
# - Contract ABI: (copiez depuis Etherscan ou Alchemy)

L'init configure le manifest de base et télécharge l'ABI. Fournissez l'adresse exacte du contrat ERC20 déployé sur Sepolia. Si ABI manquant, exportez-le depuis Sepolia Etherscan.

Définition du schema GraphQL

Analogie : Le schema est le blueprint de votre base de données décentralisée, comme une table SQL mais queryable en GraphQL. On définit Transfer avec entités pour from/to/value/block.

Schema GraphQL complet

schema.graphql
type Transfer @entity {
  id: ID!
  from: Bytes! # adresse hex
  to: Bytes!
  value: BigInt!
  blockNumber: BigInt!
  blockTimestamp: BigInt!
  transactionHash: Bytes!
}

type Account @entity {
  id: ID!
  totalTransfers: BigInt!
  totalSent: BigInt!
  totalReceived: BigInt!
}

type Token @entity {
  id: ID!
  totalSupply: BigInt!
  totalTransfers: BigInt!
}

Définit trois entités : Transfer (événements primaires), Account (agrégats par adresse), Token (métadonnées globales). Utilisez BigInt pour les uint256 Solidity. @entity active l'indexation automatique.

Manifest subgraph.yaml

subgraph.yaml
specVersion: 0.0.5
schema:
  file: ./schema.graphql

dataSources:
  - kind: ethereum/contract
    name: ERC20
    network: sepolia
    source:
      address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
      abi: ERC20
      startBlock: 5000000 # bloc de déploiement approx.
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.8
      language: wasm/assemblyscript
      entities:
        - Transfer
        - Account
        - Token
      abis:
        - name: ERC20
          file: ./abis/ERC20.json
      eventHandlers:
        - event: Transfer(indexed address,indexed address,uint256)
          handler: handleTransfer
      file: ./src/mapping.ts

Le manifest lie schema, ABI et mappings. startBlock optimise l'indexation (trouvez-le sur Etherscan). apiVersion 0.0.8 supporte les dernières features WASM. Téléchargez ABI dans ./abis/.

Écriture des mappings AssemblyScript

Les mappings traitent les événements blockchain en entités. handleTransfer crée/updates Transfer, incrémente compteurs Account/Token. Utilisez ctx.Token.createOrUpdate pour idempotence.

Mappings complets (mapping.ts)

src/mapping.ts
import { Transfer as TransferEvent } from "../generated/ERC20/ERC20";
import { Transfer, Account, Token } from "../generated/schema";
import { Address, BigInt, log } from "@graphprotocol/graph-ts";

export function handleTransfer(event: TransferEvent): void {
  let transferId = event.transaction.hash.toHex() + "-" + event.logIndex.toString();
  let transfer = new Transfer(transferId);
  transfer.from = event.params.from.toHex();
  transfer.to = event.params.to.toHex();
  transfer.value = event.params.value;
  transfer.blockNumber = event.block.number;
  transfer.blockTimestamp = event.block.timestamp;
  transfer.transactionHash = event.transaction.hash;
  transfer.save();

  let tokenId = "current";
  let token = Token.load(tokenId);
  if (token == null) {
    token = new Token(tokenId);
    token.totalSupply = BigInt.fromI32(0);
  }
  token.totalTransfers = token.totalTransfers.plus(BigInt.fromI32(1));
  token.save();

  let fromId = event.params.from.toHex();
  let fromAccount = Account.load(fromId);
  if (fromAccount == null) {
    fromAccount = new Account(fromId);
    fromAccount.totalSent = BigInt.fromI32(0);
    fromAccount.totalReceived = BigInt.fromI32(0);
    fromAccount.totalTransfers = BigInt.fromI32(0);
  }
  fromAccount.totalSent = fromAccount.totalSent.plus(event.params.value);
  fromAccount.totalTransfers = fromAccount.totalTransfers.plus(BigInt.fromI32(1));
  fromAccount.save();

  let toId = event.params.to.toHex();
  let toAccount = Account.load(toId);
  if (toAccount == null) {
    toAccount = new Account(toId);
    toAccount.totalSent = BigInt.fromI32(0);
    toAccount.totalReceived = BigInt.fromI32(0);
    toAccount.totalTransfers = BigInt.fromI32(0);
  }
  toAccount.totalReceived = toAccount.totalReceived.plus(event.params.value);
  toAccount.totalTransfers = toAccount.totalTransfers.plus(BigInt.fromI32(1));
  toAccount.save();
}

Génère un ID unique par log. load/create assure upserts atomiques. Incrémente agrégats pour analytics (ex: totalSent). Loggez avec log.info pour debug. Testez avec événements réels post-5000000.

Génération des types et build

terminal
graph codegen
graph build
ls generated/ # vérifiez erc20/ERC20.ts

Codegen génère les types TS depuis ABI/schema (ex: TransferEvent). Build compile en WASM. Erreur courante : ABI malformé ; validez JSON.

Déploiement local avec Docker

Setup local : Lancez graph-node pour tester sans frais. Fournissez votre RPC Alchemy Sepolia dans docker-compose.yml.

Docker Compose pour graph-node

docker-compose.yml
version: '3.6'
services:
  postgres:
    image: postgres
    environment:
      POSTGRES_DB: subgraph
      POSTGRES_USER: subgraph
      POSTGRES_PASSWORD: subgraph
    ports:
      - "5432:5432"
  graph-node:
    image: semaphoreui/graph-node:v0.38.0
    depends_on: [postgres]
    environment:
      postgres_host: postgres
      postgres_db: subgraph
      postgres_user: subgraph
      postgres_pass: subgraph
      ethereum: sepolia https://eth-sepolia.g.alchemy.com/v2/VOTRE_CLE_API
      GRAPH_LOG: info
    ports:
      - "8020:8020"
      - "8000:8000"
      - "8001:8001"
  indexer-agent:
    image: semaphoreui/indexer-agent:v0.6.0
    depends_on: [graph-node]
    environment:
      GRAPH_NODE: http://graph-node:8020
      INDEXER: http://indexer:80

Remplacez VOTRE_CLE_API par votre Alchemy key. Ports : 8000/GraphQL, 8020/admin, 8001/query. up -d pour background.

Déployer et query local

terminal
docker-compose up -d
graph create-local --node http://localhost:8020/ erc20-sepolia
graph deploy --version-label v0.1.0 --node http://localhost:8020/ --ipfs http://localhost:5001 erc20-sepolia

# Query playground
curl -X POST -H 'Content-Type: application/json' --data '{"query": "{ transfers(first:5, orderBy: blockTimestamp, orderDirection: desc) { id from to value } }"}' http://localhost:8000/subgraphs/name/erc20-sepolia

Crée le subgraph local, déploie le build WASM. Query via curl ou localhost:8001. Attendez sync (vérifiez logs docker logs graph-node).

Déploiement sur Subgraph Studio

Authentifiez-vous et déployez vers le hosted service, puis migrez vers décentralisé.

Déployer sur Studio

terminal
graph auth --studio VOTRE_ACCESS_TOKEN
# Obtenez-le sur thegraph.com/studio

graph subgraph create --studio erc20-sepolia
graph deploy --studio erc20-sepolia

# Endpoint: https://api.studio.thegraph.com/query/XXXXXX/erc20-sepolia/v0.1.0

Token depuis dashboard Studio. Premier deploy indexe ; suivants updatent. Endpoint queryable publiquement. Pour décentralisé : graph deploy --network mainnet post-indexing.

Bonnes pratiques

  • StartBlock précis : Utilisez Etherscan pour minimiser sync time (ex: 5000000 pour notre contrat).
  • Indexation paginée : Ajoutez skip/first dans queries ; limitez à 1000 entités/page.
  • Agrégats dénormalisés : Stockez totalsSent dans Account pour éviter joins coûteux.
  • Tests unitaires : Utilisez matchstick-as pour mocker événements.
  • Monitoring : Surveillez fatal errors via Studio dashboard ; retry avec versioning.

Erreurs courantes à éviter

  • ABI incomplet : Oublier Transfer event → mappings crash. Copiez toujours full ABI.
  • ID non-unique : tx.hash + logIndex empêche doublons lors de reorgs.
  • BigInt overflow : AssemblyScript gère natif ; évitez JS Number.
  • Sync bloqué : RPC rate-limit ; upgradez Alchemy Pro ou utilisez snapshots.

Pour aller plus loin

Comment déployer un subgraph The Graph en 2026 | Learni