Traçage et graphes de transactions · Leçon 1 sur 6
Graphes de transactions et métriques de graphes
16 min de lecture
Presque toute question de traçage, de « où sont allés les fonds volés ? » à « ce dépôt est-il exposé à un service sous sanctions ? », est une question portant sur un graphe. Le choix des nœuds et des arêtes détermine, sans que cela soit toujours apparent, les réponses possibles. Une fois le graphe construit, vous devez disposer de moyens de repérer ce qui importe sans examiner manuellement des milliers d’arêtes. Cette leçon montre comment construire un graphe dont vous pouvez justifier les choix, puis présente les métriques et les formes récurrentes que les analystes utilisent pour le lire, et explique pourquoi aucune ne constitue une preuve à elle seule.
Trois graphes à partir des mêmes données
Les mêmes données de blocs peuvent être modélisées de trois manières, et les analystes passent constamment de l’une à l’autre.
| Graphe | Nœuds | Arêtes | Usage privilégié |
|---|---|---|---|
| Graphe de transactions | Transactions (et, dans les blockchains UTXO, les sorties qu’elles créent) | Une sortie créée par une transaction et dépensée par une autre | Traçage UTXO exact et sans perte d’information |
| Graphe d’adresses | Adresses | Valeur envoyée d’une adresse à une autre | Blockchains à modèle de comptes, vues d’ensemble rapides |
| Graphe d’entités | Regroupements ou services étiquetés | Flux agrégés entre entités | Rapports, exposition, analyse des contreparties |
Le graphe de transactions est le plus proche des données brutes. Dans Bitcoin, chaque sortie reste non dépensée ou est consommée par exactement une entrée ultérieure ; les relations de dépense forment donc un graphe orienté acyclique précis : l’argent ne peut pas remonter le temps et rien n’est inféré. Le graphe d’adresses fait de chaque adresse un nœud. Il convient naturellement aux blockchains à modèle de comptes, où un transfert va réellement d’un compte à un autre, mais il introduit une ambiguïté dans les blockchains UTXO, comme le montre l’exemple ci-dessous. Le graphe d’entités remplace les adresses par des regroupements (« Portefeuilles à chaud de la plateforme d’échange X »). La plupart des rapports le présentent, mais chaque nœud dépend du regroupement et de l’attribution, qui ont leurs propres taux d’erreur (leçon 4.1) ; conservez donc la possibilité de développer les couches inférieures derrière chaque arête entre entités.
De nombreux outils de traçage visuel dessinent un graphe biparti hybride comportant deux types de nœuds, les adresses et les transactions : les arêtes vont d’une adresse vers une transaction (une entrée) et d’une transaction vers une adresse (une sortie). Il préserve l’exactitude du graphe de transactions tout en montrant qui détient quoi.
Arêtes : direction, poids et temps
Une arête utile contient davantage que « A a payé B ». Conservez au minimum :
- Direction : source et destination. Le traçage vers l’aval suit les arêtes sortantes ; le traçage vers l’amont suit les arêtes entrantes.
- Poids : le montant en unités natives après conversion décimale, éventuellement accompagné de sa valeur dans une devise de référence au moment considéré, en citant la source du prix.
- Temps : hauteur de bloc et horodatage du bloc en UTC. La hauteur ordonne les événements de manière fiable ; les horodatages sont approximatifs (leçon 2.1).
- Identité : empreinte de transaction accompagnée de l’indice de sortie (UTXO), ou de l’indice de journal ou de la position dans la trace (modèle de comptes), afin que l’arête soit unique et puisse être vérifiée auprès d’un nœud.
- Actif : cryptomonnaie native ou adresse du contrat du jeton. N’additionnez jamais des arêtes portant sur des actifs différents.
Deux adresses peuvent être reliées par de nombreuses arêtes à des moments différents (un multigraphe). Les agréger en une seule arête « total envoyé » convient à un graphique, mais détruit l’ordre dont dépend le traçage : des fonds arrivés après un paiement ne peuvent pas l’avoir financé.
D’une transaction UTXO aux arêtes
Prenons une transaction Bitcoin décodée 4f3a…c21e au bloc 871 204, enrichie de l’adresse et de la valeur de chaque sortie dépensée (les entrées brutes ne font référence qu’à un outpoint ; un indexeur ou une seconde recherche fournit donc ces champs) :
| Côté | Référence | Adresse | Valeur (BTC) |
|---|---|---|---|
| Entrée | 9b1e…04aa:1 | bc1q…7k3f | 0,60000000 |
| Entrée | c07d…e912:0 | bc1q…m2pz | 0,50000000 |
| Sortie 0 | 4f3a…c21e:0 | bc1q…x9td | 0,80000000 |
| Sortie 1 | 4f3a…c21e:1 | bc1q…h4wa | 0,29000000 |
Les entrées totalisent 1,10 BTC et les sorties 1,09 BTC ; les frais s’élèvent donc à 0,01 BTC.
Dans le graphe de transactions, cela correspond à un nœud avec deux arêtes entrantes (les outpoints) et deux arêtes sortantes (les sorties) ; aucune hypothèse n’est nécessaire. Dans le graphe d’adresses, Bitcoin n’indique pas quelle entrée a payé quelle sortie, car les entrées sont mises en commun. Relier chaque entrée à chaque sortie donne quatre arêtes (2 entrées × 2 sorties), et vous devez choisir leurs poids. Le choix courant est l’allocation proportionnelle : la première entrée a fourni 0,60 ÷ 1,10 = 54,55 % de la valeur ; on lui attribue donc 54,55 % de chaque sortie, et 45,45 % à la seconde.
| Arête | Calcul | Poids (BTC) |
|---|---|---|
| bc1q…7k3f → bc1q…x9td | 0,80 × 0,5455 | 0,4364 |
| bc1q…7k3f → bc1q…h4wa | 0,29 × 0,5455 | 0,1582 |
| bc1q…m2pz → bc1q…x9td | 0,80 × 0,4545 | 0,3636 |
| bc1q…m2pz → bc1q…h4wa | 0,29 × 0,4545 | 0,1318 |
La somme des poids est de 1,09 BTC ; les frais quittent le graphe (certains analystes ajoutent un nœud puits « frais » afin de conserver la valeur). Une transaction à 50 entrées et 50 sorties créerait 2 500 arêtes de ce type, ce qui explique pourquoi les consolidations et les paiements par lots submergent les graphes d’adresses. Déterminer si bc1q…h4wa est un paiement ou une sortie de monnaie rendue constitue une inférence distincte (leçon 4.2), et la pondération proportionnelle n’est qu’une règle d’allocation parmi d’autres (leçon 3.3).
Des données du modèle de comptes aux arêtes
Sur les blockchains de type Ethereum, les arêtes proviennent de trois sources, et un graphe construit à partir d’une seule d’entre elles omettra des fonds :
- Transactions de premier niveau dont le champ
valueest non nul : du signataire vers l’adresseto. - Transferts internes de cryptomonnaie native effectués par les contrats pendant l’exécution, qui n’apparaissent que dans les traces (cadres
callavec une valeur). - Transferts de jetons, décodés à partir des journaux : un événement ERC-20
Transfer(address,address,uint256)a pour topic00xddf252ad…b3ef, l’expéditeur et le destinataire dans les topics 1 et 2, et le montant brut dans le champ de données.
Excluez les transactions annulées (champ status du reçu = 0) et les cadres de trace annulés : ils n’ont déplacé aucun fonds, même si l’expéditeur a tout de même payé le gaz. Traitez les contrats comme des nœuds étiquetés, car un routeur DEX ou un contrat de jeton est un mécanisme, pas une contrepartie. Un échange d’actifs produit généralement deux arêtes portant sur des actifs différents, utilisateur → pool et pool → utilisateur (leçon 5.2).
La plupart des travaux sur les graphes commencent par une liste d’arêtes à plat dans un entrepôt de données, construite à partir du schéma générique de la leçon 2.7 et enregistrée dans une table edges que réutilisent les requêtes de ce module et du suivant :
-- Liste d’arêtes (enregistrée dans edges) : ETH natif issu des traces et transferts ERC-20
SELECT block_number, block_timestamp, transaction_hash,
from_address AS src, to_address AS dst,
'ETH' AS asset, value / 1e18 AS amount -- wei vers ETH
FROM traces
WHERE value > 0
AND (call_type IS NULL OR call_type = 'call') -- ni delegatecall ni staticcall
AND status = 1 AND tx_status = 1 -- cadres réussis uniquement
AND block_number BETWEEN 21000000 AND 21050000
UNION ALL
SELECT tt.block_number, tt.block_timestamp, tt.transaction_hash,
tt.from_address, tt.to_address,
tt.token_address, tt.amount_raw / POWER(10, tk.decimals)
FROM token_transfers AS tt
JOIN tokens AS tk ON tk.token_address = tt.token_address -- décimales par jeton
WHERE tt.block_number BETWEEN 21000000 AND 21050000;
La partie consacrée aux traces inclut les appels de premier niveau ainsi que les appels internes ; elle n’a donc pas besoin de la table transactions. UNION ALL conserve les lignes d’apparence identique, qui sont des transferts réels et distincts, et la plage de blocs commune maintient le résultat dans des limites définies et le rend reproductible. La jointure interne élimine silencieusement les jetons absents de tokens ; comparez les nombres de lignes (la leçon 2.9 couvre les filtres de traces, la leçon 2.8 les jointures).
Choix pratiques avant le traçage
- Délimitez le graphe. Fixez un point de départ, une fenêtre temporelle et une limite de sauts avant de lancer la requête ; une expansion sans limite atteint toutes les plateformes d’échange en quelques sauts et cesse d’avoir une valeur probante.
- Marquez les supernœuds. Les portefeuilles à chaud des plateformes d’échange, les ponts et les contrats populaires comptent des millions d’arêtes ; signalez-les comme points d’arrêt.
- Adaptez le stockage à la question. Les listes d’arêtes SQL conviennent à l’agrégation et au filtrage ; les bases de données de graphes et les bibliothèques telles que NetworkX ou igraph conviennent à la recherche de chemins et à la centralité. De nombreuses équipes exportent donc un sous-graphe délimité vers un outil de graphes.
- Conservez la provenance de chaque arête : txid, indice, hauteur de bloc et requête qui l’a produite, afin qu’un autre analyste puisse reconstruire le même graphe.
Degré et flux de valeur
Les métriques les plus simples sont des dénombrements et des sommes par nœud, calculés sur une fenêtre temporelle fixe et pour un seul actif :
- Degré entrant : nombre de contreparties distinctes ayant envoyé des fonds au nœud. Degré sortant : nombre de contreparties auxquelles il en a envoyé.
- Degré pondéré : valeur totale reçue et envoyée.
- Ratio de transit : valeur sortante ÷ valeur entrante sur la fenêtre. Un ratio proche de 1, associé à une courte durée de détention, signale un intermédiaire qui retransmet ce qu’il reçoit plutôt que de le conserver.
- Période d’activité et durée de détention : première et dernière activités, et temps écoulé entre la réception et l’envoi.
Ces seules métriques permettent de distinguer de nombreux rôles. Un portefeuille personnel a un faible degré et conserve les fonds pendant des semaines. Une adresse de dépôt de plateforme d’échange présente quelques flux entrants provenant de différents expéditeurs et des flux sortants vers une destination unique, le portefeuille de collecte. Un portefeuille à chaud présente des degrés de plusieurs dizaines de milliers. Un intermédiaire de blanchiment présente souvent un degré entrant de 1, un degré sortant de 2 à 20, un ratio de transit proche de 1 et une durée de détention de quelques minutes. La requête ci-dessous dresse un profil à partir d’un mois d’arêtes en cryptomonnaie native.
WITH io AS ( -- une ligne par côté de chaque arête
SELECT dst AS address, src AS peer, amount AS amt_in, 0 AS amt_out, block_timestamp AS ts
FROM edges WHERE asset = 'ETH'
UNION ALL
SELECT src, dst, 0, amount, block_timestamp
FROM edges WHERE asset = 'ETH'
)
SELECT address,
COUNT(DISTINCT CASE WHEN amt_in > 0 THEN peer END) AS in_degree,
COUNT(DISTINCT CASE WHEN amt_out > 0 THEN peer END) AS out_degree,
SUM(amt_in) AS value_in, SUM(amt_out) AS value_out,
SUM(amt_out) / NULLIF(SUM(amt_in), 0) AS pass_through,
MIN(ts) AS first_seen, MAX(ts) AS last_seen
FROM io
WHERE ts >= TIMESTAMP '2026-03-01' AND ts < TIMESTAMP '2026-04-01'
GROUP BY address
HAVING COUNT(DISTINCT CASE WHEN amt_out > 0 THEN peer END) >= 20;
La CTE transforme chaque arête en une ligne pour le destinataire et une ligne pour l’expéditeur, de sorte qu’un seul GROUP BY fournit les deux directions ; NULLIF évite la division par zéro, et HAVING conserve les nœuds à forte dispersion. La fenêtre ne montre que l’activité qui s’y déroule : une adresse alimentée en février affiche un ratio de transit très supérieur à 1 en mars.
Centralité
La centralité mesure l’importance d’un nœud dans la structure du graphe, et pas seulement son niveau d’activité.
| Métrique | Ce qu’elle mesure | Usage typique |
|---|---|---|
| Centralité de degré | Nombre de connexions directes | Repérer les pôles et les services |
| Centralité d’intermédiarité | Fréquence à laquelle le nœud se trouve sur les plus courts chemins entre d’autres nœuds | Repérer les intermédiaires et les goulets d’étranglement entre des groupes autrement séparés |
| PageRank | Importance héritée de voisins importants | Classer les nœuds dans de grands graphes de flux |
Dans un sous-graphe d’enquête, une adresse ayant une forte intermédiarité mais un degré modeste est souvent le nœud le plus intéressant : l’adresse collectrice vers laquelle revient chaque chemin de dispersion, ou le seul lien entre un regroupement lié à un vol et les plateformes d’échange utilisées pour convertir ses fonds en monnaie fiduciaire. Calculez la centralité sur un sous-graphe délimité en prenant les services comme points terminaux ; sur l’ensemble de la blockchain, les plateformes d’échange et les contrats populaires dominent tous les classements. Les bibliothèques de graphes calculent ces métriques ; le SQL seul permet de calculer le degré, mais pas l’intermédiarité.
Schémas : dispersion, convergence et chaînes d’épluchage
La dispersion correspond à un nœud qui envoie des fonds à de nombreux autres sur une courte période ; la convergence correspond à de nombreux nœuds qui envoient des fonds vers un seul. Toutes deux sont normales (retraits par lots, collectes, paiements de minage, distributions gratuites de jetons) ; les questions portent sur l’identité des parties et sur ce qui se produit ensuite :
- Dispersion des fonds : une adresse liée à un vol disperse des montants similaires vers des dizaines de nouvelles adresses sans historique préalable. La similitude des montants et la nouveauté des destinataires distinguent ce schéma d’un paiement d’entreprise.
- Collecte : de nombreuses victimes d’escroquerie paient une même adresse (convergence), qui retransmet ensuite le total.
- Consolidation : dans les blockchains UTXO, une transaction de convergence qui dépense ensemble de nombreuses sorties constitue aussi un indice de regroupement (leçon 4.1).
Une chaîne d’épluchage, décrite dans l’étude de 2013 « A Fistful of Bitcoins » de Meiklejohn et ses collègues, commence par un montant important sur une adresse. Chaque transaction en détache un petit paiement et envoie le reliquat important vers une nouvelle adresse, qui répète le processus. Avec des frais de 0,01 BTC par étape :
| Étape | Entrée | Montant détaché | Reliquat (monnaie rendue) |
|---|---|---|---|
| T1 | 50,00 | 1,20 → dépôt sur une plateforme d’échange | 48,79 |
| T2 | 48,79 | 0,80 → dépôt sur une plateforme d’échange | 47,98 |
| T3 | 47,98 | 2,50 → courtier OTC | 45,47 |
| T4 | 45,47 | 0,95 → dépôt sur une plateforme d’échange | 44,51 |
Signes : une entrée et deux sorties par transaction ; une sortie beaucoup plus importante et rapidement dépensée dans une transaction de même structure ; le même type de script et les mêmes empreintes caractéristiques de portefeuille ; des sauts espacés de quelques minutes ou de quelques blocs. Une étude de 2023 de Gong, Chow, Yiu et Ting (« Analyzing the Peeling Chain Patterns on the Bitcoin Blockchain ») a constaté qu’environ 71 % des transactions des chaînes identifiées détachaient moins de 1 % de l’entrée, et qu’environ 79 % des chaînes étaient créées en l’espace d’une journée. Le reliquat porte l’essentiel de la valeur ; l’analyste le suit donc et consigne chaque montant détaché comme un point de conversion en monnaie fiduciaire. Cette forme n’est pas intrinsèquement illicite : un portefeuille qui paie des factures à partir d’un solde important, ou un portefeuille à chaud qui règle les retraits un par un, présente le même aspect.
Empilement, cycles et motifs
L’empilement, étape du blanchiment qui éloigne les fonds de leur origine, apparaît sur la blockchain sous forme de longues chaînes de nouvelles adresses à courte durée de vie, de sauts automatisés rapides, de divisions et de regroupements des fonds, d’échanges d’actifs et de passages entre blockchains. Aucun saut pris isolément n’est suspect ; c’est leur combinaison qui l’est. Un aller-retour de fonds correspond à une valeur qui revient à son nœud, ou à un autre nœud de la même partie : un cycle. Les cycles courts peuvent gonfler le volume de négociation d’un jeton ou d’un NFT (transactions fictives, ou wash trading), fabriquer un historique de paiements ou recycler des fonds par l’intermédiaire d’un service. La détection des cycles fonctionne mieux sur un graphe d’entités, car une partie qui renvoie des fonds vers une autre de ses propres adresses ne forme un cycle qu’après regroupement.
Un motif est une petite forme de sous-graphe qui se répète plus souvent que ne le prédit le hasard. Un jeu de données synthétiques largement utilisé pour entraîner des modèles de lutte contre le blanchiment (Altman et ses collègues, NeurIPS 2023) en génère huit : dispersion, convergence, convergence-dispersion, dispersion-convergence, cycle, biparti, empilement de couches et aléatoire. Dans une dispersion-convergence, une source répartit les fonds entre des intermédiaires qui les retransmettent tous vers une même destination, ajoutant des sauts sans changer la propriété ; une convergence-dispersion correspond à de nombreuses sources convergeant vers un nœud qui disperse le total, ce qui est typique d’une adresse de collecte d’escroquerie ; un empilement de couches correspond à deux couches d’intermédiaires entièrement connectées entre elles. Les recherches de motifs prennent la forme de requêtes de motifs dans une base de données de graphes ou d’auto-jointures soumises à des contraintes temporelles sur la liste d’arêtes. La fenêtre temporelle est le paramètre clé : une dispersion-convergence en une heure constitue un signal fort ; sur un an, elle relève du commerce quotidien.
Des signaux, pas des conclusions
Les arêtes sont des faits enregistrés ; les rôles, les schémas et les motifs sont des interprétations pouvant avoir des explications innocentes. Traitez chacun comme une raison d’examiner la situation de plus près, combinez des signaux indépendants avant de tirer une inférence et consignez les seuils utilisés (seuils de degré, fenêtres temporelles, tolérances sur les montants) afin qu’un autre analyste puisse les reproduire et les contester.
Points clés pour l’examen : la différence entre les graphes de transactions, d’adresses et d’entités et les usages de chacun ; pourquoi le graphe de dépenses UTXO est exact alors que le graphe d’adresses nécessite une hypothèse d’allocation ; le calcul des poids proportionnels des arêtes pour une transaction à plusieurs entrées et plusieurs sorties ; les attributs nécessaires à chaque arête et la raison pour laquelle les arêtes parallèles conservent leurs horodatages ; les trois sources d’arêtes du modèle de comptes et la raison de l’exclusion des transferts annulés ; la délimitation d’un graphe et le traitement des supernœuds comme points d’arrêt ; le degré, le ratio de transit et la durée de détention comme indicateurs de rôle ; l’intermédiarité sur un sous-graphe délimité ; la convergence, la dispersion, les chaînes d’épluchage (et la raison pour laquelle le reliquat est suivi), les cycles et les motifs de dispersion-convergence comme signaux nécessitant une corroboration et des seuils documentés.
Questions d’entraînement
Vérifiez votre compréhension. Ces questions ne comptent pas pour l’examen.
Connectez-vous pour enregistrer votre progression et reprendre là où vous vous êtes arrêté. C’est gratuit. Se connecter