yeick010/arbitrage-vault

GitHub: yeick010/arbitrage-vault

一个基于 ERC-4626 标准的 EVM 跨 DEX 套利收益金库智能合约,采用多重安全机制防护,适用于 DeFi 安全研究和测试网部署。

Stars: 0 | Forks: 0

# ArbitrageVault 一个用于 EVM 网络上跨 DEX 套利的 ERC-4626 收益金库(已准备好部署至 Sepolia 测试网)。 使用 Foundry + OpenZeppelin Contracts **v5.0.2** + Solidity **^0.8.24** 构建。 ## 目录 1. [架构](#architecture) 2. [安全态势](#security-posture) 3. [目录结构](#directory-layout) 4. [构建、测试、覆盖率](#build-test-coverage) 5. [静态分析](#static-analysis) 6. [部署 (Sepolia)](#deployment-sepolia) 7. [威胁模型](#threat-model) 8. [ABI 接口](#abi-surface) 9. [许可证](#license) ## 架构 ``` ┌────────────────────────────────────────────────────────────────┐ │ ArbitrageVault │ │ (ERC-4626, Pausable, AC) │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ deposit / mint / withdraw / redeem nonReentrant │ │ │ │ executeRebalance(params) onlyKeeper │ │ │ │ HWM accounting → perf fee 10% │ │ │ │ Timelock 48h on setFeeCollector / setStrategy / setOracle│ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ StrategyExecutor FeeCollector OracleAdapter │ │ · whitelisted · immutable · Chainlink primary │ │ routers treasury · TWAP fallback │ │ · minAmountOut · fee BPS ≤ 10% · ≤ 2% deviation │ │ enforced │ └────────────────────────────────────────────────────────────────┘ AccessManager (role registry) · ADMIN_ROLE · KEEPER_ROLE · PAUSER_ROLE ``` ### 合约 | 合约 | 用途 | | --------------------------------- | ---------------------------------------------------------------------------- | | `src/ArbitrageVault.sol` | ERC-4626 金库,HWM 利润核算,时间锁设置器,紧急暂停 | | `src/StrategyExecutor.sol` | 执行 UniV3 风格的 `exactInput` 兑换;路由白名单 + 强制滑点保护 | | `src/FeeCollector.sol` | 将 10% 的绩效费用转发给 **不可变 (immutable)** 国库 | | `src/OracleAdapter.sol` | Chainlink 主预言机 + TWAP 备用预言机,最大 2% 偏差,陈旧价格回退 | | `src/AccessManager.sol` | 独立的 AccessControl 注册表,用于 ADMIN / KEEPER / PAUSER 角色 | | `src/common/Errors.sol` | 所有自定义错误(节省 Gas,结构化的回退数据) | | `src/common/Const.sol` | 共享常量(BPS 分母,费用上限,最低存款,时间锁延迟) | ### 份额核算 (ERC-4626) - OpenZeppelin v5 虚拟份额,带有 `_decimalsOffset = 6` → 可抵抗通胀攻击。 - `totalAssets()` 返回金库的实时 ERC20 余额(策略是同步的——没有挂起的托管)。 - `minDeposit = 1e6` wei 和 `maxAssetsPerTx` 限制了每个用户的操作,以防止粉尘攻击和 DoS。 ### 费用模型 - 绩效费用**仅对高于高水位线 (HWM) 的已实现利润收取**。 - 费用上限为 **1_000 BPS (10%)**;在 `FeeCollector` 构造函数和每次 `setPerformanceFee` 时均会强制执行。 - 国库是**不可变的 (immutable)**——无法重新分配。 ## 安全态势 | 控制项 | 实现方式 | | ---------------------------------------- | -------------------------------------------------------------------- | | 重入攻击 | 在 `deposit/mint/withdraw/redeem/rebalance/syncHWM/rescue` 上使用 `ReentrancyGuard` | | 紧急停止 | 由专用 `PAUSER_ROLE` 控制的 `Pausable` | | 访问控制 | OZ `AccessControl` (ADMIN / KEEPER / PAUSER) — 无 EOA 所有者 | | 通胀攻击 | OZ v5 虚拟份额 + `_decimalsOffset = 6` | | DoS / 粉尘攻击 | `minDeposit = 1e6` + `maxAssetsPerTx` 上限 | | 预言机操纵 | Chainlink 主预言机 + TWAP 备用预言机,偏差 ≤ 2%,陈旧度检查 | | 滑点 | `executeRebalance` 上强制要求 `minAmountOut`,在两侧均重新检查 | | 特权更改 | `setFeeCollector / setStrategy / setOracle` 上的 48 小时时间锁 | | ERC20 安全性 | 到处使用 `SafeERC20` — `safeTransfer(From)` / `forceApprove` | | 任意 `from` | 已消除 — `FeeCollector.collect` & `StrategyExecutor` 使用 `msg.sender` | | CEI (检查-生效-交互) | 效果(HWM 更新,事件)在外部调用之前发出 | | 非标准代币 | `forceApprove` 处理 USDT 风格的 `approve` 回退 | | 多签就绪 | 所有 admin / pauser / treasury 都是为多签设计的纯地址 | ### 预审计清单状态 - [x] 在所有资金流动入口点上使用 `ReentrancyGuard` - [x] 无 `tx.origin` 授权 - [x] 无对不可信代码的 `delegatecall` - [x] 所有 ERC20 交互通过 `SafeERC20` - [x] 源码中没有硬编码地址 - [x] 每次状态更改都会发出事件(在分支处注明原因:`ChangeScheduled/Applied/Cancelled`) - [x] `.env` 位于 `.gitignore` 中,已提供 `.env.example` - [x] 预言机陈旧度 + 偏差检查 - [x] 测试覆盖率 ≥ 90% 行(已达到 **97.98%**) - [x] 在关键路径上进行 10_000 次运行的模糊测试 - [x] 不变式测试(费用上限,minPricePerShare,资产守恒) - [x] Slither 0 个高危,0 个中危(仅保留有意的时间戳比较低危问题) ## 目录结构 ``` arbitrage-vault/ ├── src/ │ ├── ArbitrageVault.sol │ ├── StrategyExecutor.sol │ ├── FeeCollector.sol │ ├── OracleAdapter.sol │ ├── AccessManager.sol │ ├── common/{Const.sol,Errors.sol} │ └── interfaces/{IFeeCollector,IOracleAdapter,IStrategyExecutor}.sol ├── test/ │ ├── Base.t.sol # shared test harness │ ├── ArbitrageVault.t.sol # 39 unit / fuzz tests │ ├── FeeCollector.t.sol # 15 unit tests │ ├── OracleAdapter.t.sol # 18 unit tests │ ├── StrategyExecutor.t.sol # 5 unit tests │ ├── AccessManager.t.sol # 5 unit tests │ ├── Invariants.t.sol # 4 invariant tests + handler │ └── mocks/{MockERC20,MockChainlinkFeed,MockTWAPSource,MockSwapRouter}.sol ├── script/ │ └── Deploy.s.sol # Sepolia deployment entrypoint ├── audit/ │ ├── slither.md # Slither checklist output │ └── THREAT_MODEL.md # STRIDE-based threat model ├── config/ # (populated per network) ├── deployments/ # (populated post-deploy) ├── foundry.toml ├── remappings.txt ├── .env.example ├── CHANGELOG.md └── README.md ``` ## 构建、测试、覆盖率 ### 前置条件 - [Foundry](https://book.getfoundry.sh/) (`forge`, `cast`, `anvil`) - Python 3.9+ (用于 Slither) ### 命令 ``` # 安装依赖项(版本已锁定) forge install # 编译 forge build # 运行完整测试套件并启用 traces forge test -vvv # 仅运行 fuzz/invariant 配置(10_000 次 fuzz 运行,64 次 invariant 运行 × 深度 32) forge test # 快速 CI 配置(1_000 次 fuzz 运行) FOUNDRY_PROFILE=ci forge test # 覆盖率摘要(仅限 src) FOUNDRY_PROFILE=ci forge coverage --no-match-coverage "test/" --report summary # gas 报告 forge test --gas-report ``` ### 测试结果(最近一次运行) ``` Ran 6 test suites: 86 tests passed, 0 failed, 0 skipped (86 total tests) src/AccessManager.sol 100.00% (15/15) 100.00% funcs src/ArbitrageVault.sol 98.44% (126/128) 96.55% funcs src/FeeCollector.sol 100.00% (27/27) 100.00% funcs src/OracleAdapter.sol 96.15% (50/52) 100.00% funcs src/StrategyExecutor.sol 96.15% (25/26) 100.00% funcs ──────────────────────────────────────────────────────── Total: 97.98% lines · 94.24% stmts · 98.00% funcs ``` ## 静态分析 ### Slither ``` slither . --filter-paths "lib|test" --checklist > audit/slither.md ``` 当前结果(参见 `audit/slither.md`): | 严重程度 | 数量 | 状态 | | -------- | ----- | ------------ | | 高危 | 0 | ✔ 已全部修复 | | 中危 | 0 | ✔ 已全部修复 | | 低危 | 4 | 符合预期(参见 audit/slither.md——用于 deadline/timelock/staleness 的时间戳 + 良性的授权重置) | | 信息 | 0 | — | 提交历史记录了每次修复: - `fix(security): eliminate arbitrary-send-erc20 HIGH` — 移除了 `FeeCollector.collect` 和 `StrategyExecutor.executeArbitrage` 中任意的 `from`,这也解决了 3 个 `reentrancy-balance` 高危问题。 - `fix(security): resolve reentrancy-no-eth and unused-return MEDIUM` — `syncHighWaterMark` 增加了 `nonReentrant`;`_getPrimaryPrice` 捕获了 `startedAt`。 - `fix(security): address Slither informational findings` — 在 `ChangeScheduled/Applied` 中索引了地址,CEI 重新排序了 `rescueToken`。 - `fix(security): move highWaterMark update before fee-collect external call (CEI)` — 将最后一个中危降级为良性的低危。 ## 部署 (Sepolia) ### 1. 复制并填写环境变量 ``` cp .env.example .env $EDITOR .env # fill PRIVATE_KEY, RPC, asset, admin multisig, etc. source .env ``` 关键:`.env` 已被 git 忽略。**切勿**提交或将私钥粘贴到日志中。 ### 2. 试运行 ``` forge script script/Deploy.s.sol \ --rpc-url $SEPOLIA_RPC_URL \ -vvvv ``` 在广播之前,请检查打印出的 `POST-DEPLOY CHECKLIST`。 ### 3. 广播 + 验证 ``` forge script script/Deploy.s.sol \ --rpc-url $SEPOLIA_RPC_URL \ --broadcast \ --verify ``` ### 4. 部署后连接(通过 admin 多签) 1. `executor.setRouterWhitelist(, true)` 2. `vault.scheduleStrategy(executor)` → 等待 **48 小时** → `vault.applyStrategy()` 3. (可选) `feeCollector.setAuthorisedCollector(vault, true)` 如果 admin ≠ 部署者 4. 使用打印出的地址更新 `deployments/sepolia.env` 5. 标记发行版:`git tag v0.1.0-sepolia && git push --tags` ### 5. 链上冒烟测试 ``` cast call $VAULT "totalSupply()(uint256)" --rpc-url $SEPOLIA_RPC_URL cast call $VAULT "asset()(address)" --rpc-url $SEPOLIA_RPC_URL cast call $FEE_COLLECTOR "treasury()(address)" --rpc-url $SEPOLIA_RPC_URL ``` ## 威胁模型 有关完整的 STRIDE 演练,请参见 [`audit/THREAT_MODEL.md`](audit/THREAT_MODEL.md)。 总结——该系统可防御: | 威胁类别 | 示例 | 缓解措施 | | ------------------ | ----------------------------------------- | -------------------------------------------------------------------------- | | **S**poofing (欺骗) | EOA 伪装成金库 | 在执行器上使用 `onlyVault` (不可变);到处使用基于 `msg.sender` 的授权 | | **T**ampering (篡改) | 恶意管理员替换国库 / 策略 | 国库不可变;strategy/fc/oracle 受 48 小时时间锁保护 | | **R**epudiation (抵赖) | 否认费用转发 | `FeesCollected` 事件 + 明确的链上转账日志 | | **I**nfo disclosure (信息泄露)| 预言机价格泄露 | 不适用——价格是公开的;TWAP 防止操纵 | | **D**oS (拒绝服务) | 粉尘存款泛滥,预言机数据陈旧 | `minDeposit`,`maxAssetsPerTx`,`StalePrice` 回退 | | **E**levation (提权) | Keeper 尝试管理员操作 | 分离的 ADMIN / KEEPER / PAUSER 角色;无跨角色隐式授权 | | 经济性 | 通胀攻击,夹子攻击,闪电贷 | 虚拟份额,滑点限制,偏差限制,nonReentrant | ## ABI 接口 关键金库入口点: ``` // ERC-4626 standard function deposit(uint256 assets, address receiver) external returns (uint256 shares); function mint(uint256 shares, address receiver) external returns (uint256 assets); function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); // Vault-specific function executeRebalance(IStrategyExecutor.ArbitrageParams calldata params) external returns (uint256 profit); function pause() external; // PAUSER_ROLE function unpause() external; // ADMIN_ROLE function syncHighWaterMark() external; // ADMIN_ROLE // Timelocked (48 h) function scheduleFeeCollector(address newValue) external; function applyFeeCollector() external; function cancelFeeCollector() external; // … and identical trio for strategy, oracle ``` 完整的构建产物会在 `forge build` 之后输出到 `out/`。要导出 ABI: ``` forge inspect ArbitrageVault abi > abi/ArbitrageVault.json forge inspect FeeCollector abi > abi/FeeCollector.json forge inspect OracleAdapter abi > abi/OracleAdapter.json ``` ## 许可证 MIT — 请参阅每个源文件中的 SPDX 标头。 由 ArbitrageVault 开发团队构建。未经第三方审计;**在没有独立安全审查的情况下请勿用于生产环境**。
标签:AMM, CEI模式, Chainlink, CISA项目, DeFi, ERC-4626, EVM, Foundry, HWM, OpenZeppelin, Sepolia测试网, Solidity, Streamlit, TWAP, Vault, Web3, 代币化策略, 加密货币, 区块链, 套利, 安全, 审计, 性能费, 提示词模板, 提示词注入, 收益, 收益聚合器, 时间锁, 智能合约, 智能合约开发, 暂停机制, 流动性管理, 算法交易, 自动化做市商, 访问控制, 超时处理, 跨DEX, 跨去中心化交易所, 量化交易, 金库, 防重入, 预言机, 高水位线