Interchaînes, DeFi et contrats intelligents · Leçon 2 sur 6
Swaps sur les DEX, plateformes d'échange instantané et flux de liquidité
15 min de lecture
Presque toute piste de blanchiment comporte un changement d'actif à un moment donné, et la manière dont il s'effectue détermine la solidité du lien suivant. Un swap sur une plateforme d'échange décentralisée (DEX) est enregistré dans une seule transaction, avec l'événement du pool, les transferts de jetons et les réserves avant et après. Un protocole de swap interchaînes peut inscrire la destination sur la chaîne source et la source sur la chaîne de destination. Un service de plateforme d'échange instantané ou un bureau OTC ne laisse qu'un dépôt d'un côté et un versement de l'autre. Cette leçon montre comment interpréter chaque type de swap comme élément de preuve, ce que révèlent les événements de liquidité, quels enregistrements existent hors chaîne et ce que vous pouvez affirmer au sujet de chaque lien. Le décodage général est abordé dans la leçon 5.1, le rapprochement des étapes entre chaînes dans la leçon 5.3 et les ponts dans la leçon 5.4.
Interpréter un swap sur un DEX
Pools, token0 et token1
Une paire de type Uniswap v2 est un contrat qui détient deux jetons. Le jeton dont l'adresse est la plus basse est token0 et l'autre token1 ; cet ordre est fixé à la création et n'a rien à voir avec le jeton qui représente « le prix ». Chaque événement indique les montants dans cet ordre : vérifiez donc token0, token1 et le nombre de décimales de chacun avant toute conversion.
L'événement v2 est Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to), avec topic0 0xd78ad95f…d822. Après chaque modification des réserves, la paire émet également Sync(uint112 reserve0, uint112 reserve1). Voici un swap décodé dans une paire où token0 est USDC (6 décimales) et token1 est WETH (18 décimales) :
{
"event": "Swap",
"pair": "0x3f8a…e2d1",
"sender": "0x7a2c…48d0",
"to": "0xa1b2c3d4…9f0e",
"amount0In": "0",
"amount1In": "5000000000000000000",
"amount0Out": "14880819116",
"amount1Out": "0",
"next_log": {"event": "Sync", "reserve0": "2985119180884", "reserve1": "1005000000000000000000"}
}
Cinq WETH sont entrés et 14 880,819116 USDC sont sortis, soit un prix d'exécution de 2 976,16 USDC par WETH. Le champ sender désigne généralement un routeur, et non le trader, et to indique où les fonds de sortie ont été envoyés ; confirmez l'identité du trader à partir des transferts de jetons de la même transaction.
Autres modèles de pools
Les pools Uniswap v3 émettent Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick), avec topic0 0xc42079f9…ca67, et des montants signés du point de vue du pool : positifs pour les entrées dans le pool, négatifs pour les sorties. Un swap de 2 WETH contre des USDC affiche amount0 = -5994120000 (5 994,12 USDC en sortie) et amount1 = 2000000000000000000 (2 WETH en entrée). Le prix après le swap est price_raw = (sqrtPriceX96 ÷ 2^96)², en unités de base de token1 par unité de base de token0, multiplié par 10^(decimals0 − decimals1). Pour sqrtPriceX96 = 1446501726624926496477173928747177, price_raw ≈ 333 333 333,33 ; multiplié par 10^−12, cela donne 0,000333333 WETH par USDC, soit 3 000 USDC par WETH (tick ≈ 196 256, puisque price_raw = 1,0001^tick). Omettre l'ajustement des décimales donne un prix erroné d'un facteur 10^12.
Uniswap v4 (2025) conserve tous les pools dans un unique PoolManager, de sorte que le champ address du journal n'identifie plus le pool ; c'est le champ indexé id du pool qui le fait. Son événement Swap (topic0 0x40e9cecb…112f) utilise des montants signés du point de vue de l'utilisateur, à l'inverse de v3. Les pools Curve émettent TokenExchange avec des index de jetons. Conservez un décodeur par protocole et par version, testé sur une transaction dont vous connaissez le résultat.
Quatre règles pour le traçage
- Le lien est déterministe, l'actif change. L'entrée et la sortie figurent dans la même transaction. Consignez les deux montants, le taux effectif et, pour une valeur en monnaie fiduciaire, la source du cours et l'heure. Quelle que soit la méthode de traçage appliquée (leçon 3.3), la sortie du swap est le produit de son entrée.
- Le pool n'est pas une contrepartie. Un pool de liquidité est un contrat qui détient les fonds de nombreux fournisseurs. Les fonds ne « vont » pas au propriétaire du pool ; suivez la sortie, pas le pool.
- Le destinataire peut différer de l'expéditeur. Les routeurs et les agrégateurs acceptent un paramètre de destinataire, de sorte que la sortie peut être versée à une nouvelle adresse dans la même transaction. Lisez l'appel décodé ou les transferts ; ne supposez jamais que l'appelant a reçu la sortie.
- Calculez le bilan net du parcours. Un agrégateur répartit un ordre entre plusieurs pools dans une seule transaction. Ce qui a quitté le sujet et ce qui est parvenu au destinataire constituent les faits ; le parcours relève du détail.
Les contrats des DEX n'ont pas d'opérateur qui conserve des enregistrements, mais l'interface utilisée par un sujet peut en avoir un : les interfaces web et les API d'agrégateurs peuvent journaliser les adresses IP, les agents utilisateurs et les demandes de cotation, et les applications de portefeuille peuvent acheminer les swaps par leurs propres API. La durée de conservation dépend de l'opérateur.
Calculer le bilan net d'un parcours d'agrégateur
| logIndex | Jeton | De | À | Montant |
|---|---|---|---|---|
| 10 | WETH | Trader | Routeur | 10 |
| 11 | WETH | Routeur | Pool A (WETH/USDC) | 6 |
| 12 | USDC | Pool A | Routeur | 17 880 |
| 13 | WETH | Routeur | Pool B (WETH/DAI) | 4 |
| 14 | DAI | Pool B | Pool C (DAI/USDC) | 11 930 |
| 15 | USDC | Pool C | Routeur | 11 925 |
| 16 | USDC | Routeur | Trader | 29 805 |
Le calcul du bilan net des entrées et sorties de chaque adresse ramène l'ensemble à un seul constat : le trader a vendu 10 WETH contre 29 805 USDC, soit une moyenne de 2 980,50 USDC par WETH. Le solde net du routeur est nul et celui de chaque pool correspond à sa propre variation de réserves.
-- Variation nette des jetons par adresse au sein d'une transaction
SELECT address, token_address, SUM(delta) AS net_raw
FROM (
SELECT to_address AS address, token_address, amount_raw AS delta
FROM token_transfers WHERE transaction_hash = '0x9e1d…b7a4'
UNION ALL
SELECT from_address, token_address, -amount_raw
FROM token_transfers WHERE transaction_hash = '0x9e1d…b7a4'
) t
GROUP BY address, token_address
HAVING SUM(delta) <> 0;
Les étapes en ETH natif doivent être ajoutées à partir des traces. Dans les systèmes fondés sur les intentions, c'est un solveur, et non l'utilisateur, qui envoie la transaction : tx.from désigne donc le solveur ; retrouvez l'utilisateur à partir des événements de négociation et des transferts du contrat de règlement.
Flux de liquidité, impact sur le prix et MEV
Ajouts et retraits
Ajouter des fonds volés à un pool puis les retirer ultérieurement n'est pas un swap : le déposant reçoit un jeton LP ou une position, et le retrait restitue sa quote-part. Suivez la position, pas le solde du pool.
| Protocole | Ajout | Retrait | Enregistrement de propriété |
|---|---|---|---|
| Uniswap v2 | Mint(sender, amount0, amount1) et Transfer de jetons LP depuis l'adresse zéro | Jetons LP envoyés à la paire, Burn(sender, amount0, amount1, to), Transfer de jetons LP vers l'adresse zéro | Jeton LP fongible (le contrat de la paire) |
| Uniswap v3 | Mint du pool avec une plage de ticks ; IncreaseLiquidity sur le gestionnaire de positions | Burn du pool (crédite les jetons), puis Collect (les verse) ; DecreaseLiquidity | NFT de position (ERC-721) |
| Uniswap v4 | ModifyLiquidity dans le PoolManager | Même événement, variation de liquidité négative | Enregistrements de position, souvent un NFT |
Deux pièges : en v3, le Mint du pool indique le gestionnaire de positions comme propriétaire ; suivez donc le NFT de position jusqu'au véritable fournisseur ; de plus, un Burn v3 ne déplace aucun jeton, les fonds sortent lors de Collect. Un rug pull classique est le fait d'un déployeur qui crée un jeton, ajoute de la liquidité, attend les acheteurs, puis retire presque toute la liquidité en une seule transaction ; les montants de Burn ou de DecreaseLiquidity mesurent ce qui a été emporté.
Impact sur le prix
L'impact sur le prix compare le prix d'exécution au prix au comptant du pool juste avant l'opération. Pour une paire v2, les réserves avant le swap sont égales aux réserves de son événement Sync, moins les entrées, plus les sorties. Dans le swap ci-dessus : 2 985 119,18 + 14 880,82 = 3 000 000 USDC et 1 005 − 5 = 1 000 WETH, soit un prix au comptant de 3 000.
| Mesure | Valeur |
|---|---|
| Prix au comptant avant | 3 000,00 USDC par WETH |
| Prix d'exécution | 2 976,16 (−0,79 %) |
| Sortie sans les frais de 0,30 % | 14 925,37, prix de 2 985,07 (−0,50 %) |
| Prix au comptant après (d'après Sync) | 2 970,27 (−0,99 %) |
Sur l'écart de 0,79 %, environ 0,30 % correspond aux frais et 0,50 % à l'impact pur sur le prix ; le prix au comptant a varié d'environ deux fois l'écart du prix moyen payé, ce qui est normal pour les pools à produit constant. Un impact important sur un pool peu liquide signale une vente forcée, par exemple lorsqu'un attaquant liquide un jeton volé.
Schémas de MEV
La valeur maximale extractible (MEV) présente des schémas reconnaissables. Dans une attaque sandwich, au sein d'un même bloc et d'un même pool, l'acteur X achète le jeton T, une victime achète T, puis X revend T immédiatement après, en rémunérant souvent directement le constructeur du bloc (un transfert d'ETH au destinataire des frais, visible dans les traces) ; définissez l'acteur comme le contrat du bot ayant reçu la sortie, car les bots changent d'adresses d'envoi. L'arbitrage atomique effectue des swaps selon un cycle de pools (WETH → USDC → DAI → WETH) dans une seule transaction et se termine avec davantage du jeton initial. La liquidité juste à temps (JIT) correspond à un Mint v3 juste avant un swap important, suivi d'un Burn et d'un Collect juste après, par une seule adresse. Les détections ne sont que des cas possibles : vérifiez les quantités et le bénéfice, et écartez les explications innocentes, comme deux arbitragistes sans lien entre eux.
Protocoles de swap interchaînes : les mémos comme éléments de preuve
Les protocoles de swap interchaînes échangent des actifs natifs entre chaînes par l'intermédiaire de coffres contrôlés par les nœuds du protocole. THORChain est l'exemple de référence, et ses enregistrements sont particulièrement utiles, car les deux côtés portent un texte qui désigne l'autre.
Du côté entrant, l'utilisateur envoie l'actif au coffre du protocole : sur les chaînes EVM, par un contrat de routeur qui consigne le mémo dans son événement de dépôt ; sur Bitcoin, dans une sortie OP_RETURN, que la documentation du protocole limite à 80 octets. Le format du mémo de swap est SWAP:ASSET:DESTADDR/REFUNDADDR:LIMIT/INTERVAL/QUANTITY:AFFILIATE:FEE (l'adresse de remboursement est facultative), généralement abrégé avec = pour un swap au marché. Du côté sortant, le coffre verse l'actif de destination dans une transaction dont le mémo est OUT: suivi du hachage de la transaction entrante ; un swap échoué est remboursé avec un mémo REFUND: contenant le même hachage. Voici une paire fictive :
Ethereum (entrant, fictif)
tx 0x9a3f…c21e de 0x3f9c…a1d7 vers routeur de swap 130.0 ETH
mémo de l'événement de dépôt "=:BTC.BTC:bc1q…r7w2::xx:20"
Bitcoin (sortant, fictif)
txid 6d0b…e45a depuis le coffre bc1q…v9tn
vout 0 5.16800000 BTC bc1q…r7w2
vout 1 OP_RETURN "OUT:9A3F…C21E"
Le mémo entrant désigne le destinataire Bitcoin ; le mémo sortant désigne la transaction Ethereum. La paire peut être vérifiée sur les deux chaînes à partir de vos propres nœuds, et les enregistrements publics du protocole fournissent une troisième confirmation indépendante. Trois détails sont importants :
- Temporalité. Les swaps progressifs s'exécutent sous forme de sous-swaps sur plusieurs blocs, et les swaps à cours limité peuvent, par défaut, attendre dans une file jusqu'à 43 200 blocs du protocole (environ trois jours). Définissez les fenêtres temporelles à partir des paramètres du mémo.
- Affiliés. Le champ d'affilié désigne, par un nom court enregistré, l'interface ou le portefeuille qui a construit la transaction : une source possible de journaux, bien que le protocole lui-même n'en ait aucun.
- Mémos de référence. Pour économiser de l'espace dans le mémo, un mémo peut être enregistré à l'avance puis référencé, par exemple au moyen d'une référence encodée dans le montant ; les enregistrements expirent après la durée définie par le paramètre
MemolessTxnTTL, soit par défaut 3 600 blocs (environ six heures). Conservez l'enregistrement du mémo avec les transactions.
D'autres protocoles utilisent des champs différents, mais la méthode reste la même : trouvez ce que chaque côté indique au sujet de l'autre.
Services de plateformes d'échange instantané et bureaux OTC
Les services de plateformes d'échange instantané convertissent un actif en un autre sans compte : l'utilisateur fournit une adresse de versement, reçoit une nouvelle adresse de dépôt pour l'ordre, envoie les fonds et reçoit le versement, souvent sur une autre chaîne. Beaucoup se présentent comme non dépositaires parce qu'ils ne conservent aucun solde, mais ils contrôlent les fonds entre le dépôt et le versement, ce qui explique la rupture de la piste à cet endroit ; en outre, la conversion d'un actif virtuel en un autre pour un client ou pour son compte constitue une activité de prestataire de services d'actifs virtuels (VASP) selon la définition du GAFI utilisée dans la Recommandation 15. Sur la chaîne, ils ressemblent à n'importe quel service dépositaire : adresses de dépôt propres à chaque ordre, regroupements des fonds, versements depuis un portefeuille à chaud. Sans enregistrements, le lien dépôt-versement est une inférence fondée sur le montant et le temps (leçon 5.3) ; avec des enregistrements, il est documenté. Un service peut détenir :
| Enregistrement | Utilité probatoire |
|---|---|
| Identifiant de l'ordre, heure de création, actifs et taux proposé | Rattache une adresse de dépôt à un ordre |
| Adresse de dépôt et txid du dépôt | Confirme quel dépôt appartient à l'ordre |
| Adresse de versement et txid du versement | Transforme le lien inféré en lien consigné |
| Adresse de remboursement | Souvent un portefeuille contrôlé par le sujet ; permet de relier d'autres ordres |
| Adresse IP, agent utilisateur, paramètres de langue | Pistes d'attribution (leçon 4.7) |
| Adresse électronique ou coordonnées fournies à l'assistance | Identifiant permettant des démarches judiciaires complémentaires |
| Identifiant de partenaire ou d'affilié | Identifie le portefeuille ou le site web à l'origine de l'ordre |
| Indicateurs de risque, blocages et résultats de filtrage | Indique si le service a gelé l'ordre ou demandé des précisions à son sujet |
Demandez tous les ordres partageant l'adresse de versement, l'adresse de remboursement ou l'adresse IP sur la période, et pas seulement celui que vous avez trouvé : l'historique révèle souvent d'autres portefeuilles du sujet. Les adresses IP peuvent être celles de VPN et les coordonnées ne sont pas vérifiées. La coopération est souvent lente ; envoyez donc des demandes de conservation dès que le dépôt est identifié (leçon 1.4).
Un bureau OTC négocie des opérations hors chaîne et effectue les règlements depuis et vers ses propres adresses. Les étapes peuvent se trouver sur des chaînes différentes, ou l'une d'elles peut être un virement bancaire ; il n'existe donc souvent aucun lien sur la chaîne. Les enregistrements du bureau (vigilance à l'égard de la clientèle, confirmations d'opérations, instructions de règlement, journaux de discussion, coordonnées bancaires) sont alors le seul moyen de relier les étapes. Un courtier qui négocie au moyen d'un compte auprès d'une plateforme d'échange plus importante ajoute un intermédiaire : la plateforme d'échange ne voit qu'un seul client, le courtier (leçon 6.5).
Ce que vous pouvez affirmer au sujet de chaque lien de swap
| Éléments de preuve disponibles | Fondement du lien | Formulation dans un rapport |
|---|---|---|
| Swap sur un DEX dans une même transaction | Déterministe (grade A) | « Dans la transaction T, X a été échangé contre Y, qui a été versé à l'adresse B » |
| Mémo interchaînes sur les deux chaînes | Déterministe sur les deux chaînes (grade A), également consigné par le protocole | « Le protocole a versé Z à l'adresse B au titre de la transaction entrante A » |
| Plateforme d'échange instantané, montant et temps uniquement | Inférence (grade D) | « Compatible avec », en précisant le nombre de candidats et le taux de correspondances fortuites |
| Plateforme d'échange instantané avec enregistrement de l'ordre | Confirmé par un enregistrement (grade B) | « Selon les enregistrements du service, l'ordre N a versé Z à l'adresse B » |
| Bureau OTC, sans enregistrements | Aucun | « La destination de ces fonds n'est pas connue » |
Les grades sont ceux de la leçon 3.2. Un lien confirmé par un enregistrement n'est fiable qu'à la mesure de cet enregistrement : indiquez qui l'a produit, sa date de réception et le hachage du fichier tel qu'il a été reçu.
Points clés pour l'examen : ordre token0/token1 et décimales ; événements Swap et Sync de v2 ; montants signés de v3 (positifs pour les entrées dans le pool) et conversion de sqrtPriceX96 avec ajustement des décimales ; PoolManager, identifiant de pool et signe inversé de v4 ; swaps sur les DEX comme liens déterministes qui changent l'actif, pools ne constituant pas des contreparties et paramètres de destinataire ; calcul du bilan net d'un parcours d'agrégateur et raisons pour lesquelles tx.from peut être un routeur ou un solveur ; NFT de position, séquence Burn puis Collect et rug pulls ; impact sur le prix à partir des réserves ; signatures des attaques sandwich, de l'arbitrage et de la liquidité JIT ; mémos interchaînes, OUT: et REFUND: contenant le hachage entrant, temporalité des swaps, affiliés et mémos de référence ; plateformes d'échange instantané en tant que VASP et leurs enregistrements ; bureaux OTC sans lien sur la chaîne ; adaptation de la formulation au fondement de chaque lien.
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