perimetersec/fuzzlib

GitHub: perimetersec/fuzzlib

这是一个兼容 Foundry、Echidna 和 Medusa 的通用 Solidity 智能合约模糊测试库,提供了断言、值限制和日志记录等工具以辅助编写测试。

Stars: 59 | Forks: 14

# Fuzzlib Fuzzlib 是一个通用的、非固执己见的 Solidity 模糊测试库,支持有状态和无状态模糊测试。兼容 Echidna、Medusa 和 Foundry。 通过简单的 `fl` 命名空间提供模糊测试的常用工具:断言、值限制、日志记录、数学运算等。 由 [Perimeter](https://www.perimetersec.io) 维护 —— 自 2022 年以来,通过模糊测试保障 DeFi 安全的领导者。 ## 核心特性 - **基本断言**:用于常见测试条件和相等性检查的辅助函数 - **高级断言**:如通过 `errAllow` 处理预期失败的错误处理等工具 - **值限制**:将值限制在均匀分布的范围内,以获得更好的模糊测试效果 - **日志工具**:用于调试和跟踪的统一日志记录 - **数学工具**:如最小值、最大值、绝对值和差值计算等运算 - **随机工具**:Fisher-Yates 数组洗牌算法 - **函数调用助手**:使用 actor pranking 进行函数调用的工具 - **全面测试**:包含单元测试和模糊测试的广泛测试套件 - **文档完善**:清晰且完整,遵循 OpenZeppelin 风格的约定 ## 安装说明 ### 使用 Foundry ``` forge install perimetersec/fuzzlib ``` ### 使用 Soldeer ``` soldeer install perimetersec-fuzzlib~1.0.0 ``` ### 使用 npm ``` npm install @perimetersec/fuzzlib ``` 添加到你的 `remappings.txt`: ``` fuzzlib/=lib/fuzzlib/src/ ``` ## 快速开始 通过继承 `FuzzBase` 创建一个简单的模糊测试: ``` import {FuzzBase} from "fuzzlib/FuzzBase.sol"; contract MyFuzzer is FuzzBase { function testMath(uint256 a, uint256 b) public { // Clamp inputs to reasonable ranges uint256 x = fl.clamp(a, 0, 1000); uint256 y = fl.clamp(b, 0, 1000); // Log for debugging fl.log("Testing max function. x =", x); fl.log("Testing max function. y =", y); // Test mathematical properties fl.gte(fl.max(x, y), x, "Max should be >= x"); fl.gte(fl.max(x, y), y, "Max should be >= y"); } } ``` ## 函数参考 ### 基本断言 ``` // Fundamental assertions fl.t(exists, "Property X exists"); fl.eq(result, 100, "Result should equal 100"); fl.neq(userA, userB, "Users should be different"); // Comparison assertions fl.gt(balance, 1000, "Balance should be greater than 1000"); fl.gte(amount, 50, "Amount should be greater than or equal to 50"); fl.lt(fee, 100, "Fee should be less than 100"); fl.lte(price, 500, "Price should be less than or equal to 500"); ``` ### 高级断言 ``` // Allow specific require messages string[] memory allowedMessages = new string[](1); allowedMessages[0] = "Insufficient balance"; fl.errAllow(errorData, allowedMessages, "Message X should be allowed"); // Allow specific custom errors bytes4[] memory allowedErrors = new bytes4[](1); allowedErrors[0] = CustomError.selector; fl.errAllow(errorSelector, allowedErrors, "Error X should be allowed"); // Combined error handling fl.errAllow(errorData, allowedMessages, allowedErrors, "Either should be allowed"); ``` ### 值限制 ``` // Value clamping with uniform distribution uint256 clamped = fl.clamp(inputValue, 0, 100); // Clamp to greater than value uint256 clampedGt = fl.clampGt(inputValue, 50); // Clamp to greater than or equal uint256 clampedGte = fl.clampGte(inputValue, 50); // Clamp to less than value uint256 clampedLt = fl.clampLt(inputValue, 100); // Clamp to less than or equal uint256 clampedLte = fl.clampLte(inputValue, 100); ``` ### 日志记录 ``` // Simple logging fl.log("Testing scenario"); // Logging with values fl.log("Balance:", balance); fl.log("User count:", 42); // Failure logging fl.logFail("This test failed"); fl.logFail("Invalid amount:", amount); ``` ### 数学工具 ``` // Min/max operations uint256 maximum = fl.max(150, 300); int256 minimum = fl.min(-50, 25); // Absolute value and difference uint256 absolute = fl.abs(-42); uint256 difference = fl.diff(100, 75); ``` ### 随机工具 ``` // Shuffle arrays uint256[] memory array = new uint256[](10); fl.shuffleArray(array, entropy); ``` ### 函数调用助手 ``` // Make function calls bytes memory result = fl.doFunctionCall( address(target), abi.encodeWithSignature("getValue()"), msg.sender // actor ); // Calls with automatic pranking (bool success, bytes memory data) = fl.doFunctionCall( address(target), abi.encodeWithSignature("transfer(address,uint256)", recipient, amount), sender ); // Static calls (view functions) (bool success, bytes memory data) = fl.doFunctionStaticCall( address(target), abi.encodeWithSignature("balanceOf(address)", user) ); ``` ## 已知限制 - **有符号整数限制**:限制在 `int128` 范围内,以避免范围计算中的溢出问题 - **Gas 优化**:库优先考虑功能性而非 gas 优化 - **函数选择器冲突**:在使用 errAllow 时,如果错误选择器与 `Error(string)` 冲突,可能会发生意外行为 ## 路线图 - [ ] 支持更多平台 - [ ] 添加更多辅助函数 - [ ] 性能优化 ## 贡献 我们欢迎贡献!详情请参阅我们的[贡献指南](CONTRIBUTING.md)。 ## 许可证 本项目根据 GNU General Public License v3.0 许可。详情请参阅 [LICENSE](LICENSE) 文件。 部分代码修改自 [Crytic Properties](https://github.com/crytic/properties/blob/main/contracts/util/PropertiesHelper.sol),其根据 GNU Affero General Public License v3.0 (AGPL-3.0) 许可。 部分代码修改自 [OpenZeppelin Contracts](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol),其根据 MIT License 许可。 ## 免责声明 本软件“按原样”提供,不提供任何担保。主分支包含新的实验性功能,可能不稳定。对于生产环境,我们建议使用经过充分测试的官方 tagged releases。虽然我们对任何错误或问题不承担责任,但我们维护着一个仅适用于官方发布的漏洞赏金计划。
标签:DeFi安全, Echidna, ETW劫持, Foundry, Fuzzing, Medusa, SOC Prime, Solidity, 区块链安全, 单元测试, 开发工具, 数值计算, 断言, 无状态测试, 日志记录, 智能合约, 有状态测试, 测试库, 随机数生成