caliperforge/euler-earn-invariants
GitHub: caliperforge/euler-earn-invariants
针对 Euler Earn 合约 M-01 份额会计漏洞的防御侧有状态不变量测试框架,通过纯净/植入孪生对持续验证不变量能捕获特定漏洞类别。
Stars: 0 | Forks: 0
# euler-earn-invariants
用于 Euler Earn allocator + vault 的有状态不变量测试框架
共享会计逻辑,针对真实的 Euler Earn 合约运行
(锁定 submodule,除了标准的 EVault strategy
fixture 不使用任何 mock,Euler Earn 自己的测试套件已在使用该 fixture)。
初始版本中包含一个测试用例,以同源
纯净/植入孪生对的形式编码,对应 `euler-_xyz/euler-earn` 仓库的 `f07f6b1c5e1e` 提交
(这是 Pashov Audit Group 在 Euler
Earn 安全审查中 M-01 漏洞的修复提交)。纯净孪生体在 256 次运行 x 深度 50 的有状态模糊测试中保持了所设定的不变量。植入孪生体是
相同的代码树,仅在
`PublicAllocator.sol` 上单块还原了 M-01 的修复;不变量测试套件在该测试分支上报告
`INVARIANT VIOLATED ` 且返回码非零。两个孪生体
都会在每次提交时运行 CI,因此该测试框架提供了持续的证明,表明
所设定的不变量确实能捕获它们声称能捕获的漏洞类别。此外,
植入孪生体已通过一组固定的 16 个种子进行认证
(见 [`docs/reachability.md`](docs/reachability.md)):每个种子都因
不变量标记而失败,因此“植入孪生体被触发”是
该测试用例的确定性属性,而不是单次
随机游走的结果。**可达性已认证:是(按要求 16/16 全部失败)**
认证时间 2026-07-13。
## 这是什么,以及它不是什么
- **这是**一个防御侧的回归测试 fixture,针对 Pashov Audit Group 在 Euler Earn
审查中标记为 M-01 的份额跟踪
漂移类漏洞,它在真实的 Euler Earn 合约之上被编码为有状态的多操作不变量,并作为纯净/植入孪生对提供。
- **这不是**审计、运行时守护程序,或用于
发现新漏洞类的引擎。M-01 类已经是公开的,并且已经在
引入的源代码中修复。纯净孪生体展示了修复后代码树的样貌;
植入孪生体是相同的代码树,仅还原了一行修复代码,
其存在只是为了让 CI 植入分支有一个同源的
回归测试可供捕获。
- 该测试套件并不声称它能提前发现 M-01;它只是
证明了所设定的不变量能捕获该修复所解决的漏洞类。
## 测试用例
| 用例 | 合约 | 植入的规范回归 | 不变量标记 | 纯净分支 | 植入分支 |
|---|---|---|---|---|---|
| **M01** [详情](src/cases/m01-share-accounting-solvency/README.md) | `PublicAllocator`(真实子类,来自 `euler-xyz/euler-earn@f07f6b1c5e1e`) | 在 `PublicAllocator.sol` 第 120 行单块还原 M-01 修复: `IEulerEarn(vault).expectedSupplyAssets(id)` 被还原为 `id.maxWithdraw(vault)` | `INVARIANT VIOLATED m01_reallocation_movement_matches_request` 和 `INVARIANT VIOLATED m01_reallocation_flowcap_matches_movement` | 绿灯 | 红灯并附带标记 |
每个分支的形态(根据 `test/m01/` 中的不变量测试套件):
- 纯净孪生体:三个不变量(`m01_solvency`、
`m01_reallocation_movement_matches_request`、
`m01_reallocation_flowcap_matches_movement`)在针对四个 handler 原语(deposit、
directShareDeposit、reallocateToStrategy、reallocateFromStrategy)的有状态
模糊测试活动中成立。
一个确定性回归测试与 PAG 自己在同一提交中的
`testRellocateToWithDirectStrategySharesTransfer` 相呼应并通过。
- 植入孪生体:当模糊测试游走访问到可达的序列
`directShareDeposit -> reallocateFromStrategy` 时,`m01_reallocation_movement_matches_request` 和
`m01_reallocation_flowcap_matches_movement` 不变量就会失败;确定性
回归测试独立于种子触发相同的两个标记。
`m01_solvency` 依然成立(它是一个参考偿付能力不变量,
两个孪生体在构造上都满足该不变量)。
## Pashov Audit Group 和 Euler Labs 的贡献
M-01 发现及其附带的测试(锁定提交处 `test/PublicAllocatorTest.sol` 中的
`testRellocateToWithDirectStrategySharesTransfer`)由 Pashov
Audit Group 编写。该修复属于 Euler Labs 的提交
`f07f6b1c5e1e`(“M-01 fix, PAG audit”)。本仓库建立在
这两项贡献之上:
## 目录结构
- `src/cases/m01-share-accounting-solvency/{clean,planted}/PublicAllocator.sol`
,即孪生对。纯净孪生体是 Euler 修复提交处的文件,
仅针对此代码树的深度调整了其导入路径(六行
前缀重写,无逻辑更改)。植入孪生体是同一个
文件,但在第 120 行进行了单块还原。
- `test/m01/`,即不变量测试套件。`M01Base.t.sol` 继承自 Euler
Earn 自己的 `IntegrationTest` fixture,因此 vault、EVC、permit2、
strategy 工厂和角色连线与 Euler Earn 自己的
测试套件所使用的完全一致。`M01Handler.sol` 暴露了四个模糊测试原语。
`M01SolvencyClean.t.sol` 和 `M01SolvencyPlanted.t.sol` 的区别仅在于它们部署了哪个孪生体的 `PublicAllocator`。
- `lib/euler-earn/`,锁定在 `f07f6b1c5e1e` 的 submodule,使用
`--recursive` 初始化,以获取传递依赖的 euler-vault-kit / EVC /
permit2 / OpenZeppelin。
- `ci/{clean_leg.sh,planted_leg.sh}`,这两个 CI 分支。纯净分支
运行 `forge test --no-match-contract 'Planted$' -vv`,要求 rc=0,
并且要求输出中没有 `INVARIANT VIOLATED` 标记。植入
分支则相反:每个 `*Planted` 测试套件必须非零退出并
打印至少一个标记;这些标记会被复制到
GitHub job summary 中。
## 工具链和锁定版本
- `solc` 精确到 0.8.26(与 Euler Earn 自己的 pragma 匹配)。
- `evm_version = "cancun"`(transient storage;EVC +
euler-vault-kit 所需)。
- `via_ir = true`(与 Euler Earn 自己的 profile 匹配;如果不使用 via-IR,EVault 部署
路径会超出 24kb 的 runtime 限制)。
- `foundry-rs/foundry-toolchain@v1` 位于 `v1.7.1`。
- Invariant 活动:`runs = 256, depth = 50, fail_on_revert = false`
(fuzzer 在探索 reallocation 空间时会访问许多良性的 revert 状态;
`fail_on_revert = false` 可让活动专注于
守恒属性)。
```
git clone --recursive
cd euler-earn-invariants
forge build
bash ci/clean_leg.sh # rc=0, no markers
bash ci/planted_leg.sh # rc=0, marker written to GITHUB_STEP_SUMMARY
```
## 许可证
本仓库自己的代码(`lib/` 之外的所有内容)采用
GNU General Public License,version 2 or later 授权。有关完整文本,请参见 `LICENSE`,
有关各组件的归属说明,请参见 `NOTICE`。
Euler Earn 作为锁定的 git submodule 引入到 `lib/euler-earn`
中,位于其 GPL-2.0-or-later 分支(Euler Earn 采用双重许可
GPL-2.0-or-later OR BUSL-1.1;本仓库在 GPL
分支下使用)。位于
`src/cases/m01-share-accounting-solvency/clean/PublicAllocator.sol` 的纯净孪生体是
`euler-xyz/euler-earn/src/PublicAllocator.sol` 在提交
`f07f6b1c5e1e` 处的派生作品;植入孪生体是同一个
文件的单块还原。两者都带有与上游源代码相同的 `SPDX-License-Identifier:
GPL-2.0-or-later` 头部标识。
## AI 披露
CaliperForge 的创作堆栈是 AI 增强的。关于此仓库中哪些部分使用了 AI 以及限制它的审查机制,已在
`AI_DISCLOSURE.md` 中披露。CI 裁定和许可声明不涉及 AI。
标签:DeFi, Solidity, 不变量测试, 安全测试, 对称加密, 攻击性安全, 智能合约, 自动化审计