这是我的 AI + Web3 实战营 的第七篇研发日志,前六篇如下:
AI+Web3实战营日志 #4 | Rebalancer合约
另外,关于 AI + Web3 实战营的相关介绍则有如下几篇文章:
之前我们一直采用每天晚上 8 点直播的方式推进研发,每次 1.5–2 小时,一周六天。
不过随着参与直播的同学越来越少,加上每天的时间投入有限,整体进度偏慢。于是我提出取消直播,改为我白天集中录制研发过程,大家根据自己的时间去看回放。这样不仅能让我投入更多时间推进项目,也有余力去做功能迭代和完善。征得大家同意后,从当天起,直播正式取消。
过去两天,我录制了 4 个视频,总时长近 5 小时。加上最初的 1.5 小时测试时间,累计约 6.5 小时,终于把 BlockETFCore 合约的所有测试用例全部跑通。
下面就来总结下这次测试成果。
针对 BlockETFCore 合约,总计设计并完成 337 个测试用例,涵盖 9 大模块,具体如下:
模块 | 测试数量 | 覆盖率 | 关键程度 | 状态 |
|---|---|---|---|---|
初始化 | 53 | 100% | 关键 | ✅ |
铸造操作 | 38 | 100% | 关键 | ✅ |
精确份额铸造 | 25 | 100% | 高 | ✅ |
销毁操作 | 36 | 100% | 关键 | ✅ |
计算逻辑 | 41 | 100% | 关键 | ✅ |
费用管理 | 30 | 100% | 高 | ✅ |
重新平衡 | 59 | 100% | 关键 | ✅ |
访问控制 | 31 | 100% | 关键 | ✅ |
权重调整 | 24 | 100% | 中 | ✅ |
合计 | 337 | 100% | - | ✅ |
代码覆盖率详情则如下,涵盖了所有公开函数和内部函数:
╔════════════════════════════════════════════════════════════════╗
║ 文件/函数 │ 语句覆盖 │ 分支覆盖 │ 函数覆盖 ║
╠════════════════════════════════════════════════════════════════╣
║ BlockETFCore.sol │ 100.00% │ 100.00% │ 100.00% ║
║ ├─ 核心业务功能 │ │ │ ║
║ │ ├─ initialize() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ mint() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ mintExactShares() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ burn() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ flashRebalance() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ executeRebalance() │ 100.00% │ 100.00% │ 100.00% ║
║ │ └─ adjustWeights() │ 100.00% │ 100.00% │ 100.00% ║
║ ├─ 计算核心函数 │ │ │ ║
║ │ ├─ calculateMintRatio() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ calculateBurnAmounts() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ calculateRequiredAssets() │ 100.00% │ 100.00% │ 100.00% ║
║ │ └─ calculateManagementFee() │ 100.00% │ 100.00% │ 100.00% ║
║ ├─ 管理与配置功能 │ │ │ ║
║ │ ├─ collectManagementFee() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ setManagementFeeRate() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ setWithdrawFeeRate() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ setFeeCollector() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ setRebalancer() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ setPriceOracle() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ pause() │ 100.00% │ 100.00% │ 100.00% ║
║ │ └─ unpause() │ 100.00% │ 100.00% │ 100.00% ║
║ ├─ 查询与状态函数 │ │ │ ║
║ │ ├─ getRebalanceInfo() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ assetInfo() │ 100.00% │ 100.00% │ 100.00% ║
║ │ ├─ isAsset() │ 100.00% │ 100.00% │ 100.00% ║
║ │ └─ feeInfo() │ 100.00% │ 100.00% │ 100.00% ║
║ └─ 内部辅助函数 │ │ │ ║
║ ├─ _collectFee() │ 100.00% │ 100.00% │ 100.00% ║
║ ├─ _updateReserves() │ 100.00% │ 100.00% │ 100.00% ║
║ ├─ _validateWeights() │ 100.00% │ 100.00% │ 100.00% ║
║ └─ _transferAssets() │ 100.00% │ 100.00% │ 100.00% ║
╚════════════════════════════════════════════════════════════════╝
安全测试方面,也覆盖了重入、溢出、访问控制、抢先交易、闪电贷、拒绝服务、预言机操纵、精度损失等常见攻击向量,均未发现漏洞:
漏洞类型 | 测试数量 | 发现问题 | 严重程度 | 解决方案 |
|---|---|---|---|---|
重入攻击 | 12 | 0 | 关键 | 不适用 - 已防护 |
整数溢出/下溢 | 15 | 0 | 高 | 不适用 - Solidity 0.8 |
访问控制绕过 | 18 | 0 | 关键 | 不适用 - 安全 |
抢先交易 | 8 | 0 | 中 | 不适用 - 已缓解 |
闪电贷攻击 | 6 | 0 | 高 | 不适用 - 已防护 |
拒绝服务攻击 | 10 | 0 | 高 | 不适用 - 已防护 |
预言机操纵 | 5 | 0 | 关键 | 不适用 - 已验证 |
精度损失 | 12 | 0 | 中 | 不适用 - 已控制 |
在完整测试过程中,我们也发现并完成了多项优化:
setPriceOracle,过程有点繁琐,也存在中间步骤失败的风险。于是我们把 Oracle 地址直接放进构造函数里,部署时一步完成,既减少操作步骤,也更直观。initialize 函数加上了 nonReentrant 修饰符,让逻辑执行更安全。transferFrom,这种方式在失败时可能静默不报错。现在统一改为 SafeERC20,确保转账失败会直接 revert,避免出现账面和实际不一致的问题。initialize 函数最初有 4 个独立 for 循环,最终优化到只有 1 个 for 循环,大大节省了 gas。flashRebalance 和 executeRebalance,两个函数都有 onlyRebalancer 的条件限制, executeRebalance 会调用 flashRebalance。之前,是通过 this 的方式去调用 flashRebalance 的。测试时发现,出现了权限错误。因为使用了 this 方式调用,对于 flashRebalance 来说,现在的 msg.sender 其实是当前合约,而不是 rebalancer,而因为有 onlyRebalancer 的限制,所以就报出权限错误了。最终,将 flashRebalance 的可见性改为了 public,调用时去掉了 this,改为直接调用,问题就解决了。正是因为有了非常完善全面的测试,我们才能发现这些优化的地方。
这一次,我们在 BlockETFCore 合约测试 上累计投入了 6 个半小时,时间甚至超过了合约本身的开发。但这种投入非常值得:
如果放在传统的测试流程中,这样规模的测试通常需要一个 2–3 人的测试团队,至少耗时 2–3 周 才能完成。而我们仅凭个人+AI 协作,就在不到 7 个小时里完成了同等甚至更高质量的测试。这种效率差距,本身就是一次 研发范式的变革。
从这一步开始,我们真正建立起了“开发 + 测试 + 优化”的完整闭环。下一步,我们将继续推进 Router、Rebalancer、Oracle 等合约的全面测试,直到整个 BlockETF 系统实现端到端的安全与稳定。
这个实战营,每一天都在进步。 🚀