solidity-defi
solidity-defi: DeFi プロトコル開発スキル
DeFi プロトコル開発における主要パターン(AMM、レンディング、オラクル、Vault)を提供するドメイン特化スキル。
対象
- AMM / DEX(Uniswap V2/V3 型、Curve 型)
- レンディングプロトコル(Aave / Compound 型)
- 価格オラクル統合(Chainlink、TWAP)
- Vault / yield 戦略(ERC4626)
ワークフロー
Step 1: DeFi ドメイン判定
ユーザーの要件から対象ドメインを判定する:
| ユースケース | 対応ドメイン | リファレンス |
|---|---|---|
| トークン交換・流動性提供 | AMM / DEX | references/amm-patterns.md — Constant Product (Uniswap V2)、Concentrated Liquidity (V3)、StableSwap (Curve) から選択 |
| 貸付・借入・清算 | レンディング | references/lending-patterns.md — 金利モデル、担保管理、清算メカニズムを確認 |
| 外部価格データ取得 | オラクル | references/oracle-patterns.md — Chainlink Data Feed、TWAP、複合オラクルから選択 |
| 預入・利回り・戦略 | Vault | references/vault-patterns.md — ERC4626 標準、inflation attack 防御、マルチ戦略 |
複数のドメインが関連する場合(例: Vault + オラクル)は、全ての該当リファレンスを読み込む。
ユーザーの要件が不明確な場合は AskUserQuestion で DeFi の具体的なユースケースを確認する。
検証ゲート: 対象ドメインが上記 4 つのいずれかに該当すること。
Step 2: リファレンス読み込み
Step 1 で特定したリファレンスファイルを読み込み、以下を確認する:
- 該当パターンの設計思想と制約条件
- 必要なインターフェース(ERC4626、Chainlink AggregatorV3 等)
- コード例の前提条件(Solidity バージョン、依存ライブラリ)
検証ゲート: リファレンスが正常に読み込め、該当パターンが特定できること。
Step 3: コード生成
solidity-coreのlanguage-patterns.mdに従い NatSpec・コーディング規約を適用する。- DeFi 固有のセキュリティ対策を組み込む:
- 全ての state-changing 関数に
nonReentrant修飾子 - スリッページ保護パラメータ(
minAmountOut,deadline) - 適切な数値精度(WAD / RAY / BPS)
- 全ての state-changing 関数に
- テストコードを同時に生成する:
- 正常系(swap、deposit、withdraw)
- 異常系(スリッページ超過、残高不足、権限不足)
- Fuzz テスト(数値入力のある関数)
- Invariant テスト(プールの不変条件:
k >= kBefore)
検証ゲート: forge build がエラーなく完了すること。
Step 4: DeFi セキュリティ確認
DeFi 特有のセキュリティリスクを solidity-core の security-checklist.md と合わせて確認する:
- フラッシュローン攻撃: 1 トランザクション内での価格操作に耐性があるか。TWAP を使用しているか。
- 価格操作: オラクルがスポット価格のみに依存していないか。Chainlink の
latestRoundDataで stale check をしているか。 - Reentrancy: CEI パターン +
nonReentrantを遵守しているか。特にwithdraw/redeem関数。 - スリッページ保護: ユーザーが
minAmountOutを指定でき、フロントランニングから保護されているか。 - MEV 対策:
deadlineパラメータでサンドイッチ攻撃のウィンドウを制限しているか。 - Inflation Attack(ERC4626): 初回デポジットのシェア膨張攻撃に対して virtual shares / virtual assets で防御しているか。
検証ゲート: CRITICAL レベルのセキュリティ問題が 0 件であること。
使用例
例 1: Uniswap V2 型 AMM の実装
ユーザー入力: 「シンプルな AMM を作りたい。流動性追加とトークンスワップができるようにして」
アクション:
- Step 1: AMM / DEX と判定 →
references/amm-patterns.mdを選択 - Step 2: Constant Product AMM パターンを読み込み
- Step 3: 以下を生成:
src/ConstantProductAMM.sol— Pair コントラクト(x * y = kロジック、nonReentrant、スリッページ保護)src/interfaces/IAMM.sol— インターフェース定義test/ConstantProductAMM.t.sol— addLiquidity / swap / removeLiquidity のテスト + K 値 invariant テスト
- Step 4: セキュリティ確認 → Reentrancy 防止、スリッページ保護、K 値検証を確認
結果: スリッページ保護・Reentrancy 防止を備えた AMM とテストスイートが生成される。
例 2: ERC4626 Vault の実装
ユーザー入力: 「ERC4626 の Vault を作りたい。ETH ステーキングの利回りを分配するもの」
アクション:
- Step 1: Vault と判定 →
references/vault-patterns.mdを選択 - Step 2: ERC4626 標準 + inflation attack 防御パターンを読み込み
- Step 3: 以下を生成:
src/StakingVault.sol— OpenZeppelinERC4626を継承。virtual shares / virtual assets で inflation attack を防御。deposit/withdraw/redeem実装test/StakingVault.t.sol— デポジット・引出のテスト + 初回デポジット攻撃の防御テスト + share 計算の Fuzz テスト
- Step 4: inflation attack 防御の確認、Reentrancy 確認
結果: Inflation attack に耐性のある ERC4626 Vault がテスト付きで生成される。
例 3: Chainlink オラクル統合
ユーザー入力: 「ETH/USD の価格を Chainlink で取得して、USD 建ての計算をしたい」
アクション:
- Step 1: オラクルと判定 →
references/oracle-patterns.mdを選択 - Step 2: Chainlink Data Feed パターンを読み込み
- Step 3: 以下を生成:
src/PriceConsumer.sol—AggregatorV3Interfaceを使用。stale price チェック(updatedAt+ 閾値)、negative price チェック、decimals 正規化test/PriceConsumer.t.sol— モックオラクルでテスト。stale price / negative price / decimals 変換のテスト
- Step 4: stale check の閾値(heartbeat 設定に基づく)、フォールバックオラクルの有無を確認
結果: Stale / negative price に対するガードを備えた Chainlink オラクル統合が生成される。
トラブルシューティング
1. K 値 invariant テストが失敗する
症状: AMM の require(k >= kBefore) でリバート
原因と対策:
- 丸め誤差: Solidity の整数除算による丸めで K 値が微小に減少する。
require(k >= kBefore - 1)で許容誤差を設定するか、mulDiv関数で精度を向上させる。 - 手数料計算の順序: 手数料を差し引いてからスワップ計算を行っているか確認する。手数料を考慮した K 値検証にする。
2. Chainlink オラクルが stale 価格を返す
症状: require(updatedAt > block.timestamp - STALE_THRESHOLD) でリバート
原因と対策:
- heartbeat 設定の不一致: Chainlink の Data Feed ごとに heartbeat(更新間隔)が異なる。ETH/USD(Mainnet)は 3600 秒。対象 feed の heartbeat を確認し、
STALE_THRESHOLDを heartbeat + バッファ(例:3600 + 300)に設定する。 - テストネットの挙動: テストネットの Chainlink feed は本番より更新が遅い場合がある。テストではモックオラクルを使用する。
- フォールバック: Chainlink が応答しない場合に備え、TWAP 等のフォールバックオラクルを設定する。
3. ERC4626 の share 計算がゼロになる
症状: deposit 後に balanceOf(user) がゼロ
原因と対策:
- Inflation attack: 攻撃者が最初に 1 wei をデポジット後、大量のトークンを直接 Vault に送信して share 価値を膨張させた。OpenZeppelin の
ERC4626は v5.x でデフォルトで virtual shares/assets(オフセット = 1)を使用するため、最新版を使用する。 - decimals の不一致: 基礎トークンと Vault の decimals が異なる。
decimalsOffset()を確認する。
4. swap トランザクションがフロントランされる
症状: 予想よりも不利なレートでスワップが実行される
原因と対策:
- スリッページ保護の不足:
minAmountOutパラメータが 0 に設定されている。フロントエンドで適切なスリッページ(0.5-1%)を計算して設定する。 - deadline 未設定:
deadlineパラメータでトランザクションの有効期限を設定する。block.timestamp + 300(5分)が一般的。 - Private mempool: Flashbots Protect 等のプライベート RPC を使用し、パブリック mempool にトランザクションを公開しない。
5. Reentrancy による資金流出
症状: withdraw 関数が繰り返し呼び出され、想定以上の資金が引き出される
原因と対策:
- CEI パターン違反: 外部呼び出し(
token.transfer)の前に状態を更新(残高減算)しているか確認する。Checks-Effects-Interactions の順序を厳守する。 nonReentrant未使用: 全ての資金移動関数に OpenZeppelin のReentrancyGuard.nonReentrantを適用する。- コールバック関数: ERC777 や
receive()/fallback()からの再帰呼び出しに注意する。
注意事項
- DeFi プロトコルは攻撃対象になりやすいため、セキュリティを最優先にする。
- 数値計算は精度が重要。WAD(1e18)、RAY(1e27)、BPS(1e4)を一貫して使用する。
- 基盤的なパターン(アクセス制御、ガス最適化等)は
solidity-coreを参照する。 - フロントエンド統合は
web3-frontendを参照する。 - 本番デプロイ前に外部監査を推奨する。
- OpenZeppelin コントラクト(
ERC4626,ReentrancyGuard等)の利用を推奨し、独自実装は避ける。