Contract 0x4D2Dbc2130681F55354e8D7CEe65085061E72C44

  Note: Our ether balance display is temporarily unavailable. Please check back later.

Contract Overview

Balance:
Txn Hash
Method
Block
From
To
Value
0xc9e59c9d288165ff8bd99df0026bad6e3b87794c4a0b11fa593d942a53d353ad0x60a06040124323082022-06-20 8:49:12171 days 21 hrs ago0x42a7ba5dbd5a0f032e3c50f67a7934b19e776ede IN  Create: Lens0 Ether0.01166111 3
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Lens

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : Lens.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

import "./interfaces/compound/ICompound.sol";
import "./interfaces/IMorpho.sol";
import "./interfaces/ILens.sol";

import "@rari-capital/solmate/src/utils/SafeTransferLib.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./libraries/CompoundMath.sol";

/// @title Lens.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @notice User accessible getters.
contract Lens is ILens {
    using CompoundMath for uint256;

    /// STRUCTS ///

    struct P2PIndexesParams {
        uint256 lastP2PSupplyIndex; // The last peer-to-peer supply index.
        uint256 lastP2PBorrowIndex; // The last peer-to-peer borrow index
        uint256 poolSupplyIndex; // The current pool supply index.
        uint256 poolBorrowIndex; // The current pool borrow index.
        uint256 lastPoolSupplyIndex; // The pool supply index at last update.
        uint256 lastPoolBorrowIndex; // The pool borrow index at last update.
        uint256 reserveFactor; // The reserve factor percentage (10 000 = 100%).
        uint256 p2pIndexCursor; // The peer-to-peer index cursor (10 000 = 100%).
        Types.Delta delta; // The deltas and peer-to-peer amounts.
    }

    struct RateParams {
        uint256 p2pIndex; // The peer-to-peer index.
        uint256 poolIndex; // The pool index.
        uint256 lastPoolIndex; // The pool index at last update.
        uint256 reserveFactor; // The reserve factor percentage (10 000 = 100%).
        uint256 p2pAmount; // Sum of all stored peer-to-peer balance in supply or borrow (in peer-to-peer unit).
        uint256 p2pDelta; // Sum of all stored peer-to-peer in supply or borrow (in peer-to-peer unit).
    }

    /// STORAGE ///

    uint256 public constant MAX_BASIS_POINTS = 10_000; // 100% (in basis points).
    uint256 public constant WAD = 1e18;
    IMorpho public immutable morpho;

    /// CONSTRUCTOR ///

    constructor(address _morphoAddress) {
        morpho = IMorpho(_morphoAddress);
    }

    /// ERRORS ///

    /// @notice Thrown when the Compound's oracle failed.
    error CompoundOracleFailed();

    ///////////////////////////////////
    ///           GETTERS           ///
    ///////////////////////////////////

    /// MARKET STATUSES ///

    /// @notice Checks if a market is created.
    /// @param _poolTokenAddress The address of the market to check.
    /// @return true if the market is created and not paused, otherwise false.
    function isMarketCreated(address _poolTokenAddress) external view returns (bool) {
        return morpho.marketStatus(_poolTokenAddress).isCreated;
    }

    /// @notice Checks if a market is created and not paused.
    /// @param _poolTokenAddress The address of the market to check.
    /// @return true if the market is created and not paused, otherwise false.
    function isMarketCreatedAndNotPaused(address _poolTokenAddress) external view returns (bool) {
        Types.MarketStatus memory marketStatus = morpho.marketStatus(_poolTokenAddress);
        return marketStatus.isCreated && !marketStatus.isPaused;
    }

    /// @notice Checks if a market is created and not paused or partially paused.
    /// @param _poolTokenAddress The address of the market to check.
    /// @return true if the market is created, not paused and not partially paused, otherwise false.
    function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolTokenAddress)
        external
        view
        returns (bool)
    {
        Types.MarketStatus memory marketStatus = morpho.marketStatus(_poolTokenAddress);
        return marketStatus.isCreated && !marketStatus.isPaused && !marketStatus.isPartiallyPaused;
    }

    /// MARKET INFO ///

    /// @notice Returns all markets entered by a given user.
    /// @param _user The address of the user.
    /// @return enteredMarkets_ The list of markets entered by this user.
    function getEnteredMarkets(address _user)
        external
        view
        returns (address[] memory enteredMarkets_)
    {
        return morpho.getEnteredMarkets(_user);
    }

    /// @notice Returns all created markets.
    /// @return marketsCreated_ The list of market addresses.
    function getAllMarkets() external view returns (address[] memory marketsCreated_) {
        return morpho.getAllMarkets();
    }

    /// @notice Returns market's data.
    /// @return p2pSupplyIndex_ The peer-to-peer supply index of the market.
    /// @return p2pBorrowIndex_ The peer-to-peer borrow index of the market.
    /// @return lastUpdateBlockNumber_ The last block number when peer-to-peer indexes were updated.
    /// @return p2pSupplyDelta_ The peer-to-peer supply delta (in scaled balance).
    /// @return p2pBorrowDelta_ The peer-to-peer borrow delta (in cdUnit).
    /// @return p2pSupplyAmount_ The peer-to-peer supply amount (in peer-to-peer unit).
    /// @return p2pBorrowAmount_ The peer-to-peer borrow amount (in peer-to-peer unit).
    function getMarketData(address _poolTokenAddress)
        external
        view
        returns (
            uint256 p2pSupplyIndex_,
            uint256 p2pBorrowIndex_,
            uint32 lastUpdateBlockNumber_,
            uint256 p2pSupplyDelta_,
            uint256 p2pBorrowDelta_,
            uint256 p2pSupplyAmount_,
            uint256 p2pBorrowAmount_
        )
    {
        {
            Types.Delta memory delta = morpho.deltas(_poolTokenAddress);
            p2pSupplyDelta_ = delta.p2pSupplyDelta;
            p2pBorrowDelta_ = delta.p2pBorrowDelta;
            p2pSupplyAmount_ = delta.p2pSupplyAmount;
            p2pBorrowAmount_ = delta.p2pBorrowAmount;
        }
        p2pSupplyIndex_ = morpho.p2pSupplyIndex(_poolTokenAddress);
        p2pBorrowIndex_ = morpho.p2pBorrowIndex(_poolTokenAddress);
        lastUpdateBlockNumber_ = morpho.lastPoolIndexes(_poolTokenAddress).lastUpdateBlockNumber;
    }

    /// @notice Returns market's configuration.
    /// @return underlying_ The underlying token address.
    /// @return isCreated_ Whether the market is created or not.
    /// @return p2pDisabled_ Whether user are put in peer-to-peer or not.
    /// @return isPaused_ Whether the market is paused or not (all entry points on Morpho are frozen; supply, borrow, withdraw, repay and liquidate).
    /// @return isPartiallyPaused_ Whether the market is partially paused or not (only supply and borrow are frozen).
    /// @return reserveFactor_ The reserve actor applied to this market.
    /// @return collateralFactor_ The pool collateral factor also used by Morpho.
    function getMarketConfiguration(address _poolTokenAddress)
        external
        view
        returns (
            address underlying_,
            bool isCreated_,
            bool p2pDisabled_,
            bool isPaused_,
            bool isPartiallyPaused_,
            uint256 reserveFactor_,
            uint256 collateralFactor_
        )
    {
        underlying_ = ICToken(_poolTokenAddress).underlying();
        Types.MarketStatus memory marketStatus = morpho.marketStatus(_poolTokenAddress);
        isCreated_ = marketStatus.isCreated;
        p2pDisabled_ = morpho.p2pDisabled(_poolTokenAddress);
        isPaused_ = marketStatus.isPaused;
        isPartiallyPaused_ = marketStatus.isPartiallyPaused;
        reserveFactor_ = morpho.marketParameters(_poolTokenAddress).reserveFactor;
        (, collateralFactor_, ) = morpho.comptroller().markets(_poolTokenAddress);
    }

    /// @notice Computes and returns peer-to-peer and pool rates for a specific market (without taking into account deltas!).
    /// @param _poolTokenAddress The market address.
    /// @return p2pSupplyRate_ The market's peer-to-peer supply rate per block (in wad).
    /// @return p2pBorrowRate_ The market's peer-to-peer borrow rate per block (in wad).
    /// @return poolSupplyRate_ The market's pool supply rate per block (in wad).
    /// @return poolBorrowRate_ The market's pool borrow rate per block (in wad).
    function getRates(address _poolTokenAddress)
        public
        view
        returns (
            uint256 p2pSupplyRate_,
            uint256 p2pBorrowRate_,
            uint256 poolSupplyRate_,
            uint256 poolBorrowRate_
        )
    {
        ICToken cToken = ICToken(_poolTokenAddress);

        poolSupplyRate_ = cToken.supplyRatePerBlock();
        poolBorrowRate_ = cToken.borrowRatePerBlock();
        Types.MarketParameters memory marketParams = morpho.marketParameters(_poolTokenAddress);

        uint256 p2pRate = ((MAX_BASIS_POINTS - marketParams.p2pIndexCursor) *
            poolSupplyRate_ +
            marketParams.p2pIndexCursor *
            poolBorrowRate_) / MAX_BASIS_POINTS;

        p2pSupplyRate_ =
            p2pRate -
            (marketParams.reserveFactor * (p2pRate - poolSupplyRate_)) /
            MAX_BASIS_POINTS;
        p2pBorrowRate_ =
            p2pRate +
            (marketParams.reserveFactor * (poolBorrowRate_ - p2pRate)) /
            MAX_BASIS_POINTS;
    }

    /// BALANCES ///

    /// @notice Returns the collateral value, debt value and max debt value of a given user.
    /// @param _user The user to determine liquidity for.
    /// @param _updatedMarkets The list of markets of which to compute virtually updated pool and peer-to-peer indexes.
    /// @return collateralValue The collateral value of the user.
    /// @return debtValue The current debt value of the user.
    /// @return maxDebtValue The maximum possible debt value of the user.
    function getUserBalanceStates(address _user, address[] calldata _updatedMarkets)
        external
        view
        returns (
            uint256 collateralValue,
            uint256 debtValue,
            uint256 maxDebtValue
        )
    {
        ICompoundOracle oracle = ICompoundOracle(morpho.comptroller().oracle());
        address[] memory enteredMarkets = morpho.getEnteredMarkets(_user);

        uint256 nbEnteredMarkets = enteredMarkets.length;
        uint256 nbUpdatedMarkets = _updatedMarkets.length;
        for (uint256 i; i < nbEnteredMarkets; ) {
            address poolTokenEntered = enteredMarkets[i];

            bool shouldUpdateIndexes;
            for (uint256 j; j < nbUpdatedMarkets; ) {
                if (_updatedMarkets[j] == poolTokenEntered) {
                    shouldUpdateIndexes = true;
                    break;
                }

                unchecked {
                    ++j;
                }
            }

            Types.AssetLiquidityData memory assetData = getUserLiquidityDataForAsset(
                _user,
                poolTokenEntered,
                shouldUpdateIndexes,
                oracle
            );

            collateralValue += assetData.collateralValue;
            maxDebtValue += assetData.maxDebtValue;
            debtValue += assetData.debtValue;

            unchecked {
                ++i;
            }
        }
    }

    /// @notice Returns the balance in underlying of a given user in a given market.
    /// @param _user The user to determine balances of.
    /// @param _poolTokenAddress The address of the market.
    /// @return balanceOnPool The balance on pool of the user (in underlying).
    /// @return balanceInP2P The balance in peer-to-peer of the user (in underlying).
    /// @return totalBalance The total balance of the user (in underlying).
    function getUpdatedUserSupplyBalance(address _user, address _poolTokenAddress)
        public
        view
        returns (
            uint256 balanceOnPool,
            uint256 balanceInP2P,
            uint256 totalBalance
        )
    {
        (uint256 poolSupplyIndex, ) = _computePoolIndexes(_poolTokenAddress);

        balanceOnPool = morpho.supplyBalanceInOf(_poolTokenAddress, _user).onPool.mul(
            poolSupplyIndex
        );
        balanceInP2P = morpho.supplyBalanceInOf(_poolTokenAddress, _user).inP2P.mul(
            getUpdatedP2PSupplyIndex(_poolTokenAddress)
        );

        totalBalance = balanceOnPool + balanceInP2P;
    }

    /// @notice Returns the borrow balance in underlying of a given user in a given market.
    /// @param _user The user to determine balances of.
    /// @param _poolTokenAddress The address of the market.
    /// @return balanceOnPool The balance on pool of the user (in underlying).
    /// @return balanceInP2P The balance in peer-to-peer of the user (in underlying).
    /// @return totalBalance The total balance of the user (in underlying).
    function getUpdatedUserBorrowBalance(address _user, address _poolTokenAddress)
        public
        view
        returns (
            uint256 balanceOnPool,
            uint256 balanceInP2P,
            uint256 totalBalance
        )
    {
        (, uint256 newBorrowIndex) = _computePoolIndexes(_poolTokenAddress);

        balanceOnPool = morpho.borrowBalanceInOf(_poolTokenAddress, _user).onPool.mul(
            newBorrowIndex
        );
        balanceInP2P = morpho.borrowBalanceInOf(_poolTokenAddress, _user).inP2P.mul(
            getUpdatedP2PBorrowIndex(_poolTokenAddress)
        );

        totalBalance = balanceOnPool + balanceInP2P;
    }

    /// @notice Returns the maximum amount available to withdraw and borrow for `_user` related to `_poolTokenAddress` (in underlyings).
    /// @dev Note: must be called after calling `accrueInterest()` on the cToken to have the most up to date values.
    /// @param _user The user to determine the capacities for.
    /// @param _poolTokenAddress The address of the market.
    /// @return withdrawable The maximum withdrawable amount of underlying token allowed (in underlying).
    /// @return borrowable The maximum borrowable amount of underlying token allowed (in underlying).
    function getUserMaxCapacitiesForAsset(address _user, address _poolTokenAddress)
        external
        view
        returns (uint256 withdrawable, uint256 borrowable)
    {
        Types.LiquidityData memory data;
        Types.AssetLiquidityData memory assetData;
        ICompoundOracle oracle = ICompoundOracle(morpho.comptroller().oracle());
        address[] memory enteredMarkets = morpho.getEnteredMarkets(_user);

        uint256 nbEnteredMarkets = enteredMarkets.length;
        for (uint256 i; i < nbEnteredMarkets; ) {
            address poolTokenEntered = enteredMarkets[i];

            if (_poolTokenAddress != poolTokenEntered) {
                assetData = getUserLiquidityDataForAsset(_user, poolTokenEntered, true, oracle);

                data.maxDebtValue += assetData.maxDebtValue;
                data.debtValue += assetData.debtValue;
            }

            unchecked {
                ++i;
            }
        }

        assetData = getUserLiquidityDataForAsset(_user, _poolTokenAddress, true, oracle);

        data.maxDebtValue += assetData.maxDebtValue;
        data.debtValue += assetData.debtValue;

        // Not possible to withdraw nor borrow.
        if (data.maxDebtValue < data.debtValue) return (0, 0);

        uint256 differenceInUnderlying = (data.maxDebtValue - data.debtValue).div(
            assetData.underlyingPrice
        );

        withdrawable = assetData.collateralValue.div(assetData.underlyingPrice);
        if (assetData.collateralFactor != 0) {
            withdrawable = Math.min(
                withdrawable,
                differenceInUnderlying.div(assetData.collateralFactor)
            );
        }

        borrowable = differenceInUnderlying;
    }

    /// @dev Returns the debt value, max debt value of a given user.
    /// @param _user The user to determine liquidity for.
    /// @param _poolTokenAddress The market to hypothetically withdraw/borrow in.
    /// @param _withdrawnAmount The number of tokens to hypothetically withdraw (in underlying).
    /// @param _borrowedAmount The amount of tokens to hypothetically borrow (in underlying).
    /// @return debtValue The current debt value of the user.
    /// @return maxDebtValue The maximum debt value possible of the user.
    function getUserHypotheticalBalanceStates(
        address _user,
        address _poolTokenAddress,
        uint256 _withdrawnAmount,
        uint256 _borrowedAmount
    ) public view returns (uint256 debtValue, uint256 maxDebtValue) {
        ICompoundOracle oracle = ICompoundOracle(morpho.comptroller().oracle());
        address[] memory enteredMarkets = morpho.getEnteredMarkets(_user);

        uint256 nbEnteredMarkets = enteredMarkets.length;
        for (uint256 i; i < nbEnteredMarkets; ) {
            address poolTokenEntered = enteredMarkets[i];

            Types.AssetLiquidityData memory assetData = getUserLiquidityDataForAsset(
                _user,
                poolTokenEntered,
                true,
                oracle
            );

            maxDebtValue += assetData.maxDebtValue;
            debtValue += assetData.debtValue;
            unchecked {
                ++i;
            }

            if (_poolTokenAddress == poolTokenEntered) {
                if (_borrowedAmount > 0)
                    debtValue += _borrowedAmount.mul(assetData.underlyingPrice);

                if (_withdrawnAmount > 0)
                    maxDebtValue -= _withdrawnAmount.mul(assetData.underlyingPrice).mul(
                        assetData.collateralFactor
                    );
            }
        }
    }

    /// @notice Returns the data related to `_poolTokenAddress` for the `_user`, by optionally computing virtually updated pool and peer-to-peer indexes.
    /// @param _user The user to determine data for.
    /// @param _poolTokenAddress The address of the market.
    /// @param _computeUpdatedIndexes Whether to compute virtually updated pool and peer-to-peer indexes.
    /// @param _oracle The oracle used.
    /// @return assetData The data related to this asset.
    function getUserLiquidityDataForAsset(
        address _user,
        address _poolTokenAddress,
        bool _computeUpdatedIndexes,
        ICompoundOracle _oracle
    ) public view returns (Types.AssetLiquidityData memory assetData) {
        assetData.underlyingPrice = _oracle.getUnderlyingPrice(_poolTokenAddress);
        if (assetData.underlyingPrice == 0) revert CompoundOracleFailed();

        (, assetData.collateralFactor, ) = morpho.comptroller().markets(_poolTokenAddress);

        (
            uint256 p2pSupplyIndex,
            uint256 p2pBorrowIndex,
            uint256 poolSupplyIndex,
            uint256 poolBorrowIndex
        ) = getIndexes(_poolTokenAddress, _computeUpdatedIndexes);

        assetData.collateralValue = _computeUserSupplyBalanceInOf(
            _poolTokenAddress,
            _user,
            p2pSupplyIndex,
            poolSupplyIndex
        ).mul(assetData.underlyingPrice);

        assetData.debtValue = _computeUserBorrowBalanceInOf(
            _poolTokenAddress,
            _user,
            p2pBorrowIndex,
            poolBorrowIndex
        ).mul(assetData.underlyingPrice);

        assetData.maxDebtValue = assetData.collateralValue.mul(assetData.collateralFactor);
    }

    /// INDEXES ///

    /// @notice Returns the updated peer-to-peer supply index.
    /// @param _poolTokenAddress The address of the market.
    /// @return newP2PSupplyIndex The updated peer-to-peer supply index.
    function getUpdatedP2PSupplyIndex(address _poolTokenAddress) public view returns (uint256) {
        if (block.number == morpho.lastPoolIndexes(_poolTokenAddress).lastUpdateBlockNumber)
            return morpho.p2pSupplyIndex(_poolTokenAddress);
        else {
            Types.LastPoolIndexes memory poolIndexes = morpho.lastPoolIndexes(_poolTokenAddress);
            Types.MarketParameters memory marketParams = morpho.marketParameters(_poolTokenAddress);

            (uint256 poolSupplyIndex, uint256 poolBorrowIndex) = _computePoolIndexes(
                _poolTokenAddress
            );

            P2PIndexesParams memory params = P2PIndexesParams(
                morpho.p2pSupplyIndex(_poolTokenAddress),
                morpho.p2pBorrowIndex(_poolTokenAddress),
                poolSupplyIndex,
                poolBorrowIndex,
                poolIndexes.lastSupplyPoolIndex,
                poolIndexes.lastBorrowPoolIndex,
                marketParams.reserveFactor,
                marketParams.p2pIndexCursor,
                morpho.deltas(_poolTokenAddress)
            );

            return _computeP2PSupplyIndex(params);
        }
    }

    /// @notice Returns the updated peer-to-peer borrow index.
    /// @param _poolTokenAddress The address of the market.
    /// @return newP2PBorrowIndex The updated peer-to-peer borrow index.
    function getUpdatedP2PBorrowIndex(address _poolTokenAddress) public view returns (uint256) {
        if (block.number == morpho.lastPoolIndexes(_poolTokenAddress).lastUpdateBlockNumber)
            return morpho.p2pBorrowIndex(_poolTokenAddress);
        else {
            Types.LastPoolIndexes memory poolIndexes = morpho.lastPoolIndexes(_poolTokenAddress);
            Types.MarketParameters memory marketParams = morpho.marketParameters(_poolTokenAddress);

            (uint256 poolSupplyIndex, uint256 poolBorrowIndex) = _computePoolIndexes(
                _poolTokenAddress
            );

            P2PIndexesParams memory params = P2PIndexesParams(
                morpho.p2pSupplyIndex(_poolTokenAddress),
                morpho.p2pBorrowIndex(_poolTokenAddress),
                poolSupplyIndex,
                poolBorrowIndex,
                poolIndexes.lastSupplyPoolIndex,
                poolIndexes.lastBorrowPoolIndex,
                marketParams.reserveFactor,
                marketParams.p2pIndexCursor,
                morpho.deltas(_poolTokenAddress)
            );

            return _computeP2PBorrowIndex(params);
        }
    }

    /// @notice Returns the updated peer-to-peer and pool indexes.
    /// @param _poolTokenAddress The address of the market.
    /// @param _computeUpdatedIndexes Whether to compute virtually updated pool and peer-to-peer indexes.
    /// @return newP2PSupplyIndex The updated peer-to-peer supply index.
    /// @return newP2PBorrowIndex The updated peer-to-peer borrow index.
    /// @return newPoolSupplyIndex The updated pool supply index.
    /// @return newPoolBorrowIndex The updated pool borrow index.
    function getIndexes(address _poolTokenAddress, bool _computeUpdatedIndexes)
        public
        view
        returns (
            uint256 newP2PSupplyIndex,
            uint256 newP2PBorrowIndex,
            uint256 newPoolSupplyIndex,
            uint256 newPoolBorrowIndex
        )
    {
        if (!_computeUpdatedIndexes) {
            ICToken cToken = ICToken(_poolTokenAddress);

            newPoolSupplyIndex = cToken.exchangeRateStored();
            newPoolBorrowIndex = cToken.borrowIndex();
        } else {
            (newPoolSupplyIndex, newPoolBorrowIndex) = _computePoolIndexes(_poolTokenAddress);
        }

        if (
            !_computeUpdatedIndexes ||
            block.number == morpho.lastPoolIndexes(_poolTokenAddress).lastUpdateBlockNumber
        ) {
            newP2PSupplyIndex = morpho.p2pSupplyIndex(_poolTokenAddress);
            newP2PBorrowIndex = morpho.p2pBorrowIndex(_poolTokenAddress);
        } else {
            Types.LastPoolIndexes memory poolIndexes = morpho.lastPoolIndexes(_poolTokenAddress);
            Types.MarketParameters memory marketParams = morpho.marketParameters(_poolTokenAddress);

            P2PIndexesParams memory params = P2PIndexesParams(
                morpho.p2pSupplyIndex(_poolTokenAddress),
                morpho.p2pBorrowIndex(_poolTokenAddress),
                newPoolSupplyIndex,
                newPoolBorrowIndex,
                poolIndexes.lastSupplyPoolIndex,
                poolIndexes.lastBorrowPoolIndex,
                marketParams.reserveFactor,
                marketParams.p2pIndexCursor,
                morpho.deltas(_poolTokenAddress)
            );

            (newP2PSupplyIndex, newP2PBorrowIndex) = _computeP2PIndexes(params);
        }
    }

    /// LIQUIDATION ///

    /// @dev Checks whether the user has enough collateral to maintain such a borrow position.
    /// @param _user The user to check.
    /// @param _updatedMarkets The list of markets of which to compute virtually updated pool and peer-to-peer indexes.
    /// @return isLiquidatable_ whether or not the user is liquidatable.
    function isLiquidatable(address _user, address[] memory _updatedMarkets)
        public
        view
        returns (bool)
    {
        ICompoundOracle oracle = ICompoundOracle(morpho.comptroller().oracle());
        address[] memory enteredMarkets = morpho.getEnteredMarkets(_user);

        uint256 maxDebtValue;
        uint256 debtValue;

        uint256 nbEnteredMarkets = enteredMarkets.length;
        uint256 nbUpdatedMarkets = _updatedMarkets.length;
        for (uint256 i; i < nbEnteredMarkets; ) {
            address poolTokenEntered = enteredMarkets[i];

            bool shouldUpdateIndexes;
            for (uint256 j; j < nbUpdatedMarkets; ) {
                if (_updatedMarkets[j] == poolTokenEntered) {
                    shouldUpdateIndexes = true;
                    break;
                }

                unchecked {
                    ++j;
                }
            }

            Types.AssetLiquidityData memory assetData = getUserLiquidityDataForAsset(
                _user,
                poolTokenEntered,
                shouldUpdateIndexes,
                oracle
            );

            maxDebtValue += assetData.maxDebtValue;
            debtValue += assetData.debtValue;

            unchecked {
                ++i;
            }
        }

        return debtValue > maxDebtValue;
    }

    /// @dev Computes the maximum repayable amount for a potential liquidation.
    /// @param _user The potential liquidatee.
    /// @param _poolTokenBorrowedAddress The address of the market to repay.
    /// @param _poolTokenCollateralAddress The address of the market to seize.
    /// @param _updatedMarkets The list of markets of which to compute virtually updated pool and peer-to-peer indexes.
    function computeLiquidationRepayAmount(
        address _user,
        address _poolTokenBorrowedAddress,
        address _poolTokenCollateralAddress,
        address[] calldata _updatedMarkets
    ) external view returns (uint256 toRepay) {
        address[] memory updatedMarkets = new address[](_updatedMarkets.length + 2);

        uint256 nbUpdatedMarkets = _updatedMarkets.length;
        for (uint256 i; i < nbUpdatedMarkets; ) {
            updatedMarkets[i] = _updatedMarkets[i];

            unchecked {
                ++i;
            }
        }

        updatedMarkets[updatedMarkets.length - 2] = _poolTokenBorrowedAddress;
        updatedMarkets[updatedMarkets.length - 1] = _poolTokenCollateralAddress;
        if (!isLiquidatable(_user, updatedMarkets)) return 0;

        IComptroller comptroller = morpho.comptroller();
        ICompoundOracle compoundOracle = ICompoundOracle(comptroller.oracle());

        (, , uint256 totalCollateralBalance) = getUpdatedUserSupplyBalance(
            _user,
            _poolTokenCollateralAddress
        );
        (, , uint256 totalBorrowBalance) = getUpdatedUserBorrowBalance(
            _user,
            _poolTokenBorrowedAddress
        );

        uint256 borrowedPrice = compoundOracle.getUnderlyingPrice(_poolTokenBorrowedAddress);
        uint256 collateralPrice = compoundOracle.getUnderlyingPrice(_poolTokenCollateralAddress);
        if (borrowedPrice == 0 || collateralPrice == 0) revert CompoundOracleFailed();

        uint256 maxROIRepay = totalCollateralBalance.mul(collateralPrice).div(borrowedPrice).div(
            comptroller.liquidationIncentiveMantissa()
        );

        uint256 maxRepayable = totalBorrowBalance.mul(comptroller.closeFactorMantissa());

        toRepay = maxROIRepay > maxRepayable ? maxRepayable : maxROIRepay;
    }

    ////////////////////////////////////
    ///           INTERNAL           ///
    ////////////////////////////////////

    /// @dev Returns the supply balance of `_user` in the `_poolTokenAddress` market.
    /// @dev Note: Compute the result with the index stored and not the most up to date one.
    /// @param _user The address of the user.
    /// @param _poolTokenAddress The market where to get the supply amount.
    /// @return The supply balance of the user (in underlying).
    function _computeUserSupplyBalanceInOf(
        address _poolTokenAddress,
        address _user,
        uint256 _p2pSupplyIndex,
        uint256 _poolSupplyIndex
    ) internal view returns (uint256) {
        return
            morpho.supplyBalanceInOf(_poolTokenAddress, _user).inP2P.mul(_p2pSupplyIndex) +
            morpho.supplyBalanceInOf(_poolTokenAddress, _user).onPool.mul(_poolSupplyIndex);
    }

    /// @dev Returns the borrow balance of `_user` in the `_poolTokenAddress` market.
    /// @param _user The address of the user.
    /// @param _poolTokenAddress The market where to get the borrow amount.
    /// @return The borrow balance of the user (in underlying).
    function _computeUserBorrowBalanceInOf(
        address _poolTokenAddress,
        address _user,
        uint256 _p2pBorrowIndex,
        uint256 _poolBorrowIndex
    ) internal view returns (uint256) {
        return
            morpho.borrowBalanceInOf(_poolTokenAddress, _user).inP2P.mul(_p2pBorrowIndex) +
            morpho.borrowBalanceInOf(_poolTokenAddress, _user).onPool.mul(_poolBorrowIndex);
    }

    /// INDEXES ///

    /// @dev Returns Compound's indexes, optionally computing their virtually updated values.
    /// @param _poolTokenAddress The address of the market.
    /// @return newSupplyIndex The supply index.
    /// @return newBorrowIndex The borrow index.
    function _computePoolIndexes(address _poolTokenAddress)
        internal
        view
        returns (uint256 newSupplyIndex, uint256 newBorrowIndex)
    {
        ICToken cToken = ICToken(_poolTokenAddress);

        uint256 accrualBlockNumberPrior = cToken.accrualBlockNumber();
        if (block.number == accrualBlockNumberPrior)
            return (cToken.exchangeRateStored(), cToken.borrowIndex());

        // Read the previous values out of storage
        uint256 cashPrior = cToken.getCash();
        uint256 totalSupply = cToken.totalSupply();
        uint256 borrowsPrior = cToken.totalBorrows();
        uint256 reservesPrior = cToken.totalReserves();
        uint256 borrowIndexPrior = cToken.borrowIndex();

        // Calculate the current borrow interest rate
        uint256 borrowRateMantissa = cToken.borrowRatePerBlock();
        require(borrowRateMantissa <= 0.0005e16, "borrow rate is absurdly high");

        uint256 blockDelta = block.number - accrualBlockNumberPrior;

        // Calculate the interest accumulated into borrows and reserves and the new index.
        uint256 simpleInterestFactor = borrowRateMantissa * blockDelta;
        uint256 interestAccumulated = simpleInterestFactor.mul(borrowsPrior);
        uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;
        uint256 totalReservesNew = cToken.reserveFactorMantissa().mul(interestAccumulated) +
            reservesPrior;

        newSupplyIndex = totalSupply > 0
            ? (cashPrior + totalBorrowsNew - totalReservesNew).div(totalSupply)
            : cToken.initialExchangeRateMantissa();
        newBorrowIndex = simpleInterestFactor.mul(borrowIndexPrior) + borrowIndexPrior;
    }

    /// @notice Computes and returns virtually updated peer-to-peer indexes.
    /// @param _params Computation parameters.
    /// @return newP2PSupplyIndex The updated peer-to-peer supply index.
    /// @return newP2PBorrowIndex The updated peer-to-peer borrow index.
    function _computeP2PIndexes(P2PIndexesParams memory _params)
        internal
        pure
        returns (uint256 newP2PSupplyIndex, uint256 newP2PBorrowIndex)
    {
        // Compute pool growth factors

        uint256 poolSupplyGrowthFactor = _params.poolSupplyIndex.div(_params.lastPoolSupplyIndex);
        uint256 poolBorrowGrowthFactor = _params.poolBorrowIndex.div(_params.lastPoolBorrowIndex);

        // Compute peer-to-peer growth factors

        uint256 p2pGrowthFactor = ((MAX_BASIS_POINTS - _params.p2pIndexCursor) *
            poolSupplyGrowthFactor +
            _params.p2pIndexCursor *
            poolBorrowGrowthFactor) / MAX_BASIS_POINTS;
        uint256 p2pSupplyGrowthFactor = p2pGrowthFactor -
            (_params.reserveFactor * (p2pGrowthFactor - poolSupplyGrowthFactor)) /
            MAX_BASIS_POINTS;
        uint256 p2pBorrowGrowthFactor = p2pGrowthFactor +
            (_params.reserveFactor * (poolBorrowGrowthFactor - p2pGrowthFactor)) /
            MAX_BASIS_POINTS;

        // Compute new peer-to-peer supply index

        if (_params.delta.p2pSupplyAmount == 0 || _params.delta.p2pSupplyDelta == 0) {
            newP2PSupplyIndex = _params.lastP2PSupplyIndex.mul(p2pSupplyGrowthFactor);
        } else {
            uint256 shareOfTheDelta = CompoundMath.min(
                (_params.delta.p2pSupplyDelta.mul(_params.lastPoolSupplyIndex)).div(
                    (_params.delta.p2pSupplyAmount).mul(_params.lastP2PSupplyIndex)
                ),
                WAD // To avoid shareOfTheDelta > 1 with rounding errors.
            );

            newP2PSupplyIndex = _params.lastP2PSupplyIndex.mul(
                (WAD - shareOfTheDelta).mul(p2pSupplyGrowthFactor) +
                    shareOfTheDelta.mul(poolSupplyGrowthFactor)
            );
        }

        // Compute new peer-to-peer borrow index

        if (_params.delta.p2pBorrowAmount == 0 || _params.delta.p2pBorrowDelta == 0) {
            newP2PBorrowIndex = _params.lastP2PBorrowIndex.mul(p2pBorrowGrowthFactor);
        } else {
            uint256 shareOfTheDelta = CompoundMath.min(
                (_params.delta.p2pBorrowDelta.mul(_params.poolBorrowIndex)).div(
                    (_params.delta.p2pBorrowAmount).mul(_params.lastP2PBorrowIndex)
                ),
                WAD // To avoid shareOfTheDelta > 1 with rounding errors.
            );

            newP2PBorrowIndex = _params.lastP2PBorrowIndex.mul(
                (WAD - shareOfTheDelta).mul(p2pBorrowGrowthFactor) +
                    shareOfTheDelta.mul(poolBorrowGrowthFactor)
            );
        }
    }

    /// @notice Computes and returns the new peer-to-peer supply index.
    /// @param _params Computation parameters.
    /// @return newP2PSupplyIndex The updated p2pSupplyIndex.
    function _computeP2PSupplyIndex(P2PIndexesParams memory _params)
        internal
        pure
        returns (uint256 newP2PSupplyIndex)
    {
        // Compute pool growth factors

        uint256 poolSupplyGrowthFactor = _params.poolSupplyIndex.div(_params.lastPoolSupplyIndex);
        uint256 poolBorrowGrowthFactor = _params.poolBorrowIndex.div(_params.lastPoolBorrowIndex);

        // Compute peer-to-peer growth factors

        uint256 p2pGrowthFactor = ((MAX_BASIS_POINTS - _params.p2pIndexCursor) *
            poolSupplyGrowthFactor +
            _params.p2pIndexCursor *
            poolBorrowGrowthFactor) / MAX_BASIS_POINTS;
        uint256 p2pSupplyGrowthFactor = p2pGrowthFactor -
            (_params.reserveFactor * (p2pGrowthFactor - poolSupplyGrowthFactor)) /
            MAX_BASIS_POINTS;

        // Compute new peer-to-peer supply index

        if (_params.delta.p2pSupplyAmount == 0 || _params.delta.p2pSupplyDelta == 0) {
            newP2PSupplyIndex = _params.lastP2PSupplyIndex.mul(p2pSupplyGrowthFactor);
        } else {
            uint256 shareOfTheDelta = CompoundMath.min(
                (_params.delta.p2pSupplyDelta.mul(_params.lastPoolSupplyIndex)).div(
                    (_params.delta.p2pSupplyAmount).mul(_params.lastP2PSupplyIndex)
                ),
                WAD // To avoid shareOfTheDelta > 1 with rounding errors.
            );

            newP2PSupplyIndex = _params.lastP2PSupplyIndex.mul(
                (WAD - shareOfTheDelta).mul(p2pSupplyGrowthFactor) +
                    shareOfTheDelta.mul(poolSupplyGrowthFactor)
            );
        }
    }

    /// @notice Computes and return the new peer-to-peer borrow index.
    /// @param _params Computation parameters.
    /// @return newP2PBorrowIndex The updated p2pBorrowIndex.
    function _computeP2PBorrowIndex(P2PIndexesParams memory _params)
        internal
        pure
        returns (uint256 newP2PBorrowIndex)
    {
        // Compute pool growth factors

        uint256 poolSupplyGrowthFactor = _params.poolSupplyIndex.div(_params.lastPoolSupplyIndex);
        uint256 poolBorrowGrowthFactor = _params.poolBorrowIndex.div(_params.lastPoolBorrowIndex);

        // Compute peer-to-peer growth factors

        uint256 p2pGrowthFactor = ((MAX_BASIS_POINTS - _params.p2pIndexCursor) *
            poolSupplyGrowthFactor +
            _params.p2pIndexCursor *
            poolBorrowGrowthFactor) / MAX_BASIS_POINTS;
        uint256 p2pBorrowGrowthFactor = p2pGrowthFactor +
            (_params.reserveFactor * (poolBorrowGrowthFactor - p2pGrowthFactor)) /
            MAX_BASIS_POINTS;

        // Compute new peer-to-peer borrow index

        if (_params.delta.p2pBorrowAmount == 0 || _params.delta.p2pBorrowDelta == 0) {
            newP2PBorrowIndex = _params.lastP2PBorrowIndex.mul(p2pBorrowGrowthFactor);
        } else {
            uint256 shareOfTheDelta = CompoundMath.min(
                (_params.delta.p2pBorrowDelta.mul(_params.poolBorrowIndex)).div(
                    (_params.delta.p2pBorrowAmount).mul(_params.lastP2PBorrowIndex)
                ),
                WAD // To avoid shareOfTheDelta > 1 with rounding errors.
            );

            newP2PBorrowIndex = _params.lastP2PBorrowIndex.mul(
                (WAD - shareOfTheDelta).mul(p2pBorrowGrowthFactor) +
                    shareOfTheDelta.mul(poolBorrowGrowthFactor)
            );
        }
    }
}

File 2 of 14 : ICompound.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

interface ICEth {
    function accrueInterest() external returns (uint256);

    function borrowRate() external returns (uint256);

    function borrowIndex() external returns (uint256);

    function borrowBalanceStored(address) external returns (uint256);

    function mint() external payable;

    function exchangeRateCurrent() external returns (uint256);

    function exchangeRateStored() external view returns (uint256);

    function supplyRatePerBlock() external returns (uint256);

    function redeem(uint256) external returns (uint256);

    function redeemUnderlying(uint256) external returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address,
        address,
        uint256
    ) external returns (bool);

    function transfer(address dst, uint256 amount) external returns (bool);

    function balanceOf(address) external returns (uint256);

    function balanceOfUnderlying(address account) external returns (uint256);

    function borrow(uint256) external returns (uint256);

    function repayBorrow() external payable;

    function borrowBalanceCurrent(address) external returns (uint256);

    function borrowRatePerBlock() external view returns (uint256);
}

interface IComptroller {
    struct CompMarketState {
        /// @notice The market's last updated compBorrowIndex or compSupplyIndex
        uint224 index;
        /// @notice The block number the index was last updated at
        uint32 block;
    }

    function liquidationIncentiveMantissa() external view returns (uint256);

    function closeFactorMantissa() external view returns (uint256);

    function admin() external view returns (address);

    function oracle() external view returns (address);

    function borrowCaps(address) external view returns (uint256);

    function markets(address)
        external
        view
        returns (
            bool isListed,
            uint256 collateralFactorMantissa,
            bool isComped
        );

    function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory);

    function exitMarket(address cToken) external returns (uint256);

    function mintAllowed(
        address cToken,
        address minter,
        uint256 mintAmount
    ) external returns (uint256);

    function mintVerify(
        address cToken,
        address minter,
        uint256 mintAmount,
        uint256 mintTokens
    ) external;

    function redeemAllowed(
        address cToken,
        address redeemer,
        uint256 redeemTokens
    ) external returns (uint256);

    function redeemVerify(
        address cToken,
        address redeemer,
        uint256 redeemAmount,
        uint256 redeemTokens
    ) external;

    function borrowAllowed(
        address cToken,
        address borrower,
        uint256 borrowAmount
    ) external returns (uint256);

    function borrowVerify(
        address cToken,
        address borrower,
        uint256 borrowAmount
    ) external;

    function repayBorrowAllowed(
        address cToken,
        address payer,
        address borrower,
        uint256 repayAmount
    ) external returns (uint256);

    function repayBorrowVerify(
        address cToken,
        address payer,
        address borrower,
        uint256 repayAmount,
        uint256 borrowerIndex
    ) external;

    function liquidateBorrowAllowed(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint256 repayAmount
    ) external returns (uint256);

    function liquidateBorrowVerify(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint256 repayAmount,
        uint256 seizeTokens
    ) external;

    function seizeAllowed(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint256 seizeTokens
    ) external returns (uint256);

    function seizeVerify(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint256 seizeTokens
    ) external;

    function transferAllowed(
        address cToken,
        address src,
        address dst,
        uint256 transferTokens
    ) external returns (uint256);

    function transferVerify(
        address cToken,
        address src,
        address dst,
        uint256 transferTokens
    ) external;

    /*** Liquidity/Liquidation Calculations ***/

    function liquidateCalculateSeizeTokens(
        address cTokenBorrowed,
        address cTokenCollateral,
        uint256 repayAmount
    ) external view returns (uint256, uint256);

    function getAccountLiquidity(address)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );

    function getHypotheticalAccountLiquidity(
        address,
        address,
        uint256,
        uint256
    )
        external
        returns (
            uint256,
            uint256,
            uint256
        );

    function checkMembership(address, address) external view returns (bool);

    function claimComp(address holder) external;

    function claimComp(address holder, address[] memory cTokens) external;

    function compSpeeds(address) external view returns (uint256);

    function compSupplySpeeds(address) external view returns (uint256);

    function compBorrowSpeeds(address) external view returns (uint256);

    function compSupplyState(address) external view returns (CompMarketState memory);

    function compBorrowState(address) external view returns (CompMarketState memory);

    function getCompAddress() external view returns (address);

    function _setPriceOracle(address newOracle) external returns (uint256);

    function _setMintPaused(ICToken cToken, bool state) external returns (bool);

    function _setBorrowPaused(ICToken cToken, bool state) external returns (bool);

    function _setCollateralFactor(ICToken cToken, uint256 newCollateralFactorMantissa)
        external
        returns (uint256);

    function _setCompSpeeds(
        ICToken[] memory cTokens,
        uint256[] memory supplySpeeds,
        uint256[] memory borrowSpeeds
    ) external;
}

interface IInterestRateModel {
    function getBorrowRate(
        uint256 cash,
        uint256 borrows,
        uint256 reserves
    ) external view returns (uint256);

    function getSupplyRate(
        uint256 cash,
        uint256 borrows,
        uint256 reserves,
        uint256 reserveFactorMantissa
    ) external view returns (uint256);
}

interface ICToken {
    function isCToken() external returns (bool);

    function transfer(address dst, uint256 amount) external returns (bool);

    function transferFrom(
        address src,
        address dst,
        uint256 amount
    ) external returns (bool);

    function approve(address spender, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function balanceOfUnderlying(address owner) external returns (uint256);

    function getAccountSnapshot(address account)
        external
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        );

    function borrowRatePerBlock() external view returns (uint256);

    function supplyRatePerBlock() external view returns (uint256);

    function totalBorrowsCurrent() external returns (uint256);

    function borrowBalanceCurrent(address account) external returns (uint256);

    function borrowBalanceStored(address account) external view returns (uint256);

    function exchangeRateCurrent() external returns (uint256);

    function exchangeRateStored() external view returns (uint256);

    function getCash() external view returns (uint256);

    function seize(
        address liquidator,
        address borrower,
        uint256 seizeTokens
    ) external returns (uint256);

    function borrowRate() external returns (uint256);

    function borrowIndex() external view returns (uint256);

    function borrow(uint256) external returns (uint256);

    function repayBorrow(uint256) external returns (uint256);

    function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);

    function liquidateBorrow(
        address borrower,
        uint256 repayAmount,
        address cTokenCollateral
    ) external returns (uint256);

    function underlying() external view returns (address);

    function mint(uint256) external returns (uint256);

    function redeemUnderlying(uint256) external returns (uint256);

    function accrueInterest() external returns (uint256);

    function totalSupply() external view returns (uint256);

    function totalBorrows() external view returns (uint256);

    function accrualBlockNumber() external view returns (uint256);

    function totalReserves() external view returns (uint256);

    function interestRateModel() external view returns (IInterestRateModel);

    function reserveFactorMantissa() external view returns (uint256);

    function initialExchangeRateMantissa() external view returns (uint256);

    /*** Admin Functions ***/

    function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256);

    function _acceptAdmin() external returns (uint256);

    function _setComptroller(IComptroller newComptroller) external returns (uint256);

    function _setReserveFactor(uint256 newReserveFactorMantissa) external returns (uint256);

    function _reduceReserves(uint256 reduceAmount) external returns (uint256);

    function _setInterestRateModel(IInterestRateModel newInterestRateModel)
        external
        returns (uint256);
}

interface ICEther is ICToken {
    function mint() external payable;

    function repayBorrow() external payable;
}

interface ICompoundOracle {
    function getUnderlyingPrice(address) external view returns (uint256);
}

File 3 of 14 : IMorpho.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

import "./IInterestRatesManager.sol";
import "./IRewardsManager.sol";
import "./IPositionsManager.sol";
import "./IIncentivesVault.sol";

import "../libraries/Types.sol";

// prettier-ignore
interface IMorpho {

    /// STORAGE ///

    function defaultMaxGasForMatching() external view returns (Types.MaxGasForMatching memory);
    function maxSortedUsers() external view returns (uint256);
    function dustThreshold() external view returns (uint256);
    function supplyBalanceInOf(address, address) external view returns (Types.SupplyBalance memory);
    function borrowBalanceInOf(address, address) external view returns (Types.BorrowBalance memory);
    function enteredMarkets(address) external view returns (address);
    function deltas(address) external view returns (Types.Delta memory);
    function marketsCreated() external view returns (address[] memory);
    function marketParameters(address) external view returns (Types.MarketParameters memory);
    function p2pDisabled(address) external view returns (bool);
    function p2pSupplyIndex(address) external view returns (uint256);
    function p2pBorrowIndex(address) external view returns (uint256);
    function lastPoolIndexes(address) external view returns (Types.LastPoolIndexes memory);
    function marketStatus(address) external view returns (Types.MarketStatus memory);
    function comptroller() external view returns (IComptroller);
    function interestRatesManager() external view returns (IInterestRatesManager);
    function rewardsManager() external view returns (IRewardsManager);
    function positionsManager() external view returns (IPositionsManager);
    function incentiveVault() external view returns (IIncentivesVault);
    function treasuryVault() external view returns (address);
    function cEth() external view returns (address);
    function wEth() external view returns (address);

    /// GETTERS ///

    function updateP2PIndexes(address _poolTokenAddress) external;
    function getEnteredMarkets(address _user) external view returns (address[] memory enteredMarkets_);
    function getAllMarkets() external view returns (address[] memory marketsCreated_);
    function getHead(address _poolTokenAddress, Types.PositionType _positionType) external view returns (address head);
    function getNext(address _poolTokenAddress, Types.PositionType _positionType, address _user) external view returns (address next);

    /// GOVERNANCE ///

    function setMaxSortedUsers(uint256 _newMaxSortedUsers) external;
    function setDefaultMaxGasForMatching(Types.MaxGasForMatching memory _maxGasForMatching) external;
    function setTreasuryVault(address _newTreasuryVaultAddress) external;
    function setIncentivesVault(address _newIncentivesVault) external;
    function setRewardsManager(address _rewardsManagerAddress) external;
    function setDustThreshold(uint256 _dustThreshold) external;
    function setP2PDisable(address _poolTokenAddress, bool _p2pDisabled) external;
    function setReserveFactor(address _poolTokenAddress, uint256 _newReserveFactor) external;
    function setP2PIndexCursor(address _poolTokenAddress, uint16 _p2pIndexCursor) external;
    function setPauseStatus(address _poolTokenAddress) external;
    function setPartialPauseStatus(address _poolTokenAddress) external;
    function claimToTreasury(address _poolTokenAddress, uint256 _amount) external;
    function createMarket(address _poolTokenAddress, Types.MarketParameters calldata _params) external;

    /// USERS ///

    function supply(address _poolTokenAddress, address _onBehalf, uint256 _amount) external;
    function supply(address _poolTokenAddress, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching) external;
    function borrow(address _poolTokenAddress, uint256 _amount) external;
    function borrow(address _poolTokenAddress, uint256 _amount, uint256 _maxGasForMatching) external;
    function withdraw(address _poolTokenAddress, uint256 _amount) external;
    function repay(address _poolTokenAddress, address _onBehalf, uint256 _amount) external;
    function liquidate(address _poolTokenBorrowedAddress, address _poolTokenCollateralAddress, address _borrower, uint256 _amount) external;
    function claimRewards(address[] calldata _cTokenAddresses, bool _tradeForMorphoToken) external;
}

File 4 of 14 : ILens.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity 0.8.13;

import "./compound/ICompound.sol";
import "./IMorpho.sol";

interface ILens {
    function MAX_BASIS_POINTS() external view returns (uint256);

    function WAD() external view returns (uint256);

    function morpho() external view returns (IMorpho);

    function isMarketCreated(address _poolTokenAddress) external view returns (bool);

    function isMarketCreatedAndNotPaused(address _poolTokenAddress) external view returns (bool);

    function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolTokenAddress)
        external
        view
        returns (bool);

    function getEnteredMarkets(address _user)
        external
        view
        returns (address[] memory enteredMarkets_);

    function getAllMarkets() external view returns (address[] memory marketsCreated_);

    function getMarketData(address _poolTokenAddress)
        external
        view
        returns (
            uint256 p2pSupplyIndex_,
            uint256 p2pBorrowIndex_,
            uint32 lastUpdateBlockNumber_,
            uint256 p2pSupplyDelta_,
            uint256 p2pBorrowDelta_,
            uint256 p2pSupplyAmount_,
            uint256 p2pBorrowAmount_
        );

    function getMarketConfiguration(address _poolTokenAddress)
        external
        view
        returns (
            address underlying_,
            bool isCreated_,
            bool p2pDisabled_,
            bool isPaused_,
            bool isPartiallyPaused_,
            uint256 reserveFactor_,
            uint256 collateralFactor_
        );

    function getRates(address _poolTokenAddress)
        external
        view
        returns (
            uint256 p2pSupplyRate_,
            uint256 p2pBorrowRate_,
            uint256 poolSupplyRate_,
            uint256 poolBorrowRate_
        );

    function getUserBalanceStates(address _user, address[] calldata _updatedMarkets)
        external
        view
        returns (
            uint256 collateralValue,
            uint256 debtValue,
            uint256 maxDebtValue
        );

    function getUpdatedUserSupplyBalance(address _user, address _poolTokenAddress)
        external
        view
        returns (
            uint256 balanceOnPool,
            uint256 balanceInP2P,
            uint256 totalBalance
        );

    function getUpdatedUserBorrowBalance(address _user, address _poolTokenAddress)
        external
        view
        returns (
            uint256 balanceOnPool,
            uint256 balanceInP2P,
            uint256 totalBalance
        );

    function getUserMaxCapacitiesForAsset(address _user, address _poolTokenAddress)
        external
        view
        returns (uint256 withdrawable, uint256 borrowable);

    function getUserHypotheticalBalanceStates(
        address _user,
        address _poolTokenAddress,
        uint256 _withdrawnAmount,
        uint256 _borrowedAmount
    ) external view returns (uint256 debtValue, uint256 maxDebtValue);

    function getUserLiquidityDataForAsset(
        address _user,
        address _poolTokenAddress,
        bool _computeUpdatedIndexes,
        ICompoundOracle _oracle
    ) external view returns (Types.AssetLiquidityData memory assetData);

    function getUpdatedP2PSupplyIndex(address _poolTokenAddress) external view returns (uint256);

    function getUpdatedP2PBorrowIndex(address _poolTokenAddress) external view returns (uint256);

    function getIndexes(address _poolTokenAddress, bool _computeUpdatedIndexes)
        external
        view
        returns (
            uint256 newP2PSupplyIndex,
            uint256 newP2PBorrowIndex,
            uint256 newPoolSupplyIndex,
            uint256 newPoolBorrowIndex
        );

    function isLiquidatable(address _user, address[] memory _updatedMarkets)
        external
        view
        returns (bool);

    function computeLiquidationRepayAmount(
        address _user,
        address _poolTokenBorrowedAddress,
        address _poolTokenCollateralAddress,
        address[] memory _updatedMarkets
    ) external view returns (uint256 toRepay);
}

File 5 of 14 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    event Debug(bool one, bool two, uint256 retsize);

    /*///////////////////////////////////////////////////////////////
                            ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*///////////////////////////////////////////////////////////////
                           ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (not just any non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the addition in the
                // order of operations or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (not just any non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the addition in the
                // order of operations or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (not just any non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the addition in the
                // order of operations or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

File 6 of 14 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

File 7 of 14 : CompoundMath.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

/// @title CompoundMath.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @dev Library emulating in solidity 8+ the behavior of Compound's mulScalarTruncate and divScalarByExpTruncate functions.
library CompoundMath {
    /// ERRORS ///

    /// @notice Reverts when the number exceeds 224 bits.
    error NumberExceeds224Bits();

    /// @notice Reverts when the number exceeds 32 bits.
    error NumberExceeds32Bits();

    /// INTERNAL ///

    function mul(uint256 x, uint256 y) internal pure returns (uint256) {
        return (x * y) / 1e18;
    }

    function div(uint256 x, uint256 y) internal pure returns (uint256) {
        return ((1e18 * x * 1e18) / y) / 1e18;
    }

    function safe224(uint256 n) internal pure returns (uint224) {
        if (n >= 2**224) revert NumberExceeds224Bits();
        return uint224(n);
    }

    function safe32(uint256 n) internal pure returns (uint32) {
        if (n >= 2**32) revert NumberExceeds32Bits();
        return uint32(n);
    }

    function min(
        uint256 a,
        uint256 b,
        uint256 c
    ) internal pure returns (uint256) {
        return a < b ? a < c ? a : c : b < c ? b : c;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a - b : 0;
    }
}

File 8 of 14 : IInterestRatesManager.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

interface IInterestRatesManager {
    function updateP2PIndexes(address _marketAddress) external;
}

File 9 of 14 : IRewardsManager.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

import "./compound/ICompound.sol";

interface IRewardsManager {
    function initialize(address _morpho) external;

    function claimRewards(address[] calldata, address) external returns (uint256);

    function userUnclaimedCompRewards(address) external view returns (uint256);

    function compSupplierIndex(address, address) external view returns (uint256);

    function compBorrowerIndex(address, address) external view returns (uint256);

    function getLocalCompSupplyState(address _cTokenAddress)
        external
        view
        returns (IComptroller.CompMarketState memory);

    function getLocalCompBorrowState(address _cTokenAddress)
        external
        view
        returns (IComptroller.CompMarketState memory);

    function accrueUserSupplyUnclaimedRewards(
        address,
        address,
        uint256
    ) external;

    function accrueUserBorrowUnclaimedRewards(
        address,
        address,
        uint256
    ) external;
}

File 10 of 14 : IPositionsManager.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

interface IPositionsManager {
    function supplyLogic(
        address _poolTokenAddress,
        address _supplier,
        address _onBehalf,
        uint256 _amount,
        uint256 _maxGasForMatching
    ) external;

    function borrowLogic(
        address _poolTokenAddress,
        uint256 _amount,
        uint256 _maxGasForMatching
    ) external;

    function withdrawLogic(
        address _poolTokenAddress,
        uint256 _amount,
        address _supplier,
        address _receiver,
        uint256 _maxGasForMatching
    ) external;

    function repayLogic(
        address _poolTokenAddress,
        address _repayer,
        address _onBehalf,
        uint256 _amount,
        uint256 _maxGasForMatching
    ) external;

    function liquidateLogic(
        address _poolTokenBorrowedAddress,
        address _poolTokenCollateralAddress,
        address _borrower,
        uint256 _amount
    ) external;
}

File 11 of 14 : IIncentivesVault.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

import "./IOracle.sol";

interface IIncentivesVault {
    function setOracle(IOracle _newOracle) external;

    function setMorphoDao(address _newMorphoDao) external;

    function setBonus(uint256 _newBonus) external;

    function setPauseStatus(bool _newStatus) external;

    function transferMorphoTokensToDao(uint256 _amount) external;

    function tradeCompForMorphoTokens(address _to, uint256 _amount) external;
}

File 12 of 14 : Types.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

/// @title Types.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @dev Common types and structs used in Moprho contracts.
library Types {
    /// ENUMS ///

    enum PositionType {
        SUPPLIERS_IN_P2P,
        SUPPLIERS_ON_POOL,
        BORROWERS_IN_P2P,
        BORROWERS_ON_POOL
    }

    /// STRUCTS ///

    struct SupplyBalance {
        uint256 inP2P; // In supplier's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the peer-to-peer supply index to get the underlying amount.
        uint256 onPool; // In cToken. Multiply by the pool supply index to get the underlying amount.
    }

    struct BorrowBalance {
        uint256 inP2P; // In borrower's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the peer-to-peer borrow index to get the underlying amount.
        uint256 onPool; // In cdUnit, a unit that grows in value, to keep track of the debt increase when borrowers are on Compound. Multiply by the pool borrow index to get the underlying amount.
    }

    // Max gas to consume during the matching process for supply, borrow, withdraw and repay functions.
    struct MaxGasForMatching {
        uint64 supply;
        uint64 borrow;
        uint64 withdraw;
        uint64 repay;
    }

    struct Delta {
        uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the real peer-to-peer supply amount (in cToken).
        uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the real peer-to-peer borrow amount (in cdUnit).
        uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer unit).
        uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer unit).
    }

    struct AssetLiquidityData {
        uint256 collateralValue; // The collateral value of the asset.
        uint256 maxDebtValue; // The maximum possible debt value of the asset.
        uint256 debtValue; // The debt value of the asset.
        uint256 underlyingPrice; // The price of the token.
        uint256 collateralFactor; // The liquidation threshold applied on this token.
    }

    struct LiquidityData {
        uint256 collateralValue; // The collateral value.
        uint256 maxDebtValue; // The maximum debt value possible.
        uint256 debtValue; // The debt value.
    }

    // Variables are packed together to save gas (will not exceed their limit during Morpho's lifetime).
    struct LastPoolIndexes {
        uint32 lastUpdateBlockNumber; // The last time the peer-to-peer indexes were updated.
        uint112 lastSupplyPoolIndex; // Last pool supply index.
        uint112 lastBorrowPoolIndex; // Last pool borrow index.
    }

    struct MarketParameters {
        uint16 reserveFactor; // Proportion of the interest earned by users sent to the DAO for each market, in basis point (100% = 10 000). The value is set at market creation.
        uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine the weights of the weighted arithmetic average in the indexes computations ((1 - p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point).
    }

    struct MarketStatus {
        bool isCreated; // Whether or not this market is created.
        bool isPaused; // Whether the market is paused or not (all entry points on Morpho are frozen; supply, borrow, withdraw, repay and liquidate).
        bool isPartiallyPaused; // Whether the market is partially paused or not (only supply and borrow are frozen).
    }
}

File 13 of 14 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*///////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*///////////////////////////////////////////////////////////////
                             METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*///////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*///////////////////////////////////////////////////////////////
                             EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*///////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*///////////////////////////////////////////////////////////////
                              ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*///////////////////////////////////////////////////////////////
                              EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*///////////////////////////////////////////////////////////////
                       INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 14 of 14 : IOracle.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

interface IOracle {
    function consult(uint256 _amountIn) external returns (uint256);
}

Settings
{
  "remappings": [
    "@aave/core-v3/=lib/aave-v3-core/",
    "@aave/periphery-v3/=lib/aave-v3-periphery/",
    "@config/=config/ropsten/compound/",
    "@contracts/=contracts/",
    "@ensdomains/=node_modules/@ensdomains/",
    "@morpho/data-structures/=lib/data-structures/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@rari-capital/solmate/=lib/solmate/",
    "@uniswap/=node_modules/@uniswap/",
    "aave-v3-core/=lib/aave-v3-core/",
    "aave-v3-periphery/=lib/aave-v3-periphery/contracts/",
    "base64-sol/=node_modules/base64-sol/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "solmate/=lib/solmate/src/",
    "compound/=contracts/compound/",
    "test/=test/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_morphoAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CompoundOracleFailed","type":"error"},{"inputs":[],"name":"MAX_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_poolTokenBorrowedAddress","type":"address"},{"internalType":"address","name":"_poolTokenCollateralAddress","type":"address"},{"internalType":"address[]","name":"_updatedMarkets","type":"address[]"}],"name":"computeLiquidationRepayAmount","outputs":[{"internalType":"uint256","name":"toRepay","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"address[]","name":"marketsCreated_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getEnteredMarkets","outputs":[{"internalType":"address[]","name":"enteredMarkets_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"bool","name":"_computeUpdatedIndexes","type":"bool"}],"name":"getIndexes","outputs":[{"internalType":"uint256","name":"newP2PSupplyIndex","type":"uint256"},{"internalType":"uint256","name":"newP2PBorrowIndex","type":"uint256"},{"internalType":"uint256","name":"newPoolSupplyIndex","type":"uint256"},{"internalType":"uint256","name":"newPoolBorrowIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getMarketConfiguration","outputs":[{"internalType":"address","name":"underlying_","type":"address"},{"internalType":"bool","name":"isCreated_","type":"bool"},{"internalType":"bool","name":"p2pDisabled_","type":"bool"},{"internalType":"bool","name":"isPaused_","type":"bool"},{"internalType":"bool","name":"isPartiallyPaused_","type":"bool"},{"internalType":"uint256","name":"reserveFactor_","type":"uint256"},{"internalType":"uint256","name":"collateralFactor_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getMarketData","outputs":[{"internalType":"uint256","name":"p2pSupplyIndex_","type":"uint256"},{"internalType":"uint256","name":"p2pBorrowIndex_","type":"uint256"},{"internalType":"uint32","name":"lastUpdateBlockNumber_","type":"uint32"},{"internalType":"uint256","name":"p2pSupplyDelta_","type":"uint256"},{"internalType":"uint256","name":"p2pBorrowDelta_","type":"uint256"},{"internalType":"uint256","name":"p2pSupplyAmount_","type":"uint256"},{"internalType":"uint256","name":"p2pBorrowAmount_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getRates","outputs":[{"internalType":"uint256","name":"p2pSupplyRate_","type":"uint256"},{"internalType":"uint256","name":"p2pBorrowRate_","type":"uint256"},{"internalType":"uint256","name":"poolSupplyRate_","type":"uint256"},{"internalType":"uint256","name":"poolBorrowRate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getUpdatedP2PBorrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getUpdatedP2PSupplyIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getUpdatedUserBorrowBalance","outputs":[{"internalType":"uint256","name":"balanceOnPool","type":"uint256"},{"internalType":"uint256","name":"balanceInP2P","type":"uint256"},{"internalType":"uint256","name":"totalBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getUpdatedUserSupplyBalance","outputs":[{"internalType":"uint256","name":"balanceOnPool","type":"uint256"},{"internalType":"uint256","name":"balanceInP2P","type":"uint256"},{"internalType":"uint256","name":"totalBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address[]","name":"_updatedMarkets","type":"address[]"}],"name":"getUserBalanceStates","outputs":[{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"debtValue","type":"uint256"},{"internalType":"uint256","name":"maxDebtValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"uint256","name":"_withdrawnAmount","type":"uint256"},{"internalType":"uint256","name":"_borrowedAmount","type":"uint256"}],"name":"getUserHypotheticalBalanceStates","outputs":[{"internalType":"uint256","name":"debtValue","type":"uint256"},{"internalType":"uint256","name":"maxDebtValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_poolTokenAddress","type":"address"},{"internalType":"bool","name":"_computeUpdatedIndexes","type":"bool"},{"internalType":"contract ICompoundOracle","name":"_oracle","type":"address"}],"name":"getUserLiquidityDataForAsset","outputs":[{"components":[{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"maxDebtValue","type":"uint256"},{"internalType":"uint256","name":"debtValue","type":"uint256"},{"internalType":"uint256","name":"underlyingPrice","type":"uint256"},{"internalType":"uint256","name":"collateralFactor","type":"uint256"}],"internalType":"struct Types.AssetLiquidityData","name":"assetData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"getUserMaxCapacitiesForAsset","outputs":[{"internalType":"uint256","name":"withdrawable","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address[]","name":"_updatedMarkets","type":"address[]"}],"name":"isLiquidatable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"isMarketCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"isMarketCreatedAndNotPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolTokenAddress","type":"address"}],"name":"isMarketCreatedAndNotPausedNorPartiallyPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"morpho","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b506040516200479f3803806200479f833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b6080516145916200020e600039600081816103ef0152818161053b0152818161066f015281816107750152818161092c01528181610a3201528181610c3001528181610cc901528181610d5d01528181610def01528181610e9d01528181610f2f01528181610fef015281816111fb0152818161153b01528181611652015281816116e401528181611780015281816117f8015281816119bd01528181611b4101528181611bd701528181611c7001528181611cc101528181611d5301528181611e0101528181611e9301528181611f5301528181612012015281816120cd0152818161218301528181612202015281816122d901528181612367015281816123f60152818161247601528181612523015281816126c701528181612763015281816127f00152818161288601528181612918015281816129b501528181612a4701528181612b0701528181612bd801528181612c4901528181612c8701528181612d8d01528181612eec01528181612ff201528181613880015281816138d201528181613930015261398201526145916000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806384dd6154116100b8578063cfa671271161007c578063cfa67127146103b1578063d6018737146103c4578063d61bb596146103d7578063d8fbc833146103ea578063e7cb547d14610429578063f4ea93d81461043c57600080fd5b806384dd6154146103105780638ccb720b14610323578063a30c302d14610343578063b0772d0b14610396578063cd26e92d1461039e57600080fd5b806336cd097c1161010a57806336cd097c146102095780635a208d521461022c5780636a146024146102865780637705dd3114610295578063790bf725146102ea5780637d7ee5e7146102fd57600080fd5b806302f55b61146101475780630feddf881461017f578063140680b3146101ad57806319d9d471146101d557806336849501146101f6575b600080fd5b61015a610155366004613dab565b610445565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b61019261018d366004613e0d565b610667565b60408051938452602084019290925290820152606001610176565b6101c06101bb366004613e62565b6108cf565b60408051928352602083019190915201610176565b6101e86101e3366004613dab565b610c0e565b604051908152602001610176565b6101e8610204366004613e9b565b6110a6565b61021c610217366004613dab565b611517565b6040519015158152602001610176565b61023f61023a366004613dab565b6115c0565b604080516001600160a01b03909816885295151560208801529315159486019490945290151560608501521515608084015260a083019190915260c082015260e001610176565b6101e8670de0b6b3a764000081565b6102a86102a3366004613f25565b6118f8565b6040516101769190600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b61021c6102f8366004613dab565b611b1f565b6101e861030b366004613dab565b611bb5565b61019261031e366004613e62565b611ffa565b610336610331366004613dab565b612161565b6040516101769190613f81565b610356610351366004613dab565b6121f4565b60408051978852602088019690965263ffffffff909416948601949094526060850191909152608084015260a083019190915260c082015260e001610176565b610336612472565b61021c6103ac366004613dab565b6124ff565b61015a6103bf366004613fce565b6125b3565b6101926103d2366004613e62565b612bc0565b6101c06103e5366004613ffc565b612c80565b6104117f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610176565b61021c6104373660046140d6565b612ee7565b6101e861271081565b6000806000806000859050806001600160a01b031663ae9d70b06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561048e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b2919061418a565b9250806001600160a01b031663f8f9da286040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610516919061418a565b6040516325af544b60e21b81526001600160a01b0388811660048301529193506000917f000000000000000000000000000000000000000000000000000000000000000016906396bd512c906024016040805180830381865afa158015610581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a591906141b5565b9050600061271084836020015161ffff166105c09190614226565b86846020015161ffff166127106105d79190614245565b6105e19190614226565b6105eb919061425c565b6105f59190614274565b90506127106106048683614245565b8351610614919061ffff16614226565b61061e9190614274565b6106289082614245565b96506127106106378286614245565b8351610647919061ffff16614226565b6106519190614274565b61065b908261425c565b95505050509193509193565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ef9190614296565b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190614296565b604051638ccb720b60e01b81526001600160a01b0389811660048301529192506000917f00000000000000000000000000000000000000000000000000000000000000001690638ccb720b90602401600060405180830381865afa1580156107bc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107e491908101906142b3565b80519091508660005b828110156108c157600084828151811061080957610809614342565b602002602001015190506000805b8481101561086f57826001600160a01b03168d8d8381811061083b5761083b614342565b90506020020160208101906108509190613dab565b6001600160a01b031603610867576001915061086f565b600101610817565b50600061087e8e84848b6118f8565b805190915061088d908c61425c565b9a5080602001518961089f919061425c565b985080604001518a6108b1919061425c565b99508360010193505050506107ed565b505050505093509350939050565b6000806108f660405180606001604052806000815260200160008152602001600081525090565b6109286040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610988573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ac9190614296565b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0d9190614296565b604051638ccb720b60e01b81526001600160a01b0389811660048301529192506000917f00000000000000000000000000000000000000000000000000000000000000001690638ccb720b90602401600060405180830381865afa158015610a79573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610aa191908101906142b3565b805190915060005b81811015610b33576000838281518110610ac557610ac5614342565b60200260200101519050806001600160a01b03168a6001600160a01b031614610b2a57610af58b826001886118f8565b9550856020015187602001818151610b0d919061425c565b9052506040808701519088018051610b2690839061425c565b9052505b50600101610aa9565b50610b4189896001866118f8565b9350836020015185602001818151610b59919061425c565b9052506040808501519086018051610b7290839061425c565b905250604085015160208601511015610b9657600080965096505050505050610c07565b6000610bba856060015187604001518860200151610bb49190614245565b90613135565b60608601518651919250610bce9190613135565b97508460800151600014610bff57610bfc88610bf787608001518461313590919063ffffffff16565b613171565b97505b955050505050505b9250929050565b60405163db0577fd60e01b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063db0577fd90602401606060405180830381865afa158015610c79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9d919061436f565b5163ffffffff164303610d3b5760405163854f7ebb60e01b81526001600160a01b0383811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063854f7ebb906024015b602060405180830381865afa158015610d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d35919061418a565b92915050565b60405163db0577fd60e01b81526001600160a01b0383811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063db0577fd90602401606060405180830381865afa158015610da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dca919061436f565b6040516325af544b60e21b81526001600160a01b0385811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906396bd512c906024016040805180830381865afa158015610e35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5991906141b5565b9050600080610e6786613187565b6040805161012081019182905263854f7ebb60e01b9091526001600160a01b0389811661012483015292945090925060009181907f00000000000000000000000000000000000000000000000000000000000000001663854f7ebb6101448301602060405180830381865afa158015610ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f08919061418a565b8152604051630175fa5f60e51b81526001600160a01b038a811660048301526020909201917f00000000000000000000000000000000000000000000000000000000000000001690632ebf4be090602401602060405180830381865afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a919061418a565b815260200184815260200183815260200186602001516001600160701b0316815260200186604001516001600160701b03168152602001856000015161ffff168152602001856020015161ffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a086fc228a6040518263ffffffff1660e01b815260040161104891906001600160a01b0391909116815260200190565b608060405180830381865afa158015611065573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108991906143c8565b90529050611096816136e9565b979650505050505050565b919050565b6000806110b483600261425c565b67ffffffffffffffff8111156110cc576110cc614042565b6040519080825280602002602001820160405280156110f5578160200160208202803683370190505b5090508260005b8181101561115d5785858281811061111657611116614342565b905060200201602081019061112b9190613dab565b83828151811061113d5761113d614342565b6001600160a01b03909216602092830291909101909101526001016110fc565b5086826002845161116e9190614245565b8151811061117e5761117e614342565b60200260200101906001600160a01b031690816001600160a01b0316815250508582600184516111ae9190614245565b815181106111be576111be614342565b60200260200101906001600160a01b031690816001600160a01b0316815250506111e88883612ee7565b6111f75760009250505061150e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127b9190614296565b90506000816001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e19190614296565b905060006112ef8b8a611ffa565b9250505060006112ff8c8c612bc0565b60405163fc57d4df60e01b81526001600160a01b038f8116600483015291945060009350908616915063fc57d4df90602401602060405180830381865afa15801561134e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611372919061418a565b60405163fc57d4df60e01b81526001600160a01b038d8116600483015291925060009186169063fc57d4df90602401602060405180830381865afa1580156113be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e2919061418a565b90508115806113ef575080155b1561140d57604051634b6b62e560e01b815260040160405180910390fd5b6000611480876001600160a01b0316634ada90af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611450573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611474919061418a565b610bb485818987613863565b905060006114f0886001600160a01b031663e87554466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e9919061418a565b8690613863565b90508082116114ff5781611501565b805b9a50505050505050505050505b95945050505050565b604051636ace4f5b60e11b81526001600160a01b03828116600483015260009182917f0000000000000000000000000000000000000000000000000000000000000000169063d59c9eb690602401606060405180830381865afa158015611582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a6919061442e565b805190915080156115b957508060200151155b9392505050565b6000806000806000806000876001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162d9190614296565b604051636ace4f5b60e11b81526001600160a01b038a811660048301529198506000917f0000000000000000000000000000000000000000000000000000000000000000169063d59c9eb690602401606060405180830381865afa158015611699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bd919061442e565b80516040516320c342d960e01b81526001600160a01b038c811660048301529199509192507f000000000000000000000000000000000000000000000000000000000000000016906320c342d990602401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190614476565b602082015160408084015190516325af544b60e21b81526001600160a01b038d8116600483015293995091975095507f0000000000000000000000000000000000000000000000000000000000000000909116906396bd512c906024016040805180830381865afa1580156117c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ec91906141b5565b6000015161ffff1692507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611854573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118789190614296565b604051638e8f294b60e01b81526001600160a01b038b811660048301529190911690638e8f294b90602401606060405180830381865afa1580156118c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e49190614493565b909150508092505050919395979092949650565b61192a6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405163fc57d4df60e01b81526001600160a01b03858116600483015283169063fc57d4df90602401602060405180830381865afa158015611970573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611994919061418a565b606082018190526000036119bb57604051634b6b62e560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3d9190614296565b604051638e8f294b60e01b81526001600160a01b0386811660048301529190911690638e8f294b90602401606060405180830381865afa158015611a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa99190614493565b506080830152506000808080611abf88886125b3565b9350935093509350611ae18560600151611adb8a8c8887613878565b90613863565b85526060850151611af890611adb8a8c8786613928565b604086015260808501518551611b0d91613863565b60208601525092979650505050505050565b604051636ace4f5b60e11b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d59c9eb690602401606060405180830381865afa158015611b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bae919061442e565b5192915050565b60405163db0577fd60e01b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063db0577fd90602401606060405180830381865afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c44919061436f565b5163ffffffff164303611c9f57604051630175fa5f60e51b81526001600160a01b0383811660048301527f00000000000000000000000000000000000000000000000000000000000000001690632ebf4be090602401610cf4565b60405163db0577fd60e01b81526001600160a01b0383811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063db0577fd90602401606060405180830381865afa158015611d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2e919061436f565b6040516325af544b60e21b81526001600160a01b0385811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906396bd512c906024016040805180830381865afa158015611d99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbd91906141b5565b9050600080611dcb86613187565b6040805161012081019182905263854f7ebb60e01b9091526001600160a01b0389811661012483015292945090925060009181907f00000000000000000000000000000000000000000000000000000000000000001663854f7ebb6101448301602060405180830381865afa158015611e48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6c919061418a565b8152604051630175fa5f60e51b81526001600160a01b038a811660048301526020909201917f00000000000000000000000000000000000000000000000000000000000000001690632ebf4be090602401602060405180830381865afa158015611eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611efe919061418a565b815260200184815260200183815260200186602001516001600160701b0316815260200186604001516001600160701b03168152602001856000015161ffff168152602001856020015161ffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a086fc228a6040518263ffffffff1660e01b8152600401611fac91906001600160a01b0391909116815260200190565b608060405180830381865afa158015611fc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fed91906143c8565b90529050611096816139ce565b60008060008061200985613187565b5090506120a8817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e501ed04888a6040518363ffffffff1660e01b815260040161205e9291906144d6565b6040805180830381865afa15801561207a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209e919061453f565b6020015190613863565b935061214b6120b686610c0e565b6040516339407b4160e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e501ed0490612104908a908c906004016144d6565b6040805180830381865afa158015612120573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612144919061453f565b5190613863565b9250612157838561425c565b9150509250925092565b604051638ccb720b60e01b81526001600160a01b0382811660048301526060917f000000000000000000000000000000000000000000000000000000000000000090911690638ccb720b90602401600060405180830381865afa1580156121cc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d3591908101906142b3565b6000806000806000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a086fc228a6040518263ffffffff1660e01b815260040161225b91906001600160a01b0391909116815260200190565b608060405180830381865afa158015612278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229c91906143c8565b80516020820151604080840151606090940151905163854f7ebb60e01b81526001600160a01b038e811660048301529399509197509295509193507f000000000000000000000000000000000000000000000000000000000000000016915063854f7ebb90602401602060405180830381865afa158015612321573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612345919061418a565b604051630175fa5f60e51b81526001600160a01b038a811660048301529198507f000000000000000000000000000000000000000000000000000000000000000090911690632ebf4be090602401602060405180830381865afa1580156123b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d4919061418a565b60405163db0577fd60e01b81526001600160a01b038a811660048301529197507f00000000000000000000000000000000000000000000000000000000000000009091169063db0577fd90602401606060405180830381865afa15801561243f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612463919061436f565b51969895975092949193509190565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0772d0b6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156124d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124fa91908101906142b3565b905090565b604051636ace4f5b60e11b81526001600160a01b03828116600483015260009182917f0000000000000000000000000000000000000000000000000000000000000000169063d59c9eb690602401606060405180830381865afa15801561256a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061258e919061442e565b805190915080156125a157508060200151155b80156115b95750604001511592915050565b60008060008084612691576000869050806001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015612601573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612625919061418a565b9250806001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612665573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612689919061418a565b9150506126a0565b61269a86613187565b90925090505b84158061273f575060405163db0577fd60e01b81526001600160a01b0387811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063db0577fd90602401606060405180830381865afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612732919061436f565b6000015163ffffffff1643145b156128645760405163854f7ebb60e01b81526001600160a01b0387811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063854f7ebb90602401602060405180830381865afa1580156127aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ce919061418a565b604051630175fa5f60e51b81526001600160a01b0388811660048301529195507f000000000000000000000000000000000000000000000000000000000000000090911690632ebf4be090602401602060405180830381865afa158015612839573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061285d919061418a565b9250612bb7565b60405163db0577fd60e01b81526001600160a01b0387811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063db0577fd90602401606060405180830381865afa1580156128cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f3919061436f565b6040516325af544b60e21b81526001600160a01b0389811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906396bd512c906024016040805180830381865afa15801561295e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298291906141b5565b6040805161012081019182905263854f7ebb60e01b9091526001600160a01b038a811661012483015291925060009181907f00000000000000000000000000000000000000000000000000000000000000001663854f7ebb6101448301602060405180830381865afa1580156129fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a20919061418a565b8152604051630175fa5f60e51b81526001600160a01b038c811660048301526020909201917f00000000000000000000000000000000000000000000000000000000000000001690632ebf4be090602401602060405180830381865afa158015612a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab2919061418a565b815260200186815260200185815260200184602001516001600160701b0316815260200184604001516001600160701b03168152602001836000015161ffff168152602001836020015161ffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a086fc228c6040518263ffffffff1660e01b8152600401612b6091906001600160a01b0391909116815260200190565b608060405180830381865afa158015612b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba191906143c8565b90529050612bae81613b36565b90975095505050505b92959194509250565b600080600080612bcf85613187565b915050612c24817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663947574ac888a6040518363ffffffff1660e01b815260040161205e9291906144d6565b935061214b612c3286611bb5565b60405163251d5d2b60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063947574ac90612104908a908c906004016144d6565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d079190614296565b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d689190614296565b604051638ccb720b60e01b81526001600160a01b0389811660048301529192506000917f00000000000000000000000000000000000000000000000000000000000000001690638ccb720b90602401600060405180830381865afa158015612dd4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612dfc91908101906142b3565b805190915060005b81811015612eda576000838281518110612e2057612e20614342565b602002602001015190506000612e398c836001896118f8565b9050806020015187612e4b919061425c565b9650806040015188612e5d919061425c565b9750826001019250816001600160a01b03168b6001600160a01b031603612ed3578815612ea1576060810151612e94908a90613863565b612e9e908961425c565b97505b8915612ed357612ec68160800151611adb83606001518d61386390919063ffffffff16565b612ed09088614245565b96505b5050612e04565b5050505094509492505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f6c9190614296565b6001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fcd9190614296565b604051638ccb720b60e01b81526001600160a01b0386811660048301529192506000917f00000000000000000000000000000000000000000000000000000000000000001690638ccb720b90602401600060405180830381865afa158015613039573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261306191908101906142b3565b80518551919250600091829190825b8281101561312857600086828151811061308c5761308c614342565b602002602001015190506000805b848110156130e557826001600160a01b03168c82815181106130be576130be614342565b60200260200101516001600160a01b0316036130dd57600191506130e5565b60010161309a565b5060006130f48d84848d6118f8565b9050806020015188613106919061425c565b9750806040015187613118919061425c565b9650836001019350505050613070565b5050501195945050505050565b6000670de0b6b3a76400008261314b8583614226565b61315d90670de0b6b3a7640000614226565b6131679190614274565b6115b99190614274565b600081831061318057816115b9565b5090919050565b60008060008390506000816001600160a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156131cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f3919061418a565b90508043036132cb57816001600160a01b031663182df0f56040518163ffffffff1660e01b8152600401602060405180830381865afa15801561323a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061325e919061418a565b826001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561329c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132c0919061418a565b935093505050915091565b6000826001600160a01b0316633b1d21a26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561330b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332f919061418a565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613371573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613395919061418a565b90506000846001600160a01b03166347bd37186040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fb919061418a565b90506000856001600160a01b0316638f840ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561343d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613461919061418a565b90506000866001600160a01b031663aa5af0fd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156134a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c7919061418a565b90506000876001600160a01b031663f8f9da286040518163ffffffff1660e01b8152600401602060405180830381865afa158015613509573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352d919061418a565b905065048c273950008111156135895760405162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c79206869676800000000604482015260640160405180910390fd5b60006135958843614245565b905060006135a38284614226565b905060006135b18288613863565b905060006135bf888361425c565b905060008761362a848f6001600160a01b031663173b99046040518163ffffffff1660e01b8152600401602060405180830381865afa158015613606573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adb919061418a565b613634919061425c565b905060008a116136a5578c6001600160a01b031663675d972c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561367c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a0919061418a565b6136be565b6136be8a826136b4858f61425c565b610bb49190614245565b9e50866136cb8582613863565b6136d5919061425c565b9d5050505050505050505050505050915091565b6000806137078360800151846040015161313590919063ffffffff16565b905060006137268460a00151856060015161313590919063ffffffff16565b90506000612710828660e0015161373d9190614226565b848760e001516127106137509190614245565b61375a9190614226565b613764919061425c565b61376e9190614274565b9050600061271061377f8584614245565b8760c0015161378e9190614226565b6137989190614274565b6137a29083614245565b905085610100015160400151600014806137c0575061010086015151155b156137d85785516137d19082613863565b945061385a565b600061382361381561380089600001518a61010001516040015161386390919063ffffffff16565b60808a01516101008b015151610bb491613863565b670de0b6b3a7640000613171565b90506110966138328287613863565b61384884611adb85670de0b6b3a7640000614245565b613852919061425c565b885190613863565b50505050919050565b6000670de0b6b3a76400006131678385614226565b60006138cc827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e501ed0488886040518363ffffffff1660e01b815260040161205e9291906144d6565b61391e847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e501ed0489896040518363ffffffff1660e01b81526004016121049291906144d6565b61150e919061425c565b600061397c827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663947574ac88886040518363ffffffff1660e01b815260040161205e9291906144d6565b61391e847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663947574ac89896040518363ffffffff1660e01b81526004016121049291906144d6565b6000806139ec8360800151846040015161313590919063ffffffff16565b90506000613a0b8460a00151856060015161313590919063ffffffff16565b90506000612710828660e00151613a229190614226565b848760e00151612710613a359190614245565b613a3f9190614226565b613a49919061425c565b613a539190614274565b90506000612710613a648385614245565b8760c00151613a739190614226565b613a7d9190614274565b613a87908361425c565b90508561010001516060015160001480613aa8575061010086015160200151155b15613abc5760208601516137d19082613863565b6000613afc613815613ae489602001518a61010001516060015161386390919063ffffffff16565b60608a01516101008b015160200151610bb491613863565b9050611096613b0b8286613863565b613b2184611adb85670de0b6b3a7640000614245565b613b2b919061425c565b602089015190613863565b6000806000613b568460800151856040015161313590919063ffffffff16565b90506000613b758560a00151866060015161313590919063ffffffff16565b90506000612710828760e00151613b8c9190614226565b848860e00151612710613b9f9190614245565b613ba99190614226565b613bb3919061425c565b613bbd9190614274565b90506000612710613bce8584614245565b8860c00151613bdd9190614226565b613be79190614274565b613bf19083614245565b90506000612710613c028486614245565b8960c00151613c119190614226565b613c1b9190614274565b613c25908461425c565b90508761010001516040015160001480613c43575061010088015151155b15613c5b578751613c549083613863565b9650613cd3565b6000613c98613815613c838b600001518c61010001516040015161386390919063ffffffff16565b60808c01516101008d015151610bb491613863565b9050613ccf613ca78288613863565b613cbd85611adb85670de0b6b3a7640000614245565b613cc7919061425c565b8a5190613863565b9750505b610100880151606001511580613cf0575061010088015160200151155b15613d0b576020880151613d049082613863565b9550613d89565b6000613d4b613815613d338b602001518c61010001516060015161386390919063ffffffff16565b60608c01516101008d015160200151610bb491613863565b9050613d85613d5a8287613863565b613d7084611adb85670de0b6b3a7640000614245565b613d7a919061425c565b60208b015190613863565b9650505b5050505050915091565b6001600160a01b0381168114613da857600080fd5b50565b600060208284031215613dbd57600080fd5b81356115b981613d93565b60008083601f840112613dda57600080fd5b50813567ffffffffffffffff811115613df257600080fd5b6020830191508360208260051b8501011115610c0757600080fd5b600080600060408486031215613e2257600080fd5b8335613e2d81613d93565b9250602084013567ffffffffffffffff811115613e4957600080fd5b613e5586828701613dc8565b9497909650939450505050565b60008060408385031215613e7557600080fd5b8235613e8081613d93565b91506020830135613e9081613d93565b809150509250929050565b600080600080600060808688031215613eb357600080fd5b8535613ebe81613d93565b94506020860135613ece81613d93565b93506040860135613ede81613d93565b9250606086013567ffffffffffffffff811115613efa57600080fd5b613f0688828901613dc8565b969995985093965092949392505050565b8015158114613da857600080fd5b60008060008060808587031215613f3b57600080fd5b8435613f4681613d93565b93506020850135613f5681613d93565b92506040850135613f6681613f17565b91506060850135613f7681613d93565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b81811015613fc25783516001600160a01b031683529284019291840191600101613f9d565b50909695505050505050565b60008060408385031215613fe157600080fd5b8235613fec81613d93565b91506020830135613e9081613f17565b6000806000806080858703121561401257600080fd5b843561401d81613d93565b9350602085013561402d81613d93565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561407b5761407b614042565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156140aa576140aa614042565b604052919050565b600067ffffffffffffffff8211156140cc576140cc614042565b5060051b60200190565b600080604083850312156140e957600080fd5b82356140f481613d93565b915060208381013567ffffffffffffffff81111561411157600080fd5b8401601f8101861361412257600080fd5b8035614135614130826140b2565b614081565b81815260059190911b8201830190838101908883111561415457600080fd5b928401925b8284101561417b57833561416c81613d93565b82529284019290840190614159565b80955050505050509250929050565b60006020828403121561419c57600080fd5b5051919050565b805161ffff811681146110a157600080fd5b6000604082840312156141c757600080fd5b6040516040810181811067ffffffffffffffff821117156141ea576141ea614042565b6040526141f6836141a3565b8152614204602084016141a3565b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561424057614240614210565b500290565b60008282101561425757614257614210565b500390565b6000821982111561426f5761426f614210565b500190565b60008261429157634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156142a857600080fd5b81516115b981613d93565b600060208083850312156142c657600080fd5b825167ffffffffffffffff8111156142dd57600080fd5b8301601f810185136142ee57600080fd5b80516142fc614130826140b2565b81815260059190911b8201830190838101908783111561431b57600080fd5b928401925b8284101561109657835161433381613d93565b82529284019290840190614320565b634e487b7160e01b600052603260045260246000fd5b80516001600160701b03811681146110a157600080fd5b60006060828403121561438157600080fd5b614389614058565b825163ffffffff8116811461439d57600080fd5b81526143ab60208401614358565b60208201526143bc60408401614358565b60408201529392505050565b6000608082840312156143da57600080fd5b6040516080810181811067ffffffffffffffff821117156143fd576143fd614042565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b60006060828403121561444057600080fd5b614448614058565b825161445381613f17565b8152602083015161446381613f17565b602082015260408301516143bc81613f17565b60006020828403121561448857600080fd5b81516115b981613f17565b6000806000606084860312156144a857600080fd5b83516144b381613f17565b6020850151604086015191945092506144cb81613f17565b809150509250925092565b6001600160a01b0392831681529116602082015260400190565b60006040828403121561450257600080fd5b6040516040810181811067ffffffffffffffff8211171561452557614525614042565b604052825181526020928301519281019290925250919050565b60006040828403121561455157600080fd5b6115b983836144f056fea2646970667358221220729de472f7e5eb31a8d7a3ff3f24531ced6525aed5b6a2d0570e9ede0b61cd5c64736f6c634300080d003300000000000000000000000068416e5225668e1af28f859eb1f2982c5b0756d4

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000068416e5225668e1af28f859eb1f2982c5b0756d4

-----Decoded View---------------
Arg [0] : _morphoAddress (address): 0x68416e5225668E1af28F859eB1f2982C5B0756D4

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000068416e5225668e1af28f859eb1f2982c5b0756d4


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.