v4-hook-generator について
v4-hook-generatorは、OpenZeppelin Contracts Wizardを使ってUniswap v4のhookコントラクトを設定・生成するスキルです。Solidity開発者がhookの種類や設定を選び、MCPリクエストを組み立てて、生成後のセキュリティ確認につなげます。
主な機能
- 01目的に応じた14種類のhookを比較
- 02権限、ユーティリティ、シェア、アクセス制御の設定
- 03標準的なMCPツール呼び出しJSONの組み立て
- 04hook固有の数値入力の選択
- 05生成からセキュリティ確認までの手順
活用シーン
- 01手数料、オラクル、MEV対策hookの雛形作成
- 02カスタムhookの権限選定
- 03generate_hookリクエストの準備
- 04実装前の設定選択肢の比較
MCP 対応
OpenZeppelin Contracts WizardのMCPツール`generate_hook`に渡すリクエストの作成を案内し、Solidityのhookコード生成につなげます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uniswap/ uniswap-ai --skill v4-hook-generatorインストール後、Claude Code で/v4-hook-generatorを入力して読み込まれたか確認します。
詳細
v4 Hook Generator
OpenZeppelin Contracts Wizard MCP ツールを使って Uniswap v4 のフックコントラクトを生成します。このスキルでは、適切なフックタイプの選択、権限とユーティリティの設定、標準的な MCP JSON の組み立て、MCP ツールの呼び出しによるコンパイル可能な Solidity コードの生成について説明します。
セキュリティ関連スキル:生成されたフックコードは、資金を扱うコントラクトに関わります。デプロイ前に必ず生成直後に
v4-security-foundationsスキルを適用し、権限、デルタの計算、アクセス制御を監査してください。
このスキルを使用する場面
次のような場合に、このスキルを使用します。
- Uniswap v4 の新しいフックコントラクトを一から作成する
- 特定のユースケース(手数料、MEV 対策、オラクルなど)に適したベースフックタイプを選択する
- フックの権限、ユーティリティライブラリ、シェア、アクセス制御を設定する
- OpenZeppelin Contracts Wizard を呼び出すための標準的な MCP ツール呼び出し JSON を作成する
- 実装を確定する前に、フック設定の選択肢ごとのトレードオフを理解する
前提条件/関連スキル:v4-security-foundations — カスタムロジックを書く前と、デプロイ前に再度実行してください。フックの設定を誤ると、ユーザーの資金が流出するおそれがあります。
フックタイプの選択表
主な目的に合ったベースフックタイプを選択します。フックに複数の目的がある場合は、最も重要な懸念に対応するタイプを選び、その上に追加のロジックを重ねてください。
| 目的 | 使用するフック |
|---|---|
| カスタムスワップロジック | BaseHook |
| 非同期/遅延スワップ | BaseAsyncSwap |
| フック所有の流動性 | BaseCustomAccounting |
| カスタムカーブ | BaseCustomCurve |
| 動的 LP 手数料 | BaseDynamicFee |
| 動的スワップ手数料 | BaseOverrideFee |
| スワップ後の手数料 | BaseDynamicAfterFee |
| 固定フック手数料 | BaseHookFee |
| MEV 対策 | AntiSandwichHook |
| JIT 対策 | LiquidityPenaltyHook |
| 指値注文 | LimitOrderHook |
| 待機中の利回り | ReHypothecationHook |
| オラクル | BaseOracleHook |
| V3 互換オラクル | OracleHookWithV3Adapters |
選択のヒント:
BaseHookは汎用的な出発点です。組み込みロジックに具体的な利点がある場合に限り、特殊なタイプを選択してください。BaseCustomCurveは AMM の計算全体を置き換えます。新しい価格設定アルゴリズムを実装する場合に限り使用してください。AntiSandwichHookとLiquidityPenaltyHookはどちらも MEV に対処しますが、対象となるアクター(トレーダーと JIT LP)は異なります。どの攻撃ベクトルを軽減するのかを明確にしてください。- 下流の統合先で Uniswap v3 の
IUniswapV3Pool互換オラクルインターフェースが必要な場合は、OracleHookWithV3Adaptersが適しています。
最小限の選択チェックリスト
MCP ツールを呼び出す前に、次の 6 項目をすべて決定してください。
- フックタイプ — 上の選択表から選択します
- 有効にする権限 — ロジックで実際に使用するコールバックのみ(
beforeSwap、afterSwapなど) - ユーティリティライブラリ — 必要に応じて
currencySettler、safeCast、transientStorage - シェア —
false、ERC20、ERC6909、ERC1155のいずれか - アクセス制御 —
ownable、roles、managedのいずれか - フックの入力値 —
blockNumberOffset、maxAbsTickDelta(これらを使用するフックタイプのみ)
権限の設定
14 個すべての権限フラグと、それぞれを有効にするタイミングに関するガイダンスです。すべてのフラグを false にした状態から始め、フックのロジックで必要なものだけを有効にしてください。有効にする権限が増えるたびにフックの攻撃対象領域が広がり、デプロイ済みアドレスに特定のビットを設定する必要があります(下記のアドレスエンコーディングに関する注記を参照)。
| 権限フラグ | 有効にするタイミング | リスク |
|---|---|---|
beforeInitialize | プール作成時のパラメーターを検証または制限する必要がある場合 | 低 |
afterInitialize | プール作成後に状態を設定する必要がある場合 | 低 |
beforeAddLiquidity | LP の預け入れを制限または変更する必要がある場合 | 中 |
afterAddLiquidity | LP のポジションを追跡したり、報酬を分配したりする場合 | 低 |
beforeRemoveLiquidity | ロックアップ期間や退出時の手数料ロジックが必要な場合 | 高 |
afterRemoveLiquidity | 会計処理のためにポジションの削除を追跡する場合 | 低 |
beforeSwap | スワップの動作を変更したり、動的手数料を適用したり、スワップをブロックしたりする場合 | 高 |
afterSwap | オラクルや会計処理のために、スワップ後の最終状態を観測する場合 | 中 |
beforeDonate | プールへの寄付を許可するユーザーを制限する場合 | 低 |
afterDonate | 寄付イベントを追跡する場合 | 低 |
beforeSwapReturnDelta | カスタム AMM カーブまたは JIT 流動性を実装する場合(重大:NoOp 攻撃ベクトル — v4-security-foundations を参照) | 重大 |
afterSwapReturnDelta | スワップの出力からフック手数料を徴収する場合 | 高 |
afterAddLiquidityReturnDelta | 預け入れ時に LP トークンの数量を調整する場合 | 高 |
afterRemoveLiquidityReturnDelta | 引き出し額を調整する場合 | 高 |
アドレスエンコーディングに関する注記:権限はフックコントラクトのデプロイ済みアドレスのビットとしてエンコードされます。デプロイ時にアドレスに正しいビットが設定されていないと、PoolManager によってリバートされます。HookMiner(v4-periphery のもの)を使用し、正しいビットパターンを持つアドレスが生成されるソルトをマイニングしてください。デプロイ後に権限を変更してはいけません。アドレスは不変です。
ユーティリティライブラリの選択
生成されるフックには、3つのオプションのユーティリティライブラリを含めることができます。フックのロジックで使用するものだけを含めてください。
| ライブラリ | 含める場合 |
|---|---|
currencySettler | フックが自身と PoolManager の間でトークンを移動する場合(例:カスタム会計、手数料の徴収) |
safeCast | フックで整数型間のキャスト時にオーバーフローする可能性がある演算を行う場合 |
transientStorage | ストレージに永続化せずに、単一トランザクション内のコールバック間でデータを渡す必要がある場合(EVM Cancun 以降、Solidity >= 0.8.24 が必要) |
ガイダンス:
beforeSwapReturnDelta、afterSwapReturnDelta、afterAddLiquidityReturnDelta、またはafterRemoveLiquidityReturnDeltaが有効な場合、ほぼ常にcurrencySettlerが必要です。正しいsync → transfer → settleの順序を実装するsettleおよびtakeヘルパーを提供します。transientStorageは、トランザクション内の状態を保存するためのストレージスロットに代わる、ガス効率の高い方法です。 コールド SSTORE に 20k gas を費やさずに、beforeSwapからafterSwapにフラグや値を渡すために使用します。safeCastは、int256/uint256の変換から導出される金額を計算する場合、特に手数料の計算での使用を推奨します。
シェアの設定
shares オプションは、生成されるフックがユーザーのシェアを表すトークンを発行するかどうかを制御します
(例:フックが所有する流動性プール内の LP ポジション)。
| オプション | 説明 | 使用する場合 |
|---|---|---|
false | シェアトークンなし — フックは預け入れられた資産の所有権を追跡しません | ユーザー資金を保有しないシンプルなフック |
ERC20 | 代替可能なシェアトークン — 1つのトークンがフック保有資産全体に対する比例所有権を表します | 交換可能なシェアを持つ、フックが管理する流動性プール |
ERC6909 | マルチトークン(最小構成)— 1つのコントラクトで、ERC1155 より低いオーバーヘッドで複数のトークン ID を管理します | フックが複数の異なる資産クラスを効率的に管理する場合 |
ERC1155 | マルチトークン(標準)— メタデータ URI に対応した完全な ERC1155 | 幅広いウォレットやマーケットプレイスとの互換性が必要な場合 |
トレードオフ:
false:バイトコードが最小で、シェア会計のオーバーヘッドもありません。手数料フックやオラクルに適しています。ERC20:最もシンプルな代替可能シェアです。DeFi とのコンポーザビリティに優れています(例:担保として使用)。ERC6909:最小限のインターフェースを備えた、ガス効率の高いマルチトークンです。新しいプロトコルの設計に適しています。ERC1155:エコシステムで最も幅広くサポートされています(ウォレット、エクスプローラー、NFT マーケットプレイス)。転送時のガスコストは ERC6909 より高くなります。
アクセス制御のオプション
access オプションは、生成されるフックのコンストラクターと管理インターフェースの形式を決定します。
| オプション | コンストラクターの形式 | 用途 |
|---|---|---|
ownable | constructor(IPoolManager, address initialOwner) | 1 人のオーナーがすべての管理機能を制御する場合 |
roles | constructor(IPoolManager, address admin) | 細分化された権限を持つ複数のロールを使用する場合(OpenZeppelin AccessControl) |
managed | constructor(IPoolManager, address authority) | 外部の権限コントラクトがアクセス許可を管理する場合(OpenZeppelin AccessManaged) |
ガイダンス:
ownableは最もシンプルです。1 つのアドレスですべての特権操作を実行できます。初期段階のフックや個人用ツールに適しています。rolesは OpenZeppelinAccessControlを通じてADMIN_ROLE、PAUSER_ROLEなどを追加します。チームメンバーごとに異なる権限が必要な場合に使用してください(例:手数料は更新できるが、コントラクトはアップグレードできないキーパーボット)。managedは、すべてのアクセス許可チェックを別個のAccessManagerコントラクトに委譲します。複数のコントラクトにまたがる統一的なガバナンスレイヤーが必要な場合や、管理操作にタイムロックを設ける場合に使用してください。
注:
accessオプションを変更すると、コンストラクターのシグネチャも変わります。それに応じてデプロイスクリプトと初期化ロジックを更新してください。ownableを使用する場合は、initialOwnerがゼロアドレスでないことを確認してください。OpenZeppelin のOwnableは v5 以降、ゼロアドレスを指定するとリバートします。
フック入力のリファレンス
一部のフックタイプでは、動作を調整する数値の設定入力を受け付けます。これらは MCP ツール呼び出しの inputs オブジェクトとして渡します。
| 入力 | 型 | 使用するフック | 説明 |
|---|---|---|---|
blockNumberOffset | uint256 | AntiSandwichHook、LiquidityPenaltyHook | サンドイッチ/JIT 検出ウィンドウが開くまでのブロック数 |
maxAbsTickDelta | int24 | AntiSandwichHook | MEV 保護が作動するまでに許容される、ブロックごとの最大ティック変動幅 |
これらの入力を使用しないフックタイプでは、inputs フィールドを省略するか、空のオブジェクト {} を渡してください。
サポートされていない入力を MCP ツールに渡してもエラーにはなりませんが、値は無視されます。
MCP ツール呼び出し(標準形式)
OpenZeppelin Contracts Wizard は generate_hook MCP ツールを公開しています。以下は標準的な JSON スキーマです。上のセクションで決めた内容に従って各フィールドを設定し、このオブジェクトをツールの引数として渡してください。
{
"hook": "BaseHook",
"name": "MyHook",
"pausable": false,
"currencySettler": true,
"safeCast": true,
"transientStorage": false,
"shares": { "options": false },
"permissions": {
"beforeInitialize": false,
"afterInitialize": false,
"beforeAddLiquidity": false,
"beforeRemoveLiquidity": false,
"afterAddLiquidity": false,
"afterRemoveLiquidity": false,
"beforeSwap": true,
"afterSwap": false,
"beforeDonate": false,
"afterDonate": false,
"beforeSwapReturnDelta": false,
"afterSwapReturnDelta": false,
"afterAddLiquidityReturnDelta": false,
"afterRemoveLiquidityReturnDelta": false
},
"inputs": {
"blockNumberOffset": 1,
"maxAbsTickDelta": 100
},
"access": "ownable",
"info": { "license": "MIT" }
}
フィールドの説明:
hook:文字列 — 選択表にある 14 種類のフックのいずれかname:文字列 — Solidity コントラクト名(パスカルケース、スペースなし)pausable:ブール値 — フックを OpenZeppelinPausableでラップし、管理機能としてpause()/unpause()を追加しますshares.options:false|"ERC20"|"ERC6909"|"ERC1155"access:"ownable"|"roles"|"managed"info.license:SPDX ライセンス識別子 — オープンソースのフックには"MIT"を使用してくださいinputs:blockNumberOffset/maxAbsTickDeltaを使用しないフックタイプでは、省略するか{}を渡します
ワークフロー:収集 → 設定 → 生成 → セキュリティ確保
このスキルを使用する際は、毎回以下の手順に従ってください。
ステップ 1:要件を収集する
ユーザーに質問するか、コンテキストから推測します。
- フックの主な目的は何ですか?(判定表に照らし合わせます。)
- フックがインターセプトする必要があるライフサイクルイベントはどれですか?(権限に照らし合わせます。)
- フックはユーザーの資金を保持または移動しますか?(
currencySettlerとsharesを決定します。) - フックの管理者は誰ですか?(単一のオーナー、ロールベースのチーム、外部ガバナンスのいずれですか?)
- フックは、1 回のトランザクション内でコールバック間の状態を受け渡す必要がありますか?
- EVM Cancun に対応するチェーンで使用しますか?(
transientStorageに必要です。)
ステップ 2:フックの種類を選択する
判定表を使って、最適なフックの種類を 1 つ特定します。ユーザーの目的が複数の種類に該当する場合は、トレードオフを説明して確認を求めます。選択した種類と、その理由を記録します。
ステップ 3:6 つすべての設定を決定する
最小限の判断チェックリストに沿って進めます。
hookを選択した種類に設定します。- 各権限フラグを設定します。デフォルトは
falseとし、ロジックで必要なものだけを有効にします。 - ユーティリティライブラリのガイダンスに基づいて、
currencySettler、safeCast、transientStorageを設定します。 - shares のガイダンスに基づいて、
shares.optionsを設定します。 - アクセス制御のガイダンスに基づいて、
accessを設定します。 - フックの種類で
blockNumberOffsetまたはmaxAbsTickDeltaを使用する場合に限り、inputsを設定します。
ステップ 4:MCP ツールを組み立てて呼び出す
ステップ 3 の設定から JSON オブジェクトを構成し、それを指定して OpenZeppelin Contracts Wizard MCP ツールを呼び出します。ツールは Solidity ソースコードを返します。ファイルを自動的に書き込むことはありません。
生成されたコードを受け取った後:
- コードをユーザーに表示します。
- 生成された主要なセクション(コンストラクター、
getHookPermissions、有効化されたコールバック)を説明します。 - 必要な手動作業(アドレスのマイニングに HookMiner を使うこと、
accessがrolesまたはmanagedの場合はコンストラクター引数に合わせてデプロイスクリプトを更新すること)を伝えます。
ステップ 5:セキュリティの基盤を適用する
コードをデプロイする前に、必ずユーザーに注意を促し、v4-security-foundations を実行します。
- 有効化されたすべてのコールバックで
msg.sender == address(poolManager)を確認していることを検証します。 - 有効化された
*ReturnDelta権限について、NoOp 攻撃にさらされるリスクを確認します。 - すべての実行パスでデルタの合計がゼロになることを確認します。
v4-security-foundationsにあるデプロイ前監査チェックリストをすべて実行します。
重要な注意事項
- アクセス制御によってコンストラクターの形式が変わります:
ownableを選ぶとinitialOwnerパラメーターが追加されます。rolesではadminパラメーターが、managedではauthorityパラメーターが追加されます。それに応じて、デプロイスクリプトとファクトリーコントラクトを更新してください。 - 権限はフックのアドレスにエンコードされます:有効化された各権限フラグは、デプロイされたフックアドレスの下位バイトの特定のビットに対応します。PoolManager は、コールバックのたびにこれらのビットを検証します。一致するアドレスを生成するデプロイ用ソルトをマイニングするには、
v4-peripheryのHookMinerを使用します。 - MCP が返すのはコードのみです。ファイルは書き込みません:生成された Solidity は文字列として返されます。自分でディスクに書き込む必要があります(例:
packages/contracts/src/hooks/MyHook.sol)。
関連スキル
v4-security-foundations— 生成後に実行してください。 Uniswap v4 フックのセキュリティ監査:権限リスクマトリックス、NoOp 攻撃パターン、デルタ会計、アクセス制御の検証、デプロイ前監査チェックリスト全体が含まれます。このレビューを完了せずに、生成されたフックコードをデプロイしてはいけません。viem-integration— 生成されたフックコントラクトをデプロイし、viem/wagmi を使って操作しますv4-sdk-integration— Uniswap v4 SDK を使ってデプロイ済みフックを操作します