đ Data & Analytics Crypto
Analyse dense : Le ProblÚme de la Donnée, TheGraph (Indexation API), Dune (Analyse SQL) & Python (web3.py, Pandas).
Le ProblÚme de la Donnée On-Chain
Pourquoi `SELECT *` est impossible. L'ETL (Extract, Transform, Load). Le "State" vs l'historique (Logs/Events).
ETLOptimisation (Write)LogsTheGraph : L'Indexeur (GraphQL)
Le "Google" de la Blockchain. Un protocole d'indexation décentralisé pour les DApps. Le "Subgraph" comme API temps-réel.
TheGraphGraphQLAPI (DApp)TheGraph : Architecture (Subgraph)
Anatomie d'un Subgraph : Le Manifest (subgraph.yaml), le Schema (schema.graphql), et les Mappings (AssemblyScript).
Dune : L'Agrégateur (SQL)
Le "Looker Studio" du Web3. Une plateforme d'analyse SQL centralisée. Raw Data vs Decoded Tables vs Spells.
DuneSQLDashboardsSpellsComparaison : TheGraph vs Dune
Le choix stratégique : API temps-réel décentralisée (DApp) vs Analyse ad-hoc centralisée (Humain).
ComparatifAPI vs AnalysePython : AccĂšs Bas Niveau (web3.py)
Interagir avec un nĆud (JSON-RPC). `w3.eth.get_block()`, `w3.eth.get_logs()`. Le dĂ©codage manuel des "Events".
Pythonweb3.pyJSON-RPCPython : API Dune (dune-client)
Utiliser `dune-client` pour exĂ©cuter des requĂȘtes (Query ID) et importer les rĂ©sultats dans un DataFrame `pandas`.
Pythondune-clientPandasPython : API TheGraph (GraphQL)
Utiliser `requests` ou `gql` pour envoyer des requĂȘtes POST (GraphQL) Ă un endpoint de Subgraph et les charger dans `pandas`.
PythonGraphQLPandasLa blockchain est une base de donnĂ©es publique et transparente. Cependant, elle est **optimisĂ©e pour l'ĂCRITURE (Write), pas pour la LECTURE (Read)**.
L'architecture de l'EVM est une **machine Ă Ă©tats (State Machine)**. Son objectif est de calculer (et de se mettre d'accord par consensus) sur l'**"Ătat Actuel" (World State)**. Un nĆud Ethereum est conçu pour rĂ©pondre rapidement Ă la question : "Quel est le solde de l'adresse X *maintenant* ?" (eth_getBalance).
Un nĆud Ethereum n'est **pas** une base de donnĂ©es SQL. Il n'a pas d'"index" sur l'historique. Il ne peut pas rĂ©pondre (nativement) Ă des questions simples comme :
- "Quels sont tous les transferts de $USDC effectués par l'adresse X ?"
- "Quels sont les 10 plus gros détenteurs (holders) du token $APE ?"
- "Quel est le volume de "swap" sur Uniswap pour la paire ETH/DAI hier ?"
La Seule Solution "Native" : Les "Events" (Logs)
La *seule* façon d'obtenir ces données historiques est d'utiliser l'appel RPC eth_getLogs.
Les dĂ©veloppeurs de smart contracts Ă©mettent des **"Events" (ĂvĂ©nements)** pour cette raison prĂ©cise. Un contrat ERC-20 Ă©met un Ă©vĂ©nement `Transfer` Ă chaque transfert. C'est un "log" (journal) stockĂ© dans le reçu de la transaction, conçu pour ĂȘtre peu coĂ»teux.
// Solidity event Transfer(address indexed from, address indexed to, uint256 amount); ... emit Transfer(msg.sender, to, amount);
Cet "Event" est stocké sous une forme brute (le "data blob" et les "topics" hachés) dans la structure du bloc.
Le Processus ETL (Extract, Transform, Load)
Pour répondre à notre question ("Tous les transferts USDC de X"), vous devez construire un **pipeline ETL (Extract, Transform, Load)** :
- 1. Extract (Extraire) : Parcourir **chaque bloc** (de 0 Ă N). Dans chaque bloc, utiliser
eth_getLogspour demander les "Logs" émis par le contrat USDC. - 2. Transform (Transformer) : Les "Logs" sont bruts (ex:
data: 0x...00a...,topic1: 0x...123...). Vous devez les **décoder** (en utilisant l'ABI) pour les transformer en données lisibles (JSON/SQL). Ex: (from: "0x...", to: "0x...", amount: 100). - 3. Load (Charger) : Insérer ces données transformées dans votre *propre* base de données (ex: PostgreSQL, BigQuery) que vous contrÎlez.
Vous venez de **centraliser** et de **dupliquer** la blockchain, juste pour pouvoir enfin faire votre SELECT * FROM my_usdc_transfers WHERE from = 'X'.
**TheGraph** est un **protocole d'indexation décentralisé** (et un réseau). Son objectif est de fournir le service ETL (décrit en 1.1) de maniÚre décentralisée, et de fournir aux développeurs de **DApps** une **API temps-réel (GraphQL)** pour récupérer ces données historiques.
Analogie : C'est le **"Google" de la Blockchain**. Google indexe le "chaos" du Web (HTML) dans une base de données structurée. TheGraph indexe le "chaos" de la Blockchain (Logs/Events) dans une base de données structurée.
Objectif : API Temps-Réel pour les DApps
TheGraph est conçu pour rĂ©pondre au besoin des **frontends (DApps)**. Le site `uniswap.info` (l'interface d'analyse d'Uniswap) doit afficher des graphiques, l'historique des swaps, la liquiditĂ© totale, etc. Il ne peut pas obtenir ces donnĂ©es d'un nĆud Ethereum.
Le frontend d'Uniswap fait donc des requĂȘtes **GraphQL** Ă un "endpoint" (une URL) du Subgraph d'Uniswap, hĂ©bergĂ© sur TheGraph.
Le "Subgraph"
L'unité de travail de TheGraph est le **"Subgraph"**. Un Subgraph est un **"module d'indexation"** open-source que n'importe qui peut créer et publier. C'est un "manuel d'instructions" qui dit à TheGraph :
- Quoi indexer (ex: les événements `Swap` du contrat Uniswap V3).
- Comment transformer ces données (ex: "calculer le volume en USD").
- OĂč les stocker (le "schĂ©ma" de la base de donnĂ©es finale).
(L'architecture exacte du Subgraph est détaillée en 2.2).
GraphQL (vs REST)
TheGraph a choisi **GraphQL** (une technologie de Meta/Facebook) comme langage de requĂȘte, et non REST. C'est un choix crucial :
- REST (API Web2) : Vous avez des *endpoints fixes* (
/users,/users/1/posts). Si vous voulez les posts d'un utilisateur, vous devez faire *deux* requĂȘtes (GET /user/1, puis GET /posts?userId=1). - GraphQL (API Web3) : Vous avez un *seul endpoint*. C'est le *client* (la DApp) qui dĂ©finit la "forme" (shape) des donnĂ©es qu'il souhaite en *une seule* requĂȘte.
// RequĂȘte GraphQL pour un Subgraph
query {
user(id: "0x123...") {
id
balance
transactions(orderBy: timestamp, orderDirection: desc, first: 10) {
id
amount
timestamp
}
}
}
// Renvoie l'utilisateur, son solde, ET ses 10 derniĂšres tx
// ... le tout en 1 seul appel réseau.
Le Réseau Décentralisé (Token $GRT)
TheGraph n'est pas une entreprise (comme Dune). C'est un **protocole** et un **réseau** (comme Ethereum). Il utilise son token ($GRT) pour créer un marché d'incitations économiques entre différents acteurs.
| Acteur | RĂŽle | Incitation (Token $GRT) |
|---|---|---|
| DĂ©veloppeurs de Subgraphs | CrĂ©ent et publient les Subgraphs (ex: l'Ă©quipe Uniswap publie le Subgraph Uniswap). | (Reçoivent une part des frais de requĂȘte si leur Subgraph est populaire). |
| Indexers (Indexeurs) | Les "Mineurs" / "Validateurs" du rĂ©seau. Ce sont des opĂ©rateurs de nĆuds qui **stakent (verrouillent) du $GRT**. Ils allouent des ressources pour *exĂ©cuter* le Subgraph (faire l'ETL) et *servir* les requĂȘtes GraphQL. | Gagnent des $GRT (inflation) et les **frais de requĂȘte** payĂ©s par les DApps. Risquent d'ĂȘtre **"slashĂ©s"** (perdre leur stake) s'ils servent des donnĂ©es incorrectes. |
| Curators (Curateurs) | Les "Experts QualitĂ©". Ils utilisent leurs $GRT pour "signaler" (en stakant sur une "bonding curve") les Subgraphs qui leur semblent de haute qualitĂ© et utiles. | Gagnent une part des frais de requĂȘte de ce Subgraph. Ils "prouvent" aux Indexers quels Subgraphs mĂ©ritent d'ĂȘtre indexĂ©s. |
| Delegators (DĂ©lĂ©gants) | Les "Stakers Passifs". Ils n'ont pas de nĆud. Ils **dĂ©lĂšguent** leurs $GRT Ă un Indexer qu'ils estiment fiable et performant. | Gagnent une part des revenus de l'Indexer (moins une commission), sans le travail technique. |
| Consommateurs (DApps) | Ex: Uniswap.info, Aave App. | Paient des $GRT (micro-paiements) pour chaque requĂȘte GraphQL qu'ils consomment. |
Construire un "Subgraph" (le module d'indexation) consiste Ă dĂ©finir trois fichiers fondamentaux. C'est le "manuel d'instructions" que le nĆud Indexer de TheGraph va suivre pour rĂ©aliser l'ETL.
1. Le Manifeste (subgraph.yaml) - Le "QUOI"
C'est le fichier de configuration principal. Il définit les **sources de données (dataSources)** à écouter.
specVersion: 0.0.5
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum/contract
name: MyToken
network: mainnet
source:
# L'adresse du contrat Ă surveiller
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F"
# L'ABI (pour que TheGraph puisse décoder)
abi: MyToken
# Par oĂč commencer l'indexation (bloc de dĂ©ploiement)
startBlock: 6627917
mapping:
kind: ethereum/events
apiVersion: 0.0.7
language: wasm/assemblyscript
entities: # Les types de données du Schéma
- User
- Transfer
abis: # Le nom de l'ABI Ă utiliser
- name: MyToken
file: ./abis/MyToken.json
# Le lien crucial : QUEL Event écouter, et QUELLE fonction appeler
eventHandlers:
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer # Appelle la fonction handleTransfer()
file: ./src/mapping.ts # Le fichier contenant la logique
2. Le SchĂ©ma (schema.graphql) - Le "OĂ" (La BDD)
C'est la définition de la **base de données** finale (la "destination" du L de ETL). Vous définissez la structure de vos tables (appelées "Entities") en utilisant la syntaxe GraphQL.
# Définition de l'entité "User" (table User)
type User @entity {
# L'ID unique (ex: l'adresse 0x...)
id: ID!
# Le solde, stocké en BigInt
balance: BigInt! @derivedFrom(field: "user")
# La liste des transactions (relation 1-N)
transactions: [Transaction!]! @derivedFrom(field: "user")
}
# Définition de l'entité "Transaction" (table Transaction)
type Transaction @entity {
# L'ID unique (ex: le hash de la tx)
id: ID!
from: User!
to: User!
amount: BigInt!
timestamp: BigInt!
}
3. Les Mappings (src/mapping.ts) - Le "COMMENT" (La Logique ETL)
C'est le "cerveau" (le T de ETL). C'est un fichier écrit en **AssemblyScript** (un sous-ensemble strict de TypeScript, compilable en WASM). Il contient les fonctions "handlers" définies dans le `yaml`.
Cette fonction `handleTransfer` sera appelée par l'Indexer **à chaque fois** qu'un événement `Transfer` est trouvé.
import { Transfer as TransferEvent } from "../generated/MyToken/MyToken"
import { User, Transaction } from "../generated/schema"
import { BigInt } from "@graphprotocol/graph-ts"
// La fonction "handler" appelée par le YAML
export function handleTransfer(event: TransferEvent): void {
// =======================================================
// ĂTAPE T (Transformer)
// =======================================================
// 1. Charger ou créer l'expéditeur (User "from")
let from = User.load(event.params.from.toHex())
if (from == null) {
from = new User(event.params.from.toHex())
from.balance = BigInt.fromI32(0)
}
// 2. Charger ou créer le destinataire (User "to")
let to = User.load(event.params.to.toHex())
if (to == null) {
to = new User(event.params.to.toHex())
to.balance = BigInt.fromI32(0)
}
// 3. Mettre Ă jour leurs soldes
from.balance = from.balance.minus(event.params.amount)
to.balance = to.balance.plus(event.params.amount)
// 4. Créer l'entité Transaction
let tx = new Transaction(event.transaction.hash.toHex())
tx.from = from.id
tx.to = to.id
tx.amount = event.params.amount
tx.timestamp = event.block.timestamp
// =======================================================
// ĂTAPE L (Load)
// =======================================================
// Sauvegarder les entités modifiées dans la BDD de TheGraph
from.save()
to.save()
tx.save()
}
**Dune** (anciennement Dune Analytics) est une **plateforme d'analyse de donnĂ©es (SaaS) centralisĂ©e**. Son objectif n'est *pas* de fournir des APIs temps-rĂ©el aux DApps, mais de fournir aux **analystes, data scientists et au grand public** une interface **SQL** simple pour requĂȘter, agrĂ©ger et visualiser les donnĂ©es on-chain.
Analogie : C'est le **"Tableau", "Looker Studio" ou "BigQuery"** du Web3. C'est un outil d'**Analyse (BI)**, pas une API de production.
Architecture (Centralisée)
Dune exécute son propre pipeline ETL massif et propriétaire :
- 1. Extraction (NĆuds) : Dune gĂšre des nĆuds (Full Nodes) pour Ethereum, Solana, Polygon, etc.
- 2. Chargement (Raw Data) : Ils "dumpent" (déversent) *toutes* les données brutes (
traces,logs,blocks,transactions) dans un Data Warehouse (entrepÎt de données) massivement parallÚle (ex: Snowflake/BigQuery). - 3. Transformation (Le "Decoding") : C'est la magie de Dune. L'équipe de Dune (et maintenant la communauté, via les "Wizards") écrit des "décodeurs" (parsers).
Les Niveaux d'Abstraction de Données
Niveau 1 : Données Brutes (ethereum.logs)
Les données brutes, difficiles à utiliser. Vous devez décoder manuellement les "topics" et les "data blobs".
SELECT * FROM ethereum.logs WHERE contract_address = '0x...'
Niveau 2 : Tables Décodées (aave_v3_ethereum.Borrow)
Dune pré-traite (Transforme) les logs bruts en "tables par événement". Si le contrat Aave a un événement `Borrow`, Dune crée une table `aave_v3_ethereum.Borrow` avec des colonnes propres : `user` (address), `reserve` (address), `amount` (uint256).
Niveau 3 : "Spells" (dex.trades)
Les "Spells" (SortilÚges) sont le plus haut niveau d'abstraction, créé par la communauté (les "Wizards"). Un Spell est une **vue SQL** qui **unifie** des données similaires à travers différents protocoles.
ProblĂšme : Si je veux le volume des DEX, dois-je faire un UNION de `uniswap_v2.swap`, `uniswap_v3.swap`, `sushiswap.swap`, `curve.swap`...? Oui.
Solution : Un Wizard crĂ©e le Spell dex.trades qui fait cet UNION pour vous. En tant qu'analyste, vous pouvez maintenant requĂȘter *une seule table* pour obtenir *tous* les trades de *tous* les DEX.
L'Expérience : SQL & Dashboards
L'interface de Dune est un éditeur SQL dans le navigateur.
Exemple : Trouver les 10 plus gros "swaps" Uniswap V3 des derniĂšres 24h
-- Dune utilise SQL (Spark SQL / SQL:2011)
-- On requĂȘte la table "dĂ©codĂ©e" par la communautĂ©
SELECT
tx_hash,
block_time,
"from" AS user_address,
"to" AS contract_address,
amount0_unadjusted / 1e18 AS amount0, -- (Décodage des décimales)
amount1_unadjusted / 1e6 AS amount1,
(amount0 * p0.price) + (amount1 * p1.price) AS usd_volume -- (Jointure avec les prix)
FROM uniswap_v3_ethereum.Swap AS t -- Table décodée
JOIN prices.usd AS p0 ON p0.contract_address = t.token0_address
JOIN prices.usd AS p1 ON p1.contract_address = t.token1_address
WHERE t.block_time > NOW() - INTERVAL '1' DAY
ORDER BY usd_volume DESC
LIMIT 10
Dashboards
L'analyste exĂ©cute cette requĂȘte, obtient un tableau de rĂ©sultats, et peut (en un clic) transformer ce tableau en un graphique (camembert, courbe...).
Il sauvegarde ensuite ce graphique sur un **Dashboard** (Tableau de bord) public. C'est ce qui a fait le succÚs de Dune : c'est un outil d'analyse *social*. Les meilleurs analystes (ex: @hildobby) créent des dashboards de référence (ex: "NFT Marketplace Volume") que tout l'écosystÚme utilise.
TheGraph et Dune résolvent tous deux le "problÚme de l'ETL", mais pour des **utilisateurs radicalement différents** et avec des **philosophies radicalement différentes**.
- **TheGraph** est votre **API Backend (ex: NodeJS/GraphQL)**. Elle est faite pour que votre application (frontend) l'appelle 1000x/seconde.
- **Dune** est votre **Outil de BI (ex: Tableau/Looker)**. Il est fait pour qu'un analyste (humain) l'appelle 1x/heure pour générer un rapport.
| CritÚre | TheGraph (Indexeur) | Dune (Agrégateur) |
|---|---|---|
| Philosophie | **Décentralisé**. Un réseau "permissionless" d'Indexers (PoS). | **Centralisé**. Une entreprise (SaaS) qui gÚre un Data Warehouse. |
| Cible Principale | **DApps (Machines)**. A besoin d'une API temps-rĂ©el pour son frontend. | **Analystes (Humains)**. A besoin de faire des requĂȘtes complexes pour des dashboards. |
| Langage de RequĂȘte | **GraphQL**. (Pour DApps, frontends). | **SQL**. (Pour analystes, data scientists). |
| Vitesse / Latence | Temps-réel (Sub-secondaire). Conçu pour une faible latence. | Analytique (Minutes/Heures). Les données peuvent avoir un "lag" (retard) de 5 min à 4h. Pas pour du temps-réel. |
| Mise en Place (Setup) | Complexe. Vous devez *construire* votre propre Subgraph (YAML, Schema, Mappings) et le déployer. | Simple. Vous ouvrez le site, vous écrivez du SQL. Les "Decoded Tables" sont déjà là . |
| CoĂ»t | Payant (en $GRT) par requĂȘte. (Ou gratuit si vous hĂ©bergez votre propre "Graph Node"). | "Freemium". Gratuit pour l'analyse publique (avec des files d'attente). Payant (cher) pour les requĂȘtes privĂ©es/rapides (Dune API). |
| Cas d'Usage Typique | Le frontend d'Uniswap (uniswap.info) qui affiche les graphiques de prix d'un pool. | Un analyste de chez a16z qui Ă©crit une requĂȘte pour voir le "Netflow" (entrĂ©es/sorties) de $USDC sur Coinbase. |
Avant d'utiliser les API de haut niveau (Dune/Graph), on peut utiliser Python (avec la bibliothĂšque `web3.py`) pour interagir **directement** avec un nĆud Ethereum (ex: Infura, Alchemy) via JSON-RPC. C'est le "niveau 0" de l'analyse, mais il est essentiel pour des tĂąches spĂ©cifiques.
# Installation pip install web3
1. Connexion (Provider) & Lecture Simple
from web3 import Web3
# 1. DĂ©finir le Provider (endpoint du nĆud RPC)
INFURA_URL = "https://mainnet.infura.io/v3/YOUR_API_KEY"
w3 = Web3(Web3.HTTPProvider(INFURA_URL))
# 2. Vérifier la connexion
if not w3.is_connected():
print("Erreur de connexion")
exit()
# 3. Appels RPC simples (Lecture de l'"Ătat Actuel")
latest_block = w3.eth.get_block('latest')
print(f"Dernier Bloc: {latest_block.number}")
# 4. Utiliser l'ABI pour interagir avec un contrat (Lecture)
DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F"
DAI_ABI = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}, ...]' # (ABI JSON minifié)
dai_contract = w3.eth.contract(address=DAI_ADDRESS, abi=DAI_ABI)
# 5. Appeler une fonction "view" (similaire Ă .call())
dai_name = dai_contract.functions.name().call()
print(f"Nom du token: {dai_name}")
2. Extraire des Logs (Le "ETL" Manuel)
C'est ici qu'on voit la difficulté que TheGraph/Dune résolvent.
from web3 import Web3
# (Setup w3 et dai_contract...)
# 1. Définir le filtre pour l'événement "Transfer"
# On veut les logs 'Transfer' du contrat DAI, du bloc 18000000 au 18000001
event_filter = dai_contract.events.Transfer.create_filter(
fromBlock=18000000,
toBlock=18000001
)
# 2. Récupérer les logs bruts (eth_getLogs)
raw_logs = event_filter.get_all_entries()
print(f"Trouvé {len(raw_logs)} logs de transfert.")
# 3. Les logs sont bruts. On doit les transformer.
for log in raw_logs:
# web3.py peut décoder le 'data blob' en utilisant l'ABI
processed_log = dai_contract.events.Transfer().process_log(log)
# Maintenant, c'est propre !
sender = processed_log.args['from']
receiver = processed_log.args['to']
amount = processed_log.args['value']
# Convertir 'amount' (qui a 18 décimales)
human_amount = w3.from_wei(amount, 'ether')
print(f"Transfert de {human_amount} DAI de {sender} Ă {receiver}")
Conclusion : C'est faisable (pour un petit script), mais pour indexer 10 millions de blocs, c'est un cauchemar (gestion des "re-orgs", timeouts, bases de données...). On utilise donc ce niveau *uniquement* pour des tùches trÚs spécifiques.
C'est la mĂ©thode "Data Scientist". Au lieu de rĂ©inventer l'ETL, on utilise Python pour interroger la base de donnĂ©es dĂ©jĂ prĂȘte de Dune (via leur API payante), et on charge les rĂ©sultats dans **Pandas** (la bibliothĂšque reine de l'analyse de donnĂ©es en Python) pour une analyse plus poussĂ©e.
# Installation pip install dune-client pandas
1. Ăcrire et sauvegarder une **RequĂȘte (Query)** dans l'interface web de Dune (ex: Query ID = 12345).
2. Utiliser Python pour **exĂ©cuter** cette requĂȘte (via l'API).
3. Attendre les résultats (peut prendre des minutes).
4. Charger les résultats JSON dans un **DataFrame Pandas**.
5. Effectuer une analyse complexe (ML, stats, visualisations) en local.
import pandas as pd
from dune_client.client import DuneClient
from dune_client.query import Query, QueryParameter
import os
# 1. Authentification (via variable d'environnement)
dune = DuneClient(os.environ["DUNE_API_KEY"])
# 2. DĂ©finir la requĂȘte (ID d'une requĂȘte dĂ©jĂ sauvegardĂ©e sur Dune)
# (Ex: Une requĂȘte qui trouve les 10 plus gros trades sur Uniswap)
MY_QUERY_ID = 123456
# (Optionnel) DĂ©finir des paramĂštres si la requĂȘte SQL les utilise
# params = [
# QueryParameter.text_type(name="user_address", value="0x..."),
# ]
# 3. ExĂ©cuter la requĂȘte et attendre les rĂ©sultats (bloquant)
print("ExĂ©cution de la requĂȘte Dune (ID: 123456)...")
results = dune.get_latest_result(MY_QUERY_ID)
# 4. Les résultats sont dans 'rows'
# (C'est une liste de dictionnaires JSON)
raw_data = results.result.rows
print(f"Reçu {len(raw_data)} lignes.")
# 5. Charger dans Pandas (La partie la plus importante)
df = pd.DataFrame(raw_data)
# 6. Analyse de Données avec Pandas
if not df.empty:
# Convertir les colonnes (qui sont des strings)
df['usd_volume'] = pd.to_numeric(df['usd_volume'])
df['block_time'] = pd.to_datetime(df['block_time'])
print("\n--- DataFrame Pandas ---")
print(df.head())
print("\n--- Analyse Simple ---")
print(f"Volume USD Total des 10 trades: {df['usd_volume'].sum()}")
print(f"Volume USD Moyen: {df['usd_volume'].mean()}")
De mĂȘme, on peut utiliser Python pour interroger les **Subgraphs de TheGraph**. C'est utile pour des tĂąches temps-rĂ©el lĂ©gĂšres ou pour agrĂ©ger des donnĂ©es de DApps. L'API de TheGraph est **GraphQL** (pas SQL), nous devons donc utiliser des requĂȘtes HTTP POST.
# Installation pip install requests pandas # (ou une lib GQL : pip install gql)
1. Trouver le "HTTP Endpoint" du Subgraph (ex: le Subgraph Uniswap V3).
2. Ăcrire une **RequĂȘte GraphQL** (en string) pour dĂ©finir les donnĂ©es souhaitĂ©es.
3. Envoyer cette requĂȘte via HTTP POST (avec `requests`).
4. Récupérer le JSON de la réponse.
5. Charger les données (aplaties) dans un **DataFrame Pandas**.
import requests
import pandas as pd
import json
# 1. Endpoint du Subgraph (Exemple : Uniswap V3)
THEGRAPH_URL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3"
# 2. RequĂȘte GraphQL (en string)
# On veut les 5 plus gros pools de liquidité (par volume en USD)
graphql_query = """
{
pools(orderBy: volumeUSD, orderDirection: desc, first: 5) {
id
token0 {
symbol
}
token1 {
symbol
}
feeTier
totalValueLockedUSD
volumeUSD
}
}
"""
# 3. Envoyer la requĂȘte HTTP POST
try:
response = requests.post(THEGRAPH_URL, json={'query': graphql_query})
response.raise_for_status() # LĂšve une erreur si le statut n'est pas 200
# 4. Récupérer le JSON
data = response.json()
# 5. Charger dans Pandas
# Les données sont dans data['data']['pools']
pools_data = data.get('data', {}).get('pools', [])
df = pd.DataFrame(pools_data)
# 6. Nettoyer les données (le JSON est imbriqué)
# Aplatir les dictionnaires 'token0' et 'token1'
df['token0_symbol'] = df['token0'].apply(lambda x: x['symbol'])
df['token1_symbol'] = df['token1'].apply(lambda x: x['symbol'])
df = df.drop(columns=['token0', 'token1'])
print("--- Top 5 Pools Uniswap V3 (via TheGraph) ---")
print(df)
except requests.exceptions.RequestException as e:
print(f"Erreur lors de l'appel Ă TheGraph: {e}")
