# Comment gagner les concours d'audit de smart contracts
Les concours d'audit publics offrent la boucle de feedback la plus rapide et la plus brutale en securite. Vous lisez un code que le monde entier lit aussi, vous avez quelques jours, et vous n'etes paye que pour des findings uniques, valides et de haute severite. Ce guide propose un workflow qui transforme un effort disperse en classements reguliers, de votre premier concours a votre premiere place au leaderboard.
Fixez vos attentes avant de commencer
La plupart des debutants abandonnent apres un ou deux concours parce qu'ils esperaient gagner de l'argent tout de suite. La distribution des recompenses est tres asymetrique : un seul High pese plus que dix Lows, et les doublons partagent la cagnotte. Votre vrai objectif lors des dix premiers concours est la calibration : apprendre quels findings sont valides, lesquels sont du bruit, et comment les juges ponderent la severite. Considerez ces premiers concours comme de l'entrainement remunere.
La severite, dans la plupart des frameworks de concours, est une fonction de l'impact multiplie par la vraisemblance :
- High : perte directe ou blocage de fonds, ou etat clairement contraire au protocole, avec un chemin plausible.
- Medium : perte uniquement sous conditions specifiques, ou fonctionnalite centrale cassee sans vol direct.
- Low / Informational : qualite de code, aucun impact reel sur les fonds ou la logique. Cela rapporte rarement.
Si un bug ne peut pas se terminer par "et donc des fonds sont perdus, bloques ou voles", ce n'est probablement pas un High.
Phase 1 : cadrer vite (les deux premieres heures)
Ne commencez pas par la premiere ligne du plus gros fichier. Construisez d'abord une carte.
cloc ou solidity-metrics montrent ou se concentre la complexite.# carte de complexite rapide
cloc src/ --by-file
# compter les fonctions external et public, la surface d'attaque
grep -rEn 'function .*\b(external|public)\b' src/ | wc -l
A la fin de la phase un, vous devez pouvoir dire, en deux phrases, comment le protocole gagne et deplace de l'argent. Sinon, continuez la cartographie.
Phase 2 : chasser les bugs de haute severite
La generalite bat la lecture ligne par ligne. Parcourez le code a travers le prisme des classes de bugs recurrentes, car les memes erreurs reviennent d'un protocole a l'autre.
Les classes de bugs qui rapportent
- Comptabilite et arrondis. Division avant multiplication, calcul de frais qui arrondit dans le mauvais sens, manipulation du prix des parts dans les vaults (l'attaque classique d'inflation par le premier deposant sur ERC-4626).
- Failles de controle d'acces. Une fonction privilegiee sans modifier, un initializer appelable deux fois, une verification de role qui compare la mauvaise adresse.
- Reentrance, y compris read-only reentrancy. Etat lu en plein callback avant sa mise a jour. Les variantes cross-function et cross-contract sont la ou se trouve l'argent, pas le cas d'ecole mono-fonction.
- Oracle et manipulation de prix. Prix spot tire d'un seul pool AMM, pas de TWAP, pas de verification de fraicheur sur un price feed.
- Appels externes et valeurs de retour non verifies. Un token qui renvoie
falseau lieu de revert, uncallbas niveau dont le drapeau de succes est ignore.
- Slippage et deadline. Des swaps sans minimum-out ou avec un zero code en dur, exposant les utilisateurs au sandwiching.
Considerez ce pattern de vault realiste. Le bug est subtil et de haute severite :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Vault {
mapping(address => uint256) public shares;
uint256 public totalShares;
IERC20 public immutable asset;
constructor(IERC20 _asset) {
asset = _asset;
}
function deposit(uint256 amount) external returns (uint256 minted) {
uint256 totalAssets = asset.balanceOf(address(this));
// quand totalShares == 0, les parts sont emises 1:1
minted = totalShares == 0
? amount
: (amount * totalShares) / totalAssets;
shares[msg.sender] += minted;
totalShares += minted;
asset.transferFrom(msg.sender, address(this), amount);
}
}
Le finding : un attaquant depose 1 wei, recoit 1 part, puis transfere directement un gros montant de l'asset au vault. Maintenant totalAssets est enorme alors que totalShares vaut 1. Le prochain deposant honnete calcule minted = (amount * 1) / totalAssets, qui arrondit a zero part pour un depot reel, offrant ses fonds a l'attaquant. Le correctif : emettre des dead shares a la construction, ou suivre totalAssets en interne plutot que lire balanceOf.
Comment les trouver concretement
- Pour chaque fonction externe, demandez-vous : que se passe-t-il si je l'appelle avec zero, avec max uint, deux fois dans la meme transaction, ou hors de l'ordre prevu ?
- Suivez chaque
transferet chaquecall. Verifiez que la valeur de retour est controlee et que l'etat est mis a jour avant l'appel externe.
- Ecrivez une propriete et tentez de la casser avec un fuzzer. Les invariant tests de Foundry sont excellents pour les bugs de comptabilite :
function invariant_totalSharesBackedByAssets() public view {
// la valeur rachetable totale ne doit jamais depasser les assets detenus
assertLe(vault.totalShares(), asset.balanceOf(address(vault)) + 1);
}
Un test proof-of-concept qui passe transforme un "peut-etre" en High. Les juges recompensent les findings qu'ils peuvent executer.
Phase 3 : rediger des rapports que les juges recompensent
Un bug correct avec une redaction faible est retrograde ou marque comme doublon d'un mieux ecrit. Structurez chaque finding de la meme maniere :
Ecrivez pour un lecteur fatigue. Enoncez l'impact des la premiere ligne, ne l'enterrez jamais. Evitez la speculation : si vous ne pouvez pas demontrer la perte, dites-le honnetement et auto-retrogradez plutot que de risquer un marquage "invalid" qui abime votre score de precision.
Gestion du temps sur la duree du concours
Un concours d'une semaine est un marathon avec un sprint a la fin.
- Jour 1 : cadrage et cartographie uniquement. Aucun finding pour l'instant.
- Jours 2 a 4 : plongees le long des chemins de l'argent, un sous-systeme a la fois. Notez chaque soupcon dans un fichier de travail, meme a moitie forme.
- Jour 5 : construisez les tests proof-of-concept de vos meilleures pistes. Abandonnez les faibles.
- Dernier jour : peaufinez les redactions, reverifiez les severites, soumettez. Ne courez pas apres une nouvelle piste dans les dernieres heures ; terminez ce que vous pouvez prouver.
Protegez votre attention. Deux heures de revue concentree sur un sous-systeme valent mieux qu'une journee entiere a tout survoler.
Progresser depuis le niveau debutant
- Lisez les rapports juges. Apres chaque concours, etudiez les Highs qui se sont classes. Vous reverrez les memes patterns.
- Tenez une checklist personnelle de classes de bugs et passez chaque contrat dedans. Votre avantage est la reconnaissance de patterns, et une checklist la rend systematique.
- Specialisez-vous. Choisissez une niche (vaults, lending, bridges, AMMs) et creusez. Les specialistes trouvent plus que les generalistes dans leur domaine.
- Musclez le proof-of-concept. La vitesse a ecrire des tests Foundry multiplie directement le nombre de findings que vous confirmez avant la deadline.
Pratiquez en conditions reelles
Le moyen le plus rapide d'interioriser ces classes de bugs est de les exploiter deliberement dans un environnement sur, puis de les corriger. Sur app.solingo-blockchain.xyz, vous pouvez travailler des exercices facon audit, ecrire des exploits proof-of-concept et confronter votre raisonnement de severite a des solutions corrigees. Commencez par les pistes comptabilite et controle d'acces, puis passez a la reentrance et a la manipulation d'oracle. Lisez le code, cassez-le, redigez le rapport, recommencez.