Introduction
Foundry, développé par Paradigm, s'impose en 2026 comme le toolkit incontournable pour le développement et les tests de smart contracts Ethereum. Contrairement aux outils traditionnels comme Hardhat ou Truffle, Foundry excelle par sa vitesse native en Rust, son absence de dépendances JavaScript et sa philosophie 'tout en un' pour forger (forge), tester (cast, anvil) et déboguer vos contrats Solidity.
Pourquoi l'adopter ? Dans un écosystème Ethereum où les audits coûtent cher et les exploits millionnaires pullulent, Foundry permet des tests fuzzing 100x plus rapides, des simulations de chaînes locales instantanées et une reproductibilité parfaite des échecs. Imaginez tester un protocole DeFi complexe en minutes plutôt qu'en heures : c'est la promesse de Foundry. Ce tutoriel avancé, 100% théorique, déconstruit ses fondations pour que vous, développeur senior, puissiez architecturer des suites de tests scalables, anticiper les failles gas et intégrer des invariants formels. Prêt à forger des contrats blindés ? (128 mots)
Prérequis
- Maîtrise avancée de Solidity (patterns comme diamond proxy, hooks ERC-721).
- Connaissances en Rust (ownership, borrowing pour comprendre l'implémentation).
- Expérience avec des frameworks de test Ethereum (Hardhat minimum).
- Familiarité avec les concepts de fuzzing, invariants et symbolic execution.
- Environnement Linux/macOS pour les performances optimales.
Fondations théoriques de Foundry
Au cœur de Foundry réside une architecture modulaire en Rust, où Forge orchestre les tests comme un chef d'orchestre : il compile Solidity en bytecode EVM via solc, injecte des traces de gas et exécute des assertions en parallèle.
Anvil, le nœud local, simule une chaîne EVM avec persistance stateful, supportant des forks de mainnet (via RPC) pour tester contre des états réels comme Uniswap V3 pools. Analogie : Anvil est votre sandbox quantique, forkant des univers parallèles Ethereum sans miner un seul bloc.
Cast, l'outil CLI, envoie des RPC purs (eth_call, trace_transaction) pour inspecter le runtime sans déploiement. Exemple concret : simuler un flashloan sur Aave V3 en forçant un reentrancy pour valider une guard.
Cette triade (Forge/Anvil/Cast) élimine les abstractions JS lentes, offrant une latence <1ms par test. Structurez vos projets en workspaces pour scaler : foundry.toml centralise les configs remotes (etherscan API, optimizer slots).
Architectures de testing avancées
Stratégie 1 : Invariants formels. Définissez des propriétés immuables (e.g., 'totalSupply ne dépasse jamais X') testées post-chaque mutation. Foundry les vérifie via un runner dédié, comme un gardien mathématique prouvant l'intégrité state.
Stratégie 2 : Fuzzing pro. Au-delà du random basique, utilisez des corpus personnalisés (séquences d'actions DeFi) et des hooks pre/post pour cover 95% des branches. Exemple : fuzzer un DEX avec des swaps slippage-bound pour détecter des arithmetic overflows cachés.
Stratégie 3 : Snapshotting et rebasing. Capturez l'état pre-test (snapshot), mutiez, puis rollback. Idéal pour tester upgrades proxy : simulez 1000 storage slots migrations sans pollution.
Hiérarchie des tests : Unitaires (isolés, <10ms), Intégration (forks anvil), E2E (multi-contrats). Priorisez coverage >90% via --gas-report pour hunter les boucles gas-gourmandes.
Cas d'étude : Pour un lending protocol, combinez fuzzing (borrow/repay sequences) + invariants (utilization <100%) + traces (calldata decoding) pour un coverage bulletproof.
Gestion des dépendances et environnements
Foundry révolutionne les deps via remappings dans foundry.toml : mappez @openzeppelin/contracts vers un git submodule pour versioning précis, évitant npm-like hell.
Scripts forge : Définissez des tâches CLI (e.g., forge script Deploy.s.sol --rpc-url mainnet --verify) pour CI/CD. Analogie : des macros Rust pour l'EVM, paramétrables via env vars (PRIVATE_KEY, API_KEY).
Multi-chaînes : Configure etherscan-api-key par réseau dans profils TOML. Forkez arbitrum/optimism en parallèle pour cross-rollup tests.
Exemple concret : Dans un projet L2, utilisez --fork-url l2-rpc + anvil persistence pour simuler 1M blocks de sequencer data, validant des bridges sans coût gas réel.
Optimisez avec DappTools-like : integrez Slither statique en pre-test hook pour SAST avant fuzzing dynamique.
Bonnes pratiques essentielles
- Modularisez les tests : Un fichier par invariant/fuzz suite (e.g.,
InvariantLiquidation.t.sol), avec imports named pour réutilisabilité. - Gas profiling systématique : Toujours
--gas-report+ custom metrics (storage reads/writes) pour cibler <200k gas par tx. - Corpus fuzz persistant : Sauvegardez inputs crashing dans
.fuzzdirs, réinjectez pour coverage croissant (jusqu'à 10x plus efficace). - CI/CD integration : GitHub Actions avec matrix (forks mainnet/testnets) + badges coverage sur README.
- Sécurité first : Invariants > assertions ; testez reentrancy/cross-function via cheatcodes théoriques (assume, prank).
Erreurs courantes à éviter
- Fuzzing shallow : Limiter à 100 itérations ; montez à 10k+ avec
--fuzz-runset seeds custom pour cover edge cases rares comme underflows. - Oubli des cheatcodes : Sans
vm.expectRevert, les tests passent faussement ; toujours mock external calls (deal, prank). - Forks non-isolés : Réutiliser anvil state pollue ; utilisez
new AnvilForkpar suite pour pureté. - Ignore gas diffs L1/L2 : Testez sur forks spécifiques (e.g., OP stack) car calldata costs varient, faussant benchmarks.
Pour aller plus loin
- Livre de référence : Foundry Book officiel.
- Repo exemples : Paradigm Foundry templates.
- Outils complémentaires : Integrate avec Echidna pour hybrid fuzz/symbolic.
- Communauté : Discord Foundry + Ethereum Magicians forum.