最近、Uniswap Lab は次世代 AMM Uniswap V4 の開発進捗状況を正式に発表し、ホワイト ペーパーとコード リポジトリを公開しました。今回の V4 ホワイト ペーパーは 3 ページのみですが、その理由は、V4 は AMM のコア アルゴリズム ロジックにあまり多くの変更を加えず、より多くのシナリオのニーズを満たすために V3 をベースにいくつかの新機能を追加したためです。 SharkTeam は、現在のオープン ソース コードに基づいて、V4 がもたらす新機能を検討し、V4 で導入された重要な機能フックのアプリケーションのベスト プラクティスを分析します。
1. V4とV3の違い
1.1 AMM
AMM アルゴリズム レベルでは、Uniswap V4 は V3 を変更せず、定数積 x*y=k に基づく流動性アルゴリズムを引き続き使用します。
Uniswap V3 では、各取引ペアに 4 つのプール (当初は 3 つで、後に新しい 1bp プールが追加されました) を持つことができ、それぞれ 0.01%、0.05%、0.3%、1% のレート プールを表します。これらのプールは、ティック スペースに対応します。プールを作成するときは、これら 4 つのタイプのいずれか 1 つだけを選択できます。
Uniswap V4 では、理論上、各取引ペアは任意の数のプールを持つことができ、各プールの手数料率も任意の値にすることができ、これらのプールのティック スペースも任意の値にすることができます。
これはまた問題を引き起こします。Uniswap V4 の取引ペアの流動性は断片化されるため、ユーザーが最適な取引パスを見つけられるようにするには、より効果的なルーター/アグリゲーターが必要です。
1.2 フック
フックは、サード パーティまたは Uniswap 公式によって開発されたコントラクトのセットです。プールを作成するとき、プールはフックをバインドすることを選択できます。その後、トランザクションの特定の段階で、プールはバインドされたフック コントラクトを自動的に呼び出します。 Uniswap V4 は、フック コントラクト コードを実行できる次のステージを定義します。
- 初期化前
- 初期化後
- beforeModifyPosition
- afterModify位置
- スワップ前
- スワップ後
- 寄付する前に
- 寄付後
これは、プールの初期化、流動性の追加/削除、取引、寄付などの操作の前後にフック コントラクトを呼び出すことができることを意味します。
フック コントラクトでは、上記のどのステージを実行するかを明示的に指定する必要があり、プールは、対応するフックを特定のステージで実行する必要があるかどうかを知る必要があります。ガスを節約するために、これらのフラグはコントラクトには保存されませんが、フックがアドレスを示すために特定のを使用する必要があります。具体的な判定コードは以下の通りです。
フック アドレスの最初の 8 ビットは、フックを特定の段階で実行する必要があるかどうかをマークするために使用されていないことがわかります。
したがって、フックの開発者は、コントラクトをデプロイするときにプールの要件を満たすアドレスを生成する必要があります。これを実現するには、通常、Create2 とランダムなソルトの計算を使用する必要があります。
以下は、ホワイトペーパーのフック実装の例です。
スワップの実行前後に、プールはまず、プールに対応するフックが対応するフラグを有効にしているかどうかを確認し、有効になっている場合は、フック コントラクトの対応する関数を自動的に呼び出します。
1.3 動的手数料率
フックは、特定の段階でコードを実行するだけでなく、特定のプールのスワップ手数料率と引き出し率を決定することもできます。引き出しレートとは、流動性を引き出す際にユーザーがフックに支払う必要があるレートを指します。さらに、フックはスワップ手数料の一部を自分自身に指定することもできます。
プールを作成するときは、料金パラメーター (uint24) の最初の 4 ビットを使用して、プールが動的料金を使用するかどうか、およびフック スワップ料金と引き出し料金を有効にするかどうかをマークする必要があります。
動的手数料が有効な場合、プールはフック コントラクトを呼び出して、各スワップの前に現在のスワップ手数料比率を取得します。フック コントラクトは、現在のスワップ手数料比率を返すために getFee() 関数を実装する必要があります。
フックにより Uniswap V4 が開発者プラットフォームになり、AMM にさらなる可能性が与えられます。フックで実装できる機能には、TWAMM (時間加重自動マーケットメーカー)、Limit Order (指値注文)、LP 再投資などが含まれますが、これらについては後続の章で詳しく紹介します。
1.4 シングルトンコントラクト
Uniswap V3 で新しいプールが作成されるたびに、新しいコントラクトをデプロイする必要があり、大量のガスを消費しますが、実際には、これらのプールで使用されるコードは同じで、初期化パラメータのみが異なります。 Uniswap V4 では、すべてのプールを管理するための Singleton コントラクトが導入されているため、新しいプールを作成するときに新しいコントラクトをデプロイする必要がなくなり、コントラクトをデプロイするためのガスが節約されます。
Uniswap V3 で新しいプールが作成されるたびに、新しいコントラクトをデプロイする必要があり、大量のガスを消費しますが、実際には、これらのプールで使用されるコードは同じで、初期化パラメータのみが異なります。 Uniswap V4 では、すべてのプールを管理するための Singleton コントラクトが導入されているため、新しいプールを作成するときに新しいコントラクトをデプロイする必要がなくなり、コントラクトをデプロイするためのガスが節約されます。
さらに、シングルトン コントラクトを使用する利点は、すべてのプールが同じコントラクト内にあるため、トランザクション中のトークン転送を削減できることです。したがって、プール間のスワップはコントラクト内で直接完了でき、V3 では、クロスプールスワップ 異なるプール間でトークンを転送する必要があり、ガスが増加します。
同時に、V4 では、すべてのプールが同じコントラクトを使用し、コントラクト内のトークンの簿記も簡素化され、各トークンがプールごとではなくトークンごとに記帳されるようになりました。大量のトークンもより便利になります。
1.5 エクスロード
フックと他のコントラクトの統合を容易にするために、V4 コントラクトには extload 関数が追加され、コントラクトのすべての内部状態が外部から読み取り可能になり、すべてのプールの状態が外部に対して完全に透過的になります。
1.6 フラッシュアカウンティング
プール スワップ間のトークン転送を減らすために、V4 はフラッシュ アカウンティングと呼ばれる方法を使用してスワップのプロセスを標準化し、流動性/フラッシュ ローンをフラッシュ ローンのようなプロセスに追加/削除します。
(1) ユーザーがロックを取得する
(2) ユーザーは、複数のプールでのスワップ、流動性の追加/削除、フラッシュ ローンによるプールからのトークンの借用などの操作を実行します。
(3) ユーザーのすべての操作によって生成されたトークン転送はロックに記録されます。
(4) すべての操作が終了した後、ユーザーは取得したトークンを持ち帰ることができ、同時にロックに記録されている支払う必要のあるトークンを支払う必要があります。
これらのプロセスは 1 つのトランザクションで実行する必要があります。
このようにして、トランザクションを複数のプール間でスワップする必要がある場合、決済には 2 回の転送だけで十分です。たとえば、ETH->USDC-BTC のようなスワップでは、中間トークンとしての USDC は転送をまったく必要としません。
1.7 ERC1155 ミント/バーン
Flash Accountingでは、同一トランザクション内のスワップのトークン転送を削減できますが、ERC1155トークンを使用することで、複数トランザクションのトークン転送をさらに削減できます。
V4 では、ERC1155 mint を通じてトークンを V4 コントラクトに保存できるため、毎回トークンを V4 コントラクトに転送することなく、複数のトランザクションでこれらのトークンを使用できます。
V4 コントラクトに保存されているトークンは、ERC1155 書き込みを使用して引き出すことができます。
ERC1155 は、流動性のスワップや追加/削除を頻繁に行うユーザーに適しており、よく使用されるトークンを V4 コントラクトに直接保存できるため、トークン転送のガス オーバーヘッドを削減できます。
2. フックのベストプラクティスの例
2.1 TWAMM (時間加重自動マーケットメーカー)
アリスはブロックチェーン上で 1 億ドル相当のイーサを購入したいと考えています。 Uniswap などの既存の自動マーケットメーカー (AMM) プラットフォームでこの規模の注文を実行すると、アリスがより良い価格を得るために内部情報を使用するのを防ぐために、これらのプラットフォームはアリスに法外な手数料を請求する可能性が高いため、法外なコストがかかります。
より良い価格を得るために、Alice の最善のオプションは、注文を手動でいくつかの小さなサブ注文に分割し、数時間かけて段階的に実行することです。その考えは、彼女が内部情報を持っていないことに気づき、より良い価格を付けるために市場に十分な時間を与えることです。ただし、たとえ彼女が複数のより大きなサブ注文を送信したとしても、各サブ注文は依然として価格に重大な影響を与える一方、敵対的なトレーダーによる「サンドイッチ攻撃」に対して脆弱でもあります。
より良い価格を得るために、Alice の最善のオプションは、注文を手動でいくつかの小さなサブ注文に分割し、数時間かけて段階的に実行することです。その考えは、彼女が内部情報を持っていないことに気づき、より良い価格を付けるために市場に十分な時間を与えることです。ただし、たとえ彼女が複数のより大きなサブ注文を送信したとしても、各サブ注文は依然として価格に重大な影響を与える一方、敵対的なトレーダーによる「サンドイッチ攻撃」に対して脆弱でもあります。
TWAMM は、Alice に代わってトランザクションを実行することでこの問題を解決します。彼女の注文は無数の小さな仮想注文に分割され、時間内にスムーズな実行が保証されます。同時に、TWAMM は、組み込み AMM プロトコルの特別な数学的関係を使用して、これらの仮想注文間でガスコストを共有できるようにします。 TWAMM はブロック間のトランザクションを処理するため、「サンドイッチ攻撃」に対しても脆弱ではありません。
全体として、TWAMM は、アリスに大規模な取引を実行するためのより効率的な方法を提供し、高額な手数料や市場操作の可能性を回避します。
2.1.1 原則
TWAMM には他の AMM と同様に AMM が組み込まれており、ユーザーはこの AMM を通じてスポット取引を直接行ったり、AMM に流動性を追加したりすることができます。ただし、TWAMM には 2 つの TWAP 注文プールもあり、双方向で TWAP 注文を実行するために使用されます。ユーザーが注文を送信するときに、トークンの入力量とトランザクションの期間を指定すると、TWAMM は同じトランザクション方向の注文を発注します。対応するプールに転送され、指定されたトランザクション速度に従って自動的にトランザクションが実行されます。ユーザーの注文が完全に実行されると、ユーザーはトランザクションから取得したトークンを取り出すことができます。もちろん、ユーザーの注文が実行される前に、ユーザーは事前に注文をキャンセルしたり、注文で取引する必要があるトークンの数を変更したりすることもできます。
イーサリアムでは、スマート コントラクトは EOA アドレスによって開始されたトランザクションによってのみトリガーでき、自動的に実行することはできません。したがって、TWAMM は、注文プールで取引されるトークンを決済するために EOA アカウントから定期的にトランザクションを送信する必要があり、これらのトランザクションを実行するにはキーパー アカウントが必要です。
もちろん、TWAMMは、ユーザーが操作するたびに注文プールを自動的に決済することもできるため、キーパーのオーバーヘッドが節約されます。これは、DeFiプロトコルがストリーミングデータを処理する一般的な方法でもあります。
2.1.2 なぜこの取引モデルはサンドイッチ攻撃を受けにくいのでしょうか?
この種の攻撃は実装が難しく、ブロック内のタイムスタンプは変わらないため、攻撃者はブロックの最後のトランザクションでプール価格を引き上げる必要があり、その結果、次のブロックのTWAMM決済に影響が及びます。これにはサンドイッチ攻撃を複数のブロックで行う必要がありますが、他の裁定者が途中で介入して攻撃者が損失を被る可能性があるため、攻撃者に大きなリスクをもたらすことは間違いありません。
同時に、裁定業者の存在により、このような価格操作は持続不可能となる運命にあり、TWAP注文の特性上、短期間にあまり多くのトークンを取引することがないため、ほとんどの場合損失が発生します。制限する必要があります。
2.1.3 V4 の TWAMM ワークフロー
(1) このフックは、2 つのトランザクション方向の TWAP 注文をそれぞれ表す 2 つの TWAP 注文プールを維持します。
(2) ユーザーはこのフックを通じて TWAP 注文を送信でき、トランザクションのトークン、数量、時間の長さを指定する必要があります。
(3) このフックは beforeSwap と beforeModifyPosition を登録し、ユーザーがポジションを取引または調整するたびにこのフックがトリガーされます。
(4) トリガーされた後、フックは 2 つの TWAP 注文プールの決済を担当します。
(5) ユーザーはいつでも手動で決済をトリガーすることもできます
(6) ユーザーはTWAP注文のトークン数量をキャンセルまたは変更することができます
2.1.4 詳細な例
TWAMM は、フックのロジック呼び出しの 3 つのフェーズを登録し、プールの初期化前に TWAMM を初期化し、ユーザーがポジションを取引または調整するたびにこのフックをトリガーします。
2.1.4 詳細な例
TWAMM は、フックのロジック呼び出しの 3 つのフェーズを登録し、プールの初期化前に TWAMM を初期化し、ユーザーがポジションを取引または調整するたびにこのフックをトリガーします。
ユーザーは、TWAMM の submitOrder 関数を手動で呼び出して、契約に実行する必要がある注文を送信できます。
ユーザーが実行する必要がある注文をコントラクトに追加すると、その注文はプールが swap およびmodifyPosition 操作を実行するたびに自動的に実行されます。
ユーザーが v4 スワップ関数を呼び出して取引するか、modifyPosition 関数を呼び出してポジションを変更するたびに、TWAMM の実行関数がトリガーされ、関数内で内部関数 _executeTWAMMOrders が呼び出され、以前に完了していない注文の実行を継続します。
_executeTWAMMOrders 関数
以上が注文更新の実行処理ですが、実行完了後、twammの現在の注文約定時刻が更新されます。
2.2 指値注文
直前の市場価格で即座に約定される成行注文とは異なり、指値注文は所定の価格に達するとすぐに約定されます。自動マーケットメーカー (AMM) に基づくほとんどの DEX は、デフォルトで成行注文システムを選択します。シンプルで初心者にもわかりやすい。成行注文は、最大価格への影響などのパラメーターにより、実行されるか失敗します。指値注文では、資産価格が指値価格に達した場合にのみ注文が約定され、それ以外の場合、注文はオープンされたままになります。
たとえば、ETH が現在 ETH/DAI プールで 1 ETH = 1500 DAI で取引されているとします。ユーザーは利益確定注文を出すことができ、主な内容は「1 ETH = 2000 DAI の場合、自分の ETH をすべて売却する」というものです。この価格に達すると、ユーザーの ETH は完全にオンチェーンで分散型の方法で自動的に DAI に交換されます。
Uniswap の以前のバージョンでは、指値注文は事実上不可能でした。ほとんどの AMM は市場での売買のみを許可します。 V4 バージョンでは、フックの強力な機能とスケーラビリティにより、v4 で指値注文を実現するための基盤があります。
2.2.1 原則
指値注文の設計原理はtwammに比べてシンプルで、現在は流動性を追加するための指値注文が実装されており、取引のための指値注文の実装は容易になります。
v4にはtickLowerとtickUpperがあるため、プールの取引状況に応じて下限と上限が変わりますが、ユーザーは流動性を追加する際に、現在の価格で追加したくありません。このとき、指値注文フックを使用できます。この要件を実装するために使用され、フックに対応する価格を設定します。各スワップの後、フックは現在のプール価格を判断します。設定された価格に達すると、対応する流動性が追加されて収入が得られます。
2.2.2 V4 の指値注文ワークフロー
1. Limit は、さまざまな下値および取引方向に対する指値注文として複数のエポックを維持します。
2. このフックを通じて、ユーザーは下限価格と取引方向を送信し、指値注文を契約に追加します。
3. このフックは afterSwap を登録します。これは、各スワップが終了した後に価格が変化した場合にのみトリガーされます。
4. トリガーされた後、フックは現在の価格範囲をチェックし、現在の価格で流動性を追加する必要がある指値注文があるかどうかをエポックからチェックします。
5. ユーザーはいつでも資金を引き出したり、流動性を直接追加したりできます
2.2.3 詳細な例
フックはコントラクト登録の 2 段階でトリガーされます。フックはプールが初期化された後に初期化され、フック ロジックは各交換の後にトリガーされます。
ユーザーは、place 関数を呼び出して、ユーザーが追加したい流動性の数量、価格、取引方向を渡します。フックは、ユーザーが追加したい流動性をまずストレージ用のプールに追加し、次に、ユーザーに対応する指値注文。
このフックは各スワップが終了した後にトリガーされ、現在の価格帯に応じた範囲価格に存在する指値注文に基づいて流動性を追加する操作が完了します。
ユーザーは指値注文が完了する前に kill 関数を呼び出して指値注文をキャンセルすることができ、今度は流動性を追加するというメリットが得られます。
ユーザーは、流動性を削除したい場合に引き出し関数を呼び出して、必要な流動性を引き出すことができます。
一般に、この指値注文フックはユーザーにより便利な方法を提供します。ユーザーは流動性を追加したいときに価格を設定できます。プール内の価格範囲がその価格に達すると、フックは自動的にユーザーのプールに入ります。流動性を追加する操作が可能であり、ユーザーはいつでも流動性をキャンセルおよび撤回できます。
TWAMMや指値注文以外にも、LP再投資や動的手数料変更などの機能もHookをベースに実現可能ですが、紙面の都合上、追跡分析で紹介します。
TWAMMや指値注文以外にも、LP再投資や動的手数料変更などの機能もHookをベースに実現可能ですが、紙面の都合上、追跡分析で紹介します。
LP 再投資: ユーザーはフックを使用して流動性を追加、変更、削除できます。また、フックは呼び出すために afterSwap および afterModifyPosition を登録できます。ユーザーは一様にフックを使用して流動性を追加するため、poolManager に流動性を追加する唯一のアドレスはフックです。フックはトリガーされるたびに現在時刻を確認できます。一定の時間が経過した後、流動性報酬を引き出して LP を取得することを選択しますトークンによりプールに流動性が再び追加され、それによってユーザーの収入が自動的に最適化されます。
動的な料金変更: フックは beforeSwap およびその他のインターフェイスを登録して、交換前に動的な料金を変更できます。動的手数料は単に時間に応じて直線的に変化するだけでなく、1回のスワップで発生するティックジャンプ数に応じてボラティリティを定量化することで、手数料を動的に変更し、LPの永続性リスクのヘッジを実現します。これにより、流動性プロバイダーに対する取引によって引き起こされる一時的な損失の影響が軽減されます。
3. フックセキュリティのベストプラクティス
require と revert の使用を減らす
プールのフック呼び出しの関数ロジックでは、ロールバック ステートメントの使用を最小限に抑える必要があります。プール コントラクトとフック コントラクトの間の共通の関係により、フックでトランザクションのロールバックが発生した後、プール内のトランザクションもプール内の通常のトランザクションに関連しないフック内のロールバック ステートメントにより、ユーザーはプール内の関数を通常どおり使用できなくなる可能性があります。
自己破壊関数の使用を避ける
フック内で自己破壊関数を使用することは避けてください。フック内で自己破壊関数を呼び出すと、フック内のロジックに問題が発生するだけでなく、プール内の関数が失敗し、プール内のアセットが破損する可能性があります。プール全体が失われ、機能が失敗します。正常に動作します。
厳格なアクセス制御
フック コントラクト内のアクセス許可を厳密に制御して過剰なアクセス許可を持つロールを回避し、特権ロールに対してマルチシグネチャ管理を実行してシングルポイント攻撃を防ぎます。特権ロールがコントラクト状態変数を恣意的に変更できる状況を回避するために、ロジック エラーが発生してトランザクション全体がロールバックされ、プールの通常の使用に影響を与える可能性があります。最小特権の原則を検証するには、openzeppelin の AccessControl コントラクトを使用して、アクセスを制御するためのよりきめ細かいアクセス許可を実装する必要があります。これは、この方法では、各システム コンポーネントが最小特権の原則に従うように制限されるためです。
再入国制限はしっかりやれよ
プールの外部拡張コードとして、フックはコントラクト内のリエントリー攻撃の可能性にも注意を払う必要があります。たとえば、ネイティブ トークンを転送する際の指値注文でのリエントリー攻撃の可能性など、コントラクト資産の損失につながる可能性があります。外部コントラクトまたはいわゆる「check-validate-interact」パターンを呼び出す前に、すべての状態を確認して更新を試みます。この方法では、すべての状態更新が完了するため、再入可能であっても影響はありません。 。
契約アップグレード管理
契約アップグレード管理
一部の開発者は、将来的にプロキシ コントラクトを使用してフックのロジックを変更およびアップグレードする可能性がありますが、コントラクトのアップグレードで起こり得る問題にも注意する必要があります。まず、フックでプロキシ モードが採用されている場合でも、対応するステージを beforeSwap などのプロキシ コントラクトで宣言する必要があります。そうしないと、プールは正しい戻り値を検証できません。次に、デリゲートコールを呼び出す前にターゲット コントラクトが存在するかどうかを確認します。Solidity はこのチェックを実行しません。チェックを無視すると、予期しない動作やセキュリティの問題が発生する可能性があります。変数はパックされて保存されるため、変数宣言の順序を慎重に検討してください。同じスロットでは、ガスコスト、メモリレイアウト、デリゲートコールの結果などの問題に影響します。
私たちに関しては
SharkTeam のビジョンは、Web3 世界のセキュリティを包括的に保護することです。このチームは世界中から集まった経験豊富なセキュリティ専門家と上級研究者で構成されており、ブロックチェーンとスマートコントラクトの基礎理論に精通しており、スマートコントラクトの監査、オンチェーン分析、緊急対応などのサービスを提供しています。 Polkadot、Moonbeam、polygon、OKC、Huobi Global、imToken、ChainIDE など、ブロックチェーン エコシステムのさまざまな分野の主要企業と長期的な協力関係を確立しています。
全てのコメント