一、技能概述
该技能适用于编写或审计 Solidity AMM 或流动性池合约、实现持有代币余额的兑换、存款、提款、铸造或销毁流程,以及审查任何在份额或储备金计算中使用 token.balanceOf(address(this)) 的合约。它同时覆盖向 DeFi 协议添加费用设置器、暂停器、预言机更新或其他管理功能的场景。
核心原则:将其作为检查清单加模式库使用,对照各安全类别审查每个用户入口点,优先使用强化示例而非自行编写的变体。
二、核心功能
1. 重入攻击防护:强制遵循 CEI 顺序
存在漏洞的写法:先转账后更新状态(易受重入攻击):
function withdraw(uint256 amount) external {
require(balances[msg.sender] >= amount);
token.transfer(msg.sender, amount);
balances[msg.sender] -= amount;
}
安全的写法:使用 nonReentrant 修饰器,并遵循 CEI(Checks-Effects-Interactions) 顺序——先检查、再更新状态、最后进行外部交互:
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
using SafeERC20 for IERC20;
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount, "Insufficient");
balances[msg.sender] -= amount;
token.safeTransfer(msg.sender, amount);
}
原则:当存在经过验证的库时,不要自行编写防护措施。
2. 捐赠或通胀攻击防护
直接使用 token.balanceOf(address(this)) 进行份额计算,会让攻击者通过向合约发送代币(绕过预期路径)来操纵分母。
存在漏洞的写法:
function deposit(uint256 assets) external returns (uint256 shares) {
shares = (assets * totalShares) / token.balanceOf(address(this));
}
安全的写法:跟踪内部会计并衡量实际收到的代币:
uint256 private _totalAssets;
function deposit(uint256 assets) external nonReentrant returns (uint256 shares) {
uint256 balBefore = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), assets);
uint256 received = token.balanceOf(address(this)) - balBefore;
shares = totalShares == 0 ? received : (received * totalShares) / _totalAssets;
_totalAssets += received;
totalShares += shares;
}
3. 预言机操纵防护
现货价格可通过闪电贷操纵,应优先使用 TWAP(时间加权平均价格):
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = 1800;
secondsAgos[1] = 0;
(int56[] memory tickCumulatives,) = IUniswapV3Pool(pool).observe(secondsAgos);
int24 twapTick = int24(
(tickCumulatives[1] - tickCumulatives[0]) / int56(uint56(30 minutes))
);
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(twapTick);
4. 滑点保护
每个兑换路径都需要调用者提供的滑点(amountOutMin)和截止时间(deadline):
function swap(
uint256 amountIn,
uint256 amountOutMin,
uint256 deadline
) external returns (uint256 amountOut) {
require(block.timestamp <= deadline, "Expired");
amountOut = _calculateOut(amountIn);
require(amountOut >= amountOutMin, "Slippage exceeded");
_executeSwap(amountIn, amountOut);
}
5. 安全的储备金计算
对于大型储备金计算,当存在溢出风险时,避免使用简单的 a * b / c,应使用安全原语如 mulDiv:
import {FullMath} from "@uniswap/v3-core/contracts/libraries/FullMath.sol";
uint256 result = FullMath.mulDiv(a, b, c);
6. 管理控制
所有权转移应优先使用显式接受,并对每个特权路径设置门控:
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
contract MyAMM is Ownable2Step {
function setFee(uint256 fee) external onlyOwner { ... }
function pause() external onlyOwner { ... }
}
三、安全检查清单
技能提供了完整的审计检查清单:
-
暴露于重入攻击的入口点使用
nonReentrant -
遵循 CEI(检查-效果-交互)顺序
-
份额计算不依赖原始的
balanceOf(address(this)) -
ERC-20 转账使用
SafeERC20 -
存款衡量实际收到的代币
-
预言机读取使用 TWAP 或其他抗操纵源
-
兑换需要
amountOutMin和deadline -
对溢出敏感的储备金计算使用安全原语如
mulDiv -
管理函数受访问控制
-
存在紧急暂停功能并经过测试
-
在生产前运行静态分析和模糊测试
四、审计工具
技能推荐以下审计工具:
# Slither 静态分析
pip install slither-analyzer
slither . --exclude-dependencies
# Echidna 模糊测试
echidna-test . --contract YourAMM --config echidna.yaml
# Foundry 模糊测试
forge test --fuzz-runs 10000
五、主要用途
-
AMM 合约开发安全指导 —— 在编写新的流动性池或兑换合约时,对照模式库确保关键安全模式已正确实现
-
智能合约安全审计 —— 审计现有 AMM 合约时,逐项对照安全检查清单识别漏洞
-
DeFi 协议代码审查 —— 审查添加费用设置器、暂停器、预言机更新等管理功能时的安全风险
-
团队安全培训 —— 作为 Solidity 开发团队 DeFi 安全编码规范的参考文档
-
漏洞修复参考 —— 发现重入、预言机操纵、捐赠攻击等问题时,快速定位对应的强化实现方案
六、重要原则
-
使用经过验证的库:当 OpenZeppelin 等经过验证的库存在时,不要自行编写防护措施
-
跟踪内部会计:份额计算不依赖原始的
balanceOf(address(this)),应衡量实际收到的代币 -
TWAP 优先:预言机读取优先使用 TWAP 等抗操纵源,而非现货价格
-
滑点与截止时间:每个兑换路径都需要调用者提供的滑点和截止时间参数
-
使用安全数学原语:对溢出敏感的储备金计算使用
mulDiv等安全原语 -
所有权转移显式接受:使用
Ownable2Step等模式,要求新所有者显式接受所有权 -
生产前充分测试:在生产前运行静态分析(Slither)和模糊测试(Echidna/Foundry)
-
安全执行审计命令:仅在受信任的代码检出或一次性沙箱中运行审计命令,不要将不受信任的合约名称、路径或用户提供的标志拼接到 shell 命令中
七、总结
DeFi AMM Security 是一份 Solidity AMM 合约安全开发与审计的完整技能指南,覆盖重入攻击、CEI 顺序、捐赠/通胀攻击、预言机操纵、滑点保护、安全数学计算和管理控制等 6 大核心安全领域。它提供了“存在漏洞 vs 安全实现”的对比示例、完整的审计检查清单以及 Slither、Echidna、Foundry 等工具的实用命令。该技能适用于 DeFi 开发者在编写新 AMM 合约、审计现有流动性池代码、审查管理功能安全风险等场景,是一份可直接落地使用的安全检查清单与模式库。