💲

Compoundの内部実装について調べてみた Part1

に公開

とあるossのDeFiレンディングプロトコルにコントリビュートさせていただける機会があったので、レンディングプロトコルの先駆けであるCompoundの内部実装を調べてみることにしました。

ほぼメモかつ、途中のところが多々あるので、読み物としては非常に読みにくいかもですが、備忘録として容赦してもらえると、、🙏

誤り等あればぜひご指摘もお願いします!


初学用

compound resources

ディレクトリ構成

contracts/
├── main contracts/
│   ├── Comet.sol
│   ├── ScrollComet.sol
│   ├── CometWithExtendedAssetList.sol
│   ├── Configurator.sol
│   └── AssetList.sol
├── interfaces/
│   ├── IProxy.sol
│   ├── IRateProvider.sol
│   ├── ITimelock.sol
│   ├── IWETH9.sol
│   ├── IWstETH.sol
│   ├── IAssetList.sol
│   ├── IAssetListFactory.sol
│   ├── IAssetListFactoryHolder.sol
│   ├── IComp.sol
│   ├── IERC20.sol
│   ├── IERC20Metadata.sol
│   ├── IERC20NonStandard.sol
│   ├── IERC4626.sol
│   ├── IGovernorBravo.sol
│   ├── IPriceFeed.sol
│   ├── CometInterface.sol
│   ├── CometMainInterface.sol
│   └── CometExtInterface.sol
├── core/
│   ├── CometCore.sol
│   ├── CometExt.sol
│   ├── CometExtAssetList.sol
│   ├── CometConfiguration.sol
│   ├── CometMath.sol
│   ├── CometStorage.sol
│   └── CometRewards.sol
├── factory/
│   ├── CometFactory.sol
│   ├── CometFactoryWithExtendedAssetList.sol
│   ├── AssetListFactory.sol
│   └── CometProxyAdmin.sol
├── bridges/
├── bulkers/
├── liquidator/
├── pricefeeds/
├── test/
└── vendor/

  1. メインコントラクト
    • Comet.solとScrollComet.solが主要な実装
    • CometWithExtendedAssetList.solは拡張機能付きのバージョン
  2. インターフェース
    • 標準的なERC20関連のインターフェース
    • Compound特有のインターフェース(CometInterface, CometMainInterface等)
  3. コア機能
    • CometCore.solで基本的な機能を実装
    • CometExt.solで拡張機能を提供
    • 設定、ストレージ、報酬などの補助機能
  4. ファクトリー
    • コントラクトのデプロイメントと管理用
    • プロキシ管理機能も含む
  5. 特殊機能ディレクトリ
    • bridges/: クロスチェーン連携
    • bulkers/: バッチ処理
    • liquidator/: 清算機能
    • pricefeeds/: 価格フィード
    • test/: テストコード
    • vendor/: 外部依存関係

アーキテクチャ

主要機能での分類

継承関係

Comet.sol主要機能(供給、借入、返済、清算など)を統括する

CometConfiguration.solリスクパラメーター、手数料、その他設定パラメータを管理する

CometExtInterface.sol, CometMainInterface.sol外部システムとの相互作用のためのIFを定義する

レンディング機能

Core

CometStorge

  • ソースコード

    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity 0.8.15;
    
    /**
     * @title Compound's Comet Storage Interface
     * @dev Versions can enforce append-only storage slots via inheritance.
     * @author Compound
     */
    contract CometStorage {
        // 512 bits total = 2 slots
        struct TotalsBasic {
            // 1st slot
            uint64 baseSupplyIndex;
            uint64 baseBorrowIndex;
            uint64 trackingSupplyIndex;
            uint64 trackingBorrowIndex;
            // 2nd slot
            uint104 totalSupplyBase;
            uint104 totalBorrowBase;
            uint40 lastAccrualTime;
            uint8 pauseFlags;
        }
    
        struct TotalsCollateral {
            uint128 totalSupplyAsset;
            uint128 _reserved;
        }
    
        struct UserBasic {
            int104 principal;
            uint64 baseTrackingIndex;
            uint64 baseTrackingAccrued;
            uint16 assetsIn;
            uint8 _reserved;
        }
    
        struct UserCollateral {
            uint128 balance;
            uint128 _reserved;
        }
    
        struct LiquidatorPoints {
            uint32 numAbsorbs;
            uint64 numAbsorbed;
            uint128 approxSpend;
            uint32 _reserved;
        }
    
        /// @dev Aggregate variables tracked for the entire market
        uint64 internal baseSupplyIndex;
        uint64 internal baseBorrowIndex;
        uint64 internal trackingSupplyIndex;
        uint64 internal trackingBorrowIndex;
        uint104 internal totalSupplyBase;
        uint104 internal totalBorrowBase;
        uint40 internal lastAccrualTime;
        uint8 internal pauseFlags;
    
        /// @notice Aggregate variables tracked for each collateral asset
        mapping(address => TotalsCollateral) public totalsCollateral;
    
        /// @notice Mapping of users to accounts which may be permitted to manage the user account
        mapping(address => mapping(address => bool)) public isAllowed;
    
        /// @notice The next expected nonce for an address, for validating authorizations via signature
        mapping(address => uint) public userNonce;
    
        /// @notice Mapping of users to base principal and other basic data
        mapping(address => UserBasic) public userBasic;
    
        /// @notice Mapping of users to collateral data per collateral asset
        mapping(address => mapping(address => UserCollateral)) public userCollateral;
    
        /// @notice Mapping of magic liquidator points
        mapping(address => LiquidatorPoints) public liquidatorPoints;
    }
    
    
  • 役割

    プロトコル全体のデータをブロックチェーン上に記録するためのストレージの役割

  • 定義されている構造体(struct)

    • TotalsBasic

      この構造体は、市場全体の集計情報をまとめたものです。

      • baseSupplyIndex / baseBorrowIndex

        ⇒ 利息計算の基準となる指標。預入れや借入れの金利がどのように変化するか、その計算に使います。

      • trackingSupplyIndex / trackingBorrowIndex

        ⇒ 報酬(例えば、プロトコルが提供するインセンティブ)の計算など、追跡用の指標です。

      • totalSupplyBase / totalBorrowBase

        ⇒ プロトコル全体で預けられている資産や借入れている金額の合計(基本部分)を表します。

      • lastAccrualTime

        ⇒ 最後に金利などの計算をした時刻。これにより、現在までにどれくらいの時間が経ったかを計算できます。

      • pauseFlags

        ⇒ プロトコル内の機能(預入、借入、清算など)が一時停止されているかどうかを示すフラグ(オン・オフの状態)です。

    • TotalsCollateral

      各担保資産ごとの合計情報を管理する構造体

      • totalSupplyAsset

        ⇒ ある特定の担保資産について、全ユーザーが預けた合計額です。

      • _reserved

        ⇒ 今後使えるように予約されている領域で、後で機能を追加したり、互換性を保つために使います。

    • UserBasic

      個々のユーザーについての基本情報

      • principal

        ⇒ ユーザーの元本。借入れや預入の正味の残高を表し、プラス(預入の状態)やマイナス(借入の状態)になり得ます。

      • baseTrackingIndex / baseTrackingAccrued

        ⇒ ユーザーごとの報酬(インセンティブ)計算に使われる指標です。

      • assetsIn

        ⇒ ユーザーがどれくらいの種類の資産を担保として利用しているか、という数を示します。

      • _reserved

        ⇒ 今後の拡張用に予約されたスペースです。

    • UserCollateral

      ユーザーごとに、各担保資産でどれだけの額を預けているかを管理するための構造体

      • balance

        ⇒ その担保資産に対するユーザーの預入れ残高です。

      • _reserved

        ⇒ 追加機能用の予約領域です。

    • LiquidatorPoints

      プロトコル内で、清算(liquidation)に携わる人(Liquidator:清算者)に対し、どれくらいの実績があるかを管理するための構造体

      • numAbsorbs

        ⇒ 清算回数を表すカウンターです。

      • numAbsorbed

        ⇒ 清算時に吸収(処理)された合計の額です。

      • approxSpend

        ⇒ 清算にかかったおおよその金額です(単位はトークン量など)。

      • _reserved

        ⇒ 追加する場合のための予約領域です。

    • mapping

      • mapping(address => TotalsCollateral) totalsCollateral;

        各担保資産(アドレスで管理)について、全ユーザー分の合計預入額が保存されます。

      • mapping(address => mapping(address => bool)) isAllowed;

        これは、あるユーザーが他の誰か(例:家族や管理者)に自分のアカウントの管理を任せることができるかどうかを管理します。

        → 第一の address はユーザー自身、第二の address は許可された管理者のアドレスです。

      • mapping(address => uint) userNonce;

        ユーザーごとの「ノンス」と呼ばれる数字を保持します。

        → これは署名による認証など、セキュリティ目的で使われ、操作の一意性を保ちます。

      • mapping(address => UserBasic) userBasic;

        各ユーザーの基本データ(借入金額、報酬用の計算値など)を保存しています。

      • mapping(address => mapping(address => UserCollateral)) userCollateral;

        あるユーザーが、それぞれの担保資産についてどれくらい預けているのかを記録します。

        → 最初の address はユーザーのアドレス、第二の address はそのユーザーが預ける担保資産のアドレスです。

      • mapping(address => LiquidatorPoints) liquidatorPoints;

        清算処理に関与した清算者ごとに、その業績(回数、総金額など)を記録します。

CometMath

  • ソースコード

    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity 0.8.15;
    
    /**
     * @title Compound's Comet Math Contract
     * @dev Pure math functions
     * @author Compound
     */
    contract CometMath {
        /** Custom errors **/
    
        error InvalidUInt64();
        error InvalidUInt104();
        error InvalidUInt128();
        error InvalidInt104();
        error InvalidInt256();
        error NegativeNumber();
    
        function safe64(uint n) internal pure returns (uint64) {
            if (n > type(uint64).max) revert InvalidUInt64();
            return uint64(n);
        }
    
        function safe104(uint n) internal pure returns (uint104) {
            if (n > type(uint104).max) revert InvalidUInt104();
            return uint104(n);
        }
    
        function safe128(uint n) internal pure returns (uint128) {
            if (n > type(uint128).max) revert InvalidUInt128();
            return uint128(n);
        }
    
        function signed104(uint104 n) internal pure returns (int104) {
            if (n > uint104(type(int104).max)) revert InvalidInt104();
            return int104(n);
        }
    
        function signed256(uint256 n) internal pure returns (int256) {
            if (n > uint256(type(int256).max)) revert InvalidInt256();
            return int256(n);
        }
    
        function unsigned104(int104 n) internal pure returns (uint104) {
            if (n < 0) revert NegativeNumber();
            return uint104(n);
        }
    
        function unsigned256(int256 n) internal pure returns (uint256) {
            if (n < 0) revert NegativeNumber();
            return uint256(n);
        }
    
        function toUInt8(bool x) internal pure returns (uint8) {
            return x ? 1 : 0;
        }
    
        function toBool(uint8 x) internal pure returns (bool) {
            return x != 0;
        }
    }
    
    
  • 役割

    • 数値の型変換における安全性を確保
    • オーバーフローやアンダーフローを防ぐ
    • プロトコル内での数値計算の正確性を担保
  • 実装内容

    1. 安全な数値型変換
      • safe64(), safe104(), safe128(): 大きな数値をより小さいビット幅の符号なし整数に安全に変換します。オーバーフローを防ぐためのチェックが含まれています。
      • signed104(), signed256(): 符号なし整数を符号付き整数に安全に変換します。
      • unsigned104(), unsigned256(): 符号付き整数を符号なし整数に安全に変換します。
    2. エラー処理
      • 各関数には適切なエラーチェックが実装されており、以下のようなカスタムエラーを定義しています:
      • InvalidUInt64(), InvalidUInt104(), InvalidUInt128(): 数値が指定された型の最大値を超えた場合
      • InvalidInt104(), InvalidInt256(): 符号なし整数が符号付き整数の範囲を超えた場合
      • NegativeNumber(): 負の数が渡された場合

CometConfiguration.sol

  • ソースコード

    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity 0.8.15;
    
    /**
     * @title Compound's Comet Configuration Interface
     * @author Compound
     */
    contract CometConfiguration {
        struct ExtConfiguration {
            bytes32 name32;
            bytes32 symbol32;
        }
    
        struct Configuration {
            address governor;
            address pauseGuardian;
            address baseToken;
            address baseTokenPriceFeed;
            address extensionDelegate;
    
            uint64 supplyKink;
            uint64 supplyPerYearInterestRateSlopeLow;
            uint64 supplyPerYearInterestRateSlopeHigh;
            uint64 supplyPerYearInterestRateBase;
            uint64 borrowKink;
            uint64 borrowPerYearInterestRateSlopeLow;
            uint64 borrowPerYearInterestRateSlopeHigh;
            uint64 borrowPerYearInterestRateBase;
            uint64 storeFrontPriceFactor;
            uint64 trackingIndexScale;
            uint64 baseTrackingSupplySpeed;
            uint64 baseTrackingBorrowSpeed;
            uint104 baseMinForRewards;
            uint104 baseBorrowMin;
            uint104 targetReserves;
    
            AssetConfig[] assetConfigs;
        }
    
        struct AssetConfig {
            address asset;
            address priceFeed;
            uint8 decimals;
            uint64 borrowCollateralFactor;
            uint64 liquidateCollateralFactor;
            uint64 liquidationFactor;
            uint128 supplyCap;
        }
    }
    
    
  • Compoundで使われる構造体の定義

    1. ExtConfiguration 構造体

      struct ExtConfiguration {
          bytes32 name32;
          bytes32 symbol32;
      }
      
      • プロトコルの拡張機能の基本情報を保持

        →よくわかんないので調べる

    2. Configuration構造体

      struct Configuration {
              address governor;
              address pauseGuardian;
              address baseToken;
              address baseTokenPriceFeed;
              address extensionDelegate;
      
              uint64 supplyKink;
              uint64 supplyPerYearInterestRateSlopeLow;
              uint64 supplyPerYearInterestRateSlopeHigh;
              uint64 supplyPerYearInterestRateBase;
              uint64 borrowKink;
              uint64 borrowPerYearInterestRateSlopeLow;
              uint64 borrowPerYearInterestRateSlopeHigh;
              uint64 borrowPerYearInterestRateBase;
              uint64 storeFrontPriceFactor;
              uint64 trackingIndexScale;
              uint64 baseTrackingSupplySpeed;
              uint64 baseTrackingBorrowSpeed;
              uint104 baseMinForRewards;
              uint104 baseBorrowMin;
              uint104 targetReserves;
      
              AssetConfig[] assetConfigs;
          }
      
      • ガバナンスおよび管理関連の変数

        • governor

          プロトコルの管理者アドレス。重要なパラメータの変更やアップグレード、緊急停止(pause)の実行など、システム全体の運営に関する意思決定を行う権限を持つ。

        • pauseGuardian

          緊急時に市場の混乱やシステムの脆弱性に迅速に対応するため、特定の機能(供給、転送、引き出し、吸収、購入など)を一時停止できる権限を持つアカウント。governor と併せて安全性を担保。

        • extensionDelegate

          プロトコルの拡張やアップグレード時に、追加のロジックや新たな機能を委任するためのデリゲート先アドレス。プロキシパターンなどで拡張性を担保するために利用される。

      • ベースとなる資産およびオラクル関連の変数

        • baseToken

          プロトコル内で中心的に扱われる資産(ベーストークン)のアドレス。通常、借入・預入の際の基軸となる通貨(例:USDC、DAI、ETH など)として利用され、他の担保資産との交換比率や清算の際の基準となる。

        • baseTokenPriceFeed

          ベーストークンの市場価格を取得するためのオラクル(価格フィード)となるコントラクトのアドレス。担保評価、清算判定、ユーザーインターフェイスでの価格表示など、様々な場面で市場価格が参照される。

      • 金利モデル(インタレストレート)関連の変数

        Compound(Comet)では、利用率(またはその他の指標?)に応じた金利変動を実現するため、kink(転換点) と複数の 金利スロープ および ベースレート が設定されている。

        • サプライ(預入側)のパラメータ

          • supplyKink

            供給側における利用率の「折れ点」。利用率がこの値までは低い金利スロープ(slopeLow)が適用され、これを超えると高い金利スロープ(slopeHigh)が適用されるなど、供給者への報酬やインセンティブに影響を与える。

          • supplyPerYearInterestRateSlopeLow

            利用率が供給側の kink 以下の場合に適用される年率ベースの金利スロープ。利用率が低い時には、比較的緩やかな上昇率で金利が決定される。

          • supplyPerYearInterestRateSlopeHigh

            利用率が供給側の kink を超えた場合に適用される年率ベースの金利スロープ。利用率が高まると、供給金利は急激に上昇するように設計されている。

          • supplyPerYearInterestRateBase

            供給者に対して最低でも支払われる基本の年率金利。利用率にかかわらず、一定の利回りが提供されるベースレートとなる。

        • 借入側のパラメータ

          • borrowKink

            借入側における利用率の転換点。この値を基準に、低利用率時と高利用率時で借入金利の上昇幅が分かれます。

          • borrowPerYearInterestRateSlopeLow

            借入利用率が借入側の kink 以下で適用される低いスロープの借入金利。市場全体の利用状況に対して、比較的低い利率が提供されるように設定される。

          • borrowPerYearInterestRateSlopeHigh

            借入利用率が借入側の kink を超える場合に適用される、急激に上昇する金利スロープ。システム全体のリスク管理や利用促進を意図した設計となっている。

          • borrowPerYearInterestRateBase

            借入者に対して適用される基本の年率金利。利用率に関係なく、最低限この金利が借入に対して課せられる。

      • フロントエンド表示や担保評価、リスク管理に係るパラメータ

        • storeFrontPriceFactor

          ユーザーインターフェイスなどで表示される価格に対して適用される倍率や割引係数。オラクルから取得した市場価格に対し、安全マージンやシステム上の調整値を反映するために利用される。

      • 報酬・インセンティブ、追跡値に関する変数

        • trackingIndexScale

          報酬のインデックスや複利計算の精度を保つためのスケール係数。内部計算で、小数点以下の精度を扱うために用いられ、各参加者の報酬や金利計算に影響する。

        • baseTrackingSupplySpeed

          供給者向けの報酬がどの速度(例:1 秒あたり、1 ブロックあたり)で蓄積されるかを示すパラメータ。供給活動に対するインセンティブを定量化。

        • baseTrackingBorrowSpeed

          借入者向けの報酬がどの速度で蓄積されるかを示すパラメータ。借入行動に対するインセンティブ設計の一環として、報酬分配が調整される。

        • baseMinForRewards

          報酬分配の対象となる基準として、一定以上の残高(または活動量)がなければ報酬を付与しないという下限値。これにより、細かい残高での無意味な報酬計算や、ガス代無駄を防止。

        • baseBorrowMin

          借入ポジションに対する下限値。極小の借入残高の場合、システム上の計算誤差や不整合を防ぐため、一定額以下のポジションは考慮しない、といった運用ルールを反映している?

      • リザーブ(準備金)関連

        • targetReserves

          プロトコルが内部に保持すべき目標準備金額。手数料収入や余剰資金の蓄積として、安全性や流動性の担保、突発的な市場変動時のクッションとして利用される。プロトコル全体の健全性を保つためのバッファとして設定されてる。

      • 担保資産の設定

        AssetConfigを参照

    3. AssetConfig構造体

      struct AssetConfig {
              address asset;
              address priceFeed;
              uint8 decimals;
              uint64 borrowCollateralFactor;
              uint64 liquidateCollateralFactor;
              uint64 liquidationFactor;
              uint128 supplyCap;
          }
      
      • asset (address)

        • 役割

          サポートされるERC20トークンそのもののアドレス。このトークンがユーザーによって預けられ、担保として用いられる。

        • 使われ方

          ユーザーが担保として預入れることで、借入枠の計算や清算判定の基礎となる資産の価値計算が行われる。

      • priceFeed (address)

        • 役割

          この資産の市場価格を取得するために用いられるオラクル(価格フィード)のコントラクトアドレス。

        • 使われ方

          オラクルから価格情報を取得し、ユーザーの担保価値や借入のリスク計算、清算のトリガー判定に用いられる。

      • decimals (uint8)

        • 役割

          資産トークンの桁数(小数点以下の桁数)を示す。

          例として、USDCは通常6桁、DAIは18桁といった違いがある。

        • 使われ方

          トークンの最小単位から、実際の数量や金額を計算する際に利用される。特に、担保価値の計算や供給上限(supplyCap)の正規化など、正確な数値変換が必要な場面で重要。

      • borrowCollateralFactor (uint64)

        • 役割

          ユーザーがこの資産を担保として預けた場合、その資産の価値に対してどの程度の借入可能額が認められるかを示す係数。

          一般に、割合(例えば75%など)を内部のスケールで管理。

        • 使われ方

          ユーザーの担保評価の際に適用され、たとえば借入可能額 = 預入資産の価値 × borrowCollateralFactor という計算に利用される。担保としての安全性やリスク評価に直結するパラメータ。

      • liquidateCollateralFactor (uint64)

        • 役割

          ユーザーのポジションが清算(Liquidation)の対象になる際の担保評価の下限を示す係数。

          通常、borrowCollateralFactorよりも低い値に設定され、安全マージンを提供。

        • 使われ方

          市場価格の変動等で担保価値が低下した場合、ユーザーのポジションがこの閾値以下になると、清算が可能となる。プロトコルのリスク管理のための「清算閾値」として機能する。

      • liquidationFactor (uint64)

        • 役割

          清算イベント時に、清算者(Liquidator)に対して適用される割引率または報酬係数。

          これにより、清算を促進し、システムの健全性を維持するインセンティブが与えられる。

        • 使われ方

          ユーザーの担保が清算トリガーに達した場合、清算者は担保資産を割引価格で購入することが可能になるなど、実際の清算処理の計算に反映される。

      • supplyCap (uint128)

        • 役割

          この資産に対して、プロトコル内に預入れ可能な上限額(供給上限)を設定。

          資産ごとのリスク集中を避けるための仕組み。

        • 使われ方

          ユーザーが資産を預ける際に、プロトコルが設定した上限に達していないかどうかをチェック。上限を超える大量の供給が発生すると、万一の市場変動時に過度なリスクにさらされるため、供給量を抑制する効果がある。

CometCore

  • ソースコード

    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity 0.8.15;
    
    import "./CometConfiguration.sol";
    import "./CometStorage.sol";
    import "./CometMath.sol";
    
    abstract contract CometCore is CometConfiguration, CometStorage, CometMath {
        struct AssetInfo {
            uint8 offset;
            address asset;
            address priceFeed;
            uint64 scale;
            uint64 borrowCollateralFactor;
            uint64 liquidateCollateralFactor;
            uint64 liquidationFactor;
            uint128 supplyCap;
        }
    
        /** Internal constants **/
    
        /// @dev The max number of assets this contract is hardcoded to support
        ///  Do not change this variable without updating all the fields throughout the contract,
        //    including the size of UserBasic.assetsIn and corresponding integer conversions.
        uint8 internal constant MAX_ASSETS = 15;
    
        /// @dev The max number of decimals base token can have
        ///  Note this cannot just be increased arbitrarily.
        uint8 internal constant MAX_BASE_DECIMALS = 18;
    
        /// @dev The max value for a collateral factor (1)
        uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;
    
        /// @dev Offsets for specific actions in the pause flag bit array
        uint8 internal constant PAUSE_SUPPLY_OFFSET = 0;
        uint8 internal constant PAUSE_TRANSFER_OFFSET = 1;
        uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2;
        uint8 internal constant PAUSE_ABSORB_OFFSET = 3;
        uint8 internal constant PAUSE_BUY_OFFSET = 4;
    
        /// @dev The decimals required for a price feed
        uint8 internal constant PRICE_FEED_DECIMALS = 8;
    
        /// @dev 365 days * 24 hours * 60 minutes * 60 seconds
        uint64 internal constant SECONDS_PER_YEAR = 31_536_000;
    
        /// @dev The scale for base tracking accrual
        uint64 internal constant BASE_ACCRUAL_SCALE = 1e6;
    
        /// @dev The scale for base index (depends on time/rate scales, not base token)
        uint64 internal constant BASE_INDEX_SCALE = 1e15;
    
        /// @dev The scale for prices (in USD)
        uint64 internal constant PRICE_SCALE = uint64(10 ** PRICE_FEED_DECIMALS);
    
        /// @dev The scale for factors
        uint64 internal constant FACTOR_SCALE = 1e18;
    
        /// @dev The storage slot for reentrancy guard flags
        bytes32 internal constant REENTRANCY_GUARD_FLAG_SLOT = bytes32(keccak256("comet.reentrancy.guard"));
    
        /// @dev The reentrancy guard statuses
        uint256 internal constant REENTRANCY_GUARD_NOT_ENTERED = 0;
        uint256 internal constant REENTRANCY_GUARD_ENTERED = 1;
    
        /**
         * @notice Determine if the manager has permission to act on behalf of the owner
         * @param owner The owner account
         * @param manager The manager account
         * @return Whether or not the manager has permission
         */
        function hasPermission(address owner, address manager) public view returns (bool) {
            return owner == manager || isAllowed[owner][manager];
        }
    
        /**
         * @dev The positive present supply balance if positive or the negative borrow balance if negative
         */
        function presentValue(int104 principalValue_) internal view returns (int256) {
            if (principalValue_ >= 0) {
                return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_)));
            } else {
                return -signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_)));
            }
        }
    
        /**
         * @dev The principal amount projected forward by the supply index
         */
        function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) {
            return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE;
        }
    
        /**
         * @dev The principal amount projected forward by the borrow index
         */
        function presentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internal pure returns (uint256) {
            return uint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE;
        }
    
        /**
         * @dev The positive principal if positive or the negative principal if negative
         */
        function principalValue(int256 presentValue_) internal view returns (int104) {
            if (presentValue_ >= 0) {
                return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_)));
            } else {
                return -signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_)));
            }
        }
    
        /**
         * @dev The present value projected backward by the supply index (rounded down)
         *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
         */
        function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) {
            return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_);
        }
    
        /**
         * @dev The present value projected backward by the borrow index (rounded up)
         *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
         */
        function principalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internal pure returns (uint104) {
            return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ - 1) / baseBorrowIndex_);
        }
    }
    
    
  • 役割

    Cometプロトコルのコア機能を提供する抽象コントラクト。
    以下の3つのコントラクトを継承

    • CometConfiguration: 設定関連
    • CometStorage: ストレージ関連
    • CometMath: 数学演算関連
  • 実装内容

    1. AssetInfo構造体

      struct AssetInfo {
          uint8 offset;
          address asset;
          address priceFeed;
          uint64 scale;
          uint64 borrowCollateralFactor;
          uint64 liquidateCollateralFactor;
          uint64 liquidationFactor;
          uint128 supplyCap;
      }
      
      • 資産に関する重要な情報を保持
      • 担保率、清算率、供給上限などの設定を含む
    2. 定数設定

      uint8 internal constant MAX_ASSETS = 15;  // 最大資産数
      uint8 internal constant MAX_BASE_DECIMALS = 18;  // ベーストークンの最大小数点
      uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;  // 最大担保率
      uint64 internal constant SECONDS_PER_YEAR = 31_536_000;  // 1年の秒数
      
    3. 一時停止フラグの定数

      uint8 internal constant PAUSE_SUPPLY_OFFSET = 0;
      uint8 internal constant PAUSE_TRANSFER_OFFSET = 1;
      uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2;
      uint8 internal constant PAUSE_ABSORB_OFFSET = 3;
      uint8 internal constant PAUSE_BUY_OFFSET = 4;
      
    4. 権限管理

      function hasPermission(address *owner*, address *manager*) public view returns (bool)
      
      • マネージャーがオーナーの代わりに行動する権限があるかどうかを確認
    5. 価値計算関数

      function presentValue(int104 *principalValue_*) internal view returns (int256)
      
      • 元本価値を現在価値に変換
      • 供給残高と借入残高の両方に対応
    6. 供給価値計算

      function presentValueSupply(uint64 *baseSupplyIndex_*, uint104 *principalValue_*) internal pure returns (uint256)
      
      • 供給残高の現在価値を計算
    7. 借入価値計算

      function presentValueBorrow(uint64 *baseBorrowIndex_*, uint104 *principalValue_*) internal pure returns (uint256)
      
      • 借入残高の現在価値を計算
    8. 元本価値計算

      function principalValue(int256 *presentValue_*) internal view returns (int104)
      
      • 現在価値を元本価値に変換

Discussion