This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
Uniswap V3コード分析:7つの実用的な受託開発のヒント
Uniswapのコードから学ぶコントラクト開発のヒント
最近、分散型取引所の開発チュートリアルを作成する際に、Uniswap V3のコード実装を参考にして、多くの貴重な知識を学びました。以前はシンプルなNFTコントラクトしか開発したことがなかった開発者として、今回はDefiコントラクトの開発に挑戦したことで、多くの新しい収穫がありました。これらの小技術は、コントラクト開発を学びたい初心者にとって非常に役立つと信じています。
次に、これらの実用的な開発のヒントを見てみましょう。その中には、いくつかはまさに奇抜な技術と言えるものもあります。
! Web3ビギナーシリーズ:Uniswapコードから学んだ契約開発のヒント
予測可能な契約デプロイメントアドレス
通常、デプロイされたコントラクトは、一見ランダムなアドレスを得ます。これは nonce に関連しているため、コントラクトアドレスは予測が難しいです。しかし、特定の状況では、取引ペアや関連情報を通じてコントラクトアドレスを推測する必要があります。たとえば、取引権限を判断したり、プールアドレスを取得したりする場合です。
Uniswapは、saltパラメータを追加することでCREATE2方式でコントラクトを作成し、作成されたコントラクトアドレスを予測可能にします。アドレス生成ロジックは次の通りです: 新しいアドレス = hash("0xFF", 作成者アドレス, salt, initcode)。
! Web3ビギナーシリーズ:Uniswapコードから学んだ契約開発のヒント
コールバック関数を有効に活用する
Solidityでは、コントラクト同士が相互に呼び出すことができます。特定のシナリオでは、AがBのメソッドを呼び出し、Bが呼び出されたメソッド内でAをコールバックすることが非常に便利です。
Uniswapでは、UniswapV3Poolコントラクトのswapメソッドを呼び出して取引を行うと、swapCallbackがコールバックされ、コールバックには今回の取引で実際に必要なTokenが渡されます。呼び出し元はコールバック内で取引に必要なTokenをUniswapV3Poolに転送する必要があり、swapメソッドを二つの部分に分けて呼び出し元が呼び出すことはありません。これにより、swapメソッドの安全性が確保され、全体のロジックが完全に実行されることが保証され、セキュリティを確保するための面倒な変数記録は不要になります。
例外を使用して情報を渡し、catch を試してトランザクションを推定します
Uniswapのいくつかの契約では、UniswapV3Poolのswapメソッドをtry catchで包んで実行します。これは、swapメソッドをシミュレーションして取引に必要なトークンを予測するためです。予測時には実際にトークンの交換が行われないため、エラーが発生します。Uniswapは、取引コールバック関数内で特別なエラーをスローし、そのエラーを捕捉して、エラーメッセージから必要な情報を解析します。
この方法は一見少しずるいように見えますが、非常に実用的です。取引需要の予測のためにスワップ方法を改造する必要はなく、論理もよりシンプルです。
! Web3ビギナーシリーズ:Uniswapコードから学んだ契約開発のヒント
大数を使用して精度の問題を解決する
Uniswapのコードには、多くの計算ロジックが含まれており、現在の価格と流動性に基づいてトークンを交換するための計算が行われます。除算操作による精度の損失を避けるために、計算過程ではしばしば<< FixedPoint96.RESOLUTION操作を使用します。これは、96ビット左シフトすることで、2^96を掛けるのと同じです。左シフト後に除算を行うことで、通常の取引でオーバーフローが発生しない限り、精度が保証されます。
理論的には精度の損失は依然としてありますが、通常は最小単位の損失に過ぎず、許容範囲内です。
シェアを使用して収益を計算する
Uniswapでは、LP(流動性提供者)の手数料収益を記録する必要があります。明らかに、取引ごとに各LPにそれぞれの手数料を記録することはできず、これは大量のガスを消費します。
Uniswapの解決策は、ポジション構造でfeeGrowthInside0LastX128とfeeGrowthInside1LastX128を定義して、最後にポジションが引き出されたときの各流動性に支払うべき手数料を記録することです。
要するに、総手数料と各流動性に分配される手数料を記録するだけで済みます。LPが手数料を引き出すときは、保有している流動性に基づいて引き出せる手数料を計算します。これは、会社の株式を保有しているのと似ていて、株式の利益を引き出す際には、会社の過去の一株当たりの利益と最後に引き出したときの利益を知っていればよいのです。
! Web3ビギナーシリーズ:Uniswapコードから学んだ契約開発のヒント
すべての情報をブロックチェーンから取得する必要はありません
オンチェーンストレージは比較的高価であり、すべての情報をオンチェーンにする必要があるわけではありません。たとえば、Uniswapのフロントエンドウェブサイトが呼び出す多くのインターフェースは、従来のWeb2インターフェースです。
取引プールのリストや取引プールの情報などは、通常のデータベースに保存できます。いくつかは定期的にブロックチェーンから同期する必要がありますが、関連データを取得するためにリアルタイムでブロックチェーンやノードサービスが提供するRPCインターフェースを呼び出す必要はありません。
もちろん、重要な取引はチェーン上で行われなければなりません。
契約の分割を学び、既存の標準契約を利用する
1つのプロジェクトには、複数の実際にデプロイされた契約が含まれる可能性があります。実際にデプロイされる契約が1つだけであっても、継承の方法を用いて契約を複数の契約に分割して維持することができます。
例えば、Uniswap のいくつかの契約は複数の契約を継承しています。実装時には、直接 @openzeppelin/contracts/token/ERC721/ERC721.sol 契約を使用しており、NFT 方式でポジションを管理するのが便利で、既存の標準契約を利用して開発効率を高めることができます。
サマリー
自分で手を動かして開発することは、記事を読むよりも理解を深めることができます。簡易版の分散型取引所を実現するプロセスを試みることで、Uniswapのコード実装をより深く理解でき、実際のプロジェクトにおける知識も多く学ぶことができます。
! Web3ビギナーシリーズ:Uniswapコードから学んだ契約開発のヒント