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, 区块链安全, 单元测试, 开发工具, 数值计算, 断言, 无状态测试, 日志记录, 智能合约, 有状态测试, 测试库, 随机数生成