🦄

[Bunzz Decipher] UniswapV3の『TickLens』コントラクトを理解しよう!

2023/09/04に公開

はじめに

初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームはクリプトスペルズというブロックチェーンゲームです。

https://cryptospells.jp/

今回はBunzzの新機能『DeCipher』を使用して、UniswapV3の「TickLens」のコントラクトを見てみようと思います。

DeCipher』はAIを使用してコントラクトのドキュメントを自動生成してくれるサービスです。

https://www.bunzz.dev/decipher

詳しい使い方に関しては以下の記事を参考にしてください!

https://zenn.dev/heku/articles/33266f0c19d523

今回使用する『DeCipher』のリンクは以下になります。

https://app.bunzz.dev/decipher/chains/1/addresses/0xbfd8137f7d1516D3ea5cA83523914859ec47F573

Etherscanのリンクは以下になります。

https://etherscan.io/address/0xbfd8137f7d1516D3ea5cA83523914859ec47F573

概要

TickLens(ティックレンズ)コントラクトは、Uniswap V3プロトコルの一部であり、リクイディティプールに関する詳細な情報を提供します。

TickLensコントラクトは、複数のコントラクトと連携しています。
IUniswapV3PoolIUniswapV3PoolImmutablesIUniswapV3PoolStateIUniswapV3PoolDerivedStateIUniswapV3PoolActionsIUniswapV3PoolOwnerActionsIUniswapV3PoolEventsなどが含まれます。
これらのコントラクトは、TickLensコントラクトがリクイディティプールの情報を提供するために必要な機能を提供します。

TickLensコントラクトの主な役割は、リクイディティプールに関連する情報を提供することです。
これは、前述のコントラクトの機能を活用して実現されます。
ユーザーは、プールの不変な特性、現在の状態、派生状態、アクション、オーナーアクション、イベントなどのデータに、TickLensコントラクトを通じてアクセスできます。

TickLensコントラクトを使用することで、ユーザーはプールのアドレス、トークンアドレス、手数料の段階、ティックの間隔などの特性に関する情報にアクセスできます。
さらに、ユーザーはプールの現在の状態を取得し、現在のティック、リクイディティ、手数料などの情報を確認できます。

さらに、TickLensコントラクトを利用して、特定のティックでリクイディティを提供する際に得られるトークン0とトークン1の量を計算したり、特定のティック範囲で追加または削除されるリクイディティの量を推定したりできます。

使い方

目標

コントラクトの目標は、テクニカルオペレータや開発者がUniswap V3プロトコルのリクイディティプールに関する情報を取得できることです。
これにより、プールの活動の監視やリクイディティポジションの分析、情報に基づいた取引の意思決定などが支援されます。

リクイディティプールの情報を取得する手順は以下の通りです。

1. TickLensコントラクトのデプロイ

EthereumネットワークにTickLensコントラクトのインスタンスをデプロイします。

2. コントラクトの初期化

TickLensコントラクトのコンストラクタを呼び出し、対象のUniswap V3プールのアドレスを指定します。

3. プール情報の取得

プールアドレスの取得
pool関数を呼び出し、TickLensコントラクトに関連付けられたUniswap V3プールのアドレスを取得します。

プールの情報の取得
getPoolImmutables関数を呼び出し、トークンアドレス、手数料、ティック間隔などのUniswap V3プールの不変な情報を取得します。

プールの状態の取得
getPoolState関数を呼び出し、現在のリクイディティ、ティックインデックス、リクイディティ範囲などのUniswap V3プールの状態を取得します。

プールの派生状態の取得
getPoolDerivedState関数を呼び出し、現在の価格、リクイディティの値、手数料などのUniswap V3プールの派生状態情報を取得します。

プールのアクションの取得
getPoolActions関数を呼び出し、ミンティング、バーニング、スワッピングなどのUniswap V3プールでサポートされるアクションを取得します。

プールのオーナーアクションの取得
getPoolOwnerActions関数を呼び出し、手数料の収集、ティックの更新などのUniswap V3プールでサポートされるオーナーアクションを取得します。

プールのイベントの取得
getPoolEvents関数を呼び出し、リクイディティの提供、スワップ、手数料の収集など、Uniswap V3プールから発生するイベントを取得します。

TickLensコントラクトの使用

1. リクイディティプールの活動のモニタリング

  • プールの現在のリクイディティとティックインデックスを取得することで、プールの活動をリアルタイムで監視できます。
  • プールの現在の価格とリクイディティ値を取得して、プールのパフォーマンスやトレンドをトラッキングできます。
  • プールから発生するイベントを取得して、過去の活動を分析し、取引の動向や出来事を把握できます。

2. リクイディティポジションの分析

  • プールのトークンアドレス、手数料、ティック間隔などの情報を取得して、プールの設定や特性を理解できます。
  • プールのリクイディティ範囲を知ることで、どの範囲でリクイディティを提供できるかを把握できます。
  • プールが収集した手数料を取得して、リクイディティポジションの収益性を評価し、最適なポジションを選択できます。

3. 情報に基づいた取引の意思決定

  • プールでサポートされるアクションを知ることで、取引オプションを理解し、効果的な戦略を構築できます。
  • プールでサポートされるオーナーアクションを把握して、プールの管理や操作に関する選択肢を理解できます。
  • プールの過去のイベントを分析して、取引のパターンや市場のトレンドを洞察し、効果的なトレード戦略を考案できます。

関連EIP/ERC

  • EIP1620: Money Streaming Standard(マネーストリーミングスタンダード)
    • TickLensコントラクトは、マネーストリーミングスタンダードを実装したリクイディティプールに関する情報を取得するために使用できます。
  • EIP20: トークンスタンダード
    • TickLensコントラクトは、Uniswap V3プールで使用されているERC-20トークンに関する情報を取得するために使用できます。

https://chaldene.net/erc20

  • EIP721: ノンファンジブルトークンスタンダード
    • TickLensコントラクトは、Uniswap V3プールで使用されているERC-721トークンに関する情報を取得するために使用できます。

https://chaldene.net/erc721

  • EIP1155: マルチトークンスタンダード
    • TickLensコントラクトは、Uniswap V3プールで使用されているERC-1155トークンに関する情報を取得するために使用できます。

https://chaldene.net/erc1155

パラメーター

なし。

コントラクト

TickLens

PopulatedTick

PopulatedTick
struct PopulatedTick {
    int24 tick;
    int128 liquidityNet;
    uint128 liquidityGross;
}

概要
リクイディティプール内の特定のティックに関する情報を格納する構造体。

パラメータ

  • tick
    • int24型の変数で、ポピュレートされたティックの位置を示します。
    • ティックはリクイディティプール内での価格と位置を表します。
  • liquidityNet
    • int128型の変数で、ポピュレートされたティックの位置における純リクイディティを表します。
    • これは、特定のティックでの買い注文のリクイディティと売り注文のリクイディティの差を示します。
  • liquidityGross
    • uint128型の変数で、ポピュレートされたティックの位置における総リクイディティを表します。
    • これは、特定のティックの位置での全ての注文の総リクイディティを示します。

getPopulatedTicksInWord

getPopulatedTicksInWord
function getPopulatedTicksInWord(address pool, int16 tickBitmapIndex)
    public
    view
    override
    returns (PopulatedTick[] memory populatedTicks)
{
    // fetch bitmap
    uint256 bitmap = IUniswapV3Pool(pool).tickBitmap(tickBitmapIndex);

    // calculate the number of populated ticks
    uint256 numberOfPopulatedTicks;
    for (uint256 i = 0; i < 256; i++) {
        if (bitmap & (1 << i) > 0) numberOfPopulatedTicks++;
    }

    // fetch populated tick data
    int24 tickSpacing = IUniswapV3Pool(pool).tickSpacing();
    populatedTicks = new PopulatedTick[](numberOfPopulatedTicks);
    for (uint256 i = 0; i < 256; i++) {
        if (bitmap & (1 << i) > 0) {
            int24 populatedTick = ((int24(tickBitmapIndex) << 8) + int24(i)) * tickSpacing;
            (uint128 liquidityGross, int128 liquidityNet, , , , , , ) = IUniswapV3Pool(pool).ticks(populatedTick);
            populatedTicks[--numberOfPopulatedTicks] = PopulatedTick({
                tick: populatedTick,
                liquidityNet: liquidityNet,
                liquidityGross: liquidityGross
            });
        }
    }
}

概要
指定されたリクイディティプールの特定のビットマップに基づいて、PopulatedTick構造体の配列を返します。

詳細

  • 引数としてリクイディティプールのアドレスとビットマップのインデックスを指定します。
  • 関数はビットマップからポピュレートされたティックの数を計算し、それに基づいてPopulatedTick構造体の配列を作成します。
  • PopulatedTick構造体の配列には、ポピュレートされたティックのデータが含まれます。
    • ティックの位置、リクイディティのネット値、およびグロス値が記録されます。

引数

  • pool
    • 情報を取得したいUniswap V3プールのアドレス。
  • tickBitmapIndex
    • ビットマップのインデックス。

戻り値

  • PopulatedTick[] memory populatedTicks
    • PopulatedTick構造体の配列。
    • 各要素は、ティックの位置、リクイディティのネット値、リクイディティのグロス値を含みます。

コード

ITickLens

ITickLens.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

/// @title Tick Lens
/// @notice Provides functions for fetching chunks of tick data for a pool
/// @dev This avoids the waterfall of fetching the tick bitmap, parsing the bitmap to know which ticks to fetch, and
/// then sending additional multicalls to fetch the tick data
interface ITickLens {
    struct PopulatedTick {
        int24 tick;
        int128 liquidityNet;
        uint128 liquidityGross;
    }

    /// @notice Get all the tick data for the populated ticks from a word of the tick bitmap of a pool
    /// @param pool The address of the pool for which to fetch populated tick data
    /// @param tickBitmapIndex The index of the word in the tick bitmap for which to parse the bitmap and
    /// fetch all the populated ticks
    /// @return populatedTicks An array of tick data for the given word in the tick bitmap
    function getPopulatedTicksInWord(address pool, int16 tickBitmapIndex)
        external
        view
        returns (PopulatedTick[] memory populatedTicks);
}

TickLens

TickLens.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';

import '../interfaces/ITickLens.sol';

/// @title Tick Lens contract
contract TickLens is ITickLens {
    /// @inheritdoc ITickLens
    function getPopulatedTicksInWord(address pool, int16 tickBitmapIndex)
        public
        view
        override
        returns (PopulatedTick[] memory populatedTicks)
    {
        // fetch bitmap
        uint256 bitmap = IUniswapV3Pool(pool).tickBitmap(tickBitmapIndex);

        // calculate the number of populated ticks
        uint256 numberOfPopulatedTicks;
        for (uint256 i = 0; i < 256; i++) {
            if (bitmap & (1 << i) > 0) numberOfPopulatedTicks++;
        }

        // fetch populated tick data
        int24 tickSpacing = IUniswapV3Pool(pool).tickSpacing();
        populatedTicks = new PopulatedTick[](numberOfPopulatedTicks);
        for (uint256 i = 0; i < 256; i++) {
            if (bitmap & (1 << i) > 0) {
                int24 populatedTick = ((int24(tickBitmapIndex) << 8) + int24(i)) * tickSpacing;
                (uint128 liquidityGross, int128 liquidityNet, , , , , , ) = IUniswapV3Pool(pool).ticks(populatedTick);
                populatedTicks[--numberOfPopulatedTicks] = PopulatedTick({
                    tick: populatedTick,
                    liquidityNet: liquidityNet,
                    liquidityGross: liquidityGross
                });
            }
        }
    }
}

最後に

今回の記事では、Bunzzの新機能『DeCipher』を使用して、UniswapV3の「TickLens」のコントラクトを見てきました。
いかがだったでしょうか?
今後も特定のNFTやコントラクトをピックアップしてまとめて行きたいと思います。

普段はブログやQiitaでブロックチェーンやAIに関する記事を挙げているので、よければ見ていってください!

https://chaldene.net/

https://qiita.com/cardene

DeCipher |"Read me" for All of Contracts

Discussion