Il s'agit du deuxième article de notre série « Prédateurs dans les pools : L'art et les mathématiques de la liquidité JIT ». Ici, nous passons de la théorie du « vol » au calcul froid : comment un algorithme décide en 200 millisecondes s'il vaut la peine d'entrer en jeu.
Si le premier article portait sur « ce que c'est », celui-ci traite de « combien ça coûte ». Pour qu'une attaque JIT ne se transforme pas en charité au profit des mineurs/validateurs, le bot doit résoudre une équation à cinq inconnues plus vite que le bloc n'est miné.
1. Liquidité (L) : la variable principale
Dans Uniswap v3, la liquidité n'est pas juste une somme de tokens, mais le facteur L qui détermine combien d'actifs se déplacent lorsque le prix change. Formule du swap (invariant) :

Pour un bot JIT, il est crucial de calculer quelle part du L total dans une plage de prix donnée (tick) il doit occuper.
Formule de la part de commission (Fshare) :
Fshare = Ljit / Lpool + Ljit
Où :
- Ljit — liquidité apportée par le bot.
- Lpool — liquidité passive existante des LP dans le tick ciblé.
Règle pratique : Pour capter 95 % des commissions, la liquidité du bot doit être 19 fois supérieure à la liquidité actuelle du pool dans cette plage.
2. Calcul du profit du swap (Gross Profit)
Le bot voit une transaction utilisateur d’un montant S dans le mempool. Connaissant le niveau de commission du pool ($\phi$, par exemple 0,05 % ou 0,3 %), il calcule le total des frais de transaction :

Profit brut attendu pour le bot (Pgross) :

3. Prise en compte de la « taxe gas » (coûts opérationnels)
Contrairement à un LP passif qui paie le gas une seule fois pour plusieurs mois, un bot JIT paie le gas deux fois dans un même bloc (ou une transaction coûteuse avec plusieurs appels).
Coûts en gas (Cgas) :
mint(): ~150k–200k gas.decreaseLiquidity()+collect(): ~120k–180k gas.- Plus la fee prioritaire pour Flashbots pour garantir l'inclusion dans le bloc.
Sur Ethereum Mainnet, avec un gas à 30 gwei, les coûts totaux peuvent être de $50–$150. Sur L2 (Arbitrum/Polygon), les coûts sont minimes ($0,10–$0,50), mais la concurrence pour les micro-swaps est plus élevée.
4. Calcul du point d’équilibre (Break-even Point)
L'attaque n'a de sens que si :

Où Cslippage est la perte lors du retrait de liquidité (impermanent loss pendant un swap unique) et Copportunity est le coût du capital (par exemple, intérêts sur un Flash Loan).
Petit détail peu connu : Les bots expérimentés prennent en compte le « Shadow Slippage ». Quand un bot injecte une grande liquidité, le prix devient plus « rigide ». Si le swap utilisateur est très grand, le bot peut injecter moins de liquidité pour que le prix bouge plus, planifiant un arbitrage dans le bloc suivant. Mais pour un JIT pur — plus de liquidité est toujours mieux.
5. Exemple pratique de calcul (Mainnet)
- Pool : ETH/USDC (0,05 %)
- Swap utilisateur : $500,000.
- Lpool actuel dans le tick : $2,000,000.
- Bot injecte Ljit : $18,000,000.
- Commission totale : $500,000 x 0.0005 = $250.
- Part du bot : 18M / 18M + 2M = 90%.
- Revenu du bot : $250 x 0.9 = $225.
- Coût du gas : $120 (conditions moyennes).
- Profit net : $225 - $120 = $105 par bloc.
Cela semble peu ? Les meilleurs bots réalisent 500–1000 attaques de ce type par jour. Soit $50,000–$100,000 de profit net par jour avec presque aucun risque de marché.
6. Nuance technique : choix de la largeur du tick
Le bot ne choisit jamais une plage large. Plus la plage (ticks) est étroite, plus la concentration du capital est élevée et plus L est important pour la même quantité de tokens.
Standard JIT : tickLower et tickUpper avec un écart d’un pas minimum (par exemple, 10 points pour un pool à 0,05 %).
Calcul de la liquidité à partir des montants de tokens (TypeScript/Ethers) :
import { LiquidityAmounts } from '@uniswap/v3-sdk';
import { JSBI } from '@uniswap/sdk-core';
function calculateJitLiquidity(amount0, amount1, currentPrice, tickLower, tickUpper) {
const sqrtRatioX96 = encodePriceSqrt(currentPrice);
const sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
const sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
return LiquidityAmounts.getLiquidityForAmounts(
sqrtRatioX96,
sqrtRatioAX96,
sqrtRatioBX96,
amount0,
amount1,
false
);
}
Résumé de l'article
Les mathématiques JIT sont une bataille pour l'efficacité. Si vous voyez qu’un pool à 1 % de commission chute soudainement en rendement — vérifiez le mempool. Très probablement, un bot a calculé que son $L$ est 50 fois plus efficace que le vôtre.
Dans le prochain article : Nous passerons des formules au hardware et au code. Nous analyserons l’architecture du smart contract qui exécute ces calculs en temps réel et découvrirons pourquoi Rust a surpassé tous les autres langages dans ce domaine.
Maîtrise de la Liquidité JIT : Le Guide Complet du MEV sur Uniswap : Partie 2 sur 5