career·7 min de lecture·Par Solingo

Journée Type d'un Auditeur Smart Contract

Immersion dans le quotidien d'un auditeur blockchain : outils, méthodologie, et comment 80% du travail se fait avant même de lire le code.

# 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

  • ✅ Repo GitHub ?
  • ✅ Tests (couverture %) ?
  • ✅ Documentation technique ?
  • ✅ Anciens audits ?
  • ✅ Scope précis (quels contrats ?) ?
  • Red flag : pas de tests = audit impossible.

    9h00 — Setup de l'Environnement

    bash

    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.

    Prêt à mettre en pratique ?

    Applique ces concepts avec des exercices interactifs sur Solingo.

    Commencer gratuitement