[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-19-test-proprietes-fuzzing-foundry":3},{"article":4,"author":60},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":39,"related_articles":40},"d6000000-0000-0000-0000-000000000119","a0000000-0000-0000-0000-000000000062","Deep EVM #19 : Test par propriétés pour smart contracts — Fuzzing avec Foundry","deep-evm-19-test-proprietes-fuzzing-foundry","Explorez le test par propriétés et le fuzzing pour les smart contracts avec Foundry. Couvre les entrées fuzz, les tests d'invariants et le test différentiel Huff\u002FYul\u002FSolidity.","## Au-delà des tests unitaires\n\nLes tests unitaires vérifient des scénarios spécifiques, mais les smart contracts font face à des entrées adversariales de n'importe quelle adresse, avec n'importe quelle valeur, dans n'importe quel ordre. Le test par propriétés inverse le paradigme : au lieu de spécifier les sorties attendues pour des entrées spécifiques, vous définissez des propriétés qui doivent tenir pour TOUTES les entrées.\n\n## Fuzzing avec Foundry\n\nFoundry intègre un fuzzer qui génère automatiquement des entrées aléatoires :\n\n```solidity\nfunction testFuzz_transferPreservesSupply(\n    address from,\n    address to,\n    uint256 amount\n) public {\n    \u002F\u002F Setup\n    vm.assume(from != to);\n    vm.assume(amount \u003C= token.balanceOf(from));\n\n    uint256 supplyBefore = token.totalSupply();\n\n    \u002F\u002F Action\n    vm.prank(from);\n    token.transfer(to, amount);\n\n    \u002F\u002F Propriété : la supply totale ne change jamais\n    assertEq(token.totalSupply(), supplyBefore);\n}\n```\n\nLe préfixe `testFuzz_` indique à Foundry de générer des entrées aléatoires pour les paramètres. Par défaut, 256 exécutions ; configurable dans `foundry.toml`.\n\n## Test d'invariants\n\nLes tests d'invariants vont plus loin : Foundry appelle des fonctions aléatoires dans un ordre aléatoire et vérifie que les invariants tiennent après chaque séquence.\n\n```solidity\ncontract TokenInvariantTest is Test {\n    Token token;\n    Handler handler;\n\n    function setUp() public {\n        token = new Token();\n        handler = new Handler(token);\n        targetContract(address(handler));\n    }\n\n    function invariant_supplyEqualsBalances() public {\n        uint256 totalBalances = token.balanceOf(alice) +\n                                token.balanceOf(bob) +\n                                token.balanceOf(charlie);\n        assertEq(token.totalSupply(), totalBalances);\n    }\n\n    function invariant_noNegativeBalances() public {\n        assertGe(token.balanceOf(alice), 0);\n        assertGe(token.balanceOf(bob), 0);\n    }\n}\n```\n\n### Le pattern Handler\n\nLe Handler guide le fuzzer vers des séquences d'appels valides :\n\n```solidity\ncontract Handler is Test {\n    Token token;\n\n    constructor(Token _token) {\n        token = _token;\n    }\n\n    function transfer(uint256 toSeed, uint256 amount) public {\n        address to = actors[toSeed % actors.length];\n        amount = bound(amount, 0, token.balanceOf(msg.sender));\n        vm.prank(msg.sender);\n        token.transfer(to, amount);\n    }\n}\n```\n\n## Test différentiel Huff vs Solidity\n\nLe pattern le plus puissant pour valider du Huff : vérifier que votre implémentation Huff produit des résultats identiques à une référence Solidity pour des millions d'entrées aléatoires.\n\n```solidity\nfunction testFuzz_differentialAdd(\n    uint256 a,\n    uint256 b\n) public {\n    \u002F\u002F Huff\n    (bool huffOk, bytes memory huffData) = huffImpl.call(\n        abi.encodeWithSignature(\"add(uint256,uint256)\", a, b)\n    );\n\n    \u002F\u002F Solidity (vérité terrain)\n    (bool solOk, bytes memory solData) = address(solImpl).call(\n        abi.encodeWithSignature(\"add(uint256,uint256)\", a, b)\n    );\n\n    assertEq(huffOk, solOk);\n    if (huffOk && solOk) {\n        assertEq(huffData, solData);\n    }\n}\n```\n\nAvec 10 000 exécutions de fuzz, vous testez effectivement 10 000 entrées aléatoires. Si les deux implémentations divergent, Foundry affiche l'entrée problématique.\n\n## Stratégies de fuzzing avancées\n\n1. **Fuzzing guidé par dictionnaire** — Fournissez des valeurs intéressantes : 0, 1, MAX_UINT, frontières de type\n2. **Fuzzing de séquences** — Testez des séquences d'appels, pas juste des appels isolés\n3. **Fuzzing avec état** — Maintenez un état fantôme (ghost state) et vérifiez la cohérence\n4. **Minimisation de contre-exemples** — Foundry réduit automatiquement les entrées qui échouent\n\n## Conclusion\n\nLe test par propriétés et le fuzzing sont des outils essentiels pour les smart contracts. Ils découvrent des bugs que les tests unitaires manquent en explorant un espace d'entrées exponentiellement plus grand. Pour les contrats Huff et Yul, le test différentiel contre une référence Solidity est la stratégie la plus efficace.","\u003Ch2 id=\"au-del-des-tests-unitaires\">Au-delà des tests unitaires\u003C\u002Fh2>\n\u003Cp>Les tests unitaires vérifient des scénarios spécifiques, mais les smart contracts font face à des entrées adversariales de n’importe quelle adresse, avec n’importe quelle valeur, dans n’importe quel ordre. Le test par propriétés inverse le paradigme : au lieu de spécifier les sorties attendues pour des entrées spécifiques, vous définissez des propriétés qui doivent tenir pour TOUTES les entrées.\u003C\u002Fp>\n\u003Ch2 id=\"fuzzing-avec-foundry\">Fuzzing avec Foundry\u003C\u002Fh2>\n\u003Cp>Foundry intègre un fuzzer qui génère automatiquement des entrées aléatoires :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function testFuzz_transferPreservesSupply(\n    address from,\n    address to,\n    uint256 amount\n) public {\n    \u002F\u002F Setup\n    vm.assume(from != to);\n    vm.assume(amount &lt;= token.balanceOf(from));\n\n    uint256 supplyBefore = token.totalSupply();\n\n    \u002F\u002F Action\n    vm.prank(from);\n    token.transfer(to, amount);\n\n    \u002F\u002F Propriété : la supply totale ne change jamais\n    assertEq(token.totalSupply(), supplyBefore);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Le préfixe \u003Ccode>testFuzz_\u003C\u002Fcode> indique à Foundry de générer des entrées aléatoires pour les paramètres. Par défaut, 256 exécutions ; configurable dans \u003Ccode>foundry.toml\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"test-d-invariants\">Test d’invariants\u003C\u002Fh2>\n\u003Cp>Les tests d’invariants vont plus loin : Foundry appelle des fonctions aléatoires dans un ordre aléatoire et vérifie que les invariants tiennent après chaque séquence.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">contract TokenInvariantTest is Test {\n    Token token;\n    Handler handler;\n\n    function setUp() public {\n        token = new Token();\n        handler = new Handler(token);\n        targetContract(address(handler));\n    }\n\n    function invariant_supplyEqualsBalances() public {\n        uint256 totalBalances = token.balanceOf(alice) +\n                                token.balanceOf(bob) +\n                                token.balanceOf(charlie);\n        assertEq(token.totalSupply(), totalBalances);\n    }\n\n    function invariant_noNegativeBalances() public {\n        assertGe(token.balanceOf(alice), 0);\n        assertGe(token.balanceOf(bob), 0);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Le pattern Handler\u003C\u002Fh3>\n\u003Cp>Le Handler guide le fuzzer vers des séquences d’appels valides :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">contract Handler is Test {\n    Token token;\n\n    constructor(Token _token) {\n        token = _token;\n    }\n\n    function transfer(uint256 toSeed, uint256 amount) public {\n        address to = actors[toSeed % actors.length];\n        amount = bound(amount, 0, token.balanceOf(msg.sender));\n        vm.prank(msg.sender);\n        token.transfer(to, amount);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"test-diff-rentiel-huff-vs-solidity\">Test différentiel Huff vs Solidity\u003C\u002Fh2>\n\u003Cp>Le pattern le plus puissant pour valider du Huff : vérifier que votre implémentation Huff produit des résultats identiques à une référence Solidity pour des millions d’entrées aléatoires.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function testFuzz_differentialAdd(\n    uint256 a,\n    uint256 b\n) public {\n    \u002F\u002F Huff\n    (bool huffOk, bytes memory huffData) = huffImpl.call(\n        abi.encodeWithSignature(\"add(uint256,uint256)\", a, b)\n    );\n\n    \u002F\u002F Solidity (vérité terrain)\n    (bool solOk, bytes memory solData) = address(solImpl).call(\n        abi.encodeWithSignature(\"add(uint256,uint256)\", a, b)\n    );\n\n    assertEq(huffOk, solOk);\n    if (huffOk &amp;&amp; solOk) {\n        assertEq(huffData, solData);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Avec 10 000 exécutions de fuzz, vous testez effectivement 10 000 entrées aléatoires. Si les deux implémentations divergent, Foundry affiche l’entrée problématique.\u003C\u002Fp>\n\u003Ch2 id=\"strat-gies-de-fuzzing-avanc-es\">Stratégies de fuzzing avancées\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Fuzzing guidé par dictionnaire\u003C\u002Fstrong> — Fournissez des valeurs intéressantes : 0, 1, MAX_UINT, frontières de type\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fuzzing de séquences\u003C\u002Fstrong> — Testez des séquences d’appels, pas juste des appels isolés\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fuzzing avec état\u003C\u002Fstrong> — Maintenez un état fantôme (ghost state) et vérifiez la cohérence\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Minimisation de contre-exemples\u003C\u002Fstrong> — Foundry réduit automatiquement les entrées qui échouent\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"conclusion\">Conclusion\u003C\u002Fh2>\n\u003Cp>Le test par propriétés et le fuzzing sont des outils essentiels pour les smart contracts. Ils découvrent des bugs que les tests unitaires manquent en explorant un espace d’entrées exponentiellement plus grand. Pour les contrats Huff et Yul, le test différentiel contre une référence Solidity est la stratégie la plus efficace.\u003C\u002Fp>\n","fr","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.313526Z","Test par propriétés pour smart contracts — Fuzzing avec Foundry","Test par propriétés et fuzzing des smart contracts avec Foundry. Entrées fuzz, tests d'invariants et test différentiel Huff vs Yul vs Solidity.","fuzzing smart contracts foundry",null,"index, follow",[22,27,31,35],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000021","Foundry","foundry",{"id":32,"name":33,"slug":34,"created_at":26},"c0000000-0000-0000-0000-000000000013","Security","security",{"id":36,"name":37,"slug":38,"created_at":26},"c0000000-0000-0000-0000-000000000018","Yul","yul","Blockchain",[41,48,54],{"id":42,"title":43,"slug":44,"excerpt":45,"locale":12,"category_name":46,"published_at":47},"d0000000-0000-0000-0000-000000000677","Pourquoi Bali devient le hub impact-tech d'Asie du Sud-Est en 2026","pourquoi-bali-devient-hub-impact-tech-asie-sud-est-2026","Bali se classe 16e parmi les écosystèmes startups d'Asie du Sud-Est. Avec une concentration croissante de bâtisseurs Web3, de startups IA durables et d'entreprises eco-travel tech, l'île se forge une identité de capitale impact-tech de la région.","Ingénierie","2026-03-28T10:44:49.517126Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":46,"published_at":53},"d0000000-0000-0000-0000-000000000676","Le patchwork de la protection des données ASEAN : checklist de conformité pour les développeurs","patchwork-protection-donnees-asean-checklist-conformite-developpeurs","Sept pays de l'ASEAN disposent désormais de lois complètes sur la protection des données, chacune avec des modèles de consentement, des exigences de localisation et des structures de sanctions différents. Voici une checklist pratique de conformité pour les développeurs.","2026-03-28T10:44:49.504560Z",{"id":55,"title":56,"slug":57,"excerpt":58,"locale":12,"category_name":46,"published_at":59},"d0000000-0000-0000-0000-000000000675","La transformation numérique de 29 milliards de dollars d'Indonesia : opportunités pour les éditeurs de logiciels","transformation-numerique-29-milliards-dollars-indonesia-opportunites-editeurs-logiciels","Le marché des services informatiques d'Indonesia devrait atteindre 29,03 milliards de dollars en 2026, contre 24,37 milliards en 2025. L'infrastructure cloud, l'IA, le e-commerce et les centres de données tirent la croissance la plus rapide d'Asie du Sud-Est.","2026-03-28T10:44:49.469231Z",{"id":13,"name":61,"slug":62,"bio":63,"photo_url":19,"linkedin":19,"role":64,"created_at":65,"updated_at":65},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]