# Journée Type d'un Auditeur Smart Contract
Être auditeur smart contract, c'est être le dernier rempart avant qu'un protocole ne gère des millions de dollars. Voici à quoi ressemble une journée typique.
8h00 — Kick-off Call avec le Client
Client : "On lance dans 2 semaines, on a besoin d'un audit express."
Moi : "Combien de lignes de code ?"
Client : "~3000 SLOC, un DEX avec des liquidity pools custom."
Moi : ``mentalement : 3000 SLOC = minimum 2 semaines, pas 1### Checklist Initiale
Red flag : pas de tests = audit impossible.
9h00 — Setup de l'Environnementbash
git clone https://github.com/client/dex
cd dex
# Install dependencies
npm install # ou forge install
# Run tests
forge test --gas-report
# Generate coverage
forge coverage
# Run static analysis
slither . --checklist > slither-report.md
# Check for known vulnerabilities
aderyn audit . --format=table
Résultat attendu :
- Tests : >90% coverage
- Slither : 0-5 warnings (filtrés)
- Aderyn : <10 findings
Réalité :
- Tests : 47% coverage
- Slither : 87 warnings
- Build errors dans la moitié des fichiers
→ 30 minutes perdues à fix l'environnement.
10h30 — Lecture du Whitepaper
Avant de lire une ligne de code, je lis la doc :
Quel problème résout le protocole ?
Quels sont les invariants business ?
- Ex : "Le ratio collateral/debt doit toujours être >150%"
Quels sont les trust assumptions ?
- Ex : "L'admin est un multisig 3/5"
Quelles sont les edge cases connues ?
Je note dans Obsidian :
markdown
# Invariants à Vérifier
- [ ] totalSupply == sum(balances)
- [ ] reserves.X * reserves.Y >= K (constant product)
- [ ] fees accumulate correctly
- [ ] no reentrancy in swap()
- [ ] oracle manipulation resistant
## 11h30 — Première Passe : Architecture
J'utilise solidity-visual-auditor :
bash
surya graph contracts/**/*.sol | dot -Tpng > architecture.png
Je cherche :
- Héritage complexe (diamond pattern = red flag)
- Dependencies externes (Chainlink, Uniswap V2/V3)
- Upgrade patterns (proxy, beacon)
- Points d'entrée (fonctions external/public)
solidity
// Je liste tous les entry points
contracts/
Pool.sol
- deposit(uint256 amount) external
- withdraw(uint256 shares) external
- swap(address tokenIn, address tokenOut, uint256 amountIn) external
Admin.sol
- setFees(uint256 newFee) external onlyOwner
- pause() external onlyOwner
## 12h30 — Pause Déjeuner
Important : vraie pause. L'audit nécessite 100% de concentration.
13h30 — Deuxième Passe : Lecture Ligne par Ligne
Je commence par les contrats critiques (ceux qui gèrent des fonds) :
solidity
// Pool.sol
function swap(
address tokenIn,
address tokenOut,
uint256 amountIn
) external returns (uint256 amountOut) {
// ❌ BUG 1 : Pas de check sur tokenIn != tokenOut
// → Un attaquant peut swap un token contre lui-même
require(amountIn > 0, "Zero amount");
// ❌ BUG 2 : Pas de slippage protection
// → Front-running possible
uint256 reserveIn = reserves[tokenIn];
uint256 reserveOut = reserves[tokenOut];
// Calculate amountOut using constant product formula
amountOut = (amountIn * reserveOut) / (reserveIn + amountIn);
// ❌ BUG 3 : Update reserves AVANT le transfer
// → Reentrancy possible si tokenOut est un ERC777
reserves[tokenIn] += amountIn;
reserves[tokenOut] -= amountOut;
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
IERC20(tokenOut).transfer(msg.sender, amountOut);
// ✅ CORRECT : Checks-Effects-Interactions pattern non respecté
}
3 bugs en 20 lignes.
15h00 — Proof of Concept
Pour chaque bug critique, j'écris un PoC :
solidity
// test/Exploit.t.sol
function testReentrancyExploit() public {
// Setup
MaliciousToken malToken = new MaliciousToken(pool);
pool.addLiquidity(address(malToken), address(usdc), 1000e18, 1000e6);
// Attack
malToken.attack();
// Verify drain
assertEq(usdc.balanceOf(address(pool)), 0);
// Pool a été drainé !
}
contract MaliciousToken is ERC20 {
Pool pool;
uint256 attackCount;
function attack() external {
pool.swap(address(this), address(usdc), 1e18);
}
function transfer(address to, uint256 amount) public override returns (bool) {
if (attackCount < 10 && to != address(pool)) {
attackCount++;
pool.swap(address(this), address(usdc), 1e18); // Reentrancy
}
return super.transfer(to, amount);
}
}
bash
forge test --match-test testReentrancyExploit -vvvv
# Résultat : ✅ Test passed
# → Bug confirmé, severity: CRITICAL
## 17h00 — Rédaction du Rapport
Je structure mes findings :
markdown
# [CRITICAL] Reentrancy in swap()
Impact
An attacker can drain the entire pool by exploiting reentrancy in the swap function.
Proof of Concept
See test/Exploit.t.sol::testReentrancyExploit
Recommendation
// Apply Checks-Effects-Interactions pattern
reserves[tokenIn] += amountIn;
reserves[tokenOut] -= amountOut;
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
// ✅ Add reentrancy guard
require(!locked, "Reentrancy");
locked = true;
IERC20(tokenOut).transfer(msg.sender, amountOut);
locked = false;
Or use OpenZeppelin's ReentrancyGuard.
## 18h00 — Review Croisée
Dans les firms (Trail of Bits, OpenZeppelin, etc.), chaque finding est revu par un senior :
- Moi : "J'ai trouvé un reentrancy dans swap()"
- Senior : "Vérifie si l'ERC20 utilisé supporte les hooks (ERC777, ERC1363)"
- Moi : checks → "Oui, ils utilisent USDC + un token custom ERC777"
- Senior : "Upgrade severity à CRITICAL et mentionne ERC777 explicitement"
19h00 — Tools & Automation
Pendant que je rédige, je lance des tools automatiques :
bash
# Symbolic execution (cherche des paths qui violent les asserts)
manticore contracts/Pool.sol --contract Pool
# Formal verification (prouve mathématiquement les invariants)
certora specs/Pool.spec
# Mutation testing (vérifie que les tests détectent les bugs)
vertigo run --network localhost
``
Ces tools tournent pendant 2-8 heures. Je les checke le lendemain.
20h00 — Fin de Journée
Bilan :
- ✅ 3 contrats audités (~800 SLOC)
- ✅ 1 CRITICAL, 2 HIGH, 5 MEDIUM findings
- ✅ 4 PoCs rédigés
- 🚧 6 contrats restants
- 🚧 Fuzzing overnight (Echidna)
Todo demain :
- Review des tests automatiques
- Audit des contrats Admin + Governance
- Recherche de business logic bugs (plus subtils)
Outils Quotidiens
| Outil | Usage | Temps |
|-------|-------|-------|
| Slither | Static analysis | 5 min |
| Aderyn | Pattern detection | 5 min |
| Foundry | Tests/PoCs | 3h |
| Echidna | Fuzzing | overnight |
| Manticore | Symbolic exec | 2-4h |
| Certora | Formal verif | 4-8h |
| VS Code | Reading code | 6h |
Compétences Requises
Techniques :
- Solidity avancé (assembly, gas, storage layout)
- Connaissance des patterns DeFi (AMM, lending, staking)
- Outils de sécurité (Foundry, Slither, Echidna)
Soft Skills :
- Communication (expliquer un bug à un dev)
- Rigueur (un bug manqué = millions perdus)
- Curiosité (lire 8h de code/jour)
Salaire
Junior (0-2 ans) : $80-120K/an
Mid (2-5 ans) : $120-200K/an
Senior (5+ ans) : $200-400K/an
Freelance : $200-500/h selon réputation
Ressources
- Solodit : base de données de findings publics
Conclusion
Auditer, c'est 80% de préparation (tooling, tests, compréhension) et 20% de lecture de code. Les meilleurs auditeurs ne sont pas ceux qui lisent vite, mais ceux qui pensent comme des attaquants.