APE Price: $1.38 (+2.30%)

Contract

0x14F1909Cf228dcC36d4A2d5eab1345229A964F61

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60a0604048634392024-11-21 8:57:493 days ago1732179469IN
 Contract Creation
0 APE0.1314688625.42069

Parent Transaction Hash Block From To
View All Internal Transactions

Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xE14B09d9...729dC38f2
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
ApeFinance

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion
File 1 of 29 : ApeFinance.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import "./ApeFinanceStorage.sol";
import "../../interfaces/IApeFinance.sol";
import "../../interfaces/IAToken.sol";
import "../../interfaces/IDeferLiquidityCheck.sol";
import "../../interfaces/IInterestRateModel.sol";
import "../../interfaces/IPriceOracle.sol";
import "../../interfaces/IPToken.sol";
import "../../libraries/Arrays.sol";
import "../../libraries/DataTypes.sol";
import "../../libraries/PauseFlags.sol";
import "../../libraries/SubAccounts.sol";

contract ApeFinance is
    Initializable,
    UUPSUpgradeable,
    Ownable2StepUpgradeable,
    ReentrancyGuard,
    ApeFinanceStorage,
    IApeFinance
{
    using SafeERC20 for IERC20;
    using Arrays for address[];
    using PauseFlags for DataTypes.MarketConfig;
    using SubAccounts for address;

    /**
     * @notice Initialize the contract.
     * @param _admin The address of the admin
     */
    function initialize(address _admin) public initializer {
        __Ownable_init();
        __UUPSUpgradeable_init();

        transferOwnership(_admin);
    }

    /**
     * @notice Check if the caller is the market configurator.
     */
    modifier onlyMarketConfigurator() {
        _checkMarketConfigurator();
        _;
    }

    /**
     * @notice Check if the caller is the reserve manager.
     */
    modifier onlyReserveManager() {
        _checkReserveManager();
        _;
    }

    /**
     * @notice Check if the caller is the credit limit manager.
     */
    modifier onlyCreditLimitManager() {
        require(msg.sender == creditLimitManager, "!manager");
        _;
    }

    /**
     * @notice Check if the user has authorized the caller.
     */
    modifier isAuthorized(address from) {
        _checkAuthorized(from, msg.sender);
        _;
    }

    /* ========== VIEW FUNCTIONS ========== */

    /**
     * @notice Get all markets.
     * @return The list of all markets
     */
    function getAllMarkets() public view returns (address[] memory) {
        return allMarkets;
    }

    /**
     * @notice Whether or not a market is listed.
     * @param market The address of the market to check
     * @return true if the market is listed, false otherwise
     */
    function isMarketListed(address market) public view returns (bool) {
        DataTypes.Market storage m = markets[market];
        return m.config.isListed;
    }

    /**
     * @notice Get the exchange rate of a market.
     * @param market The address of the market
     * @return The exchange rate
     */
    function getExchangeRate(address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return _getExchangeRate(m);
    }

    /**
     * @notice Get the total supply of a market.
     * @param market The address of the market
     * @return The total supply
     */
    function getTotalSupply(address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return m.totalSupply;
    }

    /**
     * @notice Get the total borrow of a market.
     * @param market The address of the market
     * @return The total borrow
     */
    function getTotalBorrow(address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return m.totalBorrow;
    }

    /**
     * @notice Get the total cash of a market.
     * @param market The address of the market
     * @return The total cash
     */
    function getTotalCash(address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return m.totalCash;
    }

    /**
     * @notice Get the total reserves of a market.
     * @param market The address of the market
     * @return The total reserves
     */
    function getTotalReserves(address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return m.totalReserves;
    }

    /**
     * @notice Get the borrow balance of a user in a market.
     * @param user The address of the user
     * @param market The address of the market
     * @return The borrow balance
     */
    function getBorrowBalance(address user, address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return _getBorrowBalance(m, user);
    }

    /**
     * @notice Get the AToken balance of a user in a market.
     * @param user The address of the user
     * @param market The address of the market
     * @return The AToken balance
     */
    function getATokenBalance(address user, address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return m.userSupplies[user];
    }

    /**
     * @notice Get the supply balance of a user in a market.
     * @param user The address of the user
     * @param market The address of the market
     * @return The supply balance
     */
    function getSupplyBalance(address user, address market) public view returns (uint256) {
        DataTypes.Market storage m = markets[market];
        return (m.userSupplies[user] * _getExchangeRate(m)) / 1e18;
    }

    /**
     * @notice Get the account liquidity of a user.
     * @param user The address of the user
     * @return The total collateral value, liquidation collateral value, and total debt value of the user
     */
    function getAccountLiquidity(address user) public view returns (uint256, uint256, uint256) {
        return _getAccountLiquidity(user);
    }

    /**
     * @notice Get the user's allowed extensions.
     * @param user The address of the user
     * @return The list of allowed extensions
     */
    function getUserAllowedExtensions(address user) public view returns (address[] memory) {
        return allAllowedExtensions[user];
    }

    /**
     * @notice Whether or not a user has allowed an extension.
     * @param user The address of the user
     * @param extension The address of the extension
     * @return true if the user has allowed the extension, false otherwise
     */
    function isAllowedExtension(address user, address extension) public view returns (bool) {
        return allowedExtensions[user][extension];
    }

    /**
     * @notice Get the credit limit of a user in a market.
     * @param user The address of the user
     * @param market The address of the market
     * @return The credit limit
     */
    function getCreditLimit(address user, address market) public view returns (uint256) {
        return creditLimits[user][market];
    }

    /**
     * @notice Get the list of all credit markets for a user.
     * @param user The address of the user
     * @return The list of all credit markets
     */
    function getUserCreditMarkets(address user) public view returns (address[] memory) {
        return allCreditMarkets[user];
    }

    /**
     * @notice Whether or not an account is a credit account.
     * @param user The address of the user
     * @return true if the account is a credit account, false otherwise
     */
    function isCreditAccount(address user) public view returns (bool) {
        return allCreditMarkets[user].length > 0;
    }

    /**
     * @notice Get the configuration of a market.
     * @param market The address of the market
     * @return The market configuration
     */
    function getMarketConfiguration(address market) public view returns (DataTypes.MarketConfig memory) {
        return markets[market].config;
    }

    /**
     * @notice Check if an account is liquidatable.
     * @param user The address of the account to check
     * @return true if the account is liquidatable, false otherwise
     */
    function isUserLiquidatable(address user) public view returns (bool) {
        return _isLiquidatable(user);
    }

    /**
     * @notice Calculate the amount of aToken that can be seized in a liquidation.
     * @param marketBorrow The address of the market being borrowed from
     * @param marketCollateral The address of the market being used as collateral
     * @param repayAmount The amount of the borrowed asset being repaid
     * @return The amount of aToken that can be seized
     */
    function calculateLiquidationOpportunity(address marketBorrow, address marketCollateral, uint256 repayAmount)
        public
        view
        returns (uint256)
    {
        DataTypes.Market storage mCollateral = markets[marketCollateral];
        DataTypes.Market storage mBorrow = markets[marketCollateral];

        return _getLiquidationSeizeAmount(marketBorrow, marketCollateral, mBorrow, mCollateral, repayAmount);
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Accrue the interest of a market.
     * @param market The address of the market
     */
    function accrueInterest(address market) external {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");

        _accrueInterest(market, m);
    }

    /**
     * @notice Check the account liquidity of a user.
     * @param user The address of the user
     */
    function checkAccountLiquidity(address user) public {
        _checkAccountLiquidity(user);
    }

    /**
     * @notice Supply an amount of asset to ApeFinance.
     * @param from The address which will supply the asset
     * @param to The address which will hold the balance
     * @param market The address of the market
     * @param amount The amount of asset to supply
     */
    function supply(address from, address to, address market, uint256 amount)
        external
        nonReentrant
        isAuthorized(from)
    {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");
        require(!m.config.isSupplyPaused(), "supply paused");
        require(!isCreditAccount(to), "cannot supply to credit account");

        _accrueInterest(market, m);

        if (m.config.supplyCap != 0) {
            uint256 totalSupplyUnderlying = m.totalSupply * _getExchangeRate(m) / 1e18;
            require(totalSupplyUnderlying + amount <= m.config.supplyCap, "supply cap reached");
        }

        uint256 aTokenAmount = (amount * 1e18) / _getExchangeRate(m);
        require(aTokenAmount > 0, "zero aToken amount");

        // Update storage.
        m.totalCash += amount;
        m.totalSupply += aTokenAmount;
        unchecked {
            // Overflow not possible: supplyBalance + aTokenAmount is at most totalSupply + aTokenAmount, which is checked above.
            m.userSupplies[to] += aTokenAmount;
        }

        // Enter the market.
        if (amount > 0) {
            _enterMarket(market, to);
        }

        IAToken(m.config.aTokenAddress).mint(to, aTokenAmount); // Only emits Transfer event.
        IERC20(market).safeTransferFrom(from, address(this), amount);

        emit Supply(market, from, to, amount, aTokenAmount);
    }

    /**
     * @notice Borrow an amount of asset from ApeFinance.
     * @param from The address which will borrow the asset
     * @param to The address which will receive the token
     * @param market The address of the market
     * @param amount The amount of asset to borrow
     */
    function borrow(address from, address to, address market, uint256 amount)
        external
        nonReentrant
        isAuthorized(from)
    {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");
        require(!m.config.isBorrowPaused(), "borrow paused");
        require(m.totalCash >= amount, "insufficient cash");

        _accrueInterest(market, m);

        uint256 newTotalBorrow = m.totalBorrow + amount;
        uint256 newUserBorrowBalance;
        unchecked {
            // Overflow not possible: borrowBalance + amount is at most totalBorrow + amount, which is checked above.
            newUserBorrowBalance = _getBorrowBalance(m, from) + amount;
        }

        if (m.config.borrowCap != 0) {
            require(newTotalBorrow <= m.config.borrowCap, "borrow cap reached");
        }

        // Update storage.
        unchecked {
            m.totalCash -= amount;
        }
        m.totalBorrow = newTotalBorrow;
        m.userBorrows[from].borrowBalance = newUserBorrowBalance;
        m.userBorrows[from].borrowIndex = m.borrowIndex;

        // Enter the market.
        if (amount > 0) {
            _enterMarket(market, from);
        }

        IERC20(market).safeTransfer(to, amount);

        if (isCreditAccount(from)) {
            require(from == to, "credit account can only borrow to itself");
            require(creditLimits[from][market] >= newUserBorrowBalance, "insufficient credit limit");
        } else {
            _checkAccountLiquidity(from);
        }

        emit Borrow(market, from, to, amount, newUserBorrowBalance, newTotalBorrow);
    }

    /**
     * @notice Redeem an amount of asset from ApeFinance.
     * @param from The address which will redeem the asset
     * @param to The address which will receive the token
     * @param market The address of the market
     * @param amount The amount of asset to redeem, or type(uint256).max for max
     * @return The actual amount of asset redeemed
     */
    function redeem(address from, address to, address market, uint256 amount)
        external
        nonReentrant
        isAuthorized(from)
        returns (uint256)
    {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");

        _accrueInterest(market, m);

        uint256 userSupply = m.userSupplies[from];
        uint256 totalCash = m.totalCash;

        uint256 aTokenAmount;
        if (amount == type(uint256).max) {
            aTokenAmount = userSupply;
            amount = (aTokenAmount * _getExchangeRate(m)) / 1e18;
        } else {
            aTokenAmount = (amount * 1e18) / _getExchangeRate(m);
        }

        require(aTokenAmount > 0, "zero aToken amount");
        require(userSupply >= aTokenAmount, "insufficient balance");
        require(totalCash >= amount, "insufficient cash");

        uint256 newUserSupply;
        unchecked {
            newUserSupply = userSupply - aTokenAmount;
        }

        // Update storage.
        m.userSupplies[from] = newUserSupply;
        unchecked {
            m.totalCash = totalCash - amount;
            // Underflow not possible: aTokenAmount <= userSupply <= totalSupply.
            m.totalSupply -= aTokenAmount;
        }

        // Check if need to exit the market.
        if (newUserSupply == 0 && _getBorrowBalance(m, from) == 0) {
            _exitMarket(market, from);
        }

        IAToken(m.config.aTokenAddress).burn(from, aTokenAmount); // Only emits Transfer event.
        IERC20(market).safeTransfer(to, amount);

        _checkAccountLiquidity(from);

        emit Redeem(market, from, to, amount, aTokenAmount);

        return amount;
    }

    /**
     * @notice Repay an amount of asset to ApeFinance.
     * @param from The address which will repay the asset
     * @param to The address which will hold the balance
     * @param market The address of the market
     * @param amount The amount of asset to repay, or type(uint256).max for max
     * @return The actual amount of asset repaid
     */
    function repay(address from, address to, address market, uint256 amount)
        external
        nonReentrant
        isAuthorized(from)
        returns (uint256)
    {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");
        if (isCreditAccount(to)) {
            require(from == to, "credit account can only repay for itself");
        }

        _accrueInterest(market, m);

        return _repay(m, from, to, market, amount);
    }

    /**
     * @notice Liquidate an undercollateralized borrower.
     * @param liquidator The address which will liquidate the borrower
     * @param borrower The address of the borrower
     * @param marketBorrow The address of the borrow market
     * @param marketCollateral The address of the collateral market
     * @param repayAmount The amount of asset to repay, or type(uint256).max for max
     * @return The actual amount of asset repaid and the amount of collateral seized
     */
    function liquidate(
        address liquidator,
        address borrower,
        address marketBorrow,
        address marketCollateral,
        uint256 repayAmount
    ) external nonReentrant isAuthorized(liquidator) returns (uint256, uint256) {
        DataTypes.Market storage mBorrow = markets[marketBorrow];
        DataTypes.Market storage mCollateral = markets[marketCollateral];
        require(mBorrow.config.isListed, "borrow market not listed");
        require(mCollateral.config.isListed, "collateral market not listed");
        require(_isMarketSeizable(mCollateral), "collateral market cannot be seized");
        require(!isCreditAccount(liquidator) && !isCreditAccount(borrower), "cannot liquidate credit account");
        require(liquidator != borrower, "cannot self liquidate");

        _accrueInterest(marketBorrow, mBorrow);
        _accrueInterest(marketCollateral, mCollateral);

        // Check if the borrower is actually liquidatable.
        require(_isLiquidatable(borrower), "borrower not liquidatable");

        // Repay the debt.
        repayAmount = _repay(mBorrow, liquidator, borrower, marketBorrow, repayAmount);

        // Seize the collateral.
        uint256 aTokenAmount =
            _getLiquidationSeizeAmount(marketBorrow, marketCollateral, mBorrow, mCollateral, repayAmount);
        _transferAToken(marketCollateral, mCollateral, borrower, liquidator, aTokenAmount);
        IAToken(mCollateral.config.aTokenAddress).seize(borrower, liquidator, aTokenAmount); // Only emits Transfer event.

        emit Liquidate(liquidator, borrower, marketBorrow, marketCollateral, repayAmount, aTokenAmount);

        return (repayAmount, aTokenAmount);
    }

    /**
     * @notice Defer the liquidity check to a user.
     * @dev The message sender must implement the IDeferLiquidityCheck.
     * @param user The address of the user
     * @param data The data to pass to the callback
     */
    function deferLiquidityCheck(address user, bytes memory data) external isAuthorized(user) {
        require(!isCreditAccount(user), "credit account cannot defer liquidity check");
        require(liquidityCheckStatus[user] == LIQUIDITY_CHECK_NORMAL, "reentry defer liquidity check");
        liquidityCheckStatus[user] = LIQUIDITY_CHECK_DEFERRED;

        IDeferLiquidityCheck(msg.sender).onDeferredLiquidityCheck(data);

        uint8 status = liquidityCheckStatus[user];
        liquidityCheckStatus[user] = LIQUIDITY_CHECK_NORMAL;

        if (status == LIQUIDITY_CHECK_DIRTY) {
            _checkAccountLiquidity(user);
        }
    }

    /**
     * @notice User enables or disables an extension.
     * @param extension The address of the extension
     * @param allowed Whether to allow or disallow the extension
     */
    function setUserExtension(address extension, bool allowed) external {
        _setAccountExtension(msg.sender, extension, allowed);
    }

    /**
     * @notice Set the extension for a sub account.
     * @param primary The address of the primary account
     * @param subAccountId The ID of the sub account
     * @param allowed Whether to allow or disallow the extension
     */
    function setSubAccountExtension(address primary, uint256 subAccountId, bool allowed)
        external
        isAuthorized(primary)
    {
        address account = primary.getSubAccount(subAccountId);

        _setAccountExtension(account, msg.sender, allowed);
    }

    /**
     * @notice Transfer AToken from one account to another.
     * @dev This function is callable by the AToken contract only.
     * @param market The address of the market
     * @param from The address to transfer from
     * @param to The address to transfer to
     * @param amount The amount to transfer
     */
    function transferAToken(address market, address from, address to, uint256 amount) external {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");
        require(msg.sender == m.config.aTokenAddress, "!authorized");
        require(!m.config.isTransferPaused(), "transfer paused");
        require(from != to, "cannot self transfer");
        require(!isCreditAccount(to), "cannot transfer to credit account");

        _accrueInterest(market, m);
        _transferAToken(market, m, from, to, amount);

        _checkAccountLiquidity(from);
    }

    /* ========== RESTRICTED FUNCTIONS ========== */

    /**
     * @notice List a market.
     * @dev This function is callable by the market configurator only.
     * @param market The address of the market
     * @param config The market configuration
     */
    function listMarket(address market, DataTypes.MarketConfig calldata config) external onlyMarketConfigurator {
        DataTypes.Market storage m = markets[market];
        m.lastUpdateTimestamp = _getNow();
        m.borrowIndex = INITIAL_BORROW_INDEX;
        m.config = config;
        allMarkets.push(market);

        emit MarketListed(market, m.lastUpdateTimestamp, m.config);
    }

    /**
     * @notice Delist a market.
     * @dev This function is callable by the market configurator only.
     * @param market The address of the market
     */
    function delistMarket(address market) external onlyMarketConfigurator {
        DataTypes.Market storage m = markets[market];
        // The nested mapping like userBorrows can't be deleted completely, so we just set `isListed` to false.
        m.config.isListed = false;
        // `isDelisted` is needed to distinguish delisted markets from markets that have never been listed before.
        m.config.isDelisted = true;
        allMarkets.deleteElement(market);

        emit MarketDelisted(market);
    }

    /**
     * @notice Set the market configuration.
     * @dev This function is callable by the market configurator only.
     * @param market The address of the market
     * @param config The market configuration
     */
    function setMarketConfiguration(address market, DataTypes.MarketConfig calldata config)
        external
        onlyMarketConfigurator
    {
        DataTypes.Market storage m = markets[market];
        m.config = config;

        emit MarketConfigurationChanged(market, config);
    }

    /**
     * @notice Set the credit limit for a user in a market.
     * @dev This function is callable by the credit limit manager only.
     * @param user The address of the user
     * @param market The address of the market
     * @param credit The credit limit
     */
    function setCreditLimit(address user, address market, uint256 credit) external onlyCreditLimitManager {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");

        if (credit == 0 && creditLimits[user][market] != 0) {
            allCreditMarkets[user].deleteElement(market);
        } else if (credit != 0 && creditLimits[user][market] == 0) {
            allCreditMarkets[user].push(market);
        }

        creditLimits[user][market] = credit;
        emit CreditLimitChanged(user, market, credit);
    }

    /**
     * @notice Increase reserves by absorbing the surplus cash.
     * @dev This function is callable by the reserve manager only.
     * @param market The address of the market
     */
    function absorbToReserves(address market) external onlyReserveManager {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");

        _accrueInterest(market, m);

        uint256 amount = IERC20(market).balanceOf(address(this)) - m.totalCash;

        if (amount > 0) {
            uint256 aTokenAmount = (amount * 1e18) / _getExchangeRate(m);

            // Update internal cash, and total reserves.
            m.totalCash += amount;
            m.totalReserves += aTokenAmount;

            emit ReservesIncreased(market, aTokenAmount, amount);
        }
    }

    /**
     * @notice Reduce reserves by withdrawing the requested amount.
     * @dev This function is callable by the reserve manager only.
     * @param market The address of the market
     * @param aTokenAmount The amount of aToken to withdraw
     * @param recipient The address which will receive the underlying asset
     */
    function reduceReserves(address market, uint256 aTokenAmount, address recipient) external onlyReserveManager {
        DataTypes.Market storage m = markets[market];
        require(m.config.isListed, "not listed");

        _accrueInterest(market, m);

        uint256 amount = (aTokenAmount * _getExchangeRate(m)) / 1e18;

        require(m.totalCash >= amount, "insufficient cash");
        require(m.totalReserves >= aTokenAmount, "insufficient reserves");

        // Update internal cash, and total reserves.
        unchecked {
            m.totalCash -= amount;
            m.totalReserves -= aTokenAmount;
        }

        IERC20(market).safeTransfer(recipient, amount);

        emit ReservesDecreased(market, recipient, aTokenAmount, amount);
    }

    /**
     * @notice Set the price oracle.
     * @param oracle The address of the price oracle
     */
    function setPriceOracle(address oracle) external onlyOwner {
        priceOracle = oracle;

        emit PriceOracleSet(oracle);
    }

    /**
     * @notice Set the market configurator.
     * @param configurator The address of the market configurator
     */
    function setMarketConfigurator(address configurator) external onlyOwner {
        marketConfigurator = configurator;

        emit MarketConfiguratorSet(configurator);
    }

    /**
     * @notice Set the credit limit manager.
     * @param manager The address of the credit limit manager
     */
    function setCreditLimitManager(address manager) external onlyOwner {
        creditLimitManager = manager;

        emit CreditLimitManagerSet(manager);
    }

    /**
     * @notice Set the reserve manager.
     * @param manager The address of the reserve manager
     */
    function setReserveManager(address manager) external onlyOwner {
        reserveManager = manager;

        emit ReserveManagerSet(manager);
    }

    /**
     * @notice Seize the unlisted token.
     * @param token The address of the token
     * @param recipient The address which will receive the token
     */
    function seize(address token, address recipient) external onlyOwner {
        DataTypes.Market storage m = markets[token];
        require(!m.config.isListed, "cannot seize listed market");

        uint256 balance = IERC20(token).balanceOf(address(this));
        if (balance > 0) {
            IERC20(token).safeTransfer(recipient, balance);

            emit TokenSeized(token, recipient, balance);
        }
    }

    /* ========== INTERNAL FUNCTIONS ========== */

    /**
     * @dev _authorizeUpgrade is used by UUPSUpgradeable to determine if it's allowed to upgrade a proxy implementation.
     * @param newImplementation The new implementation
     *
     * Ref: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol
     */
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

    /**
     * @dev Get the current timestamp.
     * @return The current timestamp, casted to uint40
     */
    function _getNow() internal view virtual returns (uint40) {
        require(block.timestamp < 2 ** 40, "timestamp too large");
        return uint40(block.timestamp);
    }

    /**
     * @dev Check if the operator is authorized.
     * @param from The address of the user
     * @param operator The address of the operator
     */
    function _checkAuthorized(address from, address operator) internal view {
        require(from == operator || (!isCreditAccount(from) && isAllowedExtension(from, operator)), "!authorized");
    }

    /**
     * @dev Check if the message sender is the market configurator.
     */
    function _checkMarketConfigurator() internal view {
        require(msg.sender == marketConfigurator, "!configurator");
    }

    /**
     * @dev Check if the message sender is the credit limit manager.
     */
    function _checkReserveManager() internal view {
        require(msg.sender == reserveManager, "!reserveManager");
    }

    /**
     * @dev Get the exchange rate.
     * @param m The storage of the market
     * @return The exchange rate
     */
    function _getExchangeRate(DataTypes.Market storage m) internal view returns (uint256) {
        uint256 totalSupplyPlusReserves = m.totalSupply + m.totalReserves;
        if (totalSupplyPlusReserves == 0) {
            return m.config.initialExchangeRate;
        }
        return ((m.totalCash + m.totalBorrow) * 1e18) / totalSupplyPlusReserves;
    }

    /**
     * @dev Get the amount of aToken that can be seized in a liquidation.
     * @param marketBorrow The address of the market being borrowed from
     * @param marketCollateral The address of the market being used as collateral
     * @param mBorrow The storage of the borrow market
     * @param mCollateral The storage of the collateral market
     * @param repayAmount The amount of the borrowed asset being repaid
     * @return The amount of aToken that can be seized
     */
    function _getLiquidationSeizeAmount(
        address marketBorrow,
        address marketCollateral,
        DataTypes.Market storage mBorrow,
        DataTypes.Market storage mCollateral,
        uint256 repayAmount
    ) internal view returns (uint256) {
        uint256 borrowMarketPrice = _getMarketPrice(mBorrow, marketBorrow);
        uint256 collateralMarketPrice = _getMarketPrice(mCollateral, marketCollateral);

        // collateral amount = repayAmount * liquidationBonus * borrowMarketPrice / collateralMarketPrice
        // AToken amount = collateral amount / exchangeRate
        //   = repayAmount * (liquidationBonus * borrowMarketPrice) / (collateralMarketPrice * exchangeRate)
        uint256 numerator = (mCollateral.config.liquidationBonus * borrowMarketPrice) / FACTOR_SCALE;
        uint256 denominator = (_getExchangeRate(mCollateral) * collateralMarketPrice) / 1e18;

        return (repayAmount * numerator) / denominator;
    }

    /**
     * @dev Get the borrow balance of a user.
     * @param m The storage of the market
     * @param user The address of the user
     * @return The borrow balance
     */
    function _getBorrowBalance(DataTypes.Market storage m, address user) internal view returns (uint256) {
        DataTypes.UserBorrow memory b = m.userBorrows[user];

        if (b.borrowBalance == 0) {
            return 0;
        }

        // borrowBalanceWithInterests = borrowBalance * marketBorrowIndex / userBorrowIndex
        return (b.borrowBalance * m.borrowIndex) / b.borrowIndex;
    }

    /**
     * @dev Transfer AToken from one account to another.
     * @param market The address of the market
     * @param m The storage of the market
     * @param from The address to transfer from
     * @param to The address to transfer to
     * @param amount The amount to transfer
     */
    function _transferAToken(address market, DataTypes.Market storage m, address from, address to, uint256 amount)
        internal
    {
        require(from != address(0), "transfer from the zero address");
        require(to != address(0), "transfer to the zero address");

        uint256 fromBalance = m.userSupplies[from];
        require(amount > 0, "transfer zero amount");
        require(fromBalance >= amount, "transfer amount exceeds balance");

        _enterMarket(market, to);

        unchecked {
            m.userSupplies[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            m.userSupplies[to] += amount;
        }

        if (m.userSupplies[from] == 0 && _getBorrowBalance(m, from) == 0) {
            _exitMarket(market, from);
        }

        emit TransferAToken(market, from, to, amount);
    }

    /**
     * @dev Accrue interest to the current timestamp.
     * @param market The address of the market
     * @param m The storage of the market
     */
    function _accrueInterest(address market, DataTypes.Market storage m) internal {
        uint40 timestamp = _getNow();
        uint256 timeElapsed = uint256(timestamp - m.lastUpdateTimestamp);
        if (timeElapsed > 0) {
            uint256 totalCash = m.totalCash;
            uint256 borrowIndex = m.borrowIndex;
            uint256 totalBorrow = m.totalBorrow;
            uint256 totalSupply = m.totalSupply;
            uint256 totalReserves = m.totalReserves;

            uint256 borrowRatePerSecond =
                IInterestRateModel(m.config.interestRateModelAddress).getBorrowRate(totalCash, totalBorrow);
            uint256 interestFactor = borrowRatePerSecond * timeElapsed;
            uint256 interestIncreased = (interestFactor * totalBorrow) / 1e18;
            uint256 feeIncreased = (interestIncreased * m.config.reserveFactor) / FACTOR_SCALE;

            // Compute reservesIncreased.
            uint256 reservesIncreased = 0;
            if (feeIncreased > 0) {
                reservesIncreased = (feeIncreased * (totalSupply + totalReserves))
                    / (totalCash + totalBorrow + (interestIncreased - feeIncreased));
            }

            // Compute new states.
            borrowIndex += (interestFactor * borrowIndex) / 1e18;
            totalBorrow += interestIncreased;
            totalReserves += reservesIncreased;

            // Update state variables.
            m.lastUpdateTimestamp = timestamp;
            m.borrowIndex = borrowIndex;
            m.totalBorrow = totalBorrow;
            m.totalReserves = totalReserves;

            emit InterestAccrued(market, timestamp, borrowRatePerSecond, borrowIndex, totalBorrow, totalReserves);
        }
    }

    /**
     * @dev Enter a market.
     * @param market The address of the market
     * @param user The address of the user
     */
    function _enterMarket(address market, address user) internal {
        if (enteredMarkets[user][market]) {
            // Skip if user has entered the market.
            return;
        }

        enteredMarkets[user][market] = true;
        allEnteredMarkets[user].push(market);

        emit MarketEntered(market, user);
    }

    /**
     * @dev Exit a market.
     * @param market The address of the market
     * @param user The address of the user
     */
    function _exitMarket(address market, address user) internal {
        if (!enteredMarkets[user][market]) {
            // Skip if user has not entered the market.
            return;
        }

        enteredMarkets[user][market] = false;
        allEnteredMarkets[user].deleteElement(market);

        emit MarketExited(market, user);
    }

    /**
     * @dev Repay an amount of asset to ApeFinance.
     * @param m The market object
     * @param from The address which will repay the asset
     * @param to The address which will hold the balance
     * @param market The address of the market
     * @param amount The amount of asset to repay, or type(uint256).max for max
     * @return The actual amount repaid
     */
    function _repay(DataTypes.Market storage m, address from, address to, address market, uint256 amount)
        internal
        returns (uint256)
    {
        uint256 borrowBalance = _getBorrowBalance(m, to);
        if (amount == type(uint256).max) {
            amount = borrowBalance;
        }

        require(amount <= borrowBalance, "repay too much");

        uint256 newUserBorrowBalance;
        uint256 newTotalBorrow;
        unchecked {
            newUserBorrowBalance = borrowBalance - amount;
            // Underflow not possible: amount <= userBorrow <= totalBorrow
            newTotalBorrow = m.totalBorrow - amount;
        }

        // Update storage.
        m.userBorrows[to].borrowBalance = newUserBorrowBalance;
        m.userBorrows[to].borrowIndex = m.borrowIndex;
        m.totalCash += amount;
        m.totalBorrow = newTotalBorrow;

        // Check if need to exit the market.
        if (m.userSupplies[to] == 0 && newUserBorrowBalance == 0) {
            _exitMarket(market, to);
        }

        IERC20(market).safeTransferFrom(from, address(this), amount);

        emit Repay(market, from, to, amount, newUserBorrowBalance, newTotalBorrow);

        return amount;
    }

    /**
     * @dev Check the account liquidity of a user. If the account liquidity check is deferred, mark the status to dirty. It must be checked later.
     * @param user The address of the user
     */
    function _checkAccountLiquidity(address user) internal {
        uint8 status = liquidityCheckStatus[user];

        if (status == LIQUIDITY_CHECK_NORMAL) {
            (uint256 collateralValue,, uint256 debtValue) = _getAccountLiquidity(user);
            require(collateralValue >= debtValue, "insufficient collateral");
        } else if (status == LIQUIDITY_CHECK_DEFERRED) {
            liquidityCheckStatus[user] = LIQUIDITY_CHECK_DIRTY;
        }
    }

    /**
     * @dev Get the account liquidity of a user.
     * @param user The address of the user
     * @return The total collateral value, liquidation collateral value, and total debt value of the user
     */
    function _getAccountLiquidity(address user) internal view returns (uint256, uint256, uint256) {
        uint256 collateralValue;
        uint256 liquidationCollateralValue;
        uint256 debtValue;

        address[] memory userEnteredMarkets = allEnteredMarkets[user];
        for (uint256 i = 0; i < userEnteredMarkets.length; i++) {
            DataTypes.Market storage m = markets[userEnteredMarkets[i]];
            if (!m.config.isListed) {
                continue;
            }

            uint256 supplyBalance = m.userSupplies[user];
            uint256 borrowBalance = _getBorrowBalance(m, user);

            uint256 assetPrice = _getMarketPrice(m, userEnteredMarkets[i]);
            uint256 collateralFactor = m.config.collateralFactor;
            uint256 liquidationThreshold = m.config.liquidationThreshold;
            if (supplyBalance > 0 && collateralFactor > 0) {
                uint256 exchangeRate = _getExchangeRate(m);
                collateralValue += (supplyBalance * exchangeRate * assetPrice * collateralFactor) / 1e36 / FACTOR_SCALE;
                liquidationCollateralValue +=
                    (supplyBalance * exchangeRate * assetPrice * liquidationThreshold) / 1e36 / FACTOR_SCALE;
            }
            if (borrowBalance > 0) {
                debtValue += (borrowBalance * assetPrice) / 1e18;
            }
        }
        return (collateralValue, liquidationCollateralValue, debtValue);
    }

    /**
     * @dev Check if an account is liquidatable.
     * @param user The address of the account to check
     * @return true if the account is liquidatable, false otherwise
     */
    function _isLiquidatable(address user) internal view returns (bool) {
        (, uint256 liquidationCollateralValue, uint256 debtValue) = _getAccountLiquidity(user);
        return debtValue > liquidationCollateralValue;
    }

    /**
     * @dev Check if a market is seizable when a liquidation happens.
     * @param m The market object
     * @return true if the market is seizable, false otherwise
     */
    function _isMarketSeizable(DataTypes.Market storage m) internal view returns (bool) {
        return !m.config.isTransferPaused() && m.config.liquidationThreshold > 0;
    }

    /**
     * @dev Get the market price from the price oracle. If the market is a pToken, use its underlying to get the price.
     * @param m The market object
     * @param market The address of the market
     * @return The market price
     */
    function _getMarketPrice(DataTypes.Market storage m, address market) internal view returns (uint256) {
        address asset = m.config.isPToken ? IPToken(market).getUnderlying() : market;
        uint256 assetPrice = IPriceOracle(priceOracle).getPrice(asset);
        require(assetPrice > 0, "invalid price");
        return assetPrice;
    }

    /**
     * @dev Set the extension for an account.
     * @param account The address of the account
     * @param extension The address of the extension
     * @param allowed Whether to allow or disallow the extension
     */
    function _setAccountExtension(address account, address extension, bool allowed) internal {
        if (allowed && !allowedExtensions[account][extension]) {
            allowedExtensions[account][extension] = true;
            allAllowedExtensions[account].push(extension);

            emit ExtensionAdded(account, extension);
        } else if (!allowed && allowedExtensions[account][extension]) {
            allowedExtensions[account][extension] = false;
            allAllowedExtensions[account].deleteElement(extension);

            emit ExtensionRemoved(account, extension);
        }
    }
}

File 2 of 29 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 3 of 29 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 4 of 29 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 5 of 29 : Ownable2StepUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;

import "./OwnableUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
    function __Ownable2Step_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable2Step_init_unchained() internal onlyInitializing {
    }
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() external {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 6 of 29 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 7 of 29 : UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 8 of 29 : ApeFinanceStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./Constants.sol";
import "./Events.sol";
import "../../libraries/DataTypes.sol";

contract ApeFinanceStorage is Constants, Events {
    /// @notice The mapping of the supported markets
    mapping(address => DataTypes.Market) public markets;

    /// @notice The list of all supported markets
    address[] public allMarkets;

    /// @notice The mapping of a user's entered markets
    mapping(address => mapping(address => bool)) public enteredMarkets;

    /// @notice The list of all markets a user has entered
    mapping(address => address[]) public allEnteredMarkets;

    /// @notice The mapping of a user's allowed extensions
    mapping(address => mapping(address => bool)) public allowedExtensions;

    /// @notice The list of all allowed extensions for a user
    mapping(address => address[]) public allAllowedExtensions;

    /// @notice The mapping of the credit limits
    mapping(address => mapping(address => uint256)) public creditLimits;

    /// @notice The list of a user's credit markets
    mapping(address => address[]) public allCreditMarkets;

    /// @notice The mapping of the liquidity check status
    mapping(address => uint8) public liquidityCheckStatus;

    /// @notice The price oracle address
    address public priceOracle;

    /// @notice The market configurator address
    address public marketConfigurator;

    /// @notice The credit limit manager address
    address public creditLimitManager;

    /// @notice The reserve manager address
    address public reserveManager;
}

File 9 of 29 : IApeFinance.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../libraries/DataTypes.sol";

interface IApeFinance {
    /* ========== USER INTERFACES ========== */

    function accrueInterest(address market) external;

    function supply(address from, address to, address market, uint256 amount) external;

    function borrow(address from, address to, address asset, uint256 amount) external;

    function redeem(address from, address to, address asset, uint256 amount) external returns (uint256);

    function repay(address from, address to, address asset, uint256 amount) external returns (uint256);

    function liquidate(
        address liquidator,
        address borrower,
        address marketBorrow,
        address marketCollateral,
        uint256 repayAmount
    ) external returns (uint256, uint256);

    function deferLiquidityCheck(address user, bytes memory data) external;

    function getBorrowBalance(address user, address market) external view returns (uint256);

    function getATokenBalance(address user, address market) external view returns (uint256);

    function getSupplyBalance(address user, address market) external view returns (uint256);

    function isMarketListed(address market) external view returns (bool);

    function getExchangeRate(address market) external view returns (uint256);

    function getTotalSupply(address market) external view returns (uint256);

    function getTotalBorrow(address market) external view returns (uint256);

    function getTotalCash(address market) external view returns (uint256);

    function getTotalReserves(address market) external view returns (uint256);

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

    function isAllowedExtension(address user, address extension) external view returns (bool);

    function transferAToken(address market, address from, address to, uint256 amount) external;

    function setSubAccountExtension(address primary, uint256 subAccountId, bool allowed) external;

    /* ========== MARKET CONFIGURATOR INTERFACES ========== */

    function getMarketConfiguration(address market) external view returns (DataTypes.MarketConfig memory);

    function listMarket(address market, DataTypes.MarketConfig calldata config) external;

    function delistMarket(address market) external;

    function setMarketConfiguration(address market, DataTypes.MarketConfig calldata config) external;

    /* ========== CREDIT LIMIT MANAGER INTERFACES ========== */

    function getCreditLimit(address user, address market) external view returns (uint256);

    function getUserCreditMarkets(address user) external view returns (address[] memory);

    function isCreditAccount(address user) external view returns (bool);

    function setCreditLimit(address user, address market, uint256 credit) external;

    /* ========== RESERVE MANAGER INTERFACES ========== */

    function absorbToReserves(address market) external;

    function reduceReserves(address market, uint256 aTokenAmount, address recipient) external;
}

File 10 of 29 : IAToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IAToken {
    function mint(address account, uint256 amount) external;

    function burn(address account, uint256 amount) external;

    function seize(address from, address to, uint256 amount) external;

    function asset() external view returns (address);
}

File 11 of 29 : IDeferLiquidityCheck.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IDeferLiquidityCheck {
    /**
     * @dev The callback function that deferLiquidityCheck will invoke.
     * @param data The arbitrary data that was passed in by the caller
     */
    function onDeferredLiquidityCheck(bytes memory data) external;
}

File 12 of 29 : IInterestRateModel.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IInterestRateModel {
    function getUtilization(uint256 cash, uint256 borrow) external pure returns (uint256);

    function getBorrowRate(uint256 cash, uint256 borrow) external view returns (uint256);

    function getSupplyRate(uint256 cash, uint256 borrow) external view returns (uint256);
}

File 13 of 29 : IPriceOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IPriceOracle {
    function getPrice(address asset) external view returns (uint256);
}

File 14 of 29 : IPToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

interface IPToken is IERC20 {
    function getUnderlying() external view returns (address);

    function wrap(uint256 amount) external;

    function unwrap(uint256 amount) external;

    function absorb(address user) external;
}

File 15 of 29 : Arrays.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library Arrays {
    /**
     * @dev Delete an element from an array.
     * @param self The array to delete from
     * @param element The element to delete
     */
    function deleteElement(address[] storage self, address element) internal {
        uint256 count = self.length;
        for (uint256 i = 0; i < count;) {
            if (self[i] == element) {
                if (i != count - 1) {
                    self[i] = self[count - 1];
                }
                self.pop();
                break;
            }

            unchecked {
                i++;
            }
        }
    }
}

File 16 of 29 : DataTypes.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library DataTypes {
    struct UserBorrow {
        uint256 borrowBalance;
        uint256 borrowIndex;
    }

    struct MarketConfig {
        // 1 + 1 + 2 + 2 + 2 + 2 + 1 + 1 = 12
        bool isListed;
        uint8 pauseFlags;
        uint16 collateralFactor;
        uint16 liquidationThreshold;
        uint16 liquidationBonus;
        uint16 reserveFactor;
        bool isPToken;
        bool isDelisted;
        // 20 + 20 + 20 + 32 + 32 + 32
        address aTokenAddress;
        address debtTokenAddress;
        address interestRateModelAddress;
        uint256 supplyCap;
        uint256 borrowCap;
        uint256 initialExchangeRate;
    }

    struct Market {
        MarketConfig config;
        uint40 lastUpdateTimestamp;
        uint256 totalCash;
        uint256 totalBorrow;
        uint256 totalSupply;
        uint256 totalReserves;
        uint256 borrowIndex;
        mapping(address => UserBorrow) userBorrows;
        mapping(address => uint256) userSupplies;
    }
}

File 17 of 29 : PauseFlags.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./DataTypes.sol";

library PauseFlags {
    /// @dev Mask for specific actions in the pause flag bit array
    uint8 internal constant PAUSE_SUPPLY_MASK = 0xFE;
    uint8 internal constant PAUSE_BORROW_MASK = 0xFD;
    uint8 internal constant PAUSE_TRANSFER_MASK = 0xFB;

    /// @dev Offsets for specific actions in the pause flag bit array
    uint8 internal constant PAUSE_SUPPLY_OFFSET = 0;
    uint8 internal constant PAUSE_BORROW_OFFSET = 1;
    uint8 internal constant PAUSE_TRANSFER_OFFSET = 2;

    /// @dev Sets the market supply paused.
    function setSupplyPaused(DataTypes.MarketConfig memory self, bool paused) internal pure {
        self.pauseFlags = (self.pauseFlags & PAUSE_SUPPLY_MASK) | (toUInt8(paused) << PAUSE_SUPPLY_OFFSET);
    }

    /// @dev Returns true if the market supply is paused, and false otherwise.
    function isSupplyPaused(DataTypes.MarketConfig memory self) internal pure returns (bool) {
        return toBool(self.pauseFlags & ~PAUSE_SUPPLY_MASK);
    }

    /// @dev Sets the market borrow paused.
    function setBorrowPaused(DataTypes.MarketConfig memory self, bool paused) internal pure {
        self.pauseFlags = (self.pauseFlags & PAUSE_BORROW_MASK) | (toUInt8(paused) << PAUSE_BORROW_OFFSET);
    }

    /// @dev Returns true if the market borrow is paused, and false otherwise.
    function isBorrowPaused(DataTypes.MarketConfig memory self) internal pure returns (bool) {
        return toBool(self.pauseFlags & ~PAUSE_BORROW_MASK);
    }

    /// @dev Sets the market transfer paused.
    function setTransferPaused(DataTypes.MarketConfig memory self, bool paused) internal pure {
        self.pauseFlags = (self.pauseFlags & PAUSE_TRANSFER_MASK) | (toUInt8(paused) << PAUSE_TRANSFER_OFFSET);
    }

    /// @dev Returns true if the market transfer is paused, and false otherwise.
    function isTransferPaused(DataTypes.MarketConfig memory self) internal pure returns (bool) {
        return toBool(self.pauseFlags & ~PAUSE_TRANSFER_MASK);
    }

    /// @dev Casts a boolean to uint8.
    function toUInt8(bool x) internal pure returns (uint8) {
        return x ? 1 : 0;
    }

    /// @dev Casts a uint8 to boolean.
    function toBool(uint8 x) internal pure returns (bool) {
        return x != 0;
    }
}

File 18 of 29 : SubAccounts.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library SubAccounts {
    function getSubAccount(address primary, uint256 subAccountId) internal pure returns (address) {
        require(subAccountId < 256, "invalid sub account id");
        return address(uint160(primary) ^ uint160(subAccountId));
    }

    function isSubAccountOf(address subAccount, address primary) internal pure returns (bool) {
        return (uint160(primary) | 0xFF) == (uint160(subAccount) | 0xFF);
    }
}

File 19 of 29 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 20 of 29 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 21 of 29 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 22 of 29 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 23 of 29 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 24 of 29 : ERC1967UpgradeUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 25 of 29 : Constants.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

abstract contract Constants {
    uint256 internal constant INITIAL_BORROW_INDEX = 1e18;
    uint256 internal constant INITIAL_EXCHANGE_RATE = 1e18;
    uint256 internal constant FACTOR_SCALE = 10000;

    uint16 internal constant MAX_COLLATERAL_FACTOR = 9000; // 90%
    uint16 internal constant MAX_LIQUIDATION_THRESHOLD = 10000; // 100%
    uint16 internal constant MIN_LIQUIDATION_BONUS = 10000; // 100%
    uint16 internal constant MAX_LIQUIDATION_BONUS = 12500; // 125%
    uint16 internal constant MAX_LIQUIDATION_THRESHOLD_X_BONUS = 10000; // 100%
    uint16 internal constant MAX_RESERVE_FACTOR = 10000; // 100%

    uint8 internal constant LIQUIDITY_CHECK_NORMAL = 0;
    uint8 internal constant LIQUIDITY_CHECK_DEFERRED = 1;
    uint8 internal constant LIQUIDITY_CHECK_DIRTY = 2;
}

File 26 of 29 : Events.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../libraries/DataTypes.sol";

abstract contract Events {
    event MarketConfiguratorSet(address configurator);

    event CreditLimitManagerSet(address manager);

    event ReserveManagerSet(address manager);

    event CreditLimitChanged(address indexed user, address indexed market, uint256 credit);

    event PriceOracleSet(address priceOracle);

    event MarketListed(address indexed market, uint40 timestamp, DataTypes.MarketConfig config);

    event MarketDelisted(address indexed market);

    event MarketConfigurationChanged(address indexed market, DataTypes.MarketConfig config);

    event MarketEntered(address indexed market, address indexed user);

    event MarketExited(address indexed market, address indexed user);

    event InterestAccrued(
        address indexed market,
        uint40 timestamp,
        uint256 borrowRatePerSecond,
        uint256 borrowIndex,
        uint256 totalBorrow,
        uint256 totalReserves
    );

    event Supply(
        address indexed market, address indexed from, address indexed to, uint256 amount, uint256 aTokenAmount
    );

    event Borrow(
        address indexed market,
        address indexed from,
        address indexed to,
        uint256 amount,
        uint256 accountBorrow,
        uint256 totalBorrow
    );

    event Redeem(
        address indexed market, address indexed from, address indexed to, uint256 amount, uint256 aTokenAmount
    );

    event Repay(
        address indexed market,
        address indexed from,
        address indexed to,
        uint256 amount,
        uint256 accountBorrow,
        uint256 totalBorrow
    );

    event Liquidate(
        address indexed liquidator,
        address indexed borrower,
        address indexed marketBorrow,
        address marketCollateral,
        uint256 repayAmount,
        uint256 seizedAmount
    );

    event TransferAToken(address indexed market, address indexed from, address indexed to, uint256 aTokenAmount);

    event TokenSeized(address indexed token, address indexed recipient, uint256 amount);

    event ReservesIncreased(address indexed market, uint256 aTokenAmount, uint256 amount);

    event ReservesDecreased(address indexed market, address indexed recipient, uint256 aTokenAmount, uint256 amount);

    event ExtensionAdded(address indexed account, address indexed extension);

    event ExtensionRemoved(address indexed account, address indexed extension);
}

File 27 of 29 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 28 of 29 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 29 of 29 : StorageSlotUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrow","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrow","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"credit","type":"uint256"}],"name":"CreditLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"CreditLimitManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"extension","type":"address"}],"name":"ExtensionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"extension","type":"address"}],"name":"ExtensionRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint40","name":"timestamp","type":"uint40"},{"indexed":false,"internalType":"uint256","name":"borrowRatePerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalReserves","type":"uint256"}],"name":"InterestAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":true,"internalType":"address","name":"marketBorrow","type":"address"},{"indexed":false,"internalType":"address","name":"marketCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"seizedAmount","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"components":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"pauseFlags","type":"uint8"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationBonus","type":"uint16"},{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"bool","name":"isPToken","type":"bool"},{"internalType":"bool","name":"isDelisted","type":"bool"},{"internalType":"address","name":"aTokenAddress","type":"address"},{"internalType":"address","name":"debtTokenAddress","type":"address"},{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"uint256","name":"supplyCap","type":"uint256"},{"internalType":"uint256","name":"borrowCap","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"}],"indexed":false,"internalType":"struct DataTypes.MarketConfig","name":"config","type":"tuple"}],"name":"MarketConfigurationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"configurator","type":"address"}],"name":"MarketConfiguratorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"}],"name":"MarketDelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint40","name":"timestamp","type":"uint40"},{"components":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"pauseFlags","type":"uint8"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationBonus","type":"uint16"},{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"bool","name":"isPToken","type":"bool"},{"internalType":"bool","name":"isDelisted","type":"bool"},{"internalType":"address","name":"aTokenAddress","type":"address"},{"internalType":"address","name":"debtTokenAddress","type":"address"},{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"uint256","name":"supplyCap","type":"uint256"},{"internalType":"uint256","name":"borrowCap","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"}],"indexed":false,"internalType":"struct DataTypes.MarketConfig","name":"config","type":"tuple"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"priceOracle","type":"address"}],"name":"PriceOracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"aTokenAmount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrow","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrow","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"ReserveManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"aTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReservesDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"aTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReservesIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"aTokenAmount","type":"uint256"}],"name":"Supply","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenSeized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"aTokenAmount","type":"uint256"}],"name":"TransferAToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"absorbToReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"allAllowedExtensions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"allCreditMarkets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"allEnteredMarkets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowedExtensions","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"marketBorrow","type":"address"},{"internalType":"address","name":"marketCollateral","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"calculateLiquidationOpportunity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkAccountLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creditLimitManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"creditLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"deferLiquidityCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"delistMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"enteredMarkets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"market","type":"address"}],"name":"getATokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"market","type":"address"}],"name":"getBorrowBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"market","type":"address"}],"name":"getCreditLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getMarketConfiguration","outputs":[{"components":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"pauseFlags","type":"uint8"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationBonus","type":"uint16"},{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"bool","name":"isPToken","type":"bool"},{"internalType":"bool","name":"isDelisted","type":"bool"},{"internalType":"address","name":"aTokenAddress","type":"address"},{"internalType":"address","name":"debtTokenAddress","type":"address"},{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"uint256","name":"supplyCap","type":"uint256"},{"internalType":"uint256","name":"borrowCap","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"}],"internalType":"struct DataTypes.MarketConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"market","type":"address"}],"name":"getSupplyBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getTotalBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getTotalCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getTotalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserAllowedExtensions","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserCreditMarkets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"extension","type":"address"}],"name":"isAllowedExtension","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isCreditAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"isMarketListed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isUserLiquidatable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"marketBorrow","type":"address"},{"internalType":"address","name":"marketCollateral","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidityCheckStatus","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"components":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"pauseFlags","type":"uint8"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationBonus","type":"uint16"},{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"bool","name":"isPToken","type":"bool"},{"internalType":"bool","name":"isDelisted","type":"bool"},{"internalType":"address","name":"aTokenAddress","type":"address"},{"internalType":"address","name":"debtTokenAddress","type":"address"},{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"uint256","name":"supplyCap","type":"uint256"},{"internalType":"uint256","name":"borrowCap","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"}],"internalType":"struct DataTypes.MarketConfig","name":"config","type":"tuple"}],"name":"listMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketConfigurator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"components":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"pauseFlags","type":"uint8"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationBonus","type":"uint16"},{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"bool","name":"isPToken","type":"bool"},{"internalType":"bool","name":"isDelisted","type":"bool"},{"internalType":"address","name":"aTokenAddress","type":"address"},{"internalType":"address","name":"debtTokenAddress","type":"address"},{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"uint256","name":"supplyCap","type":"uint256"},{"internalType":"uint256","name":"borrowCap","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"}],"internalType":"struct DataTypes.MarketConfig","name":"config","type":"tuple"},{"internalType":"uint40","name":"lastUpdateTimestamp","type":"uint40"},{"internalType":"uint256","name":"totalCash","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalReserves","type":"uint256"},{"internalType":"uint256","name":"borrowIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"aTokenAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"reduceReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"seize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"credit","type":"uint256"}],"name":"setCreditLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"setCreditLimitManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"components":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"pauseFlags","type":"uint8"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationBonus","type":"uint16"},{"internalType":"uint16","name":"reserveFactor","type":"uint16"},{"internalType":"bool","name":"isPToken","type":"bool"},{"internalType":"bool","name":"isDelisted","type":"bool"},{"internalType":"address","name":"aTokenAddress","type":"address"},{"internalType":"address","name":"debtTokenAddress","type":"address"},{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"uint256","name":"supplyCap","type":"uint256"},{"internalType":"uint256","name":"borrowCap","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"}],"internalType":"struct DataTypes.MarketConfig","name":"config","type":"tuple"}],"name":"setMarketConfiguration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"configurator","type":"address"}],"name":"setMarketConfigurator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"}],"name":"setPriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"setReserveManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"primary","type":"address"},{"internalType":"uint256","name":"subAccountId","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setSubAccountExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"extension","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setUserExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"supply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]

Deployed Bytecode

0x6080604052600436106103b85760003560e01c80638da5cb5b116101f2578063c2a544811161010d578063df7da754116100a0578063efb7601d1161006f578063efb7601d14610f5d578063f2fde38b14610f7d578063fcc0c68014610f9d578063fe1e50a314610fbd57600080fd5b8063df7da75414610edf578063dfd5265b14610eff578063e1fb436814610f1f578063e30c397814610f3f57600080fd5b8063cdb66f7c116100dc578063cdb66f7c14610e5f578063d1456d4f14610e7f578063d49f8be014610e9f578063d82ecc4814610ebf57600080fd5b8063c2a5448114610ddf578063c2cc27a614610dff578063c4109c0114610e1f578063c4d66de814610e3f57600080fd5b8063b0772d0b11610185578063bb004abc11610154578063bb004abc14610d5e578063bc15830d14610d7f578063be88ea3214610d9f578063c035bd2114610dbf57600080fd5b8063b0772d0b14610ce9578063b666d84b14610cfe578063ba036b4014610d1e578063ba37773114610d3e57600080fd5b80639b990d72116101c15780639b990d7214610c3b5780639f9f794f14610c74578063a928fe1014610c94578063afef7efd14610cc957600080fd5b80638da5cb5b14610a925780638e8f294b14610ab05780639198e51514610bfa5780639414efc714610c1a57600080fd5b80634f1ef286116102e25780636da82584116102755780637e982c4b116102445780637e982c4b146109ba5780638538d14e146109f657806389b7b7a614610a2f5780638b4f33ee14610a4f57600080fd5b80636da82584146109435780636e64684714610970578063715018a61461099057806379ba5097146109a557600080fd5b80635a208d52116102b15780635a208d52146106ff5780635db22de6146108885780635ec88c79146108cf57806368da10ae1461090a57600080fd5b80634f1ef2861461069757806352d1902d146106aa57806352d84d1e146106bf578063530e784f146106df57600080fd5b80632630c12f1161035a57806341d15f6d1161032957806341d15f6d146105d25780634492ba9e146105f25780634ac511891461063c5780634e05cbb31461065c57600080fd5b80632630c12f146105285780633659cfe6146105495780633a1181d9146105695780633d98a1e51461058957600080fd5b8063118e31b711610396578063118e31b714610464578063178de7eb146104845780631a7370cc146104bd578063203660df146104dd57600080fd5b80630445254d146103bd578063050e570514610409578063107c8ed714610442575b600080fd5b3480156103c957600080fd5b506103f66103d8366004614f1d565b61010260209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561041557600080fd5b506103f6610424366004614f56565b6001600160a01b0316600090815260fc60205260409020600a015490565b34801561044e57600080fd5b5061046261045d366004614f73565b610fdd565b005b34801561047057600080fd5b506103f661047f366004614f1d565b611402565b34801561049057600080fd5b50610107546104a5906001600160a01b031681565b6040516001600160a01b039091168152602001610400565b3480156104c957600080fd5b506104a56104d8366004614fc4565b61142e565b3480156104e957600080fd5b506103f66104f8366004614f1d565b6001600160a01b03808216600090815260fc602090815260408083209386168352600d9093019052205492915050565b34801561053457600080fd5b50610105546104a5906001600160a01b031681565b34801561055557600080fd5b50610462610564366004614f56565b611467565b34801561057557600080fd5b50610462610584366004614ff0565b611547565b34801561059557600080fd5b506105c26105a4366004614f56565b6001600160a01b0316600090815260fc602052604090205460ff1690565b6040519015158152602001610400565b3480156105de57600080fd5b506103f66105ed366004615033565b6115bc565b3480156105fe57600080fd5b506105c261060d366004614f1d565b6001600160a01b0391821660009081526101006020908152604080832093909416825291909152205460ff1690565b34801561064857600080fd5b50610462610657366004614f56565b6115ee565b34801561066857600080fd5b506105c2610677366004614f1d565b60fe60209081526000928352604080842090915290825290205460ff1681565b6104626106a536600461508a565b61164c565b3480156106b657600080fd5b506103f661171d565b3480156106cb57600080fd5b506104a56106da36600461514e565b6117d0565b3480156106eb57600080fd5b506104626106fa366004614f56565b6117fa565b34801561070b57600080fd5b5061087b61071a366004614f56565b604080516101c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a0810191909152506001600160a01b03908116600090815260fc602090815260409182902082516101c081018452815460ff8082161515835261010080830482169584019590955261ffff620100008304811696840196909652600160201b820486166060840152600160301b820486166080840152600160401b820490951660a0830152600160501b81048516151560c0830152600160581b8104909416151560e0820152600160601b909304841691830191909152600181015483166101208301526002810154909216610140820152600382015461016082015260048201546101808201526005909101546101a082015290565b6040516104009190615258565b34801561089457600080fd5b506103f66108a3366004614f1d565b6001600160a01b0391821660009081526101026020908152604080832093909416825291909152205490565b3480156108db57600080fd5b506108ef6108ea366004614f56565b611851565b60408051938452602084019290925290820152606001610400565b34801561091657600080fd5b506103f6610925366004614f56565b6001600160a01b0316600090815260fc602052604090206009015490565b34801561094f57600080fd5b5061096361095e366004614f56565b61186c565b6040516104009190615267565b34801561097c57600080fd5b5061046261098b366004614f56565b6118e3565b34801561099c57600080fd5b506104626118ec565b3480156109b157600080fd5b50610462611900565b3480156109c657600080fd5b506105c26109d5366004614f1d565b61010060209081526000928352604080842090915290825290205460ff1681565b348015610a0257600080fd5b506103f6610a11366004614f56565b6001600160a01b0316600090815260fc602052604090206008015490565b348015610a3b57600080fd5b50610462610a4a36600461508a565b611977565b348015610a5b57600080fd5b50610a80610a6a366004614f56565b6101046020526000908152604090205460ff1681565b60405160ff9091168152602001610400565b348015610a9e57600080fd5b506097546001600160a01b03166104a5565b348015610abc57600080fd5b50610be7610acb366004614f56565b60fc6020908152600091825260409182902082516101c081018452815460ff8082161515835261010080830482169584019590955262010000820461ffff90811696840196909652600160201b820486166060840152600160301b820486166080840152600160401b820490951660a0830152600160501b81048516151560c0830152600160581b8104909416151560e0820152600160601b9093046001600160a01b03908116928401929092526001810154821661012084015260028101549091166101408301526003810154610160830152600481015461018083015260058101546101a08301526006810154600782015460088301546009840154600a850154600b9095015464ffffffffff9094169492939192909187565b60405161040097969594939291906152b4565b348015610c0657600080fd5b50610462610c15366004614f56565b611b07565b348015610c2657600080fd5b50610106546104a5906001600160a01b031681565b348015610c4757600080fd5b506103f6610c56366004614f56565b6001600160a01b0316600090815260fc602052604090206007015490565b348015610c8057600080fd5b50610462610c8f366004615319565b611b4a565b348015610ca057600080fd5b50610cb4610caf36600461535b565b611b7e565b60408051928352602083019190915201610400565b348015610cd557600080fd5b50610462610ce4366004614f73565b611ef7565b348015610cf557600080fd5b506109636122c8565b348015610d0a57600080fd5b50610462610d19366004614f56565b61232a565b348015610d2a57600080fd5b506103f6610d39366004614f73565b6123a6565b348015610d4a57600080fd5b506103f6610d59366004614f1d565b61268c565b348015610d6a57600080fd5b50610108546104a5906001600160a01b031681565b348015610d8b57600080fd5b50610462610d9a3660046153bf565b6126e5565b348015610dab57600080fd5b506104a5610dba366004614fc4565b6126f0565b348015610dcb57600080fd5b506103f6610dda366004614f73565b61270d565b348015610deb57600080fd5b50610462610dfa366004614f56565b612800565b348015610e0b57600080fd5b50610462610e1a366004614ff0565b612857565b348015610e2b57600080fd5b50610462610e3a366004614f56565b612946565b348015610e4b57600080fd5b50610462610e5a366004614f56565b612abc565b348015610e6b57600080fd5b50610963610e7a366004614f56565b612bde565b348015610e8b57600080fd5b50610462610e9a3660046153ed565b612c53565b348015610eab57600080fd5b506104a5610eba366004614fc4565b612dbf565b348015610ecb57600080fd5b506105c2610eda366004614f56565b612ddb565b348015610eeb57600080fd5b50610462610efa366004614f56565b612df9565b348015610f0b57600080fd5b50610462610f1a366004614f73565b612e50565b348015610f2b57600080fd5b506105c2610f3a366004614f56565b6130cc565b348015610f4b57600080fd5b5060c9546001600160a01b03166104a5565b348015610f6957600080fd5b506103f6610f78366004614f56565b6130d7565b348015610f8957600080fd5b50610462610f98366004614f56565b6130f8565b348015610fa957600080fd5b50610462610fb8366004614f1d565b613169565b348015610fc957600080fd5b50610462610fd8366004615033565b6132b5565b610fe5613466565b83610ff081336134c0565b6001600160a01b038316600090815260fc60205260409020805460ff166110325760405162461bcd60e51b815260040161102990615424565b60405180910390fd5b604080516101c081018252825460ff808216151583526101008083048216602085015261ffff620100008404811695850195909552600160201b830485166060850152600160301b830485166080850152600160401b830490941660a0840152600160501b82048116151560c0840152600160581b820416151560e08301526001600160a01b03600160601b9091048116928201929092526001830154821661012082015260028301549091166101408201526003820154610160820152600482015461018082015260058201546101a082015261110f90613551565b1561114c5760405162461bcd60e51b815260206004820152600d60248201526c1cdd5c1c1b1e481c185d5cd959609a1b6044820152606401611029565b61115585612ddb565b156111a25760405162461bcd60e51b815260206004820152601f60248201527f63616e6e6f7420737570706c7920746f20637265646974206163636f756e74006044820152606401611029565b6111ac8482613563565b60038101541561123a576000670de0b6b3a76400006111ca836137a7565b83600901546111d9919061545e565b6111e3919061547d565b60038301549091506111f5858361549f565b11156112385760405162461bcd60e51b81526020600482015260126024820152711cdd5c1c1b1e4818d85c081c995858da195960721b6044820152606401611029565b505b6000611245826137a7565b61125785670de0b6b3a764000061545e565b611261919061547d565b9050600081116112a85760405162461bcd60e51b81526020600482015260126024820152711e995c9bc818551bdad95b88185b5bdd5b9d60721b6044820152606401611029565b838260070160008282546112bc919061549f565b92505081905550808260090160008282546112d7919061549f565b90915550506001600160a01b0386166000908152600d830160205260409020805482019055831561130c5761130c85876137ff565b81546040516340c10f1960e01b81526001600160a01b03888116600483015260248201849052600160601b909204909116906340c10f1990604401600060405180830381600087803b15801561136157600080fd5b505af1158015611375573d6000803e3d6000fd5b5061138f925050506001600160a01b0386168830876138bc565b856001600160a01b0316876001600160a01b0316866001600160a01b03167fe751baae971614714a5055ecbc0892f68c0e2d70c56550cb65a76bc840fa5f6e87856040516113e7929190918252602082015260400190565b60405180910390a45050506113fc600160fb55565b50505050565b6001600160a01b038116600090815260fc602052604081206114248185613927565b9150505b92915050565b610101602052816000526040600020818154811061144b57600080fd5b6000918252602090912001546001600160a01b03169150829050565b306001600160a01b037f00000000000000000000000014f1909cf228dcc36d4a2d5eab1345229a964f611614156114b05760405162461bcd60e51b8152600401611029906154b7565b7f00000000000000000000000014f1909cf228dcc36d4a2d5eab1345229a964f616001600160a01b03166114f9600080516020615bad833981519152546001600160a01b031690565b6001600160a01b03161461151f5760405162461bcd60e51b815260040161102990615503565b61152881613983565b604080516000808252602082019092526115449183919061398b565b50565b61154f613af6565b6001600160a01b038216600090815260fc60205260409020818161157382826155c2565b905050826001600160a01b03167fdcd3ac9b517302fa7d6db6d2ae9265b3d65ccc4d3030130620d7a1701b74b2a4836040516115af91906157c4565b60405180910390a2505050565b6001600160a01b038216600090815260fc60205260408120806115e28686838088613b41565b925050505b9392505050565b6115f6613bd8565b61010680546001600160a01b0319166001600160a01b0383169081179091556040519081527fdca89ce6f30fe0a23d88a5467a028ce35ba1b7b5b8d9e9e50dbc151fe55c82ad906020015b60405180910390a150565b306001600160a01b037f00000000000000000000000014f1909cf228dcc36d4a2d5eab1345229a964f611614156116955760405162461bcd60e51b8152600401611029906154b7565b7f00000000000000000000000014f1909cf228dcc36d4a2d5eab1345229a964f616001600160a01b03166116de600080516020615bad833981519152546001600160a01b031690565b6001600160a01b0316146117045760405162461bcd60e51b815260040161102990615503565b61170d82613983565b6117198282600161398b565b5050565b6000306001600160a01b037f00000000000000000000000014f1909cf228dcc36d4a2d5eab1345229a964f6116146117bd5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401611029565b50600080516020615bad83398151915290565b60fd81815481106117e057600080fd5b6000918252602090912001546001600160a01b0316905081565b611802613bd8565b61010580546001600160a01b0319166001600160a01b0383169081179091556040519081527f6536690106168bdf4ba72c128a053d817999b1db90cae23f139b293bf862cb7590602001611641565b600080600061185f84613c32565b9250925092509193909250565b6001600160a01b038116600090815261010360209081526040918290208054835181840281018401909452808452606093928301828280156118d757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116118b9575b50505050509050919050565b61154481613e9c565b6118f4613bd8565b6118fe6000613f53565b565b60c95433906001600160a01b0316811461196e5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401611029565b61154481613f53565b8161198281336134c0565b61198b83612ddb565b156119ec5760405162461bcd60e51b815260206004820152602b60248201527f637265646974206163636f756e742063616e6e6f74206465666572206c69717560448201526a696469747920636865636b60a81b6064820152608401611029565b6001600160a01b0383166000908152610104602052604090205460ff1615611a565760405162461bcd60e51b815260206004820152601d60248201527f7265656e747279206465666572206c697175696469747920636865636b0000006044820152606401611029565b6001600160a01b0383166000908152610104602052604090819020805460ff191660011790555163a15db5c560e01b8152339063a15db5c590611a9d90859060040161593b565b600060405180830381600087803b158015611ab757600080fd5b505af1158015611acb573d6000803e3d6000fd5b505050506001600160a01b038316600090815261010460205260409020805460ff19811690915560ff1660028114156113fc576113fc84613e9c565b6001600160a01b038116600090815260fc60205260409020805460ff16611b405760405162461bcd60e51b815260040161102990615424565b6117198282613563565b82611b5581336134c0565b6000611b6a6001600160a01b03861685613f6c565b9050611b77813385613fbd565b5050505050565b600080611b89613466565b86611b9481336134c0565b6001600160a01b03808716600090815260fc602052604080822092881682529020815460ff16611c065760405162461bcd60e51b815260206004820152601860248201527f626f72726f77206d61726b6574206e6f74206c697374656400000000000000006044820152606401611029565b805460ff16611c575760405162461bcd60e51b815260206004820152601c60248201527f636f6c6c61746572616c206d61726b6574206e6f74206c6973746564000000006044820152606401611029565b611c6081614143565b611cb75760405162461bcd60e51b815260206004820152602260248201527f636f6c6c61746572616c206d61726b65742063616e6e6f74206265207365697a604482015261195960f21b6064820152608401611029565b611cc08a612ddb565b158015611cd35750611cd189612ddb565b155b611d1f5760405162461bcd60e51b815260206004820152601f60248201527f63616e6e6f74206c697175696461746520637265646974206163636f756e74006044820152606401611029565b886001600160a01b03168a6001600160a01b03161415611d795760405162461bcd60e51b815260206004820152601560248201527463616e6e6f742073656c66206c697175696461746560581b6044820152606401611029565b611d838883613563565b611d8d8782613563565b611d968961423d565b611de25760405162461bcd60e51b815260206004820152601960248201527f626f72726f776572206e6f74206c6971756964617461626c65000000000000006044820152606401611029565b611def828b8b8b8a614255565b95506000611e00898985858b613b41565b9050611e0f88838c8e856143b6565b815460405163b2a02ff160e01b81526001600160a01b038c811660048301528d8116602483015260448201849052600160601b9092049091169063b2a02ff190606401600060405180830381600087803b158015611e6c57600080fd5b505af1158015611e80573d6000803e3d6000fd5b5050604080516001600160a01b038c81168252602082018c9052918101859052818d1693508d82169250908e16907fac8bbd8fb7420b3123cf9e24d34551e40514ea69c5a1e97c10e513aaf06e7e429060600160405180910390a48695509350505050611eed600160fb55565b9550959350505050565b611eff613466565b83611f0a81336134c0565b6001600160a01b038316600090815260fc60205260409020805460ff16611f435760405162461bcd60e51b815260040161102990615424565b604080516101c081018252825460ff808216151583526101008083048216602085015261ffff620100008404811695850195909552600160201b830485166060850152600160301b830485166080850152600160401b830490941660a0840152600160501b82048116151560c0840152600160581b820416151560e08301526001600160a01b03600160601b9091048116928201929092526001830154821661012082015260028301549091166101408201526003820154610160820152600482015461018082015260058201546101a0820152612020906145cd565b1561205d5760405162461bcd60e51b815260206004820152600d60248201526c189bdc9c9bddc81c185d5cd959609a1b6044820152606401611029565b82816007015410156120815760405162461bcd60e51b81526004016110299061594e565b61208b8482613563565b600083826008015461209d919061549f565b90506000846120ac848a613927565b600485015491019150156121035760048301548211156121035760405162461bcd60e51b8152602060048201526012602482015271189bdc9c9bddc818d85c081c995858da195960721b6044820152606401611029565b6007830180548690039055600883018290556001600160a01b0388166000908152600c840160205260409020818155600b84015460019190910155841561214e5761214e86896137ff565b6121626001600160a01b03871688876145df565b61216b88612ddb565b1561225d57866001600160a01b0316886001600160a01b0316146121e25760405162461bcd60e51b815260206004820152602860248201527f637265646974206163636f756e742063616e206f6e6c7920626f72726f772074604482015267379034ba39b2b63360c11b6064820152608401611029565b6001600160a01b03808916600090815261010260209081526040808320938a16835292905220548111156122585760405162461bcd60e51b815260206004820152601960248201527f696e73756666696369656e7420637265646974206c696d6974000000000000006044820152606401611029565b612266565b61226688613e9c565b60408051868152602081018390529081018390526001600160a01b03808916918a8216918916907f4bc4b08d677fc59195d56e346dcb5cc5dc3b78b90d59f5d36740ae1b3d225db89060600160405180910390a4505050506113fc600160fb55565b606060fd80548060200260200160405190810160405280929190818152602001828054801561232057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612302575b5050505050905090565b612332613af6565b6001600160a01b038116600090815260fc6020526040902080546bff00000000000000000000ff1916600160581b17815561236e60fd8361460f565b6040516001600160a01b038316907f9710c341258431a6380fd1febe8985e6b6221e8398c287ea971f2ba85a6e1a1090600090a25050565b60006123b0613466565b846123bb81336134c0565b6001600160a01b038416600090815260fc60205260409020805460ff166123f45760405162461bcd60e51b815260040161102990615424565b6123fe8582613563565b6001600160a01b0387166000908152600d8201602052604081205460078301549091600019871415612459575081670de0b6b3a764000061243e856137a7565b612448908361545e565b612452919061547d565b9650612481565b612462846137a7565b61247488670de0b6b3a764000061545e565b61247e919061547d565b90505b600081116124c65760405162461bcd60e51b81526020600482015260126024820152711e995c9bc818551bdad95b88185b5bdd5b9d60721b6044820152606401611029565b8083101561250d5760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401611029565b8682101561252d5760405162461bcd60e51b81526004016110299061594e565b6001600160a01b038a166000908152600d850160205260409020818403908190558783036007860155600985018054839003905583821480156125775750612575858c613927565b155b1561258657612586898c61471e565b8454604051632770a7eb60e21b81526001600160a01b038d8116600483015260248201859052600160601b90920490911690639dc29fac90604401600060405180830381600087803b1580156125db57600080fd5b505af11580156125ef573d6000803e3d6000fd5b50612608925050506001600160a01b038a168b8a6145df565b6126118b613e9c565b896001600160a01b03168b6001600160a01b03168a6001600160a01b03167faee47cdf925cf525fdae94f9777ee5a06cac37e1c41220d0a8a89ed154f62d1c8b86604051612669929190918252602082015260400190565b60405180910390a4879650505050505050612684600160fb55565b949350505050565b6001600160a01b038116600090815260fc60205260408120670de0b6b3a76400006126b6826137a7565b6001600160a01b0386166000908152600d840160205260409020546126db919061545e565b611424919061547d565b611719338383613fbd565b610103602052816000526040600020818154811061144b57600080fd5b6000612717613466565b8461272281336134c0565b6001600160a01b038416600090815260fc60205260409020805460ff1661275b5760405162461bcd60e51b815260040161102990615424565b61276486612ddb565b156127db57856001600160a01b0316876001600160a01b0316146127db5760405162461bcd60e51b815260206004820152602860248201527f637265646974206163636f756e742063616e206f6e6c7920726570617920666f604482015267391034ba39b2b63360c11b6064820152608401611029565b6127e58582613563565b6127f28188888888614255565b92505050612684600160fb55565b612808613bd8565b61010780546001600160a01b0319166001600160a01b0383169081179091556040519081527f517371384ca8a07b7ae4697507862b5200ce0a12158170259cebe2cb63d33f3290602001611641565b61285f613af6565b6001600160a01b038216600090815260fc6020526040902061287f6147d5565b60068201805464ffffffffff191664ffffffffff92909216919091179055670de0b6b3a7640000600b82015581816128b782826155c2565b505060fd80546001810182556000919091527f9346ac6dd7de6b96975fec380d4d994c4c12e6a8897544f22915316cc6cca2800180546001600160a01b0319166001600160a01b03851690811790915560068201546040517fbefee0150f4933331fcee3972b8a74be870d590ef30e21f8830c9b2a9d04c987916115af9164ffffffffff909116908590615979565b61294e614827565b6001600160a01b038116600090815260fc60205260409020805460ff166129875760405162461bcd60e51b815260040161102990615424565b6129918282613563565b60078101546040516370a0823160e01b8152306004820152600091906001600160a01b038516906370a0823190602401602060405180830381865afa1580156129de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a029190615a6e565b612a0c9190615a87565b90508015612ab7576000612a1f836137a7565b612a3183670de0b6b3a764000061545e565b612a3b919061547d565b905081836007016000828254612a51919061549f565b925050819055508083600a016000828254612a6c919061549f565b909155505060408051828152602081018490526001600160a01b038616917fe08e52dead7793dd3e1f1b8c081a9d196fb9a1f26939c240e3660e9badd466b3910160405180910390a2505b505050565b600054610100900460ff1615808015612adc5750600054600160ff909116105b80612af65750303b158015612af6575060005460ff166001145b612b595760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611029565b6000805460ff191660011790558015612b7c576000805461ff0019166101001790555b612b84614874565b612b8c6148a3565b612b95826130f8565b8015611719576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6001600160a01b038116600090815261010160209081526040918290208054835181840281018401909452808452606093928301828280156118d7576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116118b95750505050509050919050565b612c5b614827565b6001600160a01b038316600090815260fc60205260409020805460ff16612c945760405162461bcd60e51b815260040161102990615424565b612c9e8482613563565b6000670de0b6b3a7640000612cb2836137a7565b612cbc908661545e565b612cc6919061547d565b90508082600701541015612cec5760405162461bcd60e51b81526004016110299061594e565b8382600a01541015612d385760405162461bcd60e51b8152602060048201526015602482015274696e73756666696369656e7420726573657276657360581b6044820152606401611029565b6007820180548290039055600a820180548590039055612d626001600160a01b03861684836145df565b826001600160a01b0316856001600160a01b03167f85d7d5527903b3bdc93c2e97283c443822adba607371569d40047426532c9c388684604051612db0929190918252602082015260400190565b60405180910390a35050505050565b60ff602052816000526040600020818154811061144b57600080fd5b6001600160a01b031660009081526101036020526040902054151590565b612e01613bd8565b61010880546001600160a01b0319166001600160a01b0383169081179091556040519081527f7e84f9bb34064cde550792818395eb9c2f7766113ce1c301d35c19cbe2e187ac90602001611641565b6001600160a01b038416600090815260fc60205260409020805460ff16612e895760405162461bcd60e51b815260040161102990615424565b8054600160601b90046001600160a01b03163314612ed75760405162461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b6044820152606401611029565b604080516101c081018252825460ff808216151583526101008083048216602085015261ffff620100008404811695850195909552600160201b830485166060850152600160301b830485166080850152600160401b830490941660a0840152600160501b82048116151560c0840152600160581b820416151560e08301526001600160a01b03600160601b9091048116928201929092526001830154821661012082015260028301549091166101408201526003820154610160820152600482015461018082015260058201546101a0820152612fb4906148ca565b15612ff35760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c881c185d5cd959608a1b6044820152606401611029565b826001600160a01b0316846001600160a01b0316141561304c5760405162461bcd60e51b815260206004820152601460248201527331b0b73737ba1039b2b633103a3930b739b332b960611b6044820152606401611029565b61305583612ddb565b156130ac5760405162461bcd60e51b815260206004820152602160248201527f63616e6e6f74207472616e7366657220746f20637265646974206163636f756e6044820152601d60fa1b6064820152608401611029565b6130b68582613563565b6130c385828686866143b6565b611b7784613e9c565b60006114288261423d565b6001600160a01b038116600090815260fc602052604081206115e7816137a7565b613100613bd8565b60c980546001600160a01b0383166001600160a01b031990911681179091556131316097546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b613171613bd8565b6001600160a01b038216600090815260fc60205260409020805460ff16156131db5760405162461bcd60e51b815260206004820152601a60248201527f63616e6e6f74207365697a65206c6973746564206d61726b65740000000000006044820152606401611029565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015613222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132469190615a6e565b905080156113fc576132626001600160a01b03851684836145df565b826001600160a01b0316846001600160a01b03167feac344312e08a6e34d3cb14733c432e8b20995a316e9abf4bc59640dc90d10ca836040516132a791815260200190565b60405180910390a350505050565b610107546001600160a01b031633146132fb5760405162461bcd60e51b815260206004820152600860248201526710b6b0b730b3b2b960c11b6044820152606401611029565b6001600160a01b038216600090815260fc60205260409020805460ff166133345760405162461bcd60e51b815260040161102990615424565b8115801561336757506001600160a01b038085166000908152610102602090815260408083209387168352929052205415155b15613394576001600160a01b03841660009081526101036020526040902061338f908461460f565b61340c565b81158015906133c757506001600160a01b0380851660009081526101026020908152604080832093871683529290522054155b1561340c576001600160a01b038481166000908152610103602090815260408220805460018101825590835291200180546001600160a01b0319169185169190911790555b6001600160a01b038481166000818152610102602090815260408083209488168084529482529182902086905590518581527fd2430896b2083037d8bf873ee97e05de0442c7137b4c9413b9e928f7212869e991016132a7565b600260fb5414156134b95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611029565b600260fb55565b806001600160a01b0316826001600160a01b0316148061351757506134e482612ddb565b15801561351757506001600160a01b038083166000908152610100602090815260408083209385168352929052205460ff165b6117195760405162461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b6044820152606401611029565b60208101516000906001161515611428565b600061356d6147d5565b60068301549091506000906135899064ffffffffff1683615a9e565b64ffffffffff16905080156113fc576007830154600b84015460088501546009860154600a87015460028801546040516329737ea560e21b815260048101879052602481018590526000916001600160a01b03169063a5cdfa9490604401602060405180830381865afa158015613604573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136289190615a6e565b90506000613636888361545e565b90506000670de0b6b3a764000061364d878461545e565b613657919061547d565b8b549091506000906127109061367890600160401b900461ffff168461545e565b613682919061547d565b9050600081156136cb576136968284615a87565b6136a0898c61549f565b6136aa919061549f565b6136b4878961549f565b6136be908461545e565b6136c8919061547d565b90505b670de0b6b3a76400006136de8a8661545e565b6136e8919061547d565b6136f2908a61549f565b98506136fe838961549f565b975061370a818761549f565b60068e01805464ffffffffff191664ffffffffff8f16908117909155600b8f018b905560088f018a9055600a8f01829055604080519182526020820188905281018b9052606081018a9052608081018290529096506001600160a01b038f16907f854365e2056d048a4a9980a18729a7e79f432f9142ee48311a63d7b64e46edeb9060a00160405180910390a25050505050505050505050505050565b60008082600a015483600901546137be919061549f565b9050806137ce5750506005015490565b80836008015484600701546137e3919061549f565b6137f590670de0b6b3a764000061545e565b6115e7919061547d565b6001600160a01b03808216600090815260fe602090815260408083209386168352929052205460ff1615613831575050565b6001600160a01b03808216600081815260fe60209081526040808320948716808452948252808320805460ff1916600190811790915584845260ff835281842080549182018155845291832090910180546001600160a01b03191685179055519192917f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a59190a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526113fc9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148dc565b6001600160a01b0381166000908152600c83016020908152604080832081518083019092528054808352600190910154928201929092529061396d576000915050611428565b6020810151600b85015482516126db919061545e565b611544613bd8565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156139be57612ab7836149ae565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613a18575060408051601f3d908101601f19168201909252613a1591810190615a6e565b60015b613a7b5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401611029565b600080516020615bad8339815191528114613aea5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401611029565b50612ab7838383614a4a565b610106546001600160a01b031633146118fe5760405162461bcd60e51b815260206004820152600d60248201526c10b1b7b73334b3bab930ba37b960991b6044820152606401611029565b600080613b4e8588614a6f565b90506000613b5c8588614a6f565b855490915060009061271090613b7e908590600160301b900461ffff1661545e565b613b88919061547d565b90506000670de0b6b3a764000083613b9f896137a7565b613ba9919061545e565b613bb3919061547d565b905080613bc0838861545e565b613bca919061547d565b9a9950505050505050505050565b6097546001600160a01b031633146118fe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611029565b600080600080600080600060ff6000896001600160a01b03166001600160a01b03168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015613cb657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613c98575b5050505050905060005b8151811015613e8e57600060fc6000848481518110613ce157613ce1615ac4565b6020908102919091018101516001600160a01b03168252810191909152604001600020805490915060ff16613d165750613e7c565b6001600160a01b038a166000908152600d8201602052604081205490613d3c838d613927565b90506000613d6384878781518110613d5657613d56615ac4565b6020026020010151614a6f565b845490915061ffff620100008204811691600160201b9004168415801590613d8b5750600082115b15613e45576000613d9b876137a7565b90506127106ec097ce7bc90715b34b9f10000000008486613dbc858b61545e565b613dc6919061545e565b613dd0919061545e565b613dda919061547d565b613de4919061547d565b613dee908d61549f565b9b506127106ec097ce7bc90715b34b9f10000000008386613e0f858b61545e565b613e19919061545e565b613e23919061545e565b613e2d919061547d565b613e37919061547d565b613e41908c61549f565b9a50505b8315613e7557670de0b6b3a7640000613e5e848661545e565b613e68919061547d565b613e72908a61549f565b98505b5050505050505b80613e8681615ada565b915050613cc0565b509297919650945092505050565b6001600160a01b0381166000908152610104602052604090205460ff1680613f1f57600080613eca84613c32565b9250509150808210156113fc5760405162461bcd60e51b815260206004820152601760248201527f696e73756666696369656e7420636f6c6c61746572616c0000000000000000006044820152606401611029565b60ff811660011415611719576001600160a01b038216600090815261010460205260409020805460ff191660021790555050565b60c980546001600160a01b031916905561154481614ba3565b60006101008210613fb85760405162461bcd60e51b81526020600482015260166024820152751a5b9d985b1a59081cdd58881858d8dbdd5b9d081a5960521b6044820152606401611029565b501890565b808015613ff157506001600160a01b038084166000908152610100602090815260408083209386168352929052205460ff16155b15614081576001600160a01b03808416600081815261010060209081526040808320948716808452948252808320805460ff19166001908117909155848452610101835281842080549182018155845291832090910180546001600160a01b03191685179055517fa9e5a03abaf4ebb6969200baf2ad7c42a89f86f7801a1689f0ba767a6e2fd5f09190a3505050565b801580156140b557506001600160a01b038084166000908152610100602090815260408083209386168352929052205460ff165b15612ab7576001600160a01b038084166000818152610100602090815260408083209487168352938152838220805460ff19169055918152610101909152206140fe908361460f565b816001600160a01b0316836001600160a01b03167f6a87827eefdfa1b8651b66ff7c8c5b7e72436f627cd2ecd358b9eeada2e9103460405160405180910390a3505050565b604080516101c081018252825460ff808216151583526101008083048216602085015261ffff620100008404811695850195909552600160201b830485166060850152600160301b830485166080850152600160401b830490941660a0840152600160501b82048116151560c0840152600160581b820416151560e08301526001600160a01b03600160601b9091048116928201929092526001830154821661012082015260028301549091166101408201526003820154610160820152600482015461018082015260058201546101a0820152600090614223906148ca565b15801561142857505054600160201b900461ffff16151590565b600080600061424b84613c32565b1195945050505050565b6000806142628786613927565b9050600019831415614272578092505b808311156142b35760405162461bcd60e51b815260206004820152600e60248201526d0e4cae0c2f240e8dede40daeac6d60931b6044820152606401611029565b60088701546001600160a01b0386166000908152600c890160205260408120858403808255600b8b015460019092019190915560078a01805491938790039287926142ff90849061549f565b9091555050600889018190556001600160a01b0387166000908152600d8a016020526040902054158015614331575081155b1561434057614340868861471e565b6143556001600160a01b0387168930886138bc565b60408051868152602081018490529081018290526001600160a01b03808916918a8216918916907f0afc5881e4003d86c77497d24dac378e531a0fa70f52e2b9269be723ff66ab4b9060600160405180910390a45092979650505050505050565b6001600160a01b03831661440c5760405162461bcd60e51b815260206004820152601e60248201527f7472616e736665722066726f6d20746865207a65726f206164647265737300006044820152606401611029565b6001600160a01b0382166144625760405162461bcd60e51b815260206004820152601c60248201527f7472616e7366657220746f20746865207a65726f2061646472657373000000006044820152606401611029565b6001600160a01b0383166000908152600d85016020526040902054816144c15760405162461bcd60e51b81526020600482015260146024820152731d1c985b9cd9995c881e995c9bc8185b5bdd5b9d60621b6044820152606401611029565b818110156145115760405162461bcd60e51b815260206004820152601f60248201527f7472616e7366657220616d6f756e7420657863656564732062616c616e6365006044820152606401611029565b61451b86846137ff565b6001600160a01b038085166000818152600d88016020526040808220868603815593871682528120805486019055525415801561455f575061455d8585613927565b155b1561456e5761456e868561471e565b826001600160a01b0316846001600160a01b0316876001600160a01b03167f88d5565fe2b249a672462d9cdbcdea595ec02e1655b48e9e7920d787aa690ee8856040516145bd91815260200190565b60405180910390a4505050505050565b60208101516000906002161515611428565b6040516001600160a01b038316602482015260448101829052612ab790849063a9059cbb60e01b906064016138f0565b815460005b818110156113fc57826001600160a01b031684828154811061463857614638615ac4565b6000918252602090912001546001600160a01b031614156147165761465e600183615a87565b81146146df5783614670600184615a87565b8154811061468057614680615ac4565b9060005260206000200160009054906101000a90046001600160a01b03168482815481106146b0576146b0615ac4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b838054806146ef576146ef615af5565b600082815260209020810160001990810180546001600160a01b03191690550190556113fc565b600101614614565b6001600160a01b03808216600090815260fe602090815260408083209386168352929052205460ff1661474f575050565b6001600160a01b03808216600081815260fe602090815260408083209487168352938152838220805460ff1916905591815260ff90915220614791908361460f565b806001600160a01b0316826001600160a01b03167fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d60405160405180910390a35050565b60006501000000000042106148225760405162461bcd60e51b815260206004820152601360248201527274696d657374616d7020746f6f206c6172676560681b6044820152606401611029565b504290565b610108546001600160a01b031633146118fe5760405162461bcd60e51b815260206004820152600f60248201526e10b932b9b2b93b32a6b0b730b3b2b960891b6044820152606401611029565b600054610100900460ff1661489b5760405162461bcd60e51b815260040161102990615b0b565b6118fe614bf5565b600054610100900460ff166118fe5760405162461bcd60e51b815260040161102990615b0b565b60208101516000906004161515611428565b6000614931826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c259092919063ffffffff16565b805190915015612ab7578080602001905181019061494f9190615b56565b612ab75760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611029565b6001600160a01b0381163b614a1b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401611029565b600080516020615bad83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b614a5383614c34565b600082511180614a605750805b15612ab7576113fc8383614c74565b81546000908190600160501b900460ff16614a8a5782614aec565b826001600160a01b0316639816f4736040518163ffffffff1660e01b8152600401602060405180830381865afa158015614ac8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aec9190615b73565b610105546040516341976e0960e01b81526001600160a01b038084166004830152929350600092909116906341976e0990602401602060405180830381865afa158015614b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b619190615a6e565b9050600081116114245760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420707269636560981b6044820152606401611029565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16614c1c5760405162461bcd60e51b815260040161102990615b0b565b6118fe33613f53565b60606126848484600085614d68565b614c3d816149ae565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b614cdc5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401611029565b600080846001600160a01b031684604051614cf79190615b90565b600060405180830381855af49150503d8060008114614d32576040519150601f19603f3d011682016040523d82523d6000602084013e614d37565b606091505b5091509150614d5f8282604051806060016040528060278152602001615bcd60279139614e43565b95945050505050565b606082471015614dc95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611029565b600080866001600160a01b03168587604051614de59190615b90565b60006040518083038185875af1925050503d8060008114614e22576040519150601f19603f3d011682016040523d82523d6000602084013e614e27565b606091505b5091509150614e3887838387614e5c565b979650505050505050565b60608315614e525750816115e7565b6115e78383614ece565b60608315614ec8578251614ec1576001600160a01b0385163b614ec15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611029565b5081612684565b61268483835b815115614ede5781518083602001fd5b8060405162461bcd60e51b8152600401611029919061593b565b6001600160a01b038116811461154457600080fd5b8035614f1881614ef8565b919050565b60008060408385031215614f3057600080fd5b8235614f3b81614ef8565b91506020830135614f4b81614ef8565b809150509250929050565b600060208284031215614f6857600080fd5b81356115e781614ef8565b60008060008060808587031215614f8957600080fd5b8435614f9481614ef8565b93506020850135614fa481614ef8565b92506040850135614fb481614ef8565b9396929550929360600135925050565b60008060408385031215614fd757600080fd5b8235614fe281614ef8565b946020939093013593505050565b6000808284036101e081121561500557600080fd5b833561501081614ef8565b92506101c0601f198201121561502557600080fd5b506020830190509250929050565b60008060006060848603121561504857600080fd5b833561505381614ef8565b9250602084013561506381614ef8565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561509d57600080fd5b82356150a881614ef8565b9150602083013567ffffffffffffffff808211156150c557600080fd5b818501915085601f8301126150d957600080fd5b8135818111156150eb576150eb615074565b604051601f8201601f19908116603f0116810190838211818310171561511357615113615074565b8160405282815288602084870101111561512c57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561516057600080fd5b5035919050565b8051151582526020810151615181602084018260ff169052565b506040810151615197604084018261ffff169052565b5060608101516151ad606084018261ffff169052565b5060808101516151c3608084018261ffff169052565b5060a08101516151d960a084018261ffff169052565b5060c08101516151ed60c084018215159052565b5060e081015161520160e084018215159052565b50610100818101516001600160a01b0390811691840191909152610120808301518216908401526101408083015190911690830152610160808201519083015261018080820151908301526101a090810151910152565b6101c081016114288284615167565b6020808252825182820181905260009190848201906040850190845b818110156152a85783516001600160a01b031683529284019291840191600101615283565b50909695505050505050565b61028081016152c3828a615167565b64ffffffffff88166101c0830152866101e08301528561020083015284610220830152836102408301528261026083015298975050505050505050565b801515811461154457600080fd5b8035614f1881615300565b60008060006060848603121561532e57600080fd5b833561533981614ef8565b925060208401359150604084013561535081615300565b809150509250925092565b600080600080600060a0868803121561537357600080fd5b853561537e81614ef8565b9450602086013561538e81614ef8565b9350604086013561539e81614ef8565b925060608601356153ae81614ef8565b949793965091946080013592915050565b600080604083850312156153d257600080fd5b82356153dd81614ef8565b91506020830135614f4b81615300565b60008060006060848603121561540257600080fd5b833561540d81614ef8565b925060208401359150604084013561535081614ef8565b6020808252600a90820152691b9bdd081b1a5cdd195960b21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561547857615478615448565b500290565b60008261549a57634e487b7160e01b600052601260045260246000fd5b500490565b600082198211156154b2576154b2615448565b500190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000813561142881615300565b60ff8116811461154457600080fd5b600081356114288161555c565b61ffff8116811461154457600080fd5b6000813561142881615578565b6000813561142881614ef8565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6155e26155ce8361554f565b825490151560ff1660ff1991909116178255565b6156076155f16020840161556b565b825461ff00191660089190911b61ff0016178255565b61563061561660408401615588565b825463ffff0000191660109190911b63ffff000016178255565b61565d61563f60608401615588565b825465ffff00000000191660209190911b65ffff0000000016178255565b61568e61566c60808401615588565b825467ffff000000000000191660309190911b67ffff00000000000016178255565b6156c361569d60a08401615588565b825469ffff0000000000000000191660409190911b69ffff000000000000000016178255565b6156f06156d260c0840161554f565b82805460ff60501b191691151560501b60ff60501b16919091179055565b61571d6156ff60e0840161554f565b82805460ff60581b191691151560581b60ff60581b16919091179055565b61575761572d6101008401615595565b82546bffffffffffffffffffffffff1660609190911b6bffffffffffffffffffffffff1916178255565b6157706157676101208401615595565b600183016155a2565b6157896157806101408401615595565b600283016155a2565b610160820135600382015561018082013560048201556101a082013560058201555050565b8035614f188161555c565b8035614f1881615578565b6101c081016157dc826157d68561530e565b15159052565b6157e8602084016157ae565b60ff1660208301526157fc604084016157b9565b61ffff166040830152615811606084016157b9565b61ffff166060830152615826608084016157b9565b61ffff16608083015261583b60a084016157b9565b61ffff1660a083015261585060c0840161530e565b151560c083015261586360e0840161530e565b151560e0830152610100615878848201614f0d565b6001600160a01b031690830152610120615893848201614f0d565b6001600160a01b0316908301526101406158ae848201614f0d565b6001600160a01b031690830152610160838101359083015261018080840135908301526101a092830135929091019190915290565b60005b838110156158fe5781810151838201526020016158e6565b838111156113fc5750506000910152565b600081518084526159278160208601602086016158e3565b601f01601f19169290920160200192915050565b6020815260006115e7602083018461590f565b6020808252601190820152700d2dce6eaccccd2c6d2cadce840c6c2e6d607b1b604082015260600190565b64ffffffffff83168152815460ff8116151560208301526101e0820190600881901c60ff16604084015261ffff601082901c811660608501526159c760808501828460201c1661ffff169052565b6159dc60a08501828460301c1661ffff169052565b6159f160c08501828460401c1661ffff169052565b50615a0660e0840160ff8360501c1615159052565b615a1b610100840160ff8360581c1615159052565b60601c61012083015260018301546001600160a01b03908116610140840152600284015416610160830152600383015461018083015260048301546101a08301526005909201546101c090910152919050565b600060208284031215615a8057600080fd5b5051919050565b600082821015615a9957615a99615448565b500390565b600064ffffffffff83811690831681811015615abc57615abc615448565b039392505050565b634e487b7160e01b600052603260045260246000fd5b6000600019821415615aee57615aee615448565b5060010190565b634e487b7160e01b600052603160045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600060208284031215615b6857600080fd5b81516115e781615300565b600060208284031215615b8557600080fd5b81516115e781614ef8565b60008251615ba28184602087016158e3565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208b90c5866cf3aae94a3f949531b88a1664918dea62b81a5012454c1ca535ae6264736f6c634300080a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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.