masonzeng702550/secure-vault-solidity

GitHub: masonzeng702550/secure-vault-solidity

一个用 Solidity 编写、基于 Foundry 测试的安全 ETH 金库合约,通过多层防御机制抵御重入等常见智能合约攻击。

Stars: 0 | Forks: 0

# SecureVault 一个安全的 Solidity ETH 金库合约,具有多层防御机制以抵御常见的智能合约攻击。使用 Foundry 构建和测试。 [![Solidity](https://img.shields.io/badge/Solidity-0.8.20-blue)](https://docs.soliditylang.org/) [![Foundry](https://img.shields.io/badge/Built%20with-Foundry-orange)](https://book.getfoundry.sh/) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) [![Tests](https://img.shields.io/badge/Tests-14%2F14%20passing-brightgreen)](test-results/forge-test-output.txt) ## 功能 - **ETH 存款 / 取款** 带有单笔交易取款上限 (`MAX_WITHDRAW = 10 ether`) - **用户间内部余额转账**(Gas 高效,无外部调用) - **双层访问控制** — `Owner` + `Operator` 角色 - **可暂停** — Operator 可以在紧急情况下停止存款/取款 - **紧急抽水** — 仅限 Owner 使用的资金救援后备方案 - **自定义错误** — 经过 Gas 优化的回退原因 (Solidity 0.8.4+) - **重入保护** — 手写的 1/2 状态模式(无 OZ 依赖) - **安全的 ETH 转账** — 使用 `call{value:..}` 并进行成功检查 - **防御性 fallback** — 未知函数调用会回退 ## 安全机制 | 威胁 | 防御手段 | | ----------------------------------- | -------------------------------------------- | | 重入攻击 | `nonReentrant` 修饰符 + CEI 模式 | | 整数溢出 / 下溢 | Solidity 0.8+ 内置检查 | | 未经授权的访问 | `onlyOwner` / `onlyOperator` 修饰符 | | ETH 转账失败(静默) | `call{value:..}` + 布尔值检查 | | 紧急锁定 | `Pausable` (`whenNotPaused`) | | 零地址 / 零金额 | `ZeroAddress` / `ZeroAmount` 自定义错误 | | 未知函数调用 | `fallback()` 回退 | ## 项目布局 ``` secure-vault-solidity/ ├── src/ │ └── SecureVault.sol # Main contract ├── test/ │ └── SecureVault.t.sol # Foundry test suite + ReentrancyAttacker ├── test-results/ │ ├── forge-test-output.txt # Captured `forge test -vv` output │ └── forge-gas-report.txt # Captured `forge test --gas-report` output ├── foundry.toml ├── LICENSE └── README.md ``` ## 快速开始 ### 前置条件 - [Foundry](https://book.getfoundry.sh/getting-started/installation) (forge, anvil, cast) 如果尚未安装,请安装 Foundry: ``` curl -L https://foundry.paradigm.xyz | bash foundryup ``` ### 克隆并安装依赖 ``` git clone https://github.com/masonzeng702550/secure-vault-solidity.git cd secure-vault-solidity forge install foundry-rs/forge-std --no-commit ``` ### 构建 ``` forge build ``` ### 运行测试 ``` # 带详细输出的标准运行 forge test -vv # 带 gas 报告 forge test --gas-report # 仅运行 reentrancy 攻击测试 forge test --match-test test_ReentrancyAttack_IsBlocked -vvvv ``` ## 测试套件 14 个测试涵盖了所有公共函数和主要攻击向量: | # | 测试名称 | 分类 | 状态 | | -- | ------------------------------------------------- | ----------------- | ------ | | 1 | `test_Deposit_UpdatesBalance` | 存款 | PASS | | 2 | `test_Deposit_RevertsOnZero` | 输入验证 | PASS | | 3 | `test_Receive_AccountsAsDeposit` | 接收 fallback | PASS | | 4 | `test_Withdraw_Success` | 取款 | PASS | | 5 | `test_Withdraw_RevertsOnExceedLimit` | 限额检查 | PASS | | 6 | `test_Withdraw_RevertsOnInsufficientBalance` | 余额检查 | PASS | | 7 | `test_TransferTo_MovesInternalBalance` | 内部转账 | PASS | | 8 | `test_OnlyOwner_CanTransferOwnership` | 访问控制 | PASS | | 9 | `test_Operator_CanPause_NonOperator_Cannot` | 角色权限 | PASS | | 10 | `test_WhenPaused_DepositReverts` | 可暂停 | PASS | | 11 | **`test_ReentrancyAttack_IsBlocked`** | **安全** | **PASS** | | 12 | `test_EmergencyWithdraw_OnlyOwner` | 仅限 Owner | PASS | | 13 | `test_EmergencyWithdraw_DrainsContract` | 紧急抽水 | PASS | | 14 | `test_Fallback_Reverts` | Fallback | PASS | ### 重入测试亮点 该套件包含一个真实的 `ReentrancyAttacker` 合约,它会: 1. 将 ETH 存入金库 2. 调用 `withdraw()`,触发向攻击者转账 ETH 3. 在 `receive()` 中,立即再次调用 `withdraw()` —— 尝试经典的递归抽水 结果:第二次调用被 `nonReentrant` 阻止,外部 ETH 转账因 `TransferFailed` 失败,攻击被原子性地回退,受害者的存款完好无损。 ``` [PASS] test_ReentrancyAttack_IsBlocked() (gas: 385,801) ``` 有关完整的原始运行记录,请参见 [`test-results/forge-test-output.txt`](test-results/forge-test-output.txt)。 ## Gas 报告(节选) | 函数 | 最小 | 平均 | 最大 | 调用次数 | | ------------------- | ------ | ------ | ------ | ----- | | `deposit` | 23,489 | 60,501 | 69,752 | 10 | | `withdraw` | 29,288 | 35,362 | 45,287 | 3 | | `transferTo` | 54,156 | 54,156 | 54,156 | 1 | | `emergencyWithdraw` | 24,171 | 43,470 | 62,769 | 2 | | `pause` | 25,733 | 27,817 | 29,974 | 3 | | `setOperator` | 48,254 | 48,254 | 48,254 | 1 | | `transferOwnership` | 24,170 | 24,170 | 24,170 | 1 | | `fallback` | 21,552 | 21,552 | 21,552 | 1 | 完整报告:[`test-results/forge-gas-report.txt`](test-results/forge-gas-report.txt) ## 设计说明 ### 为什么使用手写的 `nonReentrant`? 使用 1/2 状态标志(而不是 `bool`)可以节省 Gas —— 在两个非零值之间切换避免了每次调用时的冷 SSTORE 成本。这与 OpenZeppelin 内部使用的模式相同,在此处复制以保持合约无依赖。 ### 为什么使用自定义错误而不是 `require(.., "msg")`? 自定义错误 (Solidity 0.8.4+) 在部署时和运行时都更便宜,并且它们可以携带类型化参数以便于调试: ``` revert InsufficientBalance(requested, available); ``` ### 为什么使用 `call{value:..}` 而不是 `transfer`? `transfer` 和 `send` 仅转发 2,300 Gas,当接收方是具有复杂 fallback 逻辑的合约时,这会失效。`call` 转发所有剩余的 Gas —— 配合 CEI 模式和 `nonReentrant`,这是安全且向前兼容的。 ### 检查-生效-交互 (Checks-Effects-Interactions) 每个更改状态的函数都遵循严格的 CEI 模式:验证输入,更新状态,然后进行外部调用。即使移除了 `nonReentrant`,重入调用也会看到已更新的余额并自然失败 —— 深度防御。 ## 范围之外(改进空间) 该合约有意专注于单一的、防御严密的 ETH 金库。未涵盖的主题: - 跨函数和只读重入 - Front-running / MEV 缓解(commit-reveal, TWAP) - 签名重放保护 (EIP-712 / EIP-1271) - 可升级模式(UUPS / Transparent Proxy)和存储布局 这些都需要各自独立的合约和专用的测试文件。 ## 许可证 [MIT](LICENSE)
标签:Solidity, Web3安全, 以太坊, 区块链, 智能合约