Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

📊 Data & Analytics Crypto

Analyse dense : Le ProblÚme de la Donnée, TheGraph (Indexation API), Dune (Analyse SQL) & Python (web3.py, Pandas).

1.1

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)Logs
2.1

TheGraph : 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)
2.2

TheGraph : Architecture (Subgraph)

Anatomie d'un Subgraph : Le Manifest (subgraph.yaml), le Schema (schema.graphql), et les Mappings (AssemblyScript).

SubgraphAssemblyScriptMappings
3.1

Dune : L'Agrégateur (SQL)

Le "Looker Studio" du Web3. Une plateforme d'analyse SQL centralisée. Raw Data vs Decoded Tables vs Spells.

DuneSQLDashboardsSpells
3.2

Comparaison : TheGraph vs Dune

Le choix stratégique : API temps-réel décentralisée (DApp) vs Analyse ad-hoc centralisée (Humain).

ComparatifAPI vs Analyse
4.1

Python : 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-RPC
4.2

Python : 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-clientPandas
4.3

Python : API TheGraph (GraphQL)

Utiliser `requests` ou `gql` pour envoyer des requĂȘtes POST (GraphQL) Ă  un endpoint de Subgraph et les charger dans `pandas`.

PythonGraphQLPandas
1.1 Le ProblÚme Fondamental : La Donnée On-Chain (ETL)

La 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).

Le Défi : Les Questions "Historiques"

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. 1. Extract (Extraire) : Parcourir **chaque bloc** (de 0 à N). Dans chaque bloc, utiliser eth_getLogs pour demander les "Logs" émis par le contrat USDC.
  2. 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. 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'.

Conclusion : C'est ce processus ETL (lourd, coûteux, complexe) que **TheGraph** et **Dune** automatisent et offrent en tant que service.
2.1 TheGraph : L'Indexeur Décentralisé (GraphQL)

**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 :

  1. Quoi indexer (ex: les événements `Swap` du contrat Uniswap V3).
  2. Comment transformer ces données (ex: "calculer le volume en USD").
  3. 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.

ActeurRĂŽleIncitation (Token $GRT)
DĂ©veloppeurs de SubgraphsCrĂ©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.
2.2 TheGraph : Architecture d'un "Subgraph"

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()
}
3.1 Dune : L'Agrégateur SQL (Pour l'Analyse Humaine)

**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. 1. Extraction (NƓuds) : Dune gùre des nƓuds (Full Nodes) pour Ethereum, Solana, Polygon, etc.
  2. 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. 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.

3.2 Comparaison Stratégique : TheGraph vs Dune

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**.

Analogie Simple :
- **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ÚreTheGraph (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 / LatenceTemps-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Ă»tPayant (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 TypiqueLe 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.
4.1 Python : AccĂšs Bas Niveau (web3.py & JSON-RPC)

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.

4.2 Python : API Dune (dune-client) & Pandas

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
Flux de Travail :
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()}")
4.3 Python : API TheGraph (GraphQL) & Pandas

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)
Flux de Travail :
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}")