Install any skill in seconds. Free to start, no credit card required.
Get Started Free →DeFi自動マーケットメーカー(AMM)スマートコントラクトセキュリティ監査パターン。フラッシュローン、スリッページ、サンドイッチング攻撃、価格操作、再入攻撃、不正確な整数演算をカバー。
.claude/skills/affaan-m-defi-amm-security/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 64% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 103% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 93% | 0% |
| case-09 | ✓→✓ | = Same ✓ | 71% | 0% |
Solidity AMM 合约、LP 金库和交换函数的关键漏洞模式及强化实现。
token.balanceOf(address(this)) 的合约将其作为检查清单加模式库使用。对照以下类别审查每个用户入口点,并优先使用强化示例而非自行编写的变体。
本技能中的 shell 命令是本地审计示例。仅在受信任的代码检出或一次性沙箱中运行,不要将不受信任的合约名称、路径、RPC URL、私钥或用户提供的标志拼接到 shell 命令中。在安装工具或运行可能消耗大量本地或付费资源的长时间模糊测试/静态分析任务前,请先询问。
切勿在命令示例、日志或报告中包含机密信息、私钥、助记词、API 令牌或主网签名凭证。
存在漏洞:
solidityfunction withdraw(uint256 amount) external { require(balances[msg.sender] >= amount); token.transfer(msg.sender, amount); balances[msg.sender] -= amount; }
安全:
solidityimport {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); }
当存在经过验证的库时,不要自行编写防护措施。
直接使用 token.balanceOf(address(this)) 进行份额计算,会让攻击者通过向合约发送代币(绕过预期路径)来操纵分母。
solidity// Vulnerable function deposit(uint256 assets) external returns (uint256 shares) { shares = (assets * totalShares) / token.balanceOf(address(this)); }
solidity// Safe 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; }
跟踪内部会计并衡量实际收到的代币。
现货价格可通过闪电贷操纵。优先使用 TWAP。
solidityuint32[] 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);
每个交换路径都需要调用者提供的滑点和截止时间。
solidityfunction 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); }
solidityimport {FullMath} from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; uint256 result = FullMath.mulDiv(a, b, c);
对于大型储备金计算,当存在溢出风险时,避免使用简单的 a * b / c。
solidityimport {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; contract MyAMM is Ownable2Step { function setFee(uint256 fee) external onlyOwner { ... } function pause() external onlyOwner { ... } }
所有权转移应优先使用显式接受,并对每个特权路径设置门控。
nonReentrantbalanceOf(address(this))SafeERC20amountOutMin 和 deadlinemulDivbashpip install slither-analyzer slither . --exclude-dependencies echidna-test . --contract YourAMM --config echidna.yaml forge test --fuzz-runs 10000
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | pass→pass | 14,078 | 8,318 | -41% | 1 | 1 | 0% | 1,649 | 2,819 | +71% | 0 | 0 | — |
case-01 | fail→pass | 20,953 | 19,729 | -6% | 1 | 1 | 0% | 4,215 | 5,307 | +26% | 0 | 0 | — |
case-02 | fail→pass | 19,219 | 21,711 | +13% | 1 | 1 | 0% | 3,332 | 5,462 | +64% | 0 | 0 | — |
case-03 | pass→pass | 8,888 | 6,145 | -31% | 1 | 1 | 0% | 1,842 | 2,574 | +40% | 0 | 0 | — |
case-04 | pass→pass | 6,869 | 6,924 | +1% | 1 | 1 | 0% | 1,311 | 2,678 | +104% | 0 | 0 | — |
case-05 | pass→pass | 14,032 | 9,943 | -29% | 1 | 1 | 0% | 2,477 | 3,259 | +32% | 0 | 0 | — |
case-06 | pass→pass | 12,248 | 12,313 | +1% | 1 | 1 | 0% | 1,909 | 3,436 | +80% | 0 | 0 | — |
case-07 | pass→pass | 15,411 | 14,129 | -8% | 1 | 1 | 0% | 2,430 | 3,977 | +64% | 0 | 0 | — |
case-08 | pass→pass | 18,247 | 18,129 | -1% | 1 | 1 | 0% | 3,592 | 5,042 | +40% | 0 | 0 | — |
case-10 | pass→pass | 6,719 | 5,871 | -13% | 1 | 1 | 0% | 1,220 | 2,389 | +96% | 0 | 0 | — |
case-11 | pass→pass | 11,801 | 8,842 | -25% | 1 | 1 | 0% | 1,814 | 2,924 | +61% | 0 | 0 | — |
case-12 | fail→pass | 13,910 | 2,821 | -80% | 1 | 1 | 0% | 892 | 1,807 | +103% | 0 | 0 | — |
case-13 | pass→pass | 4,256 | 2,722 | -36% | 1 | 1 | 0% | 775 | 1,875 | +142% | 0 | 0 | — |
case-14 | fail→pass | 4,757 | 1,332 | -72% | 1 | 1 | 0% | 833 | 1,607 | +93% | 0 | 0 | — |
case-15 | pass→pass | 14,780 | 9,558 | -35% | 1 | 1 | 0% | 2,199 | 3,078 | +40% | 0 | 0 | — |
case-16 | pass→pass | 8,702 | 2,745 | -68% | 1 | 1 | 0% | 1,445 | 1,873 | +30% | 0 | 0 | — |
case-17 | pass→pass | 6,679 | 4,082 | -39% | 1 | 1 | 0% | 1,079 | 2,066 | +91% | 0 | 0 | — |
case-18 | pass→pass | 15,218 | 9,124 | -40% | 1 | 1 | 0% | 2,359 | 3,010 | +28% | 0 | 0 | — |
case-19 | pass→pass | 12,053 | 9,106 | -24% | 1 | 1 | 0% | 2,373 | 3,051 | +29% | 0 | 0 | — |
case-20 | pass→pass | 14,702 | 16,578 | +13% | 1 | 1 | 0% | 2,758 | 4,404 | +60% | 0 | 0 | — |
case-21 | pass→pass | 19,569 | 19,175 | -2% | 1 | 1 | 0% | 3,653 | 4,860 | +33% | 0 | 0 | — |
case-22 | pass→pass | 31,924 | 29,640 | -7% | 1 | 1 | 0% | 3,944 | 4,678 | +19% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 21 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.