ETH Price: $3,879.71 (-2.17%)
Gas: 0.09 GWei

Token

ERC-20: cETH (cETH)

Overview

Max Total Supply

108,459,655,261.26569942 cETH

Holders

10,789

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 8 Decimals)

Balance
2.74454026 cETH

Value
$0.00
0x2df7b510f8efd156135b6e78e6c9adbac7b56fe6
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
CEther

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSD-3-Clause license

Contract Source Code (Solidity)

/**
 *Submitted for verification at scrollscan.com on 2023-10-18
*/

// Sources flattened with hardhat v2.14.0 https://hardhat.org

// SPDX-License-Identifier: BSD-3-Clause

// File contracts/ComptrollerInterface.sol


pragma solidity ^0.8.10;

abstract contract ComptrollerInterface {
    /// @notice Indicator that this is a Comptroller contract (for inspection)
    bool public constant isComptroller = true;

    /*** Assets You Are In ***/

    function enterMarkets(address[] calldata cTokens) virtual external returns (uint[] memory);
    function exitMarket(address cToken) virtual external returns (uint);

    /*** Policy Hooks ***/

    function mintAllowed(address cToken, address minter, uint mintAmount) virtual external returns (uint);
    function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) virtual external;

    function redeemAllowed(address cToken, address redeemer, uint redeemTokens) virtual external returns (uint);
    function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) virtual external;

    function borrowAllowed(address cToken, address borrower, uint borrowAmount) virtual external returns (uint);
    function borrowVerify(address cToken, address borrower, uint borrowAmount) virtual external;

    function repayBorrowAllowed(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount) virtual external returns (uint);
    function repayBorrowVerify(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount,
        uint borrowerIndex) virtual external;

    function liquidateBorrowAllowed(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount) virtual external returns (uint);
    function liquidateBorrowVerify(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount,
        uint seizeTokens) virtual external;

    function seizeAllowed(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) virtual external returns (uint);
    function seizeVerify(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) virtual external;

    function transferAllowed(address cToken, address src, address dst, uint transferTokens) virtual external returns (uint);
    function transferVerify(address cToken, address src, address dst, uint transferTokens) virtual external;

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

    function liquidateCalculateSeizeTokens(
        address cTokenBorrowed,
        address cTokenCollateral,
        uint repayAmount) virtual external view returns (uint, uint);
}


// File contracts/EIP20NonStandardInterface.sol


pragma solidity ^0.8.10;

/**
 * @title EIP20NonStandardInterface
 * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface EIP20NonStandardInterface {

    /**
     * @notice Get the total number of tokens in circulation
     * @return The supply of tokens
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return balance The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transfer(address dst, uint256 amount) external;

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transferFrom(address src, address dst, uint256 amount) external;

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved
      * @return success Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return remaining The number of tokens allowed to be spent
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}


// File contracts/ErrorReporter.sol


pragma solidity ^0.8.10;

contract ComptrollerErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        COMPTROLLER_MISMATCH,
        INSUFFICIENT_SHORTFALL,
        INSUFFICIENT_LIQUIDITY,
        INVALID_CLOSE_FACTOR,
        INVALID_COLLATERAL_FACTOR,
        INVALID_LIQUIDATION_INCENTIVE,
        MARKET_NOT_ENTERED, // no longer possible
        MARKET_NOT_LISTED,
        MARKET_ALREADY_LISTED,
        MATH_ERROR,
        NONZERO_BORROW_BALANCE,
        PRICE_ERROR,
        REJECTION,
        SNAPSHOT_ERROR,
        TOO_MANY_ASSETS,
        TOO_MUCH_REPAY
    }

    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
        EXIT_MARKET_BALANCE_OWED,
        EXIT_MARKET_REJECTION,
        SET_CLOSE_FACTOR_OWNER_CHECK,
        SET_CLOSE_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_OWNER_CHECK,
        SET_COLLATERAL_FACTOR_NO_EXISTS,
        SET_COLLATERAL_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
        SET_IMPLEMENTATION_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_VALIDATION,
        SET_MAX_ASSETS_OWNER_CHECK,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
        SET_PRICE_ORACLE_OWNER_CHECK,
        SUPPORT_MARKET_EXISTS,
        SUPPORT_MARKET_OWNER_CHECK,
        SET_PAUSE_GUARDIAN_OWNER_CHECK
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

contract TokenErrorReporter {
    uint public constant NO_ERROR = 0; // support legacy return codes

    error TransferComptrollerRejection(uint256 errorCode);
    error TransferNotAllowed();
    error TransferNotEnough();
    error TransferTooMuch();

    error MintComptrollerRejection(uint256 errorCode);
    error MintFreshnessCheck();

    error RedeemComptrollerRejection(uint256 errorCode);
    error RedeemFreshnessCheck();
    error RedeemTransferOutNotPossible();

    error BorrowComptrollerRejection(uint256 errorCode);
    error BorrowFreshnessCheck();
    error BorrowCashNotAvailable();

    error RepayBorrowComptrollerRejection(uint256 errorCode);
    error RepayBorrowFreshnessCheck();

    error LiquidateComptrollerRejection(uint256 errorCode);
    error LiquidateFreshnessCheck();
    error LiquidateCollateralFreshnessCheck();
    error LiquidateAccrueBorrowInterestFailed(uint256 errorCode);
    error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);
    error LiquidateLiquidatorIsBorrower();
    error LiquidateCloseAmountIsZero();
    error LiquidateCloseAmountIsUintMax();
    error LiquidateRepayBorrowFreshFailed(uint256 errorCode);

    error LiquidateSeizeComptrollerRejection(uint256 errorCode);
    error LiquidateSeizeLiquidatorIsBorrower();

    error AcceptAdminPendingAdminCheck();

    error SetComptrollerOwnerCheck();
    error SetPendingAdminOwnerCheck();

    error SetReserveFactorAdminCheck();
    error SetReserveFactorFreshCheck();
    error SetReserveFactorBoundsCheck();

    error AddReservesFactorFreshCheck(uint256 actualAddAmount);

    error ReduceReservesAdminCheck();
    error ReduceReservesFreshCheck();
    error ReduceReservesCashNotAvailable();
    error ReduceReservesCashValidation();

    error SetInterestRateModelOwnerCheck();
    error SetInterestRateModelFreshCheck();
}


// File contracts/InterestRateModel.sol


pragma solidity ^0.8.10;

/**
  * @title Loanshark's InterestRateModel Interface
  * @author Loanshark
  */
abstract contract InterestRateModel {
    /// @notice Indicator that this is an InterestRateModel contract (for inspection)
    bool public constant isInterestRateModel = true;

    /**
      * @notice Calculates the current borrow interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amount of reserves the market has
      * @return The borrow rate per block (as a percentage, and scaled by 1e18)
      */
    function getBorrowRate(uint cash, uint borrows, uint reserves) virtual external view returns (uint);

    /**
      * @notice Calculates the current supply interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amount of reserves the market has
      * @param reserveFactorMantissa The current reserve factor the market has
      * @return The supply rate per block (as a percentage, and scaled by 1e18)
      */
    function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) virtual external view returns (uint);
}


// File contracts/CTokenInterfaces.sol


pragma solidity ^0.8.10;




contract CTokenStorage {
    /**
     * @dev Guard variable for re-entrancy checks
     */
    bool internal _notEntered;

    /**
     * @notice EIP-20 token name for this token
     */
    string public name;

    /**
     * @notice EIP-20 token symbol for this token
     */
    string public symbol;

    /**
     * @notice EIP-20 token decimals for this token
     */
    uint8 public decimals;

    // Maximum borrow rate that can ever be applied (.0005% / block)
    uint internal constant borrowRateMaxMantissa = 0.0005e16;

    // Maximum fraction of interest that can be set aside for reserves
    uint internal constant reserveFactorMaxMantissa = 1e18;

    /**
     * @notice Administrator for this contract
     */
    address payable public admin;

    /**
     * @notice Pending administrator for this contract
     */
    address payable public pendingAdmin;

    /**
     * @notice Contract which oversees inter-cToken operations
     */
    ComptrollerInterface public comptroller;

    /**
     * @notice Model which tells what the current interest rate should be
     */
    InterestRateModel public interestRateModel;

    // Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)
    uint internal initialExchangeRateMantissa;

    /**
     * @notice Fraction of interest currently set aside for reserves
     */
    uint public reserveFactorMantissa;

    /**
     * @notice Block number that interest was last accrued at
     */
    uint public accrualBlockNumber;

    /**
     * @notice Accumulator of the total earned interest rate since the opening of the market
     */
    uint public borrowIndex;

    /**
     * @notice Total amount of outstanding borrows of the underlying in this market
     */
    uint public totalBorrows;

    /**
     * @notice Total amount of reserves of the underlying held in this market
     */
    uint public totalReserves;

    /**
     * @notice Total number of tokens in circulation
     */
    uint public totalSupply;

    // Official record of token balances for each account
    mapping (address => uint) internal accountTokens;

    // Approved token transfer amounts on behalf of others
    mapping (address => mapping (address => uint)) internal transferAllowances;

    /**
     * @notice Container for borrow balance information
     * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
     * @member interestIndex Global borrowIndex as of the most recent balance-changing action
     */
    struct BorrowSnapshot {
        uint principal;
        uint interestIndex;
    }

    // Mapping of account addresses to outstanding borrow balances
    mapping(address => BorrowSnapshot) internal accountBorrows;

    /**
     * @notice Share of seized collateral that is added to reserves
     */
    uint public constant protocolSeizeShareMantissa = 2.8e16; //2.8%
}

abstract contract CTokenInterface is CTokenStorage {
    /**
     * @notice Indicator that this is a CToken contract (for inspection)
     */
    bool public constant isCToken = true;


    /*** Market Events ***/

    /**
     * @notice Event emitted when interest is accrued
     */
    event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);

    /**
     * @notice Event emitted when tokens are minted
     */
    event Mint(address minter, uint mintAmount, uint mintTokens);

    /**
     * @notice Event emitted when tokens are redeemed
     */
    event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);

    /**
     * @notice Event emitted when underlying is borrowed
     */
    event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);

    /**
     * @notice Event emitted when a borrow is repaid
     */
    event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);

    /**
     * @notice Event emitted when a borrow is liquidated
     */
    event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens);


    /*** Admin Events ***/

    /**
     * @notice Event emitted when pendingAdmin is changed
     */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /**
     * @notice Event emitted when pendingAdmin is accepted, which means admin is updated
     */
    event NewAdmin(address oldAdmin, address newAdmin);

    /**
     * @notice Event emitted when comptroller is changed
     */
    event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);

    /**
     * @notice Event emitted when interestRateModel is changed
     */
    event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);

    /**
     * @notice Event emitted when the reserve factor is changed
     */
    event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);

    /**
     * @notice Event emitted when the reserves are added
     */
    event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves);

    /**
     * @notice Event emitted when the reserves are reduced
     */
    event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves);

    /**
     * @notice EIP20 Transfer event
     */
    event Transfer(address indexed from, address indexed to, uint amount);

    /**
     * @notice EIP20 Approval event
     */
    event Approval(address indexed owner, address indexed spender, uint amount);


    /*** User Interface ***/

    function transfer(address dst, uint amount) virtual external returns (bool);
    function transferFrom(address src, address dst, uint amount) virtual external returns (bool);
    function approve(address spender, uint amount) virtual external returns (bool);
    function allowance(address owner, address spender) virtual external view returns (uint);
    function balanceOf(address owner) virtual external view returns (uint);
    function balanceOfUnderlying(address owner) virtual external returns (uint);
    function getAccountSnapshot(address account) virtual external view returns (uint, uint, uint, uint);
    function borrowRatePerBlock() virtual external view returns (uint);
    function supplyRatePerBlock() virtual external view returns (uint);
    function totalBorrowsCurrent() virtual external returns (uint);
    function borrowBalanceCurrent(address account) virtual external returns (uint);
    function borrowBalanceStored(address account) virtual external view returns (uint);
    function exchangeRateCurrent() virtual external returns (uint);
    function exchangeRateStored() virtual external view returns (uint);
    function getCash() virtual external view returns (uint);
    function accrueInterest() virtual external returns (uint);
    function seize(address liquidator, address borrower, uint seizeTokens) virtual external returns (uint);


    /*** Admin Functions ***/

    function _setPendingAdmin(address payable newPendingAdmin) virtual external returns (uint);
    function _acceptAdmin() virtual external returns (uint);
    function _setComptroller(ComptrollerInterface newComptroller) virtual external returns (uint);
    function _setReserveFactor(uint newReserveFactorMantissa) virtual external returns (uint);
    function _reduceReserves(uint reduceAmount) virtual external returns (uint);
    function _setInterestRateModel(InterestRateModel newInterestRateModel) virtual external returns (uint);
}

contract CErc20Storage {
    /**
     * @notice Underlying asset for this CToken
     */
    address public underlying;
}

abstract contract CErc20Interface is CErc20Storage {

    /*** User Interface ***/

    function mint(uint mintAmount) virtual external returns (uint);
    function redeem(uint redeemTokens) virtual external returns (uint);
    function redeemUnderlying(uint redeemAmount) virtual external returns (uint);
    function borrow(uint borrowAmount) virtual external returns (uint);
    function repayBorrow(uint repayAmount) virtual external returns (uint);
    function repayBorrowBehalf(address borrower, uint repayAmount) virtual external returns (uint);
    function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) virtual external returns (uint);
    function sweepToken(EIP20NonStandardInterface token) virtual external;


    /*** Admin Functions ***/

    function _addReserves(uint addAmount) virtual external returns (uint);
}

contract CDelegationStorage {
    /**
     * @notice Implementation address for this contract
     */
    address public implementation;
}

abstract contract CDelegatorInterface is CDelegationStorage {
    /**
     * @notice Emitted when implementation is changed
     */
    event NewImplementation(address oldImplementation, address newImplementation);

    /**
     * @notice Called by the admin to update the implementation of the delegator
     * @param implementation_ The address of the new implementation for delegation
     * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
     * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
     */
    function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) virtual external;
}

abstract contract CDelegateInterface is CDelegationStorage {
    /**
     * @notice Called by the delegator on a delegate to initialize it for duty
     * @dev Should revert if any issues arise which make it unfit for delegation
     * @param data The encoded bytes data for any initialization
     */
    function _becomeImplementation(bytes memory data) virtual external;

    /**
     * @notice Called by the delegator on a delegate to forfeit its responsibility
     */
    function _resignImplementation() virtual external;
}


// File contracts/EIP20Interface.sol


pragma solidity ^0.8.10;

/**
 * @title ERC 20 Token Standard Interface
 *  https://eips.ethereum.org/EIPS/eip-20
 */
interface EIP20Interface {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /**
      * @notice Get the total number of tokens in circulation
      * @return The supply of tokens
      */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return balance The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return success Whether or not the transfer succeeded
      */
    function transfer(address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return success Whether or not the transfer succeeded
      */
    function transferFrom(address src, address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved (-1 means infinite)
      * @return success Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return remaining The number of tokens allowed to be spent (-1 means infinite)
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}


// File contracts/ExponentialNoError.sol


pragma solidity ^0.8.10;

/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Loanshark
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract ExponentialNoError {
    uint constant expScale = 1e18;
    uint constant doubleScale = 1e36;
    uint constant halfExpScale = expScale/2;
    uint constant mantissaOne = expScale;

    struct Exp {
        uint mantissa;
    }

    struct Double {
        uint mantissa;
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
     */
    function truncate(Exp memory exp) pure internal returns (uint) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return truncate(product);
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return add_(truncate(product), addend);
    }

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa;
    }

    /**
     * @dev Checks if left Exp <= right Exp.
     */
    function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa <= right.mantissa;
    }

    /**
     * @dev Checks if left Exp > right Exp.
     */
    function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa > right.mantissa;
    }

    /**
     * @dev returns true if Exp is exactly zero
     */
    function isZeroExp(Exp memory value) pure internal returns (bool) {
        return value.mantissa == 0;
    }

    function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
        require(n < 2**224, errorMessage);
        return uint224(n);
    }

    function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(uint a, uint b) pure internal returns (uint) {
        return a + b;
    }

    function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(uint a, uint b) pure internal returns (uint) {
        return a - b;
    }

    function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
    }

    function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Exp memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / expScale;
    }

    function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
    }

    function mul_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Double memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / doubleScale;
    }

    function mul_(uint a, uint b) pure internal returns (uint) {
        return a * b;
    }

    function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
    }

    function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Exp memory b) pure internal returns (uint) {
        return div_(mul_(a, expScale), b.mantissa);
    }

    function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
    }

    function div_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Double memory b) pure internal returns (uint) {
        return div_(mul_(a, doubleScale), b.mantissa);
    }

    function div_(uint a, uint b) pure internal returns (uint) {
        return a / b;
    }

    function fraction(uint a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a, doubleScale), b)});
    }
}


// File contracts/CToken.sol


pragma solidity ^0.8.10;






/**
 * @title The base contract with helpful constants
 * @author The Redstone Oracles team
 * @dev It mainly contains redstone-related values, which improve readability
 * of other contracts (e.g. CalldataExtractor and RedstoneConsumerBase)
 */
contract RedstoneConstants {
  // === Abbreviations ===
  // BS - Bytes size
  // PTR - Pointer (memory location)
  // SIG - Signature

  // Solidity and YUL constants
  uint256 internal constant STANDARD_SLOT_BS = 32;
  uint256 internal constant FREE_MEMORY_PTR = 0x40;
  uint256 internal constant BYTES_ARR_LEN_VAR_BS = 32;
  uint256 internal constant FUNCTION_SIGNATURE_BS = 4;
  uint256 internal constant REVERT_MSG_OFFSET = 68; // Revert message structure described here: https://ethereum.stackexchange.com/a/66173/106364
  uint256 internal constant STRING_ERR_MESSAGE_MASK = 0x08c379a000000000000000000000000000000000000000000000000000000000;

  // RedStone protocol consts
  uint256 internal constant SIG_BS = 65;
  uint256 internal constant TIMESTAMP_BS = 6;
  uint256 internal constant DATA_PACKAGES_COUNT_BS = 2;
  uint256 internal constant DATA_POINTS_COUNT_BS = 3;
  uint256 internal constant DATA_POINT_VALUE_BYTE_SIZE_BS = 4;
  uint256 internal constant DATA_POINT_SYMBOL_BS = 32;
  uint256 internal constant DEFAULT_DATA_POINT_VALUE_BS = 32;
  uint256 internal constant UNSIGNED_METADATA_BYTE_SIZE_BS = 3;
  uint256 internal constant REDSTONE_MARKER_BS = 9; // byte size of 0x000002ed57011e0000
  uint256 internal constant REDSTONE_MARKER_MASK = 0x0000000000000000000000000000000000000000000000000002ed57011e0000;

  // Derived values (based on consts)
  uint256 internal constant TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS = 104; // SIG_BS + DATA_POINTS_COUNT_BS + DATA_POINT_VALUE_BYTE_SIZE_BS + STANDARD_SLOT_BS
  uint256 internal constant DATA_PACKAGE_WITHOUT_DATA_POINTS_BS = 78; // DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS + SIG_BS
  uint256 internal constant DATA_PACKAGE_WITHOUT_DATA_POINTS_AND_SIG_BS = 13; // DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS
  uint256 internal constant REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS = 41; // REDSTONE_MARKER_BS + STANDARD_SLOT_BS

  // Error messages
  error CalldataOverOrUnderFlow();
  error IncorrectUnsignedMetadataSize();
  error InsufficientNumberOfUniqueSigners(uint256 receivedSignersCount, uint256 requiredSignersCount);
  error EachSignerMustProvideTheSameValue();
  error EmptyCalldataPointersArr();
  error InvalidCalldataPointer();
  error CalldataMustHaveValidPayload();
  error SignerNotAuthorised(address receivedSigner);
}



library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

/**
 * @title The base contract with the main logic of data extraction from calldata
 * @author The Redstone Oracles team
 * @dev This contract was created to reuse the same logic in the RedstoneConsumerBase
 * and the ProxyConnector contracts
 */
contract CalldataExtractor is RedstoneConstants {
  using SafeMath for uint256;

  error DataPackageTimestampMustNotBeZero();
  error DataPackageTimestampsMustBeEqual();
  error RedstonePayloadMustHaveAtLeastOneDataPackage();

  function extractTimestampsAndAssertAllAreEqual() public pure returns (uint256 extractedTimestamp) {
    uint256 calldataNegativeOffset = _extractByteSizeOfUnsignedMetadata();
    uint256 dataPackagesCount = _extractDataPackagesCountFromCalldata(calldataNegativeOffset);

    if (dataPackagesCount == 0) {
      revert RedstonePayloadMustHaveAtLeastOneDataPackage();
    }

    calldataNegativeOffset += DATA_PACKAGES_COUNT_BS;
    for (uint256 dataPackageIndex = 0; dataPackageIndex < dataPackagesCount; dataPackageIndex++) {
      uint256 dataPackageByteSize = _getDataPackageByteSize(calldataNegativeOffset);

      // Extracting timestamp for the current data package
      uint48 dataPackageTimestamp; // uint48, because timestamp uses 6 bytes
      uint256 timestampNegativeOffset = (calldataNegativeOffset + TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS);
      uint256 timestampOffset = msg.data.length - timestampNegativeOffset;
      assembly {
        dataPackageTimestamp := calldataload(timestampOffset)
      }

      if (dataPackageTimestamp == 0) {
        revert DataPackageTimestampMustNotBeZero();
      }

      if (extractedTimestamp == 0) {
        extractedTimestamp = dataPackageTimestamp;
      } else if (dataPackageTimestamp != extractedTimestamp) {
        revert DataPackageTimestampsMustBeEqual();
      }

      calldataNegativeOffset += dataPackageByteSize;
    }
  }

  function _getDataPackageByteSize(uint256 calldataNegativeOffset) internal pure returns (uint256) {
    (
      uint256 dataPointsCount,
      uint256 eachDataPointValueByteSize
    ) = _extractDataPointsDetailsForDataPackage(calldataNegativeOffset);

    return
      dataPointsCount *
      (DATA_POINT_SYMBOL_BS + eachDataPointValueByteSize) +
      DATA_PACKAGE_WITHOUT_DATA_POINTS_BS;
  }

  function _extractByteSizeOfUnsignedMetadata() internal pure returns (uint256) {
    // Checking if the calldata ends with the RedStone marker
    bool hasValidRedstoneMarker;
    assembly {
      let calldataLast32Bytes := calldataload(sub(calldatasize(), STANDARD_SLOT_BS))
      hasValidRedstoneMarker := eq(
        REDSTONE_MARKER_MASK,
        and(calldataLast32Bytes, REDSTONE_MARKER_MASK)
      )
    }
    if (!hasValidRedstoneMarker) {
      revert CalldataMustHaveValidPayload();
    }

    // Using uint24, because unsigned metadata byte size number has 3 bytes
    uint24 unsignedMetadataByteSize;
    if (REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS > msg.data.length) {
      revert CalldataOverOrUnderFlow();
    }
    assembly {
      unsignedMetadataByteSize := calldataload(
        sub(calldatasize(), REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS)
      )
    }
    uint256 calldataNegativeOffset = unsignedMetadataByteSize
      + UNSIGNED_METADATA_BYTE_SIZE_BS
      + REDSTONE_MARKER_BS;
    if (calldataNegativeOffset + DATA_PACKAGES_COUNT_BS > msg.data.length) {
      revert IncorrectUnsignedMetadataSize();
    }
    return calldataNegativeOffset;
  }

  // We return uint16, because unsigned metadata byte size number has 2 bytes
  function _extractDataPackagesCountFromCalldata(uint256 calldataNegativeOffset)
    internal
    pure
    returns (uint16 dataPackagesCount)
  {
    uint256 calldataNegativeOffsetWithStandardSlot = calldataNegativeOffset + STANDARD_SLOT_BS;
    if (calldataNegativeOffsetWithStandardSlot > msg.data.length) {
      revert CalldataOverOrUnderFlow();
    }
    assembly {
      dataPackagesCount := calldataload(
        sub(calldatasize(), calldataNegativeOffsetWithStandardSlot)
      )
    }
    return dataPackagesCount;
  }

  function _extractDataPointValueAndDataFeedId(
    uint256 calldataNegativeOffsetForDataPackage,
    uint256 defaultDataPointValueByteSize,
    uint256 dataPointIndex
  ) internal pure virtual returns (bytes32 dataPointDataFeedId, uint256 dataPointValue) {
    uint256 negativeOffsetToDataPoints = calldataNegativeOffsetForDataPackage + DATA_PACKAGE_WITHOUT_DATA_POINTS_BS;
    uint256 dataPointNegativeOffset = negativeOffsetToDataPoints.add(
      (1 + dataPointIndex).mul((defaultDataPointValueByteSize + DATA_POINT_SYMBOL_BS))
    );
    uint256 dataPointCalldataOffset = msg.data.length.sub(dataPointNegativeOffset);
    assembly {
      dataPointDataFeedId := calldataload(dataPointCalldataOffset)
      dataPointValue := calldataload(add(dataPointCalldataOffset, DATA_POINT_SYMBOL_BS))
    }
  }

  function _extractDataPointsDetailsForDataPackage(uint256 calldataNegativeOffsetForDataPackage)
    internal
    pure
    returns (uint256 dataPointsCount, uint256 eachDataPointValueByteSize)
  {
    // Using uint24, because data points count byte size number has 3 bytes
    uint24 dataPointsCount_;

    // Using uint32, because data point value byte size has 4 bytes
    uint32 eachDataPointValueByteSize_;

    // Extract data points count
    uint256 negativeCalldataOffset = calldataNegativeOffsetForDataPackage + SIG_BS;
    uint256 calldataOffset = msg.data.length.sub(negativeCalldataOffset + STANDARD_SLOT_BS);
    assembly {
      dataPointsCount_ := calldataload(calldataOffset)
    }

    // Extract each data point value size
    calldataOffset = calldataOffset.sub(DATA_POINTS_COUNT_BS);
    assembly {
      eachDataPointValueByteSize_ := calldataload(calldataOffset)
    }

    // Prepare returned values
    dataPointsCount = dataPointsCount_;
    eachDataPointValueByteSize = eachDataPointValueByteSize_;
  }
}

/**
 * @title The base contract for forwarding redstone payload to other contracts
 * @author The Redstone Oracles team
 */
contract ProxyConnector is RedstoneConstants, CalldataExtractor {
  error ProxyCalldataFailedWithoutErrMsg();
  error ProxyCalldataFailedWithStringMessage(string message);
  error ProxyCalldataFailedWithCustomError(bytes result);

  function proxyCalldata(
    address contractAddress,
    bytes memory encodedFunction,
    bool forwardValue
  ) internal returns (bytes memory) {
    bytes memory message = _prepareMessage(encodedFunction);

    (bool success, bytes memory result) =
      contractAddress.call{value: forwardValue ? msg.value : 0}(message);

    return _prepareReturnValue(success, result);
  }

  function proxyDelegateCalldata(address contractAddress, bytes memory encodedFunction)
    internal
    returns (bytes memory)
  {
    bytes memory message = _prepareMessage(encodedFunction);
    (bool success, bytes memory result) = contractAddress.delegatecall(message);
    return _prepareReturnValue(success, result);
  }

  function proxyCalldataView(address contractAddress, bytes memory encodedFunction)
    internal
    view
    returns (bytes memory)
  {
    bytes memory message = _prepareMessage(encodedFunction);
    (bool success, bytes memory result) = contractAddress.staticcall(message);
    return _prepareReturnValue(success, result);
  }

  function _prepareMessage(bytes memory encodedFunction) private pure returns (bytes memory) {
    uint256 encodedFunctionBytesCount = encodedFunction.length;
    uint256 redstonePayloadByteSize = _getRedstonePayloadByteSize();
    uint256 resultMessageByteSize = encodedFunctionBytesCount + redstonePayloadByteSize;

    if (redstonePayloadByteSize > msg.data.length) {
      revert CalldataOverOrUnderFlow();
    }

    bytes memory message;

    assembly {
      message := mload(FREE_MEMORY_PTR) // sets message pointer to first free place in memory

      // Saving the byte size of the result message (it's a standard in EVM)
      mstore(message, resultMessageByteSize)

      // Copying function and its arguments
      for {
        let from := add(BYTES_ARR_LEN_VAR_BS, encodedFunction)
        let fromEnd := add(from, encodedFunctionBytesCount)
        let to := add(BYTES_ARR_LEN_VAR_BS, message)
      } lt (from, fromEnd) {
        from := add(from, STANDARD_SLOT_BS)
        to := add(to, STANDARD_SLOT_BS)
      } {
        // Copying data from encodedFunction to message (32 bytes at a time)
        mstore(to, mload(from))
      }

      // Copying redstone payload to the message bytes
      calldatacopy(
        add(message, add(BYTES_ARR_LEN_VAR_BS, encodedFunctionBytesCount)), // address
        sub(calldatasize(), redstonePayloadByteSize), // offset
        redstonePayloadByteSize // bytes length to copy
      )

      // Updating free memory pointer
      mstore(
        FREE_MEMORY_PTR,
        add(
          add(message, add(redstonePayloadByteSize, encodedFunctionBytesCount)),
          BYTES_ARR_LEN_VAR_BS
        )
      )
    }

    return message;
  }

  function _getRedstonePayloadByteSize() private pure returns (uint256) {
    uint256 calldataNegativeOffset = _extractByteSizeOfUnsignedMetadata();
    uint256 dataPackagesCount = _extractDataPackagesCountFromCalldata(calldataNegativeOffset);
    calldataNegativeOffset += DATA_PACKAGES_COUNT_BS;
    for (uint256 dataPackageIndex = 0; dataPackageIndex < dataPackagesCount; dataPackageIndex++) {
      uint256 dataPackageByteSize = _getDataPackageByteSize(calldataNegativeOffset);
      calldataNegativeOffset += dataPackageByteSize;
    }

    return calldataNegativeOffset;
  }

  function _prepareReturnValue(bool success, bytes memory result)
    internal
    pure
    returns (bytes memory)
  {
    if (!success) {

      if (result.length == 0) {
        revert ProxyCalldataFailedWithoutErrMsg();
      } else {
        bool isStringErrorMessage;
        assembly {
          let first32BytesOfResult := mload(add(result, BYTES_ARR_LEN_VAR_BS))
          isStringErrorMessage := eq(first32BytesOfResult, STRING_ERR_MESSAGE_MASK)
        }

        if (isStringErrorMessage) {
          string memory receivedErrMsg;
          assembly {
            receivedErrMsg := add(result, REVERT_MSG_OFFSET)
          }
          revert ProxyCalldataFailedWithStringMessage(receivedErrMsg);
        } else {
          revert ProxyCalldataFailedWithCustomError(result);
        }
      }
    }

    return result;
  }
}

/**
 * @title Loanshark's CToken Contract
 * @notice Abstract base for CTokens
 * @author Loanshark
 */
abstract contract CToken is CTokenInterface, ExponentialNoError, TokenErrorReporter, ProxyConnector {
    constructor() {
       admin = payable(msg.sender);   
    }
    /**
     * @notice Initialize the money market
     * @param comptroller_ The address of the Comptroller
     * @param interestRateModel_ The address of the interest rate model
     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
     * @param name_ EIP-20 name of this token
     * @param symbol_ EIP-20 symbol of this token
     * @param decimals_ EIP-20 decimal precision of this token
     */
    function initialize(ComptrollerInterface comptroller_,
                        InterestRateModel interestRateModel_,
                        uint initialExchangeRateMantissa_,
                        string memory name_,
                        string memory symbol_,
                        uint8 decimals_) public {
        require(msg.sender == admin, "only admin may initialize the market");
        require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");

        // Set initial exchange rate
        initialExchangeRateMantissa = initialExchangeRateMantissa_;
        require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");

        // Set the comptroller
        uint err = _setComptroller(comptroller_);
        require(err == NO_ERROR, "setting comptroller failed");

        // Initialize block number and borrow index (block number mocks depend on comptroller being set)
        accrualBlockNumber = getBlockNumber();
        borrowIndex = mantissaOne;

        // Set the interest rate model (depends on block number / borrow index)
        err = _setInterestRateModelFresh(interestRateModel_);
        require(err == NO_ERROR, "setting interest rate model failed");

        name = name_;
        symbol = symbol_;
        decimals = decimals_;

        // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)
        _notEntered = true;
    }

    /**
     * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`
     * @dev Called by both `transfer` and `transferFrom` internally
     * @param spender The address of the account performing the transfer
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param tokens The number of tokens to transfer
     * @return 0 if the transfer succeeded, else revert
     */
    function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {
        /* Fail if transfer not allowed */
        uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);
        if (allowed != 0) {
            revert TransferComptrollerRejection(allowed);
        }

        /* Do not allow self-transfers */
        if (src == dst) {
            revert TransferNotAllowed();
        }

        /* Get the allowance, infinite for the account owner */
        uint startingAllowance = 0;
        if (spender == src) {
            startingAllowance = type(uint).max;
        } else {
            startingAllowance = transferAllowances[src][spender];
        }

        /* Do the calculations, checking for {under,over}flow */
        uint allowanceNew = startingAllowance - tokens;
        uint srcTokensNew = accountTokens[src] - tokens;
        uint dstTokensNew = accountTokens[dst] + tokens;

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        accountTokens[src] = srcTokensNew;
        accountTokens[dst] = dstTokensNew;

        /* Eat some of the allowance (if necessary) */
        if (startingAllowance != type(uint).max) {
            transferAllowances[src][spender] = allowanceNew;
        }

        /* We emit a Transfer event */
        emit Transfer(src, dst, tokens);

        // unused function
        // comptroller.transferVerify(address(this), src, dst, tokens);

        return NO_ERROR;
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint256 amount) override external nonReentrant returns (bool) {
        return transferTokens(msg.sender, msg.sender, dst, amount) == NO_ERROR;
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint256 amount) override external nonReentrant returns (bool) {
        return transferTokens(msg.sender, src, dst, amount) == NO_ERROR;
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (uint256.max means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint256 amount) override external returns (bool) {
        address src = msg.sender;
        transferAllowances[src][spender] = amount;
        emit Approval(src, spender, amount);
        return true;
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender) override external view returns (uint256) {
        return transferAllowances[owner][spender];
    }

    /**
     * @notice Get the token balance of the `owner`
     * @param owner The address of the account to query
     * @return The number of tokens owned by `owner`
     */
    function balanceOf(address owner) override external view returns (uint256) {
        return accountTokens[owner];
    }

    /**
     * @notice Get the underlying balance of the `owner`
     * @dev This also accrues interest in a transaction
     * @param owner The address of the account to query
     * @return The amount of underlying owned by `owner`
     */
    function balanceOfUnderlying(address owner) override external returns (uint) {
        Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
        return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);
    }

    /**
     * @notice Get a snapshot of the account's balances, and the cached exchange rate
     * @dev This is used by comptroller to more efficiently perform liquidity checks.
     * @param account Address of the account to snapshot
     * @return (possible error, token balance, borrow balance, exchange rate mantissa)
     */
    function getAccountSnapshot(address account) override external view returns (uint, uint, uint, uint) {
        return (
            NO_ERROR,
            accountTokens[account],
            borrowBalanceStoredInternal(account),
            exchangeRateStoredInternal()
        );
    }

    /**
     * @dev Function to simply retrieve block number
     *  This exists mainly for inheriting test contracts to stub this result.
     */
    function getBlockNumber() virtual internal view returns (uint) {
        return block.number;
    }

    /**
     * @notice Returns the current per-block borrow interest rate for this cToken
     * @return The borrow interest rate per block, scaled by 1e18
     */
    function borrowRatePerBlock() override external view returns (uint) {
        return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
    }

    /**
     * @notice Returns the current per-block supply interest rate for this cToken
     * @return The supply interest rate per block, scaled by 1e18
     */
    function supplyRatePerBlock() override external view returns (uint) {
        return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
    }

    /**
     * @notice Returns the current total borrows plus accrued interest
     * @return The total borrows with interest
     */
    function totalBorrowsCurrent() override external nonReentrant returns (uint) {
        accrueInterest();
        return totalBorrows;
    }

    /**
     * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
     * @param account The address whose balance should be calculated after updating borrowIndex
     * @return The calculated balance
     */
    function borrowBalanceCurrent(address account) override external nonReentrant returns (uint) {
        accrueInterest();
        return borrowBalanceStored(account);
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return The calculated balance
     */
    function borrowBalanceStored(address account) override public view returns (uint) {
        return borrowBalanceStoredInternal(account);
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return (error code, the calculated balance or 0 if error code is non-zero)
     */
    function borrowBalanceStoredInternal(address account) internal view returns (uint) {
        /* Get borrowBalance and borrowIndex */
        BorrowSnapshot storage borrowSnapshot = accountBorrows[account];

        /* If borrowBalance = 0 then borrowIndex is likely also 0.
         * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
         */
        if (borrowSnapshot.principal == 0) {
            return 0;
        }

        /* Calculate new borrow balance using the interest index:
         *  recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
         */
        uint principalTimesIndex = borrowSnapshot.principal * borrowIndex;
        return principalTimesIndex / borrowSnapshot.interestIndex;
    }

    /**
     * @notice Accrue interest then return the up-to-date exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateCurrent() override public nonReentrant returns (uint) {
        accrueInterest();
        return exchangeRateStored();
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the CToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateStored() override public view returns (uint) {
        return exchangeRateStoredInternal();
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the CToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return calculated exchange rate scaled by 1e18
     */
    function exchangeRateStoredInternal() virtual internal view returns (uint) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            /*
             * If there are no tokens minted:
             *  exchangeRate = initialExchangeRate
             */
            return initialExchangeRateMantissa;
        } else {
            /*
             * Otherwise:
             *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
             */
            uint totalCash = getCashPrior();
            uint cashPlusBorrowsMinusReserves = totalCash + totalBorrows - totalReserves;
            uint exchangeRate = cashPlusBorrowsMinusReserves * expScale / _totalSupply;

            return exchangeRate;
        }
    }

    /**
     * @notice Get cash balance of this cToken in the underlying asset
     * @return The quantity of underlying asset owned by this contract
     */
    function getCash() override external view returns (uint) {
        return getCashPrior();
    }

    /**
     * @notice Applies accrued interest to total borrows and reserves
     * @dev This calculates interest accrued from the last checkpointed block
     *   up to the current block and writes new checkpoint to storage.
     */
    function accrueInterest() virtual override public returns (uint) {
        /* Remember the initial block number */
        uint currentBlockNumber = getBlockNumber();
        uint accrualBlockNumberPrior = accrualBlockNumber;

        /* Short-circuit accumulating 0 interest */
        if (accrualBlockNumberPrior == currentBlockNumber) {
            return NO_ERROR;
        }

        /* Read the previous values out of storage */
        uint cashPrior = getCashPrior();
        uint borrowsPrior = totalBorrows;
        uint reservesPrior = totalReserves;
        uint borrowIndexPrior = borrowIndex;

        /* Calculate the current borrow interest rate */
        uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
        require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");

        /* Calculate the number of blocks elapsed since the last accrual */
        uint blockDelta = currentBlockNumber - accrualBlockNumberPrior;

        /*
         * Calculate the interest accumulated into borrows and reserves and the new index:
         *  simpleInterestFactor = borrowRate * blockDelta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  totalBorrowsNew = interestAccumulated + totalBorrows
         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves
         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
         */

        Exp memory simpleInterestFactor = mul_(Exp({mantissa: borrowRateMantissa}), blockDelta);
        uint interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);
        uint totalBorrowsNew = interestAccumulated + borrowsPrior;
        uint totalReservesNew = mul_ScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
        uint borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the previously calculated values into storage */
        accrualBlockNumber = currentBlockNumber;
        borrowIndex = borrowIndexNew;
        totalBorrows = totalBorrowsNew;
        totalReserves = totalReservesNew;

        /* We emit an AccrueInterest event */
        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);

        return NO_ERROR;
    }

    /**
     * @notice Sender supplies assets into the market and receives cTokens in exchange
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param mintAmount The amount of the underlying asset to supply
     */
    function mintInternal(uint mintAmount) internal nonReentrant {
        accrueInterest();
        // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
        mintFresh(msg.sender, mintAmount);
    }

    /**
     * @notice User supplies assets into the market and receives cTokens in exchange
     * @dev Assumes interest has already been accrued up to the current block
     * @param minter The address of the account which is supplying the assets
     * @param mintAmount The amount of the underlying asset to supply
     */
    function mintFresh(address minter, uint mintAmount) internal {
        /* Fail if mint not allowed */
        uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
        if (allowed != 0) {
            revert MintComptrollerRejection(allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            revert MintFreshnessCheck();
        }

        Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()});

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         *  We call `doTransferIn` for the minter and the mintAmount.
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  `doTransferIn` reverts if anything goes wrong, since we can't be sure if
         *  side-effects occurred. The function returns the amount actually transferred,
         *  in case of a fee. On success, the cToken holds an additional `actualMintAmount`
         *  of cash.
         */
        uint actualMintAmount = doTransferIn(minter, mintAmount);

        /*
         * We get the current exchange rate and calculate the number of cTokens to be minted:
         *  mintTokens = actualMintAmount / exchangeRate
         */

        uint mintTokens = div_(actualMintAmount, exchangeRate);

        /*
         * We calculate the new total supply of cTokens and minter token balance, checking for overflow:
         *  totalSupplyNew = totalSupply + mintTokens
         *  accountTokensNew = accountTokens[minter] + mintTokens
         * And write them into storage
         */
        totalSupply = totalSupply + mintTokens;
        accountTokens[minter] = accountTokens[minter] + mintTokens;

        /* We emit a Mint event, and a Transfer event */
        emit Mint(minter, actualMintAmount, mintTokens);
        emit Transfer(address(this), minter, mintTokens);

        /* We call the defense hook */
        // unused function
        // comptroller.mintVerify(address(this), minter, actualMintAmount, mintTokens);
    }

    /**
     * @notice Sender redeems cTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of cTokens to redeem into underlying
     */
    function redeemInternal(uint redeemTokens) internal nonReentrant {
        accrueInterest();
        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        redeemFresh(payable(msg.sender), redeemTokens, 0);
    }

    /**
     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to receive from redeeming cTokens
     */
    function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant {
        accrueInterest();
        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        redeemFresh(payable(msg.sender), 0, redeemAmount);
    }

    /**
     * @notice User redeems cTokens in exchange for the underlying asset
     * @dev Assumes interest has already been accrued up to the current block
     * @param redeemer The address of the account which is redeeming the tokens
     * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     */
    function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal {
        require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");

        /* exchangeRate = invoke Exchange Rate Stored() */
        Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal() });

        uint redeemTokens;
        uint redeemAmount;
        /* If redeemTokensIn > 0: */
        if (redeemTokensIn > 0) {
            /*
             * We calculate the exchange rate and the amount of underlying to be redeemed:
             *  redeemTokens = redeemTokensIn
             *  redeemAmount = redeemTokensIn x exchangeRateCurrent
             */
            redeemTokens = redeemTokensIn;
            redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokensIn);
        } else {
            /*
             * We get the current exchange rate and calculate the amount to be redeemed:
             *  redeemTokens = redeemAmountIn / exchangeRate
             *  redeemAmount = redeemAmountIn
             */
            redeemTokens = div_(redeemAmountIn, exchangeRate);
            redeemAmount = redeemAmountIn;
        }

        /* Fail if redeem not allowed */
        /* Use Redstone */
        bytes memory encodedFunction = abi.encodeWithSelector(
            ComptrollerInterface.redeemAllowed.selector,
            address(this), 
            redeemer, 
            redeemTokens
        );

        bytes memory encodedResult = proxyCalldata(
            address(comptroller),
            encodedFunction,
            true
        );

        uint allowed = abi.decode(encodedResult, (uint256));
        if (allowed != 0) {
            revert RedeemComptrollerRejection(allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            revert RedeemFreshnessCheck();
        }

        /* Fail gracefully if protocol has insufficient cash */
        if (getCashPrior() < redeemAmount) {
            revert RedeemTransferOutNotPossible();
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)


        /*
         * We write the previously calculated values into storage.
         *  Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.
         */
        totalSupply = totalSupply - redeemTokens;
        accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens;

        /*
         * We invoke doTransferOut for the redeemer and the redeemAmount.
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken has redeemAmount less of cash.
         *  doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
         */
        doTransferOut(redeemer, redeemAmount);

        /* We emit a Transfer event, and a Redeem event */
        emit Transfer(redeemer, address(this), redeemTokens);
        emit Redeem(redeemer, redeemAmount, redeemTokens);

        /* We call the defense hook */
        comptroller.redeemVerify(address(this), redeemer, redeemAmount, redeemTokens);
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      */
    function borrowInternal(uint borrowAmount) internal nonReentrant {
        accrueInterest();
        // borrowFresh emits borrow-specific logs on errors, so we don't need to
        borrowFresh(payable(msg.sender), borrowAmount);
    }

    /**
      * @notice Users borrow assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      */
    function borrowFresh(address payable borrower, uint borrowAmount) internal {
        /* Fail if borrow not allowed */
        /* Use Redstone */
        bytes memory encodedFunction = abi.encodeWithSelector(
            ComptrollerInterface.borrowAllowed.selector,
            address(this), 
            borrower, 
            borrowAmount
        );

        bytes memory encodedResult = proxyCalldata(
            address(comptroller),
            encodedFunction,
            true
        );

        uint allowed = abi.decode(encodedResult, (uint256));

        if (allowed != 0) {
            revert BorrowComptrollerRejection(allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            revert BorrowFreshnessCheck();
        }

        /* Fail gracefully if protocol has insufficient underlying cash */
        if (getCashPrior() < borrowAmount) {
            revert BorrowCashNotAvailable();
        }

        /*
         * We calculate the new borrower and total borrow balances, failing on overflow:
         *  accountBorrowNew = accountBorrow + borrowAmount
         *  totalBorrowsNew = totalBorrows + borrowAmount
         */
        uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);
        uint accountBorrowsNew = accountBorrowsPrev + borrowAmount;
        uint totalBorrowsNew = totalBorrows + borrowAmount;

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We write the previously calculated values into storage.
         *  Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.
        `*/
        accountBorrows[borrower].principal = accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = totalBorrowsNew;

        /*
         * We invoke doTransferOut for the borrower and the borrowAmount.
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken borrowAmount less of cash.
         *  doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
         */
        doTransferOut(borrower, borrowAmount);

        /* We emit a Borrow event */
        emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);
    }

    /**
     * @notice Sender repays their own borrow
     * @param repayAmount The amount to repay, or -1 for the full outstanding amount
     */
    function repayBorrowInternal(uint repayAmount) internal nonReentrant {
        accrueInterest();
        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        repayBorrowFresh(msg.sender, msg.sender, repayAmount);
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @param borrower the account with the debt being payed off
     * @param repayAmount The amount to repay, or -1 for the full outstanding amount
     */
    function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant {
        accrueInterest();
        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        repayBorrowFresh(msg.sender, borrower, repayAmount);
    }

    /**
     * @notice Borrows are repaid by another user (possibly the borrower).
     * @param payer the account paying off the borrow
     * @param borrower the account with the debt being payed off
     * @param repayAmount the amount of underlying tokens being returned, or -1 for the full outstanding amount
     * @return (uint) the actual repayment amount.
     */
    function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint) {
        /* Fail if repayBorrow not allowed */
        uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
        if (allowed != 0) {
            revert RepayBorrowComptrollerRejection(allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            revert RepayBorrowFreshnessCheck();
        }

        /* We fetch the amount the borrower owes, with accumulated interest */
        uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);

        /* If repayAmount == -1, repayAmount = accountBorrows */
        uint repayAmountFinal = repayAmount == type(uint).max ? accountBorrowsPrev : repayAmount;

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We call doTransferIn for the payer and the repayAmount
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken holds an additional repayAmount of cash.
         *  doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
         *   it returns the amount actually transferred, in case of a fee.
         */
        uint actualRepayAmount = doTransferIn(payer, repayAmountFinal);

        /*
         * We calculate the new borrower and total borrow balances, failing on underflow:
         *  accountBorrowsNew = accountBorrows - actualRepayAmount
         *  totalBorrowsNew = totalBorrows - actualRepayAmount
         */
        uint accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;
        uint totalBorrowsNew = totalBorrows - actualRepayAmount;

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = totalBorrowsNew;

        /* We emit a RepayBorrow event */
        emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);

        return actualRepayAmount;
    }

    /**
     * @notice The sender liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this cToken to be liquidated
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     */
    function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant {
        accrueInterest();

        uint error = cTokenCollateral.accrueInterest();
        if (error != NO_ERROR) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
            revert LiquidateAccrueCollateralInterestFailed(error);
        }

        // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to
        liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral);
    }

    /**
     * @notice The liquidator liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this cToken to be liquidated
     * @param liquidator The address repaying the borrow and seizing collateral
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     */
    function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal {
        /* Fail if liquidate not allowed */
        /* Use Redstone */
        bytes memory encodedFunction = abi.encodeWithSelector(
            ComptrollerInterface.liquidateBorrowAllowed.selector,
            address(this), 
            address(cTokenCollateral), 
            liquidator,
            borrower,
            repayAmount
        );

        bytes memory encodedResult = proxyCalldata(
            address(comptroller),
            encodedFunction,
            true
        );

        uint allowed = abi.decode(encodedResult, (uint));

        if (allowed != 0) {
            revert LiquidateComptrollerRejection(allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            revert LiquidateFreshnessCheck();
        }

        /* Verify cTokenCollateral market's block number equals current block number */
        if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {
            revert LiquidateCollateralFreshnessCheck();
        }

        /* Fail if borrower = liquidator */
        if (borrower == liquidator) {
            revert LiquidateLiquidatorIsBorrower();
        }

        /* Fail if repayAmount = 0 */
        if (repayAmount == 0) {
            revert LiquidateCloseAmountIsZero();
        }

        /* Fail if repayAmount = -1 */
        if (repayAmount == type(uint).max) {
            revert LiquidateCloseAmountIsUintMax();
        }

        /* Fail if repayBorrow fails */
        uint actualRepayAmount = repayBorrowFresh(liquidator, borrower, repayAmount);

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We calculate the number of collateral tokens that will be seized */
        /* Use Redstone */
        bytes memory encodedFunction2 = abi.encodeWithSelector(
            ComptrollerInterface.liquidateCalculateSeizeTokens.selector,
            address(this), 
            address(cTokenCollateral), 
            actualRepayAmount
        );

        bytes memory encodedResult2 = proxyCalldataView(
            address(comptroller),
            encodedFunction2
        );

        (uint amountSeizeError, uint seizeTokens) = abi.decode(encodedResult2, (uint, uint));


        require(amountSeizeError == NO_ERROR, "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");

        /* Revert if borrower collateral token balance < seizeTokens */
        require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH");

        // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call
        if (address(cTokenCollateral) == address(this)) {
            seizeInternal(address(this), liquidator, borrower, seizeTokens);
        } else {
            require(cTokenCollateral.seize(liquidator, borrower, seizeTokens) == NO_ERROR, "token seizure failed");
        }

        /* We emit a LiquidateBorrow event */
        emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Will fail unless called by another cToken during the process of liquidation.
     *  Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of cTokens to seize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function seize(address liquidator, address borrower, uint seizeTokens) override external nonReentrant returns (uint) {
        seizeInternal(msg.sender, liquidator, borrower, seizeTokens);

        return NO_ERROR;
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.
     *  Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.
     * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of cTokens to seize
     */
    function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal {
        /* Fail if seize not allowed */
        uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
        if (allowed != 0) {
            revert LiquidateSeizeComptrollerRejection(allowed);
        }

        /* Fail if borrower = liquidator */
        if (borrower == liquidator) {
            revert LiquidateSeizeLiquidatorIsBorrower();
        }

        /*
         * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:
         *  borrowerTokensNew = accountTokens[borrower] - seizeTokens
         *  liquidatorTokensNew = accountTokens[liquidator] + seizeTokens
         */
        uint protocolSeizeTokens = mul_(seizeTokens, Exp({mantissa: protocolSeizeShareMantissa}));
        uint liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;
        Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()});
        uint protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);
        uint totalReservesNew = totalReserves + protocolSeizeAmount;


        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the calculated values into storage */
        totalReserves = totalReservesNew;
        totalSupply = totalSupply - protocolSeizeTokens;
        accountTokens[borrower] = accountTokens[borrower] - seizeTokens;
        accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;

        /* Emit a Transfer event */
        emit Transfer(borrower, liquidator, liquidatorSeizeTokens);
        emit Transfer(borrower, address(this), protocolSeizeTokens);
        emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);
    }


    /*** Admin Functions ***/

    /**
      * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @param newPendingAdmin New pending admin.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPendingAdmin(address payable newPendingAdmin) override external returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            revert SetPendingAdminOwnerCheck();
        }

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return NO_ERROR;
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() override external returns (uint) {
        // Check caller is pendingAdmin and pendingAdmin ??address(0)
        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            revert AcceptAdminPendingAdminCheck();
        }

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = payable(address(0));

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return NO_ERROR;
    }

    /**
      * @notice Sets a new comptroller for the market
      * @dev Admin function to set a new comptroller
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setComptroller(ComptrollerInterface newComptroller) override public returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            revert SetComptrollerOwnerCheck();
        }

        ComptrollerInterface oldComptroller = comptroller;
        // Ensure invoke comptroller.isComptroller() returns true
        require(newComptroller.isComptroller(), "marker method returned false");

        // Set market's comptroller to newComptroller
        comptroller = newComptroller;

        // Emit NewComptroller(oldComptroller, newComptroller)
        emit NewComptroller(oldComptroller, newComptroller);

        return NO_ERROR;
    }

    /**
      * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
      * @dev Admin function to accrue interest and set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactor(uint newReserveFactorMantissa) override external nonReentrant returns (uint) {
        accrueInterest();
        // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.
        return _setReserveFactorFresh(newReserveFactorMantissa);
    }

    /**
      * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
      * @dev Admin function to set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            revert SetReserveFactorAdminCheck();
        }

        // Verify market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            revert SetReserveFactorFreshCheck();
        }

        // Check newReserveFactor ??maxReserveFactor
        if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
            revert SetReserveFactorBoundsCheck();
        }

        uint oldReserveFactorMantissa = reserveFactorMantissa;
        reserveFactorMantissa = newReserveFactorMantissa;

        emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);

        return NO_ERROR;
    }

    /**
     * @notice Accrues interest and reduces reserves by transferring from msg.sender
     * @param addAmount Amount of addition to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _addReservesInternal(uint addAmount) internal nonReentrant returns (uint) {
        accrueInterest();

        // _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to.
        _addReservesFresh(addAmount);
        return NO_ERROR;
    }

    /**
     * @notice Add reserves by transferring from caller
     * @dev Requires fresh interest accrual
     * @param addAmount Amount of addition to reserves
     * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees
     */
    function _addReservesFresh(uint addAmount) internal returns (uint, uint) {
        // totalReserves + actualAddAmount
        uint totalReservesNew;
        uint actualAddAmount;

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            revert AddReservesFactorFreshCheck(actualAddAmount);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We call doTransferIn for the caller and the addAmount
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken holds an additional addAmount of cash.
         *  doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
         *  it returns the amount actually transferred, in case of a fee.
         */

        actualAddAmount = doTransferIn(msg.sender, addAmount);

        totalReservesNew = totalReserves + actualAddAmount;

        // Store reserves[n+1] = reserves[n] + actualAddAmount
        totalReserves = totalReservesNew;

        /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */
        emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);

        /* Return (NO_ERROR, actualAddAmount) */
        return (NO_ERROR, actualAddAmount);
    }


    /**
     * @notice Accrues interest and reduces reserves by transferring to admin
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReserves(uint reduceAmount) override external nonReentrant returns (uint) {
        accrueInterest();
        // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.
        return _reduceReservesFresh(reduceAmount);
    }

    /**
     * @notice Reduces reserves by transferring to admin
     * @dev Requires fresh interest accrual
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {
        // totalReserves - reduceAmount
        uint totalReservesNew;

        // Check caller is admin
        if (msg.sender != admin) {
            revert ReduceReservesAdminCheck();
        }

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            revert ReduceReservesFreshCheck();
        }

        // Fail gracefully if protocol has insufficient underlying cash
        if (getCashPrior() < reduceAmount) {
            revert ReduceReservesCashNotAvailable();
        }

        // Check reduceAmount ??reserves[n] (totalReserves)
        if (reduceAmount > totalReserves) {
            revert ReduceReservesCashValidation();
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        totalReservesNew = totalReserves - reduceAmount;

        // Store reserves[n+1] = reserves[n] - reduceAmount
        totalReserves = totalReservesNew;

        // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
        doTransferOut(admin, reduceAmount);

        emit ReservesReduced(admin, reduceAmount, totalReservesNew);

        return NO_ERROR;
    }

    /**
     * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh
     * @dev Admin function to accrue interest and update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModel(InterestRateModel newInterestRateModel) override public returns (uint) {
        accrueInterest();
        // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.
        return _setInterestRateModelFresh(newInterestRateModel);
    }

    /**
     * @notice updates the interest rate model (*requires fresh interest accrual)
     * @dev Admin function to update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {

        // Used to store old model for use in the event that is emitted on success
        InterestRateModel oldInterestRateModel;

        // Check caller is admin
        if (msg.sender != admin) {
            revert SetInterestRateModelOwnerCheck();
        }

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            revert SetInterestRateModelFreshCheck();
        }

        // Track the market's current interest rate model
        oldInterestRateModel = interestRateModel;

        // Ensure invoke newInterestRateModel.isInterestRateModel() returns true
        require(newInterestRateModel.isInterestRateModel(), "marker method returned false");

        // Set the interest rate model to newInterestRateModel
        interestRateModel = newInterestRateModel;

        // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)
        emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);

        return NO_ERROR;
    }

    /*** Safe Token ***/

    /**
     * @notice Gets balance of this contract in terms of the underlying
     * @dev This excludes the value of the current message, if any
     * @return The quantity of underlying owned by this contract
     */
    function getCashPrior() virtual internal view returns (uint);

    /**
     * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.
     *  This may revert due to insufficient balance or insufficient allowance.
     */
    function doTransferIn(address from, uint amount) virtual internal returns (uint);

    /**
     * @dev Performs a transfer out, ideally returning an explanatory error code upon failure rather than reverting.
     *  If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.
     *  If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.
     */
    function doTransferOut(address payable to, uint amount) virtual internal;


    /*** Reentrancy Guard ***/

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     */
    modifier nonReentrant() {
        require(_notEntered, "re-entered");
        _notEntered = false;
        _;
        _notEntered = true; // get a gas-refund post-Istanbul
    }
}


// File contracts/CErc20.sol


pragma solidity ^0.8.10;

interface CompLike {
    function delegate(address delegatee) external;
}

/**
 * @title Loanshark's CErc20 Contract
 * @notice CTokens which wrap an EIP-20 underlying
 * @author Loanshark
 */
contract CErc20 is CToken, CErc20Interface {
    /**
     * @notice Initialize the new money market
     * @param underlying_ The address of the underlying asset
     * @param comptroller_ The address of the Comptroller
     * @param interestRateModel_ The address of the interest rate model
     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
     * @param name_ ERC-20 name of this token
     * @param symbol_ ERC-20 symbol of this token
     * @param decimals_ ERC-20 decimal precision of this token
     */
    function initialize(address underlying_,
                        ComptrollerInterface comptroller_,
                        InterestRateModel interestRateModel_,
                        uint initialExchangeRateMantissa_,
                        string memory name_,
                        string memory symbol_,
                        uint8 decimals_) public {
        // Creator of the contract is admin during initialization
        admin = payable(msg.sender);
        
        // CToken initialize does the bulk of the work
        super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);

        // Set underlying and sanity check it
        underlying = underlying_;
        EIP20Interface(underlying).totalSupply();
    }

    /*** User Interface ***/

    /**
     * @notice Sender supplies assets into the market and receives cTokens in exchange
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param mintAmount The amount of the underlying asset to supply
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function mint(uint mintAmount) override external returns (uint) {
        mintInternal(mintAmount);
        return NO_ERROR;
    }

    /**
     * @notice Sender redeems cTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of cTokens to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeem(uint redeemTokens) override external returns (uint) {
        redeemInternal(redeemTokens);
        return NO_ERROR;
    }

    /**
     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to redeem
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemUnderlying(uint redeemAmount) override external returns (uint) {
        redeemUnderlyingInternal(redeemAmount);
        return NO_ERROR;
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrow(uint borrowAmount) override external returns (uint) {
        borrowInternal(borrowAmount);
        return NO_ERROR;
    }

    /**
     * @notice Sender repays their own borrow
     * @param repayAmount The amount to repay, or -1 for the full outstanding amount
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function repayBorrow(uint repayAmount) override external returns (uint) {
        repayBorrowInternal(repayAmount);
        return NO_ERROR;
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @param borrower the account with the debt being payed off
     * @param repayAmount The amount to repay, or -1 for the full outstanding amount
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function repayBorrowBehalf(address borrower, uint repayAmount) override external returns (uint) {
        repayBorrowBehalfInternal(borrower, repayAmount);
        return NO_ERROR;
    }

    /**
     * @notice The sender liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this cToken to be liquidated
     * @param repayAmount The amount of the underlying borrowed asset to repay
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) override external returns (uint) {
        liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
        return NO_ERROR;
    }

    /**
     * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)
     * @param token The address of the ERC-20 token to sweep
     */
    function sweepToken(EIP20NonStandardInterface token) override external {
        require(msg.sender == admin, "CErc20::sweepToken: only admin can sweep tokens");
        require(address(token) != underlying, "CErc20::sweepToken: can not sweep underlying token");
        uint256 balance = token.balanceOf(address(this));
        token.transfer(admin, balance);
    }

    /**
     * @notice The sender adds to reserves.
     * @param addAmount The amount fo underlying token to add as reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _addReserves(uint addAmount) override external returns (uint) {
        return _addReservesInternal(addAmount);
    }

    /*** Safe Token ***/

    /**
     * @notice Gets balance of this contract in terms of the underlying
     * @dev This excludes the value of the current message, if any
     * @return The quantity of underlying tokens owned by this contract
     */
    function getCashPrior() virtual override internal view returns (uint) {
        EIP20Interface token = EIP20Interface(underlying);
        return token.balanceOf(address(this));
    }

    /**
     * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.
     *      This will revert due to insufficient balance or insufficient allowance.
     *      This function returns the actual amount received,
     *      which may be less than `amount` if there is a fee attached to the transfer.
     *
     *      Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
     *            See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferIn(address from, uint amount) virtual override internal returns (uint) {
        // Read from storage once
        address underlying_ = underlying;
        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying_);
        uint balanceBefore = EIP20Interface(underlying_).balanceOf(address(this));
        token.transferFrom(from, address(this), amount);

        bool success;
        assembly {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        require(success, "TOKEN_TRANSFER_IN_FAILED");

        // Calculate the amount that was *actually* transferred
        uint balanceAfter = EIP20Interface(underlying_).balanceOf(address(this));
        return balanceAfter - balanceBefore;   // underflow already checked above, just subtract
    }

    /**
     * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory
     *      error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
     *      insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
     *      it is >= amount, this should not revert in normal conditions.
     *
     *      Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
     *            See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferOut(address payable to, uint amount) virtual override internal {
        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
        token.transfer(to, amount);

        bool success;
        assembly {
            switch returndatasize()
                case 0 {                      // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                     // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                     // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        require(success, "TOKEN_TRANSFER_OUT_FAILED");
    }

    /**
    * @notice Admin call to delegate the votes of the COMP-like underlying
    * @param compLikeDelegatee The address to delegate votes to
    * @dev CTokens whose underlying are not CompLike should revert here
    */
    function _delegateCompLikeTo(address compLikeDelegatee) external {
        require(msg.sender == admin, "only the admin may set the comp-like delegate");
        CompLike(underlying).delegate(compLikeDelegatee);
    }
}

/**
 * @title Loanshark's CEther Contract
 * @notice CToken which wraps Ether
 * @author Loanshark
 */
contract CEther is CToken {
    /**
     * @notice Construct a new CEther money market
     * @param comptroller_ The address of the Comptroller
     * @param interestRateModel_ The address of the interest rate model
     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
     * @param name_ ERC-20 name of this token
     * @param symbol_ ERC-20 symbol of this token
     * @param decimals_ ERC-20 decimal precision of this token
     * @param admin_ Address of the administrator of this token
     */
    constructor(ComptrollerInterface comptroller_,
                InterestRateModel interestRateModel_,
                uint initialExchangeRateMantissa_,
                string memory name_,
                string memory symbol_,
                uint8 decimals_,
                address payable admin_) {
        // Creator of the contract is admin during initialization
        admin = payable(msg.sender);

        initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);

        // Set the proper admin now that initialization is done
        admin = admin_;
    }


    /*** User Interface ***/

    /**
     * @notice Sender supplies assets into the market and receives cTokens in exchange
     * @dev Reverts upon any failure
     */
    function mint() external payable {
        mintInternal(msg.value);
    }

    /**
     * @notice Sender redeems cTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of cTokens to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeem(uint redeemTokens) external returns (uint) {
        redeemInternal(redeemTokens);
        return NO_ERROR;
    }

    /**
     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to redeem
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemUnderlying(uint redeemAmount) external returns (uint) {
        redeemUnderlyingInternal(redeemAmount);
        return NO_ERROR;
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrow(uint borrowAmount) external returns (uint) {
        borrowInternal(borrowAmount);
        return NO_ERROR;
    }

    /**
     * @notice Sender repays their own borrow
     * @dev Reverts upon any failure
     */
    function repayBorrow() external payable {
        repayBorrowInternal(msg.value);
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @dev Reverts upon any failure
     * @param borrower the account with the debt being payed off
     */
    function repayBorrowBehalf(address borrower) external payable {
        repayBorrowBehalfInternal(borrower, msg.value);
    }

    function repayBorrowBehalfExplictAmount(address borrower, uint repayAmount) external payable {
        repayBorrowBehalfInternal(borrower, repayAmount);
    }

    /**
     * @notice The sender liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @dev Reverts upon any failure
     * @param borrower The borrower of this cToken to be liquidated
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     */
    function liquidateBorrow(address borrower, CToken cTokenCollateral) external payable {
        liquidateBorrowInternal(borrower, msg.value, cTokenCollateral);
    }

    /**
     * @notice The sender adds to reserves.
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _addReserves() external payable returns (uint) {
        return _addReservesInternal(msg.value);
    }

    /**
     * @notice Send Ether to CEther to mint
     */
    receive() external payable {
        mintInternal(msg.value);
    }

    /*** Safe Token ***/

    /**
     * @notice Gets balance of this contract in terms of Ether, before this message
     * @dev This excludes the value of the current message, if any
     * @return The quantity of Ether owned by this contract
     */
    function getCashPrior() override internal view returns (uint) {
        return address(this).balance - msg.value;
    }

    /**
     * @notice Perform the actual transfer in, which is a no-op
     * @param from Address sending the Ether
     * @param amount Amount of Ether being sent
     * @return The actual amount of Ether transferred
     */
    function doTransferIn(address from, uint amount) override internal returns (uint) {
        // Sanity checks
        require(msg.sender == from, "sender mismatch");
        require(msg.value == amount, "value mismatch");
        return amount;
    }

    function doTransferOut(address payable to, uint amount) virtual override internal {
        /* Send the Ether, with minimal gas and revert on failure */
        to.transfer(amount);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AcceptAdminPendingAdminCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualAddAmount","type":"uint256"}],"name":"AddReservesFactorFreshCheck","type":"error"},{"inputs":[],"name":"BorrowCashNotAvailable","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"BorrowComptrollerRejection","type":"error"},{"inputs":[],"name":"BorrowFreshnessCheck","type":"error"},{"inputs":[],"name":"CalldataMustHaveValidPayload","type":"error"},{"inputs":[],"name":"CalldataOverOrUnderFlow","type":"error"},{"inputs":[],"name":"DataPackageTimestampMustNotBeZero","type":"error"},{"inputs":[],"name":"DataPackageTimestampsMustBeEqual","type":"error"},{"inputs":[],"name":"EachSignerMustProvideTheSameValue","type":"error"},{"inputs":[],"name":"EmptyCalldataPointersArr","type":"error"},{"inputs":[],"name":"IncorrectUnsignedMetadataSize","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedSignersCount","type":"uint256"},{"internalType":"uint256","name":"requiredSignersCount","type":"uint256"}],"name":"InsufficientNumberOfUniqueSigners","type":"error"},{"inputs":[],"name":"InvalidCalldataPointer","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateAccrueBorrowInterestFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateAccrueCollateralInterestFailed","type":"error"},{"inputs":[],"name":"LiquidateCloseAmountIsUintMax","type":"error"},{"inputs":[],"name":"LiquidateCloseAmountIsZero","type":"error"},{"inputs":[],"name":"LiquidateCollateralFreshnessCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateComptrollerRejection","type":"error"},{"inputs":[],"name":"LiquidateFreshnessCheck","type":"error"},{"inputs":[],"name":"LiquidateLiquidatorIsBorrower","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateRepayBorrowFreshFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"LiquidateSeizeComptrollerRejection","type":"error"},{"inputs":[],"name":"LiquidateSeizeLiquidatorIsBorrower","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"MintComptrollerRejection","type":"error"},{"inputs":[],"name":"MintFreshnessCheck","type":"error"},{"inputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"name":"ProxyCalldataFailedWithCustomError","type":"error"},{"inputs":[{"internalType":"string","name":"message","type":"string"}],"name":"ProxyCalldataFailedWithStringMessage","type":"error"},{"inputs":[],"name":"ProxyCalldataFailedWithoutErrMsg","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"RedeemComptrollerRejection","type":"error"},{"inputs":[],"name":"RedeemFreshnessCheck","type":"error"},{"inputs":[],"name":"RedeemTransferOutNotPossible","type":"error"},{"inputs":[],"name":"RedstonePayloadMustHaveAtLeastOneDataPackage","type":"error"},{"inputs":[],"name":"ReduceReservesAdminCheck","type":"error"},{"inputs":[],"name":"ReduceReservesCashNotAvailable","type":"error"},{"inputs":[],"name":"ReduceReservesCashValidation","type":"error"},{"inputs":[],"name":"ReduceReservesFreshCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"RepayBorrowComptrollerRejection","type":"error"},{"inputs":[],"name":"RepayBorrowFreshnessCheck","type":"error"},{"inputs":[],"name":"SetComptrollerOwnerCheck","type":"error"},{"inputs":[],"name":"SetInterestRateModelFreshCheck","type":"error"},{"inputs":[],"name":"SetInterestRateModelOwnerCheck","type":"error"},{"inputs":[],"name":"SetPendingAdminOwnerCheck","type":"error"},{"inputs":[],"name":"SetReserveFactorAdminCheck","type":"error"},{"inputs":[],"name":"SetReserveFactorBoundsCheck","type":"error"},{"inputs":[],"name":"SetReserveFactorFreshCheck","type":"error"},{"inputs":[{"internalType":"address","name":"receivedSigner","type":"address"}],"name":"SignerNotAuthorised","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"TransferComptrollerRejection","type":"error"},{"inputs":[],"name":"TransferNotAllowed","type":"error"},{"inputs":[],"name":"TransferNotEnough","type":"error"},{"inputs":[],"name":"TransferTooMuch","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"benefactor","type":"address"},{"indexed":false,"internalType":"uint256","name":"addAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"reduceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"NO_ERROR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_addReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"_setComptroller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extractTimestampsAndAssertAllAreEqual","outputs":[{"internalType":"uint256","name":"extractedTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"contract CToken","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolSeizeShareMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"repayBorrowBehalf","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowBehalfExplictAmount","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b50604051620043d1380380620043d18339810160408190526200003491620006bd565b60038054610100600160a81b03199081163361010002918216171790556200006187878787878762000094565b600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055506200090e945050505050565b60035461010090046001600160a01b03163314620001055760405162461bcd60e51b8152602060048201526024808201527f6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d616044820152631c9ad95d60e21b60648201526084015b60405180910390fd5b600954158015620001165750600a54155b620001705760405162461bcd60e51b815260206004820152602360248201527f6d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6044820152626e636560e81b6064820152608401620000fc565b600784905583620001dd5760405162461bcd60e51b815260206004820152603060248201527f696e697469616c2065786368616e67652072617465206d75737420626520677260448201526f32b0ba32b9103a3430b7103d32b9379760811b6064820152608401620000fc565b6000620001ea87620002f8565b905080156200023c5760405162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c65640000000000006044820152606401620000fc565b43600955670de0b6b3a7640000600a55620002578662000450565b90508015620002b45760405162461bcd60e51b815260206004820152602260248201527f73657474696e6720696e7465726573742072617465206d6f64656c206661696c604482015261195960f21b6064820152608401620000fc565b6001620002c2858262000817565b506002620002d1848262000817565b50506003805460ff90921660ff199283161790556000805490911660011790555050505050565b60035460009061010090046001600160a01b031633146200032c5760405163d219dc1f60e01b815260040160405180910390fd5b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd29160048083019260209291908290030181865afa15801562000377573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200039d9190620008e3565b620003eb5760405162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c7365000000006044820152606401620000fc565b600580546001600160a01b0319166001600160a01b0385811691821790925560408051928416835260208301919091527f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d91015b60405180910390a150600092915050565b600354600090819061010090046001600160a01b03163314620004865760405163407fded560e01b815260040160405180910390fd5b4360095414620004a957604051630be2a5cb60e11b815260040160405180910390fd5b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000500573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005269190620008e3565b620005745760405162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c7365000000006044820152606401620000fc565b600680546001600160a01b0319166001600160a01b0385811691821790925560408051928416835260208301919091527fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f92691016200043f565b6001600160a01b0381168114620005e357600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200060e57600080fd5b81516001600160401b03808211156200062b576200062b620005e6565b604051601f8301601f19908116603f01168101908282118183101715620006565762000656620005e6565b816040528381526020925086838588010111156200067357600080fd5b600091505b8382101562000697578582018301518183018401529082019062000678565b600093810190920192909252949350505050565b8051620006b881620005cd565b919050565b600080600080600080600060e0888a031215620006d957600080fd5b8751620006e681620005cd565b6020890151909750620006f981620005cd565b604089015160608a015191975095506001600160401b03808211156200071e57600080fd5b6200072c8b838c01620005fc565b955060808a01519150808211156200074357600080fd5b50620007528a828b01620005fc565b93505060a088015160ff811681146200076a57600080fd5b91506200077a60c08901620006ab565b905092959891949750929550565b600181811c908216806200079d57607f821691505b602082108103620007be57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200081257600081815260208120601f850160051c81016020861015620007ed5750805b601f850160051c820191505b818110156200080e57828155600101620007f9565b5050505b505050565b81516001600160401b03811115620008335762000833620005e6565b6200084b8162000844845462000788565b84620007c4565b602080601f8311600181146200088357600084156200086a5750858301515b600019600386901b1c1916600185901b1785556200080e565b600085815260208120601f198616915b82811015620008b45788860151825594840194600190910190840162000893565b5085821015620008d35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215620008f657600080fd5b815180151581146200090757600080fd5b9392505050565b613ab3806200091e6000396000f3fe6080604052600436106102cd5760003560e01c80638f840ddd11610175578063c37f68e2116100dc578063f2b3abbd11610095578063f8f9da281161006f578063f8f9da281461084a578063fca7820b1461085f578063fcb641471461087f578063fe9c44ae1461088757600080fd5b8063f2b3abbd146107e5578063f3fdb15a14610805578063f851a4401461082557600080fd5b8063c37f68e2146106f7578063c5ebeaec14610737578063db006a7514610757578063dd62ed3e14610777578063e5974619146107bd578063e9c714f2146107d057600080fd5b8063aa5af0fd1161012e578063aa5af0fd14610664578063aae40a2a1461067a578063ae9d70b01461068d578063b2a02ff1146106a2578063b71d1a0c146106c2578063bd6d894d146106e257600080fd5b80638f840ddd146105c457806395d89b41146105da57806395dd9193146105ef57806399d8c1b41461060f578063a6afed951461062f578063a9059cbb1461064457600080fd5b80634576b5db116102345780636752e702116101ed57806370a08231116101c757806370a082311461054657806373acee981461057c5780637cb05b2914610591578063852a12e3146105a457600080fd5b80636752e7021461050057806369ab32501461051b5780636c540baf1461053057600080fd5b80634576b5db1461046d57806347bd37181461048d5780634e4d9fea146104a357806355a547d5146104ab5780635fe3b567146104c0578063601a0bf1146104e057600080fd5b8063182df0f511610286578063182df0f51461039f57806323b872dd146103b457806326782247146103d4578063313ce5671461040c5780633af9e669146104385780633b1d21a21461045857600080fd5b806306fdde03146102e2578063095ea7b31461030d5780631249c58b1461033d578063173b99041461034557806317bfdfbc1461036957806318160ddd1461038957600080fd5b366102dd576102db3461089c565b005b600080fd5b3480156102ee57600080fd5b506102f76108f4565b6040516103049190613556565b60405180910390f35b34801561031957600080fd5b5061032d61032836600461357e565b610982565b6040519015158152602001610304565b6102db6109f2565b34801561035157600080fd5b5061035b60085481565b604051908152602001610304565b34801561037557600080fd5b5061035b6103843660046135aa565b6109fd565b34801561039557600080fd5b5061035b600d5481565b3480156103ab57600080fd5b5061035b610a50565b3480156103c057600080fd5b5061032d6103cf3660046135c7565b610a5f565b3480156103e057600080fd5b506004546103f4906001600160a01b031681565b6040516001600160a01b039091168152602001610304565b34801561041857600080fd5b506003546104269060ff1681565b60405160ff9091168152602001610304565b34801561044457600080fd5b5061035b6104533660046135aa565b610aaf565b34801561046457600080fd5b5061035b610af5565b34801561047957600080fd5b5061035b6104883660046135aa565b610aff565b34801561049957600080fd5b5061035b600b5481565b6102db610c51565b3480156104b757600080fd5b5061035b610c5a565b3480156104cc57600080fd5b506005546103f4906001600160a01b031681565b3480156104ec57600080fd5b5061035b6104fb366004613608565b610d72565b34801561050c57600080fd5b5061035b666379da05b6000081565b34801561052757600080fd5b5061035b600081565b34801561053c57600080fd5b5061035b60095481565b34801561055257600080fd5b5061035b6105613660046135aa565b6001600160a01b03166000908152600e602052604090205490565b34801561058857600080fd5b5061035b610db1565b6102db61059f36600461357e565b610dfb565b3480156105b057600080fd5b5061035b6105bf366004613608565b610e09565b3480156105d057600080fd5b5061035b600c5481565b3480156105e657600080fd5b506102f7610e1c565b3480156105fb57600080fd5b5061035b61060a3660046135aa565b610e29565b34801561061b57600080fd5b506102db61062a3660046136c4565b610e34565b34801561063b57600080fd5b5061035b611081565b34801561065057600080fd5b5061032d61065f36600461357e565b61126e565b34801561067057600080fd5b5061035b600a5481565b6102db610688366004613770565b6112bd565b34801561069957600080fd5b5061035b6112c8565b3480156106ae57600080fd5b5061035b6106bd3660046135c7565b611360565b3480156106ce57600080fd5b5061035b6106dd3660046135aa565b6113af565b3480156106ee57600080fd5b5061035b61143c565b34801561070357600080fd5b506107176107123660046135aa565b61148c565b604080519485526020850193909352918301526060820152608001610304565b34801561074357600080fd5b5061035b610752366004613608565b6114cd565b34801561076357600080fd5b5061035b610772366004613608565b6114d8565b34801561078357600080fd5b5061035b610792366004613770565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b6102db6107cb3660046135aa565b6114e3565b3480156107dc57600080fd5b5061035b6114f0565b3480156107f157600080fd5b5061035b6108003660046135aa565b6115f7565b34801561081157600080fd5b506006546103f4906001600160a01b031681565b34801561083157600080fd5b506003546103f49061010090046001600160a01b031681565b34801561085657600080fd5b5061035b61160b565b34801561086b57600080fd5b5061035b61087a366004613608565b61165e565b61035b61169d565b34801561089357600080fd5b5061032d600181565b60005460ff166108c75760405162461bcd60e51b81526004016108be906137a9565b60405180910390fd5b6000805460ff191690556108d9611081565b506108e433826116a8565b506000805460ff19166001179055565b60018054610901906137cd565b80601f016020809104026020016040519081016040528092919081815260200182805461092d906137cd565b801561097a5780601f1061094f5761010080835404028352916020019161097a565b820191906000526020600020905b81548152906001019060200180831161095d57829003601f168201915b505050505081565b336000818152600f602090815260408083206001600160a01b03871680855292528083208590555191929182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906109de9087815260200190565b60405180910390a360019150505b92915050565b6109fb3461089c565b565b6000805460ff16610a205760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055610a32611081565b50610a3c82610e29565b90506000805460ff19166001179055919050565b6000610a5a61185e565b905090565b6000805460ff16610a825760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19168155610a98338686866118c6565b1490506000805460ff191660011790559392505050565b6000806040518060200160405280610ac561143c565b90526001600160a01b0384166000908152600e6020526040902054909150610aee908290611af2565b9392505050565b6000610a5a611b12565b60035460009061010090046001600160a01b03163314610b325760405163d219dc1f60e01b815260040160405180910390fd5b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd29160048083019260209291908290030181865afa158015610b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba09190613801565b610bec5760405162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c73650000000060448201526064016108be565b600580546001600160a01b0319166001600160a01b0385811691821790925560408051928416835260208301919091527f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d91015b60405180910390a150600092915050565b6109fb34611b1e565b600080610c65611b6f565b90506000610c7282611c16565b61ffff16905080600003610c9957604051632154bfcf60e21b815260040160405180910390fd5b610ca4600283613839565b915060005b81811015610d6c576000610cbc84611c50565b9050600080610ccc606887613839565b90506000610cda823661384c565b9050803592508265ffffffffffff16600003610d0957604051630336dc9d60e41b815260040160405180910390fd5b87600003610d21578265ffffffffffff169750610d49565b878365ffffffffffff1614610d495760405163d9d1f46560e01b815260040160405180910390fd5b610d538488613839565b9650505050508080610d649061385f565b915050610ca9565b50505090565b6000805460ff16610d955760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055610da7611081565b50610a3c82611c84565b6000805460ff16610dd45760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055610de6611081565b5050600b546000805460ff1916600117905590565b610e058282611d9f565b5050565b6000610e1482611df1565b506000919050565b60028054610901906137cd565b60006109ec82611e32565b60035461010090046001600160a01b03163314610e9f5760405162461bcd60e51b8152602060048201526024808201527f6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d616044820152631c9ad95d60e21b60648201526084016108be565b600954158015610eaf5750600a54155b610f075760405162461bcd60e51b815260206004820152602360248201527f6d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6044820152626e636560e81b60648201526084016108be565b600784905583610f725760405162461bcd60e51b815260206004820152603060248201527f696e697469616c2065786368616e67652072617465206d75737420626520677260448201526f32b0ba32b9103a3430b7103d32b9379760811b60648201526084016108be565b6000610f7d87610aff565b90508015610fcd5760405162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c656400000000000060448201526064016108be565b43600955670de0b6b3a7640000600a55610fe686611e7e565b905080156110415760405162461bcd60e51b815260206004820152602260248201527f73657474696e6720696e7465726573742072617465206d6f64656c206661696c604482015261195960f21b60648201526084016108be565b600161104d85826138c6565b50600261105a84826138c6565b50506003805460ff90921660ff199283161790556000805490911660011790555050505050565b60095460009043908181036110995760009250505090565b60006110a3611b12565b600b54600c54600a546006546040516315f2405360e01b81526004810186905260248101859052604481018490529495509293919290916000916001600160a01b0316906315f2405390606401602060405180830381865afa15801561110d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111319190613986565b905065048c273950008111156111895760405162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c7920686967680000000060448201526064016108be565b6000611195878961384c565b905060006111b160405180602001604052808581525083611ff3565b905060006111bf8288611af2565b905060006111cd8883613839565b905060006111ec6040518060200160405280600854815250848a612024565b905060006111fb85898a612024565b60098e9055600a819055600b849055600c839055604080518d815260208101879052908101829052606081018590529091507f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049060800160405180910390a160009d505050505050505050505050505090565b6000805460ff166112915760405162461bcd60e51b81526004016108be906137a9565b6000805460ff191681556112a7338086866118c6565b1490506000805460ff1916600117905592915050565b610e05823483612045565b6006546000906001600160a01b031663b81688166112e4611b12565b600b54600c546008546040516001600160e01b031960e087901b16815260048101949094526024840192909252604483015260648201526084015b602060405180830381865afa15801561133c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5a9190613986565b6000805460ff166113835760405162461bcd60e51b81526004016108be906137a9565b6000805460ff1916905561139933858585612123565b50600080805460ff191660011790559392505050565b60035460009061010090046001600160a01b031633146113e257604051635cb56c2b60e01b815260040160405180910390fd5b600480546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99101610c40565b6000805460ff1661145f5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611471611081565b5061147a610a50565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600e602052604081205481908190819081906114b687611e32565b6114be61185e565b93509350935093509193509193565b6000610e148261239b565b6000610e14826123da565b6114ed8134611d9f565b50565b6004546000906001600160a01b03163314158061150b575033155b1561152957604051631ba24f2960e21b815260040160405180910390fd5b60038054600480546001600160a01b03808216610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401529290917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc910160405180910390a1600454604080516001600160a01b03808516825290921660208301527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9910160405180910390a160009250505090565b6000611601611081565b506109ec82611e7e565b6006546000906001600160a01b03166315f24053611627611b12565b600b54600c546040516001600160e01b031960e086901b16815260048101939093526024830191909152604482015260640161131f565b6000805460ff166116815760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611693611081565b50610a3c8261241b565b6000610a5a346124d7565b600554604051634ef4c3e160e01b81526000916001600160a01b031690634ef4c3e1906116dd9030908790879060040161399f565b6020604051808303816000875af11580156116fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117209190613986565b90508015611744576040516349abd4fd60e01b8152600481018290526024016108be565b4360095414611766576040516338d8859760e01b815260040160405180910390fd5b6000604051806020016040528061177b61185e565b90529050600061178b858561252e565b9050600061179982846125c0565b905080600d546117a99190613839565b600d556001600160a01b0386166000908152600e60205260409020546117d0908290613839565b6001600160a01b0387166000908152600e60205260409081902091909155517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f90611820908890859085906139c3565b60405180910390a16040518181526001600160a01b038716903090600080516020613a5e8339815191529060200160405180910390a3505050505050565b600d5460009080820361187357505060075490565b600061187d611b12565b90506000600c54600b54836118929190613839565b61189c919061384c565b90506000836118b3670de0b6b3a7640000846139e4565b6118bd91906139fb565b95945050505050565b6005546040516317b9b84b60e31b81523060048201526001600160a01b038581166024830152848116604483015260648201849052600092839291169063bdcdc258906084016020604051808303816000875af115801561192b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194f9190613986565b905080156119735760405163089d427760e11b8152600481018290526024016108be565b836001600160a01b0316856001600160a01b0316036119a557604051638cd22d1960e01b815260040160405180910390fd5b6000856001600160a01b0316876001600160a01b0316036119c957506000196119f1565b506001600160a01b038086166000908152600f60209081526040808320938a16835292905220545b60006119fd858361384c565b6001600160a01b0388166000908152600e602052604081205491925090611a2590879061384c565b6001600160a01b0388166000908152600e602052604081205491925090611a4d908890613839565b6001600160a01b03808b166000908152600e6020526040808220869055918b1681522081905590506000198414611aa7576001600160a01b03808a166000908152600f60209081526040808320938e168352929052208390555b876001600160a01b0316896001600160a01b0316600080516020613a5e83398151915289604051611ada91815260200190565b60405180910390a35060009998505050505050505050565b600080611aff8484611ff3565b9050611b0a816125de565b949350505050565b6000610a5a344761384c565b60005460ff16611b405760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611b52611081565b50611b5e3333836125f6565b50506000805460ff19166001179055565b60006602ed57011e0000601f1936013581161480611ba0576040516373bb264f60e11b815260040160405180910390fd5b60003660291115611bc457604051632bcb7bc560e11b815260040160405180910390fd5b5060281936013560006009611bdf600362ffffff8516613839565b611be99190613839565b905036611bf7600283613839565b1115610aee5760405163c30a7bd760e01b815260040160405180910390fd5b600080611c24602084613839565b905036811115611c4757604051632bcb7bc560e11b815260040160405180910390fd5b36033592915050565b6000806000611c5e8461279f565b9092509050604e611c70826020613839565b611c7a90846139e4565b611b0a9190613839565b600354600090819061010090046001600160a01b03163314611cb957604051630f7e5e6d60e41b815260040160405180910390fd5b4360095414611cdb57604051630dff50cb60e41b815260040160405180910390fd5b82611ce4611b12565b1015611d0357604051633345e99960e01b815260040160405180910390fd5b600c54831115611d26576040516378d2980560e11b815260040160405180910390fd5b82600c54611d34919061384c565b600c819055600354909150611d579061010090046001600160a01b0316846127f6565b7f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e600360019054906101000a90046001600160a01b03168483604051610c40939291906139c3565b60005460ff16611dc15760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611dd3611081565b50611ddf3383836125f6565b50506000805460ff1916600117905550565b60005460ff16611e135760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611e25611081565b506108e433600083612831565b6001600160a01b038116600090815260106020526040812080548203611e5b5750600092915050565b600a548154600091611e6c916139e4565b9050816001015481611b0a91906139fb565b600354600090819061010090046001600160a01b03163314611eb35760405163407fded560e01b815260040160405180910390fd5b4360095414611ed557604051630be2a5cb60e11b815260040160405180910390fd5b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4f9190613801565b611f9b5760405162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c73650000000060448201526064016108be565b600680546001600160a01b0319166001600160a01b0385811691821790925560408051928416835260208301919091527fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269101610c40565b604080516020810190915260008152604051806020016040528061201b856000015185612b1f565b90529392505050565b6000806120318585611ff3565b90506118bd61203f826125de565b84612b2b565b60005460ff166120675760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055612079611081565b506000816001600160a01b031663a6afed956040518163ffffffff1660e01b81526004016020604051808303816000875af11580156120bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e09190613986565b9050801561210457604051633eea49b760e11b8152600481018290526024016108be565b61211033858585612b37565b50506000805460ff191660011790555050565b60055460405163d02f735160e01b81523060048201526001600160a01b0386811660248301528581166044830152848116606483015260848201849052600092169063d02f73519060a4016020604051808303816000875af115801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b19190613986565b905080156121d5576040516363e00e3360e11b8152600481018290526024016108be565b836001600160a01b0316836001600160a01b03160361220757604051633a94626760e11b815260040160405180910390fd5b6000612228836040518060200160405280666379da05b60000815250612fff565b90506000612236828561384c565b90506000604051806020016040528061224d61185e565b90529050600061225d8285611af2565b9050600081600c5461226f9190613839565b600c819055600d5490915061228590869061384c565b600d556001600160a01b0388166000908152600e60205260409020546122ac90889061384c565b6001600160a01b03808a166000908152600e602052604080822093909355908b16815220546122dc908590613839565b6001600160a01b03808b166000818152600e602052604090819020939093559151908a1690600080516020613a5e8339815191529061231e9088815260200190565b60405180910390a360405185815230906001600160a01b038a1690600080516020613a5e8339815191529060200160405180910390a37fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5308383604051612387939291906139c3565b60405180910390a150505050505050505050565b60005460ff166123bd5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff191690556123cf611081565b506108e43382613022565b60005460ff166123fc5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff1916905561240e611081565b506108e433826000612831565b60035460009061010090046001600160a01b0316331461244e57604051631205b57b60e11b815260040160405180910390fd5b436009541461247057604051637dfca6b760e11b815260040160405180910390fd5b670de0b6b3a76400008211156124995760405163717220f360e11b815260040160405180910390fd5b600880549083905560408051828152602081018590527faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f8214609101610c40565b6000805460ff166124fa5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff1916905561250c611081565b50612516826131d2565b5050600090506000805460ff19166001179055919050565b6000336001600160a01b0384161461257a5760405162461bcd60e51b815260206004820152600f60248201526e0e6cadcc8cae440dad2e6dac2e8c6d608b1b60448201526064016108be565b8134146125ba5760405162461bcd60e51b815260206004820152600e60248201526d0ecc2d8eaca40dad2e6dac2e8c6d60931b60448201526064016108be565b50919050565b6000610aee6125d784670de0b6b3a7640000612b1f565b8351613266565b80516000906109ec90670de0b6b3a7640000906139fb565b600554604051631200453160e11b81523060048201526001600160a01b03858116602483015284811660448301526064820184905260009283929116906324008a62906084016020604051808303816000875af115801561265b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267f9190613986565b905080156126a357604051638c81362d60e01b8152600481018290526024016108be565b43600954146126c55760405163c9021e2f60e01b815260040160405180910390fd5b60006126d085611e32565b9050600060001985146126e357846126e5565b815b905060006126f3888361252e565b90506000612701828561384c565b9050600082600b54612713919061384c565b6001600160a01b038a8116600081815260106020908152604091829020878155600a54600190910155600b8590558151938f168452830191909152810185905260608101849052608081018290529091507f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a19060a00160405180910390a1509098975050505050505050565b6000808080806127b0604187613839565b905060006127c96127c2602084613839565b3690613272565b8035945090506127da816003613272565b62ffffff9490941697933563ffffffff16965092945050505050565b6040516001600160a01b0383169082156108fc029083906000818181858888f1935050505015801561282c573d6000803e3d6000fd5b505050565b81158061283c575080155b6128a55760405162461bcd60e51b815260206004820152603460248201527f6f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416044820152736d6f756e74496e206d757374206265207a65726f60601b60648201526084016108be565b600060405180602001604052806128ba61185e565b9052905060008084156128db578491506128d48386611af2565b90506128eb565b6128e584846125c0565b91508390505b600063eabe7d9160e01b30888560405160240161290a9392919061399f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915260055490915060009061295a906001600160a01b031683600161327e565b90506000818060200190518101906129729190613986565b905080156129965760405163480f424760e01b8152600481018290526024016108be565b43600954146129b8576040516397b5cfcd60e01b815260040160405180910390fd5b836129c1611b12565b10156129e0576040516391240a1b60e01b815260040160405180910390fd5b84600d546129ee919061384c565b600d556001600160a01b0389166000908152600e6020526040902054612a1590869061384c565b6001600160a01b038a166000908152600e6020526040902055612a3889856127f6565b60405185815230906001600160a01b038b1690600080516020613a5e8339815191529060200160405180910390a37fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929898587604051612a99939291906139c3565b60405180910390a16005546040516351dff98960e01b81523060048201526001600160a01b038b811660248301526044820187905260648201889052909116906351dff98990608401600060405180830381600087803b158015612afc57600080fd5b505af1158015612b10573d6000803e3d6000fd5b50505050505050505050505050565b6000610aee82846139e4565b6000610aee8284613839565b604080513060248201526001600160a01b0383811660448301528681166064830152858116608483015260a48083018690528351808403909101815260c49092019092526020810180516001600160e01b0316632fe3f38f60e11b1790526005549091600091612baa911683600161327e565b9050600081806020019051810190612bc29190613986565b90508015612be657604051630a14d17960e11b8152600481018290526024016108be565b4360095414612c08576040516380965b1b60e01b815260040160405180910390fd5b43846001600160a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c6b9190613986565b14612c8957604051631046f38d60e31b815260040160405180910390fd5b866001600160a01b0316866001600160a01b031603612cbb57604051631bd1a62160e21b815260040160405180910390fd5b84600003612cdc5760405163d29da7ef60e01b815260040160405180910390fd5b6000198503612cfe57604051635982c5bb60e11b815260040160405180910390fd5b6000612d0b8888886125f6565b9050600063c488847b60e01b308784604051602401612d2c9392919061399f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152600554909150600090612d7a906001600160a01b031683613312565b905060008082806020019051810190612d939190613a1d565b9150915060008214612e035760405162461bcd60e51b815260206004820152603360248201527f4c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455f604482015272105353d5539517d4d152569157d19052531151606a1b60648201526084016108be565b6040516370a0823160e01b81526001600160a01b038c811660048301528291908b16906370a0823190602401602060405180830381865afa158015612e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e709190613986565b1015612ebe5760405162461bcd60e51b815260206004820152601860248201527f4c49515549444154455f5345495a455f544f4f5f4d554348000000000000000060448201526064016108be565b306001600160a01b038a1603612edf57612eda308d8d84612123565b612f98565b6000896001600160a01b031663b2a02ff18e8e856040518463ffffffff1660e01b8152600401612f119392919061399f565b6020604051808303816000875af1158015612f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f549190613986565b14612f985760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881cd95a5e9d5c994819985a5b195960621b60448201526064016108be565b604080516001600160a01b038e811682528d811660208301528183018890528b1660608201526080810183905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb529181900360a00190a1505050505050505050505050565b6000670de0b6b3a7640000613018848460000151612b1f565b610aee91906139fb565b600063da3d454c60e01b3084846040516024016130419392919061399f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152600554909150600090613091906001600160a01b031683600161327e565b90506000818060200190518101906130a99190613986565b905080156130cd5760405163918db40f60e01b8152600481018290526024016108be565b43600954146130ef57604051630e8d8c6160e21b815260040160405180910390fd5b836130f8611b12565b1015613117576040516348c2588160e01b815260040160405180910390fd5b600061312286611e32565b905060006131308683613839565b9050600086600b546131429190613839565b6001600160a01b0389166000908152601060205260409020838155600a54600190910155600b819055905061317788886127f6565b604080516001600160a01b038a16815260208101899052908101839052606081018290527f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809060800160405180910390a15050505050505050565b600080808043600954146131fc576040516338acf79960e01b8152600481018290526024016108be565b613206338661252e565b905080600c546132169190613839565b915081600c819055507fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5338284604051613252939291906139c3565b60405180910390a160009590945092505050565b6000610aee82846139fb565b6000610aee828461384c565b6060600061328b84613395565b9050600080866001600160a01b0316856132a65760006132a8565b345b846040516132b69190613a41565b60006040518083038185875af1925050503d80600081146132f3576040519150601f19603f3d011682016040523d82523d6000602084013e6132f8565b606091505b50915091506133078282613424565b979650505050505050565b6060600061331f83613395565b9050600080856001600160a01b03168360405161333c9190613a41565b600060405180830381855afa9150503d8060008114613377576040519150601f19603f3d011682016040523d82523d6000602084013e61337c565b606091505b509150915061338b8282613424565b9695505050505050565b805160609060006133a461349b565b905060006133b28284613839565b9050368211156133d557604051632bcb7bc560e11b815260040160405180910390fd5b6060604051905081815285602001848101826020015b818310156134035782518152602092830192016133eb565b50505082833603856020018301379190920181016020016040529392505050565b6060826125ba57815160000361344d57604051632b3ff13d60e11b815260040160405180910390fd5b602082015162461bcd60e51b148015613480576040516301efd04f60e31b815260448401906108be908290600401613556565b8260405163fd36fde360e01b81526004016108be9190613556565b6000806134a6611b6f565b905060006134b382611c16565b61ffff1690506134c4600283613839565b915060005b818110156134fe5760006134dc84611c50565b90506134e88185613839565b93505080806134f69061385f565b9150506134c9565b509092915050565b60005b83811015613521578181015183820152602001613509565b50506000910152565b60008151808452613542816020860160208601613506565b601f01601f19169290920160200192915050565b602081526000610aee602083018461352a565b6001600160a01b03811681146114ed57600080fd5b6000806040838503121561359157600080fd5b823561359c81613569565b946020939093013593505050565b6000602082840312156135bc57600080fd5b8135610aee81613569565b6000806000606084860312156135dc57600080fd5b83356135e781613569565b925060208401356135f781613569565b929592945050506040919091013590565b60006020828403121561361a57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261364857600080fd5b813567ffffffffffffffff8082111561366357613663613621565b604051601f8301601f19908116603f0116810190828211818310171561368b5761368b613621565b816040528381528660208588010111156136a457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c087890312156136dd57600080fd5b86356136e881613569565b955060208701356136f881613569565b945060408701359350606087013567ffffffffffffffff8082111561371c57600080fd5b6137288a838b01613637565b9450608089013591508082111561373e57600080fd5b5061374b89828a01613637565b92505060a087013560ff8116811461376257600080fd5b809150509295509295509295565b6000806040838503121561378357600080fd5b823561378e81613569565b9150602083013561379e81613569565b809150509250929050565b6020808252600a90820152691c994b595b9d195c995960b21b604082015260600190565b600181811c908216806137e157607f821691505b6020821081036125ba57634e487b7160e01b600052602260045260246000fd5b60006020828403121561381357600080fd5b81518015158114610aee57600080fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156109ec576109ec613823565b818103818111156109ec576109ec613823565b60006001820161387157613871613823565b5060010190565b601f82111561282c57600081815260208120601f850160051c8101602086101561389f5750805b601f850160051c820191505b818110156138be578281556001016138ab565b505050505050565b815167ffffffffffffffff8111156138e0576138e0613621565b6138f4816138ee84546137cd565b84613878565b602080601f83116001811461392957600084156139115750858301515b600019600386901b1c1916600185901b1785556138be565b600085815260208120601f198616915b8281101561395857888601518255948401946001909101908401613939565b50858210156139765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561399857600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039390931683526020830191909152604082015260600190565b80820281158282048414176109ec576109ec613823565b600082613a1857634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215613a3057600080fd5b505080516020909101519092909150565b60008251613a53818460208701613506565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220720e43dea4a62214f8a971deda5becee7b0947a2a48a0046d34b8191f5eb1b9964736f6c63430008120033000000000000000000000000efb0697700e5c489073a9bdf7ef94a2b2bc884a500000000000000000000000038e6357e895335cc92a6076a3ace5fff4869545f00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000002254957426f17d301df996e1351a82bf79dd99a90000000000000000000000000000000000000000000000000000000000000004634554480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106102cd5760003560e01c80638f840ddd11610175578063c37f68e2116100dc578063f2b3abbd11610095578063f8f9da281161006f578063f8f9da281461084a578063fca7820b1461085f578063fcb641471461087f578063fe9c44ae1461088757600080fd5b8063f2b3abbd146107e5578063f3fdb15a14610805578063f851a4401461082557600080fd5b8063c37f68e2146106f7578063c5ebeaec14610737578063db006a7514610757578063dd62ed3e14610777578063e5974619146107bd578063e9c714f2146107d057600080fd5b8063aa5af0fd1161012e578063aa5af0fd14610664578063aae40a2a1461067a578063ae9d70b01461068d578063b2a02ff1146106a2578063b71d1a0c146106c2578063bd6d894d146106e257600080fd5b80638f840ddd146105c457806395d89b41146105da57806395dd9193146105ef57806399d8c1b41461060f578063a6afed951461062f578063a9059cbb1461064457600080fd5b80634576b5db116102345780636752e702116101ed57806370a08231116101c757806370a082311461054657806373acee981461057c5780637cb05b2914610591578063852a12e3146105a457600080fd5b80636752e7021461050057806369ab32501461051b5780636c540baf1461053057600080fd5b80634576b5db1461046d57806347bd37181461048d5780634e4d9fea146104a357806355a547d5146104ab5780635fe3b567146104c0578063601a0bf1146104e057600080fd5b8063182df0f511610286578063182df0f51461039f57806323b872dd146103b457806326782247146103d4578063313ce5671461040c5780633af9e669146104385780633b1d21a21461045857600080fd5b806306fdde03146102e2578063095ea7b31461030d5780631249c58b1461033d578063173b99041461034557806317bfdfbc1461036957806318160ddd1461038957600080fd5b366102dd576102db3461089c565b005b600080fd5b3480156102ee57600080fd5b506102f76108f4565b6040516103049190613556565b60405180910390f35b34801561031957600080fd5b5061032d61032836600461357e565b610982565b6040519015158152602001610304565b6102db6109f2565b34801561035157600080fd5b5061035b60085481565b604051908152602001610304565b34801561037557600080fd5b5061035b6103843660046135aa565b6109fd565b34801561039557600080fd5b5061035b600d5481565b3480156103ab57600080fd5b5061035b610a50565b3480156103c057600080fd5b5061032d6103cf3660046135c7565b610a5f565b3480156103e057600080fd5b506004546103f4906001600160a01b031681565b6040516001600160a01b039091168152602001610304565b34801561041857600080fd5b506003546104269060ff1681565b60405160ff9091168152602001610304565b34801561044457600080fd5b5061035b6104533660046135aa565b610aaf565b34801561046457600080fd5b5061035b610af5565b34801561047957600080fd5b5061035b6104883660046135aa565b610aff565b34801561049957600080fd5b5061035b600b5481565b6102db610c51565b3480156104b757600080fd5b5061035b610c5a565b3480156104cc57600080fd5b506005546103f4906001600160a01b031681565b3480156104ec57600080fd5b5061035b6104fb366004613608565b610d72565b34801561050c57600080fd5b5061035b666379da05b6000081565b34801561052757600080fd5b5061035b600081565b34801561053c57600080fd5b5061035b60095481565b34801561055257600080fd5b5061035b6105613660046135aa565b6001600160a01b03166000908152600e602052604090205490565b34801561058857600080fd5b5061035b610db1565b6102db61059f36600461357e565b610dfb565b3480156105b057600080fd5b5061035b6105bf366004613608565b610e09565b3480156105d057600080fd5b5061035b600c5481565b3480156105e657600080fd5b506102f7610e1c565b3480156105fb57600080fd5b5061035b61060a3660046135aa565b610e29565b34801561061b57600080fd5b506102db61062a3660046136c4565b610e34565b34801561063b57600080fd5b5061035b611081565b34801561065057600080fd5b5061032d61065f36600461357e565b61126e565b34801561067057600080fd5b5061035b600a5481565b6102db610688366004613770565b6112bd565b34801561069957600080fd5b5061035b6112c8565b3480156106ae57600080fd5b5061035b6106bd3660046135c7565b611360565b3480156106ce57600080fd5b5061035b6106dd3660046135aa565b6113af565b3480156106ee57600080fd5b5061035b61143c565b34801561070357600080fd5b506107176107123660046135aa565b61148c565b604080519485526020850193909352918301526060820152608001610304565b34801561074357600080fd5b5061035b610752366004613608565b6114cd565b34801561076357600080fd5b5061035b610772366004613608565b6114d8565b34801561078357600080fd5b5061035b610792366004613770565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b6102db6107cb3660046135aa565b6114e3565b3480156107dc57600080fd5b5061035b6114f0565b3480156107f157600080fd5b5061035b6108003660046135aa565b6115f7565b34801561081157600080fd5b506006546103f4906001600160a01b031681565b34801561083157600080fd5b506003546103f49061010090046001600160a01b031681565b34801561085657600080fd5b5061035b61160b565b34801561086b57600080fd5b5061035b61087a366004613608565b61165e565b61035b61169d565b34801561089357600080fd5b5061032d600181565b60005460ff166108c75760405162461bcd60e51b81526004016108be906137a9565b60405180910390fd5b6000805460ff191690556108d9611081565b506108e433826116a8565b506000805460ff19166001179055565b60018054610901906137cd565b80601f016020809104026020016040519081016040528092919081815260200182805461092d906137cd565b801561097a5780601f1061094f5761010080835404028352916020019161097a565b820191906000526020600020905b81548152906001019060200180831161095d57829003601f168201915b505050505081565b336000818152600f602090815260408083206001600160a01b03871680855292528083208590555191929182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906109de9087815260200190565b60405180910390a360019150505b92915050565b6109fb3461089c565b565b6000805460ff16610a205760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055610a32611081565b50610a3c82610e29565b90506000805460ff19166001179055919050565b6000610a5a61185e565b905090565b6000805460ff16610a825760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19168155610a98338686866118c6565b1490506000805460ff191660011790559392505050565b6000806040518060200160405280610ac561143c565b90526001600160a01b0384166000908152600e6020526040902054909150610aee908290611af2565b9392505050565b6000610a5a611b12565b60035460009061010090046001600160a01b03163314610b325760405163d219dc1f60e01b815260040160405180910390fd5b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd29160048083019260209291908290030181865afa158015610b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba09190613801565b610bec5760405162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c73650000000060448201526064016108be565b600580546001600160a01b0319166001600160a01b0385811691821790925560408051928416835260208301919091527f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d91015b60405180910390a150600092915050565b6109fb34611b1e565b600080610c65611b6f565b90506000610c7282611c16565b61ffff16905080600003610c9957604051632154bfcf60e21b815260040160405180910390fd5b610ca4600283613839565b915060005b81811015610d6c576000610cbc84611c50565b9050600080610ccc606887613839565b90506000610cda823661384c565b9050803592508265ffffffffffff16600003610d0957604051630336dc9d60e41b815260040160405180910390fd5b87600003610d21578265ffffffffffff169750610d49565b878365ffffffffffff1614610d495760405163d9d1f46560e01b815260040160405180910390fd5b610d538488613839565b9650505050508080610d649061385f565b915050610ca9565b50505090565b6000805460ff16610d955760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055610da7611081565b50610a3c82611c84565b6000805460ff16610dd45760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055610de6611081565b5050600b546000805460ff1916600117905590565b610e058282611d9f565b5050565b6000610e1482611df1565b506000919050565b60028054610901906137cd565b60006109ec82611e32565b60035461010090046001600160a01b03163314610e9f5760405162461bcd60e51b8152602060048201526024808201527f6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d616044820152631c9ad95d60e21b60648201526084016108be565b600954158015610eaf5750600a54155b610f075760405162461bcd60e51b815260206004820152602360248201527f6d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6044820152626e636560e81b60648201526084016108be565b600784905583610f725760405162461bcd60e51b815260206004820152603060248201527f696e697469616c2065786368616e67652072617465206d75737420626520677260448201526f32b0ba32b9103a3430b7103d32b9379760811b60648201526084016108be565b6000610f7d87610aff565b90508015610fcd5760405162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c656400000000000060448201526064016108be565b43600955670de0b6b3a7640000600a55610fe686611e7e565b905080156110415760405162461bcd60e51b815260206004820152602260248201527f73657474696e6720696e7465726573742072617465206d6f64656c206661696c604482015261195960f21b60648201526084016108be565b600161104d85826138c6565b50600261105a84826138c6565b50506003805460ff90921660ff199283161790556000805490911660011790555050505050565b60095460009043908181036110995760009250505090565b60006110a3611b12565b600b54600c54600a546006546040516315f2405360e01b81526004810186905260248101859052604481018490529495509293919290916000916001600160a01b0316906315f2405390606401602060405180830381865afa15801561110d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111319190613986565b905065048c273950008111156111895760405162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c7920686967680000000060448201526064016108be565b6000611195878961384c565b905060006111b160405180602001604052808581525083611ff3565b905060006111bf8288611af2565b905060006111cd8883613839565b905060006111ec6040518060200160405280600854815250848a612024565b905060006111fb85898a612024565b60098e9055600a819055600b849055600c839055604080518d815260208101879052908101829052606081018590529091507f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049060800160405180910390a160009d505050505050505050505050505090565b6000805460ff166112915760405162461bcd60e51b81526004016108be906137a9565b6000805460ff191681556112a7338086866118c6565b1490506000805460ff1916600117905592915050565b610e05823483612045565b6006546000906001600160a01b031663b81688166112e4611b12565b600b54600c546008546040516001600160e01b031960e087901b16815260048101949094526024840192909252604483015260648201526084015b602060405180830381865afa15801561133c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5a9190613986565b6000805460ff166113835760405162461bcd60e51b81526004016108be906137a9565b6000805460ff1916905561139933858585612123565b50600080805460ff191660011790559392505050565b60035460009061010090046001600160a01b031633146113e257604051635cb56c2b60e01b815260040160405180910390fd5b600480546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99101610c40565b6000805460ff1661145f5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611471611081565b5061147a610a50565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600e602052604081205481908190819081906114b687611e32565b6114be61185e565b93509350935093509193509193565b6000610e148261239b565b6000610e14826123da565b6114ed8134611d9f565b50565b6004546000906001600160a01b03163314158061150b575033155b1561152957604051631ba24f2960e21b815260040160405180910390fd5b60038054600480546001600160a01b03808216610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401529290917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc910160405180910390a1600454604080516001600160a01b03808516825290921660208301527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9910160405180910390a160009250505090565b6000611601611081565b506109ec82611e7e565b6006546000906001600160a01b03166315f24053611627611b12565b600b54600c546040516001600160e01b031960e086901b16815260048101939093526024830191909152604482015260640161131f565b6000805460ff166116815760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611693611081565b50610a3c8261241b565b6000610a5a346124d7565b600554604051634ef4c3e160e01b81526000916001600160a01b031690634ef4c3e1906116dd9030908790879060040161399f565b6020604051808303816000875af11580156116fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117209190613986565b90508015611744576040516349abd4fd60e01b8152600481018290526024016108be565b4360095414611766576040516338d8859760e01b815260040160405180910390fd5b6000604051806020016040528061177b61185e565b90529050600061178b858561252e565b9050600061179982846125c0565b905080600d546117a99190613839565b600d556001600160a01b0386166000908152600e60205260409020546117d0908290613839565b6001600160a01b0387166000908152600e60205260409081902091909155517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f90611820908890859085906139c3565b60405180910390a16040518181526001600160a01b038716903090600080516020613a5e8339815191529060200160405180910390a3505050505050565b600d5460009080820361187357505060075490565b600061187d611b12565b90506000600c54600b54836118929190613839565b61189c919061384c565b90506000836118b3670de0b6b3a7640000846139e4565b6118bd91906139fb565b95945050505050565b6005546040516317b9b84b60e31b81523060048201526001600160a01b038581166024830152848116604483015260648201849052600092839291169063bdcdc258906084016020604051808303816000875af115801561192b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194f9190613986565b905080156119735760405163089d427760e11b8152600481018290526024016108be565b836001600160a01b0316856001600160a01b0316036119a557604051638cd22d1960e01b815260040160405180910390fd5b6000856001600160a01b0316876001600160a01b0316036119c957506000196119f1565b506001600160a01b038086166000908152600f60209081526040808320938a16835292905220545b60006119fd858361384c565b6001600160a01b0388166000908152600e602052604081205491925090611a2590879061384c565b6001600160a01b0388166000908152600e602052604081205491925090611a4d908890613839565b6001600160a01b03808b166000908152600e6020526040808220869055918b1681522081905590506000198414611aa7576001600160a01b03808a166000908152600f60209081526040808320938e168352929052208390555b876001600160a01b0316896001600160a01b0316600080516020613a5e83398151915289604051611ada91815260200190565b60405180910390a35060009998505050505050505050565b600080611aff8484611ff3565b9050611b0a816125de565b949350505050565b6000610a5a344761384c565b60005460ff16611b405760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611b52611081565b50611b5e3333836125f6565b50506000805460ff19166001179055565b60006602ed57011e0000601f1936013581161480611ba0576040516373bb264f60e11b815260040160405180910390fd5b60003660291115611bc457604051632bcb7bc560e11b815260040160405180910390fd5b5060281936013560006009611bdf600362ffffff8516613839565b611be99190613839565b905036611bf7600283613839565b1115610aee5760405163c30a7bd760e01b815260040160405180910390fd5b600080611c24602084613839565b905036811115611c4757604051632bcb7bc560e11b815260040160405180910390fd5b36033592915050565b6000806000611c5e8461279f565b9092509050604e611c70826020613839565b611c7a90846139e4565b611b0a9190613839565b600354600090819061010090046001600160a01b03163314611cb957604051630f7e5e6d60e41b815260040160405180910390fd5b4360095414611cdb57604051630dff50cb60e41b815260040160405180910390fd5b82611ce4611b12565b1015611d0357604051633345e99960e01b815260040160405180910390fd5b600c54831115611d26576040516378d2980560e11b815260040160405180910390fd5b82600c54611d34919061384c565b600c819055600354909150611d579061010090046001600160a01b0316846127f6565b7f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e600360019054906101000a90046001600160a01b03168483604051610c40939291906139c3565b60005460ff16611dc15760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611dd3611081565b50611ddf3383836125f6565b50506000805460ff1916600117905550565b60005460ff16611e135760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055611e25611081565b506108e433600083612831565b6001600160a01b038116600090815260106020526040812080548203611e5b5750600092915050565b600a548154600091611e6c916139e4565b9050816001015481611b0a91906139fb565b600354600090819061010090046001600160a01b03163314611eb35760405163407fded560e01b815260040160405180910390fd5b4360095414611ed557604051630be2a5cb60e11b815260040160405180910390fd5b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4f9190613801565b611f9b5760405162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c73650000000060448201526064016108be565b600680546001600160a01b0319166001600160a01b0385811691821790925560408051928416835260208301919091527fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269101610c40565b604080516020810190915260008152604051806020016040528061201b856000015185612b1f565b90529392505050565b6000806120318585611ff3565b90506118bd61203f826125de565b84612b2b565b60005460ff166120675760405162461bcd60e51b81526004016108be906137a9565b6000805460ff19169055612079611081565b506000816001600160a01b031663a6afed956040518163ffffffff1660e01b81526004016020604051808303816000875af11580156120bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e09190613986565b9050801561210457604051633eea49b760e11b8152600481018290526024016108be565b61211033858585612b37565b50506000805460ff191660011790555050565b60055460405163d02f735160e01b81523060048201526001600160a01b0386811660248301528581166044830152848116606483015260848201849052600092169063d02f73519060a4016020604051808303816000875af115801561218d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b19190613986565b905080156121d5576040516363e00e3360e11b8152600481018290526024016108be565b836001600160a01b0316836001600160a01b03160361220757604051633a94626760e11b815260040160405180910390fd5b6000612228836040518060200160405280666379da05b60000815250612fff565b90506000612236828561384c565b90506000604051806020016040528061224d61185e565b90529050600061225d8285611af2565b9050600081600c5461226f9190613839565b600c819055600d5490915061228590869061384c565b600d556001600160a01b0388166000908152600e60205260409020546122ac90889061384c565b6001600160a01b03808a166000908152600e602052604080822093909355908b16815220546122dc908590613839565b6001600160a01b03808b166000818152600e602052604090819020939093559151908a1690600080516020613a5e8339815191529061231e9088815260200190565b60405180910390a360405185815230906001600160a01b038a1690600080516020613a5e8339815191529060200160405180910390a37fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5308383604051612387939291906139c3565b60405180910390a150505050505050505050565b60005460ff166123bd5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff191690556123cf611081565b506108e43382613022565b60005460ff166123fc5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff1916905561240e611081565b506108e433826000612831565b60035460009061010090046001600160a01b0316331461244e57604051631205b57b60e11b815260040160405180910390fd5b436009541461247057604051637dfca6b760e11b815260040160405180910390fd5b670de0b6b3a76400008211156124995760405163717220f360e11b815260040160405180910390fd5b600880549083905560408051828152602081018590527faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f8214609101610c40565b6000805460ff166124fa5760405162461bcd60e51b81526004016108be906137a9565b6000805460ff1916905561250c611081565b50612516826131d2565b5050600090506000805460ff19166001179055919050565b6000336001600160a01b0384161461257a5760405162461bcd60e51b815260206004820152600f60248201526e0e6cadcc8cae440dad2e6dac2e8c6d608b1b60448201526064016108be565b8134146125ba5760405162461bcd60e51b815260206004820152600e60248201526d0ecc2d8eaca40dad2e6dac2e8c6d60931b60448201526064016108be565b50919050565b6000610aee6125d784670de0b6b3a7640000612b1f565b8351613266565b80516000906109ec90670de0b6b3a7640000906139fb565b600554604051631200453160e11b81523060048201526001600160a01b03858116602483015284811660448301526064820184905260009283929116906324008a62906084016020604051808303816000875af115801561265b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267f9190613986565b905080156126a357604051638c81362d60e01b8152600481018290526024016108be565b43600954146126c55760405163c9021e2f60e01b815260040160405180910390fd5b60006126d085611e32565b9050600060001985146126e357846126e5565b815b905060006126f3888361252e565b90506000612701828561384c565b9050600082600b54612713919061384c565b6001600160a01b038a8116600081815260106020908152604091829020878155600a54600190910155600b8590558151938f168452830191909152810185905260608101849052608081018290529091507f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a19060a00160405180910390a1509098975050505050505050565b6000808080806127b0604187613839565b905060006127c96127c2602084613839565b3690613272565b8035945090506127da816003613272565b62ffffff9490941697933563ffffffff16965092945050505050565b6040516001600160a01b0383169082156108fc029083906000818181858888f1935050505015801561282c573d6000803e3d6000fd5b505050565b81158061283c575080155b6128a55760405162461bcd60e51b815260206004820152603460248201527f6f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416044820152736d6f756e74496e206d757374206265207a65726f60601b60648201526084016108be565b600060405180602001604052806128ba61185e565b9052905060008084156128db578491506128d48386611af2565b90506128eb565b6128e584846125c0565b91508390505b600063eabe7d9160e01b30888560405160240161290a9392919061399f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915260055490915060009061295a906001600160a01b031683600161327e565b90506000818060200190518101906129729190613986565b905080156129965760405163480f424760e01b8152600481018290526024016108be565b43600954146129b8576040516397b5cfcd60e01b815260040160405180910390fd5b836129c1611b12565b10156129e0576040516391240a1b60e01b815260040160405180910390fd5b84600d546129ee919061384c565b600d556001600160a01b0389166000908152600e6020526040902054612a1590869061384c565b6001600160a01b038a166000908152600e6020526040902055612a3889856127f6565b60405185815230906001600160a01b038b1690600080516020613a5e8339815191529060200160405180910390a37fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929898587604051612a99939291906139c3565b60405180910390a16005546040516351dff98960e01b81523060048201526001600160a01b038b811660248301526044820187905260648201889052909116906351dff98990608401600060405180830381600087803b158015612afc57600080fd5b505af1158015612b10573d6000803e3d6000fd5b50505050505050505050505050565b6000610aee82846139e4565b6000610aee8284613839565b604080513060248201526001600160a01b0383811660448301528681166064830152858116608483015260a48083018690528351808403909101815260c49092019092526020810180516001600160e01b0316632fe3f38f60e11b1790526005549091600091612baa911683600161327e565b9050600081806020019051810190612bc29190613986565b90508015612be657604051630a14d17960e11b8152600481018290526024016108be565b4360095414612c08576040516380965b1b60e01b815260040160405180910390fd5b43846001600160a01b0316636c540baf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c6b9190613986565b14612c8957604051631046f38d60e31b815260040160405180910390fd5b866001600160a01b0316866001600160a01b031603612cbb57604051631bd1a62160e21b815260040160405180910390fd5b84600003612cdc5760405163d29da7ef60e01b815260040160405180910390fd5b6000198503612cfe57604051635982c5bb60e11b815260040160405180910390fd5b6000612d0b8888886125f6565b9050600063c488847b60e01b308784604051602401612d2c9392919061399f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152600554909150600090612d7a906001600160a01b031683613312565b905060008082806020019051810190612d939190613a1d565b9150915060008214612e035760405162461bcd60e51b815260206004820152603360248201527f4c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455f604482015272105353d5539517d4d152569157d19052531151606a1b60648201526084016108be565b6040516370a0823160e01b81526001600160a01b038c811660048301528291908b16906370a0823190602401602060405180830381865afa158015612e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e709190613986565b1015612ebe5760405162461bcd60e51b815260206004820152601860248201527f4c49515549444154455f5345495a455f544f4f5f4d554348000000000000000060448201526064016108be565b306001600160a01b038a1603612edf57612eda308d8d84612123565b612f98565b6000896001600160a01b031663b2a02ff18e8e856040518463ffffffff1660e01b8152600401612f119392919061399f565b6020604051808303816000875af1158015612f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f549190613986565b14612f985760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881cd95a5e9d5c994819985a5b195960621b60448201526064016108be565b604080516001600160a01b038e811682528d811660208301528183018890528b1660608201526080810183905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb529181900360a00190a1505050505050505050505050565b6000670de0b6b3a7640000613018848460000151612b1f565b610aee91906139fb565b600063da3d454c60e01b3084846040516024016130419392919061399f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152600554909150600090613091906001600160a01b031683600161327e565b90506000818060200190518101906130a99190613986565b905080156130cd5760405163918db40f60e01b8152600481018290526024016108be565b43600954146130ef57604051630e8d8c6160e21b815260040160405180910390fd5b836130f8611b12565b1015613117576040516348c2588160e01b815260040160405180910390fd5b600061312286611e32565b905060006131308683613839565b9050600086600b546131429190613839565b6001600160a01b0389166000908152601060205260409020838155600a54600190910155600b819055905061317788886127f6565b604080516001600160a01b038a16815260208101899052908101839052606081018290527f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809060800160405180910390a15050505050505050565b600080808043600954146131fc576040516338acf79960e01b8152600481018290526024016108be565b613206338661252e565b905080600c546132169190613839565b915081600c819055507fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5338284604051613252939291906139c3565b60405180910390a160009590945092505050565b6000610aee82846139fb565b6000610aee828461384c565b6060600061328b84613395565b9050600080866001600160a01b0316856132a65760006132a8565b345b846040516132b69190613a41565b60006040518083038185875af1925050503d80600081146132f3576040519150601f19603f3d011682016040523d82523d6000602084013e6132f8565b606091505b50915091506133078282613424565b979650505050505050565b6060600061331f83613395565b9050600080856001600160a01b03168360405161333c9190613a41565b600060405180830381855afa9150503d8060008114613377576040519150601f19603f3d011682016040523d82523d6000602084013e61337c565b606091505b509150915061338b8282613424565b9695505050505050565b805160609060006133a461349b565b905060006133b28284613839565b9050368211156133d557604051632bcb7bc560e11b815260040160405180910390fd5b6060604051905081815285602001848101826020015b818310156134035782518152602092830192016133eb565b50505082833603856020018301379190920181016020016040529392505050565b6060826125ba57815160000361344d57604051632b3ff13d60e11b815260040160405180910390fd5b602082015162461bcd60e51b148015613480576040516301efd04f60e31b815260448401906108be908290600401613556565b8260405163fd36fde360e01b81526004016108be9190613556565b6000806134a6611b6f565b905060006134b382611c16565b61ffff1690506134c4600283613839565b915060005b818110156134fe5760006134dc84611c50565b90506134e88185613839565b93505080806134f69061385f565b9150506134c9565b509092915050565b60005b83811015613521578181015183820152602001613509565b50506000910152565b60008151808452613542816020860160208601613506565b601f01601f19169290920160200192915050565b602081526000610aee602083018461352a565b6001600160a01b03811681146114ed57600080fd5b6000806040838503121561359157600080fd5b823561359c81613569565b946020939093013593505050565b6000602082840312156135bc57600080fd5b8135610aee81613569565b6000806000606084860312156135dc57600080fd5b83356135e781613569565b925060208401356135f781613569565b929592945050506040919091013590565b60006020828403121561361a57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261364857600080fd5b813567ffffffffffffffff8082111561366357613663613621565b604051601f8301601f19908116603f0116810190828211818310171561368b5761368b613621565b816040528381528660208588010111156136a457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c087890312156136dd57600080fd5b86356136e881613569565b955060208701356136f881613569565b945060408701359350606087013567ffffffffffffffff8082111561371c57600080fd5b6137288a838b01613637565b9450608089013591508082111561373e57600080fd5b5061374b89828a01613637565b92505060a087013560ff8116811461376257600080fd5b809150509295509295509295565b6000806040838503121561378357600080fd5b823561378e81613569565b9150602083013561379e81613569565b809150509250929050565b6020808252600a90820152691c994b595b9d195c995960b21b604082015260600190565b600181811c908216806137e157607f821691505b6020821081036125ba57634e487b7160e01b600052602260045260246000fd5b60006020828403121561381357600080fd5b81518015158114610aee57600080fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156109ec576109ec613823565b818103818111156109ec576109ec613823565b60006001820161387157613871613823565b5060010190565b601f82111561282c57600081815260208120601f850160051c8101602086101561389f5750805b601f850160051c820191505b818110156138be578281556001016138ab565b505050505050565b815167ffffffffffffffff8111156138e0576138e0613621565b6138f4816138ee84546137cd565b84613878565b602080601f83116001811461392957600084156139115750858301515b600019600386901b1c1916600185901b1785556138be565b600085815260208120601f198616915b8281101561395857888601518255948401946001909101908401613939565b50858210156139765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561399857600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039390931683526020830191909152604082015260600190565b80820281158282048414176109ec576109ec613823565b600082613a1857634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215613a3057600080fd5b505080516020909101519092909150565b60008251613a53818460208701613506565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220720e43dea4a62214f8a971deda5becee7b0947a2a48a0046d34b8191f5eb1b9964736f6c63430008120033

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

000000000000000000000000efb0697700e5c489073a9bdf7ef94a2b2bc884a500000000000000000000000038e6357e895335cc92a6076a3ace5fff4869545f00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000002254957426f17d301df996e1351a82bf79dd99a90000000000000000000000000000000000000000000000000000000000000004634554480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : comptroller_ (address): 0xEFB0697700E5c489073a9BDF7EF94a2B2bc884a5
Arg [1] : interestRateModel_ (address): 0x38e6357E895335cC92a6076a3aCE5FFf4869545F
Arg [2] : initialExchangeRateMantissa_ (uint256): 500000000000000000
Arg [3] : name_ (string): cETH
Arg [4] : symbol_ (string): cETH
Arg [5] : decimals_ (uint8): 8
Arg [6] : admin_ (address): 0x2254957426F17D301df996e1351a82BF79dD99A9

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000efb0697700e5c489073a9bdf7ef94a2b2bc884a5
Arg [1] : 00000000000000000000000038e6357e895335cc92a6076a3ace5fff4869545f
Arg [2] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [6] : 0000000000000000000000002254957426f17d301df996e1351a82bf79dd99a9
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [8] : 6345544800000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [10] : 6345544800000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

113078:5527:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;117489:23;117502:9;117489:12;:23::i;:::-;113078:5527;;;;;11881:18;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;56367:246;;;;;;;;;;-1:-1:-1;56367:246:0;;;;;:::i;:::-;;:::i;:::-;;;1391:14:1;;1384:22;1366:41;;1354:2;1339:18;56367:246:0;1226:187:1;114438:75:0;;;:::i;13104:33::-;;;;;;;;;;;;;;;;;;;1564:25:1;;;1552:2;1537:18;13104:33:0;1418:177:1;60086:174:0;;;;;;;;;;-1:-1:-1;60086:174:0;;;;;:::i;:::-;;:::i;13749:23::-;;;;;;;;;;;;;;;;62233:120;;;;;;;;;;;;;:::i;55696:192::-;;;;;;;;;;-1:-1:-1;55696:192:0;;;;;:::i;:::-;;:::i;12554:35::-;;;;;;;;;;-1:-1:-1;12554:35:0;;;;-1:-1:-1;;;;;12554:35:0;;;;;;-1:-1:-1;;;;;2493:32:1;;;2475:51;;2463:2;2448:18;12554:35:0;2313:219:1;12077:21:0;;;;;;;;;;-1:-1:-1;12077:21:0;;;;;;;;;;;2709:4:1;2697:17;;;2679:36;;2667:2;2652:18;12077:21:0;2537:184:1;57662:232:0;;;;;;;;;;-1:-1:-1;57662:232:0;;;;;:::i;:::-;;:::i;63553:97::-;;;;;;;;;;;;;:::i;91686:693::-;;;;;;;;;;-1:-1:-1;91686:693:0;;;;;:::i;:::-;;:::i;13513:24::-;;;;;;;;;;;;;;;;116015:89;;;:::i;40436:1448::-;;;;;;;;;;;;;:::i;12680:39::-;;;;;;;;;;-1:-1:-1;12680:39:0;;;;-1:-1:-1;;;;;12680:39:0;;;96683:280;;;;;;;;;;-1:-1:-1;96683:280:0;;;;;:::i;:::-;;:::i;14644:56::-;;;;;;;;;;;;14694:6;14644:56;;8301:33;;;;;;;;;;;;8333:1;8301:33;;13227:30;;;;;;;;;;;;;;;;57285:121;;;;;;;;;;-1:-1:-1;57285:121:0;;;;;:::i;:::-;-1:-1:-1;;;;;57378:20:0;57351:7;57378:20;;;:13;:20;;;;;;;57285:121;59653:142;;;;;;;;;;;;;:::i;116430:160::-;;;;;;:::i;:::-;;:::i;115352:152::-;;;;;;;;;;-1:-1:-1;115352:152:0;;;;;:::i;:::-;;:::i;13643:25::-;;;;;;;;;;;;;;;;11977:20;;;;;;;;;;;;;:::i;60469:144::-;;;;;;;;;;-1:-1:-1;60469:144:0;;;;;:::i;:::-;;:::i;51379:1505::-;;;;;;;;;;-1:-1:-1;51379:1505:0;;;;;:::i;:::-;;:::i;63898:2570::-;;;;;;;;;;;;;:::i;55207:182::-;;;;;;;;;;-1:-1:-1;55207:182:0;;;;;:::i;:::-;;:::i;13378:23::-;;;;;;;;;;;;;;;;116942:166;;;;;;:::i;:::-;;:::i;59314:193::-;;;;;;;;;;;;;:::i;86681:224::-;;;;;;;;;;-1:-1:-1;86681:224:0;;;;;:::i;:::-;;:::i;89873:604::-;;;;;;;;;;-1:-1:-1;89873:604:0;;;;;:::i;:::-;;:::i;61835:148::-;;;;;;;;;;;;;:::i;58240:292::-;;;;;;;;;;-1:-1:-1;58240:292:0;;;;;:::i;:::-;;:::i;:::-;;;;6295:25:1;;;6351:2;6336:18;;6329:34;;;;6379:18;;;6372:34;6437:2;6422:18;;6415:34;6282:3;6267:19;58240:292:0;6064:391:1;115772:132:0;;;;;;;;;;-1:-1:-1;115772:132:0;;;;;:::i;:::-;;:::i;114864:::-;;;;;;;;;;-1:-1:-1;114864:132:0;;;;;:::i;:::-;;:::i;56943:152::-;;;;;;;;;;-1:-1:-1;56943:152:0;;;;;:::i;:::-;-1:-1:-1;;;;;57053:25:0;;;57026:7;57053:25;;;:18;:25;;;;;;;;:34;;;;;;;;;;;;;56943:152;116295:127;;;;;;:::i;:::-;;:::i;90755:706::-;;;;;;;;;;;;;:::i;98996:321::-;;;;;;;;;;-1:-1:-1;98996:321:0;;;;;:::i;:::-;;:::i;12821:42::-;;;;;;;;;;-1:-1:-1;12821:42:0;;;;-1:-1:-1;;;;;12821:42:0;;;12443:28;;;;;;;;;;-1:-1:-1;12443:28:0;;;;;;;-1:-1:-1;;;;;12443:28:0;;;58968:170;;;;;;;;;;;;;:::i;92682:307::-;;;;;;;;;;-1:-1:-1;92682:307:0;;;;;:::i;:::-;;:::i;117267:113::-;;;:::i;14865:36::-;;;;;;;;;;;;14897:4;14865:36;;66738:244;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;;;;;;;;;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;66810:16:::1;:14;:16::i;:::-;;66941:33;66951:10;66963;66941:9;:33::i;:::-;-1:-1:-1::0;102218:11:0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;66738:244::o;11881:18::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;56367:246::-;56475:10;56444:4;56496:23;;;:18;:23;;;;;;;;-1:-1:-1;;;;;56496:32:0;;;;;;;;;;:41;;;56553:30;56444:4;;56475:10;;;56553:30;;;;56531:6;1564:25:1;;1552:2;1537:18;;1418:177;56553:30:0;;;;;;;;56601:4;56594:11;;;56367:246;;;;;:::o;114438:75::-;114482:23;114495:9;114482:12;:23::i;:::-;114438:75::o;60086:174::-;60173:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;60190:16:::1;:14;:16::i;:::-;;60224:28;60244:7;60224:19;:28::i;:::-;60217:35;;102218:11:::0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;60086:174;;-1:-1:-1;60086:174:0:o;62233:120::-;62293:4;62317:28;:26;:28::i;:::-;62310:35;;62233:120;:::o;55696:192::-;55800:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;55824:44:::1;55839:10;55851:3:::0;55856;55861:6;55824:14:::1;:44::i;:::-;:56;55817:63;;102218:11:::0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;55696:192;;-1:-1:-1;;;55696:192:0:o;57662:232::-;57733:4;57750:23;57776:38;;;;;;;;57791:21;:19;:21::i;:::-;57776:38;;-1:-1:-1;;;;;57865:20:0;;;;;;:13;:20;;;;;;57750:64;;-1:-1:-1;57832:54:0;;57750:64;;57832:18;:54::i;:::-;57825:61;57662:232;-1:-1:-1;;;57662:232:0:o;63553:97::-;63604:4;63628:14;:12;:14::i;91686:693::-;91842:5;;91773:4;;91842:5;;;-1:-1:-1;;;;;91842:5:0;91828:10;:19;91824:85;;91871:26;;-1:-1:-1;;;91871:26:0;;;;;;;;;;;91824:85;91959:11;;92056:30;;;-1:-1:-1;;;92056:30:0;;;;-1:-1:-1;;;;;91959:11:0;;;;92056:28;;;;;:30;;;;;;;;;;;;;;:28;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92048:71;;;;-1:-1:-1;;;92048:71:0;;8571:2:1;92048:71:0;;;8553:21:1;8610:2;8590:18;;;8583:30;8649;8629:18;;;8622:58;8697:18;;92048:71:0;8369:352:1;92048:71:0;92187:11;:28;;-1:-1:-1;;;;;;92187:28:0;-1:-1:-1;;;;;92187:28:0;;;;;;;;;92297:46;;;9012:15:1;;;8994:34;;9059:2;9044:18;;9037:43;;;;92297:46:0;;8929:18:1;92297:46:0;;;;;;;;-1:-1:-1;8333:1:0;;91686:693;-1:-1:-1;;91686:693:0:o;116015:89::-;116066:30;116086:9;116066:19;:30::i;40436:1448::-;40506:26;40541:30;40574:36;:34;:36::i;:::-;40541:69;;40617:25;40645:61;40683:22;40645:37;:61::i;:::-;40617:89;;;;40719:17;40740:1;40719:22;40715:98;;40759:46;;-1:-1:-1;;;40759:46:0;;;;;;;;;;;40715:98;40821:48;31844:1;40821:48;;:::i;:::-;;;40881:24;40876:1003;40930:17;40911:16;:36;40876:1003;;;40978:27;41008:47;41032:22;41008:23;:47::i;:::-;40978:77;-1:-1:-1;41126:27:0;;41239:88;32496:3;41239:22;:88;:::i;:::-;41204:124;-1:-1:-1;41337:23:0;41363:41;41204:124;41363:8;:41;:::i;:::-;41337:67;;41470:15;41457:29;41433:53;;41509:20;:25;;41533:1;41509:25;41505:94;;41554:35;;-1:-1:-1;;;41554:35:0;;;;;;;;;;;41505:94;41613:18;41635:1;41613:23;41609:207;;41670:20;41649:41;;;;41609:207;;;41734:18;41710:20;:42;;;41706:110;;41772:34;;-1:-1:-1;;;41772:34:0;;;;;;;;;;;41706:110;41826:45;41852:19;41826:45;;:::i;:::-;;;40969:910;;;;40949:18;;;;;:::i;:::-;;;;40876:1003;;;;40534:1350;;40436:1448;:::o;96683:280::-;96767:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;96784:16:::1;:14;:16::i;:::-;;96921:34;96942:12;96921:20;:34::i;59653:142::-:0;59724:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;59741:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;59775:12:0::1;::::0;102218:11;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;59653:142;:::o;116430:160::-;116534:48;116560:8;116570:11;116534:25;:48::i;:::-;116430:160;;:::o;115352:152::-;115415:4;115432:38;115457:12;115432:24;:38::i;:::-;-1:-1:-1;8333:1:0;;115352:152;-1:-1:-1;115352:152:0:o;11977:20::-;;;;;;;:::i;60469:144::-;60545:4;60569:36;60597:7;60569:27;:36::i;51379:1505::-;51733:5;;;;;-1:-1:-1;;;;;51733:5:0;51719:10;:19;51711:68;;;;-1:-1:-1;;;51711:68:0;;9828:2:1;51711:68:0;;;9810:21:1;9867:2;9847:18;;;9840:30;9906:34;9886:18;;;9879:62;-1:-1:-1;;;9957:18:1;;;9950:34;10001:19;;51711:68:0;9626:400:1;51711:68:0;51798:18;;:23;:43;;;;-1:-1:-1;51825:11:0;;:16;51798:43;51790:91;;;;-1:-1:-1;;;51790:91:0;;10233:2:1;51790:91:0;;;10215:21:1;10272:2;10252:18;;;10245:30;10311:34;10291:18;;;10284:62;-1:-1:-1;;;10362:18:1;;;10355:33;10405:19;;51790:91:0;10031:399:1;51790:91:0;51932:27;:58;;;52009:31;52001:92;;;;-1:-1:-1;;;52001:92:0;;10637:2:1;52001:92:0;;;10619:21:1;10676:2;10656:18;;;10649:30;10715:34;10695:18;;;10688:62;-1:-1:-1;;;10766:18:1;;;10759:46;10822:19;;52001:92:0;10435:412:1;52001:92:0;52138:8;52149:29;52165:12;52149:15;:29::i;:::-;52138:40;-1:-1:-1;52197:15:0;;52189:54;;;;-1:-1:-1;;;52189:54:0;;11054:2:1;52189:54:0;;;11036:21:1;11093:2;11073:18;;;11066:30;11132:28;11112:18;;;11105:56;11178:18;;52189:54:0;10852:350:1;52189:54:0;58772:12;52362:18;:37;25213:4;52410:11;:25;52535:46;52562:18;52535:26;:46::i;:::-;52529:52;-1:-1:-1;52600:15:0;;52592:62;;;;-1:-1:-1;;;52592:62:0;;11409:2:1;52592:62:0;;;11391:21:1;11448:2;11428:18;;;11421:30;11487:34;11467:18;;;11460:62;-1:-1:-1;;;11538:18:1;;;11531:32;11580:19;;52592:62:0;11207:398:1;52592:62:0;52667:4;:12;52674:5;52667:4;:12;:::i;:::-;-1:-1:-1;52690:6:0;:16;52699:7;52690:6;:16;:::i;:::-;-1:-1:-1;;52717:8:0;:20;;;;;;-1:-1:-1;;52717:20:0;;;;;;:8;52858:18;;;;;52717:20;52858:18;;;-1:-1:-1;;;;;51379:1505:0:o;63898:2570::-;64107:18;;63957:4;;58772:12;;64195:45;;;64191:93;;8333:1;64257:15;;;;63898:2570;:::o;64191:93::-;64351:14;64368;:12;:14::i;:::-;64413:12;;64457:13;;64505:11;;64613:17;;:71;;-1:-1:-1;;;64613:71:0;;;;;14016:25:1;;;14057:18;;;14050:34;;;14100:18;;;14093:34;;;64351:31:0;;-1:-1:-1;64413:12:0;;64457:13;;64505:11;;64393:17;;-1:-1:-1;;;;;64613:17:0;;:31;;13989:18:1;;64613:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;64587:97;;12224:9;64703:18;:43;;64695:84;;;;-1:-1:-1;;;64695:84:0;;14529:2:1;64695:84:0;;;14511:21:1;14568:2;14548:18;;;14541:30;14607;14587:18;;;14580:58;14655:18;;64695:84:0;14327:352:1;64695:84:0;64869:15;64887:44;64908:23;64887:18;:44;:::i;:::-;64869:62;;65423:31;65457:53;65462:35;;;;;;;;65477:18;65462:35;;;65499:10;65457:4;:53::i;:::-;65423:87;;65521:24;65548:54;65567:20;65589:12;65548:18;:54::i;:::-;65521:81;-1:-1:-1;65613:20:0;65636:34;65658:12;65521:81;65636:34;:::i;:::-;65613:57;;65681:21;65705:101;65731:38;;;;;;;;65746:21;;65731:38;;;65771:19;65792:13;65705:25;:101::i;:::-;65681:125;;65817:19;65839:83;65865:20;65887:16;65905;65839:25;:83::i;:::-;66126:18;:39;;;66176:11;:28;;;66215:12;:30;;;66256:13;:32;;;66353:79;;;6295:25:1;;;6351:2;6336:18;;6329:34;;;6379:18;;;6372:34;;;6437:2;6422:18;;6415:34;;;66176:28:0;;-1:-1:-1;66353:79:0;;6282:3:1;6267:19;66353:79:0;;;;;;;8333:1;66445:15;;;;;;;;;;;;;;;63898:2570;:::o;55207:182::-;55294:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;55318:51:::1;55333:10;::::0;55357:3;55362:6;55318:14:::1;:51::i;:::-;:63;55311:70;;102218:11:::0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;55207:182;;-1:-1:-1;;55207:182:0:o;116942:166::-;117038:62;117062:8;117072:9;117083:16;117038:23;:62::i;59314:193::-;59400:17;;59376:4;;-1:-1:-1;;;;;59400:17:0;:31;59432:14;:12;:14::i;:::-;59448:12;;59462:13;;59477:21;;59400:99;;-1:-1:-1;;;;;;59400:99:0;;;;;;;;;;6295:25:1;;;;6336:18;;;6329:34;;;;6379:18;;;6372:34;6422:18;;;6415:34;6267:19;;59400:99:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;86681:224::-;86792:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;86809:60:::1;86823:10;86835::::0;86847:8;86857:11;86809:13:::1;:60::i;:::-;-1:-1:-1::0;8333:1:0::1;102218:11:::0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;86681:224;;-1:-1:-1;;;86681:224:0:o;89873:604::-;90027:5;;89959:4;;90027:5;;;-1:-1:-1;;;;;90027:5:0;90013:10;:19;90009:86;;90056:27;;-1:-1:-1;;;90056:27:0;;;;;;;;;;;90009:86;90194:12;;;-1:-1:-1;;;;;90277:30:0;;;-1:-1:-1;;;;;;90277:30:0;;;;;;;90392:49;;;90194:12;;;;8994:34:1;;;9059:2;9044:18;;9037:43;;;;90392:49:0;;8929:18:1;90392:49:0;8726:360:1;61835:148:0;61904:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;61921:16:::1;:14;:16::i;:::-;;61955:20;:18;:20::i;:::-;61948:27;;102218:11:::0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;61835:148;:::o;58240:292::-;-1:-1:-1;;;;;58397:22:0;;58317:4;58397:22;;;:13;:22;;;;;;58317:4;;;;;;;;58434:36;58411:7;58434:27;:36::i;:::-;58485:28;:26;:28::i;:::-;58352:172;;;;;;;;58240:292;;;;;:::o;115772:132::-;115825:4;115842:28;115857:12;115842:14;:28::i;114864:132::-;114917:4;114934:28;114949:12;114934:14;:28::i;116295:127::-;116368:46;116394:8;116404:9;116368:25;:46::i;:::-;116295:127;:::o;90755:706::-;90912:12;;90806:4;;-1:-1:-1;;;;;90912:12:0;90898:10;:26;;;:54;;-1:-1:-1;90928:10:0;:24;90898:54;90894:124;;;90976:30;;-1:-1:-1;;;90976:30:0;;;;;;;;;;;90894:124;91102:5;;;91144:12;;;-1:-1:-1;;;;;91144:12:0;;;91102:5;91217:20;;;-1:-1:-1;;;;;;91217:20:0;;;;;;;-1:-1:-1;;;;;;91286:34:0;;;;;;91338:25;;;91102:5;;;;;;8994:34:1;;;91357:5:0;;;;;9059:2:1;9044:18;;9037:43;91102:5:0;91144:12;;91338:25;;8929:18:1;91338:25:0;;;;;;;91412:12;;91379:46;;;-1:-1:-1;;;;;9012:15:1;;;8994:34;;91412:12:0;;;9059:2:1;9044:18;;9037:43;91379:46:0;;8929:18:1;91379:46:0;;;;;;;8333:1;91438:15;;;;90755:706;:::o;98996:321::-;99092:4;99109:16;:14;:16::i;:::-;;99261:48;99288:20;99261:26;:48::i;58968:170::-;59054:17;;59030:4;;-1:-1:-1;;;;;59054:17:0;:31;59086:14;:12;:14::i;:::-;59102:12;;59116:13;;59054:76;;-1:-1:-1;;;;;;59054:76:0;;;;;;;;;;14016:25:1;;;;14057:18;;;14050:34;;;;14100:18;;;14093:34;13989:18;;59054:76:0;13814:319:1;92682:307:0;92780:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;92797:16:::1;:14;:16::i;:::-;;92933:48;92956:24;92933:22;:48::i;117267:113::-:0;117317:4;117341:31;117362:9;117341:20;:31::i;67323:2215::-;67450:11;;:58;;-1:-1:-1;;;67450:58:0;;67435:12;;-1:-1:-1;;;;;67450:11:0;;:23;;:58;;67482:4;;67489:6;;67497:10;;67450:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67435:73;-1:-1:-1;67523:12:0;;67519:85;;67559:33;;-1:-1:-1;;;67559:33:0;;;;;1564:25:1;;;1537:18;;67559:33:0;1418:177:1;67519:85:0;58772:12;67692:18;;:38;67688:98;;67754:20;;-1:-1:-1;;;67754:20:0;;;;;;;;;;;67688:98;67798:23;67824:45;;;;;;;;67839:28;:26;:28::i;:::-;67824:45;;67798:71;-1:-1:-1;68478:21:0;68502:32;68515:6;68523:10;68502:12;:32::i;:::-;68478:56;;68727:15;68745:36;68750:16;68768:12;68745:4;:36::i;:::-;68727:54;;69115:10;69101:11;;:24;;;;:::i;:::-;69087:11;:38;-1:-1:-1;;;;;69160:21:0;;;;;;:13;:21;;;;;;:34;;69184:10;;69160:34;:::i;:::-;-1:-1:-1;;;;;69136:21:0;;;;;;:13;:21;;;;;;;:58;;;;69270:42;;;;;69150:6;;69283:16;;69301:10;;69270:42;:::i;:::-;;;;;;;;69328:43;;1564:25:1;;;-1:-1:-1;;;;;69328:43:0;;;69345:4;;-1:-1:-1;;;;;;;;;;;69328:43:0;1552:2:1;1537:18;69328:43:0;;;;;;;67384:2154;;;;67323:2215;;:::o;62603:780::-;62709:11;;62672:4;;62735:17;;;62731:645;;-1:-1:-1;;62908:27:0;;;62603:780::o;62731:645::-;63117:14;63134;:12;:14::i;:::-;63117:31;;63163:33;63226:13;;63211:12;;63199:9;:24;;;;:::i;:::-;:40;;;;:::i;:::-;63163:76;-1:-1:-1;63254:17:0;63316:12;63274:39;25213:4;63163:76;63274:39;:::i;:::-;:54;;;;:::i;:::-;63254:74;62603:780;-1:-1:-1;;;;;62603:780:0:o;53350:1596::-;53524:11;;:60;;-1:-1:-1;;;53524:60:0;;53560:4;53524:60;;;16395:34:1;-1:-1:-1;;;;;16465:15:1;;;16445:18;;;16438:43;16517:15;;;16497:18;;;16490:43;16549:18;;;16542:34;;;53448:4:0;;;;53524:11;;;:27;;16329:19:1;;53524:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;53509:75;-1:-1:-1;53599:12:0;;53595:89;;53635:37;;-1:-1:-1;;;53635:37:0;;;;;1564:25:1;;;1537:18;;53635:37:0;1418:177:1;53595:89:0;53750:3;-1:-1:-1;;;;;53743:10:0;:3;-1:-1:-1;;;;;53743:10:0;;53739:70;;53777:20;;-1:-1:-1;;;53777:20:0;;;;;;;;;;;53739:70;53886:22;53938:3;-1:-1:-1;;;;;53927:14:0;:7;-1:-1:-1;;;;;53927:14:0;;53923:166;;-1:-1:-1;;;53923:166:0;;;-1:-1:-1;;;;;;54045:23:0;;;;;;;:18;:23;;;;;;;;:32;;;;;;;;;;53923:166;54167:17;54187:26;54207:6;54187:17;:26;:::i;:::-;-1:-1:-1;;;;;54244:18:0;;54224:17;54244:18;;;:13;:18;;;;;;54167:46;;-1:-1:-1;54224:17:0;54244:27;;54265:6;;54244:27;:::i;:::-;-1:-1:-1;;;;;54302:18:0;;54282:17;54302:18;;;:13;:18;;;;;;54224:47;;-1:-1:-1;54282:17:0;54302:27;;54323:6;;54302:27;:::i;:::-;-1:-1:-1;;;;;54463:18:0;;;;;;;:13;:18;;;;;;:33;;;54507:18;;;;;;:33;;;54282:47;-1:-1:-1;;;54613:35:0;;54609:115;;-1:-1:-1;;;;;54665:23:0;;;;;;;:18;:23;;;;;;;;:32;;;;;;;;;:47;;;54609:115;54795:3;-1:-1:-1;;;;;54781:26:0;54790:3;-1:-1:-1;;;;;54781:26:0;-1:-1:-1;;;;;;;;;;;54800:6:0;54781:26;;;;1564:25:1;;1552:2;1537:18;;1418:177;54781:26:0;;;;;;;;-1:-1:-1;8333:1:0;;53350:1596;-1:-1:-1;;;;;;;;;53350:1596:0:o;25935:174::-;26013:4;26030:18;26051:15;26056:1;26059:6;26051:4;:15::i;:::-;26030:36;;26084:17;26093:7;26084:8;:17::i;:::-;26077:24;25935:174;-1:-1:-1;;;;25935:174:0:o;117788:121::-;117844:4;117868:33;117892:9;117868:21;:33;:::i;77768:261::-;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;77848:16:::1;:14;:16::i;:::-;;77968:53;77985:10;77997;78009:11;77968:16;:53::i;:::-;-1:-1:-1::0;;102218:11:0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;77768:261::o;42298:1200::-;42367:7;42679:20;-1:-1:-1;;42542:14:0;42538:37;42525:51;42654:46;;42610:99;;42722:83;;42767:30;;-1:-1:-1;;;42767:30:0;;;;;;;;;;;42722:83;42890:31;42975:8;32958:2;42932:58;42928:113;;;43008:25;;-1:-1:-1;;;43008:25:0;;;;;;;;;;;42928:113;-1:-1:-1;;;43120:14:0;43116:61;43093:93;43199:30;32200:1;43232:64;32147:1;43232:64;;;;:::i;:::-;:92;;;;:::i;:::-;43199:125;-1:-1:-1;43385:8:0;43335:47;31844:1;43199:125;43335:47;:::i;:::-;:65;43331:126;;;43418:31;;-1:-1:-1;;;43418:31:0;;;;;;;;;;;43583:540;43700:24;;43785:41;31229:2;43785:22;:41;:::i;:::-;43736:90;-1:-1:-1;43878:8:0;43837:56;;43833:111;;;43911:25;;-1:-1:-1;;;43911:25:0;;;;;;;;;;;43833:111;44016:14;44012:59;43989:91;;43583:540;-1:-1:-1;;43583:540:0:o;41890:402::-;41978:7;42003:23;42035:34;42079:63;42119:22;42079:39;:63::i;:::-;41994:148;;-1:-1:-1;41994:148:0;-1:-1:-1;32652:2:0;42191:49;41994:148;32018:2;42191:49;:::i;:::-;42165:76;;:15;:76;:::i;:::-;:121;;;;:::i;97240:1387::-;97451:5;;97307:4;;;;97451:5;;;-1:-1:-1;;;;;97451:5:0;97437:10;:19;97433:85;;97480:26;;-1:-1:-1;;;97480:26:0;;;;;;;;;;;97433:85;58772:12;97622:18;;:38;97618:104;;97684:26;;-1:-1:-1;;;97684:26:0;;;;;;;;;;;97618:104;97828:12;97811:14;:12;:14::i;:::-;:29;97807:101;;;97864:32;;-1:-1:-1;;;97864:32:0;;;;;;;;;;;97807:101;98000:13;;97985:12;:28;97981:98;;;98037:30;;-1:-1:-1;;;98037:30:0;;;;;;;;;;;97981:98;98247:12;98231:13;;:28;;;;:::i;:::-;98333:13;:32;;;98499:5;;98333:32;;-1:-1:-1;98485:34:0;;98499:5;;;-1:-1:-1;;;;;98499:5:0;98506:12;98485:13;:34::i;:::-;98537:54;98553:5;;;;;;;;;-1:-1:-1;;;;;98553:5:0;98560:12;98574:16;98537:54;;;;;;;;:::i;78268:283::-;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;78372:16:::1;:14;:16::i;:::-;;78492:51;78509:10;78521:8;78531:11;78492:16;:51::i;:::-;-1:-1:-1::0;;102218:11:0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;-1:-1:-1;78268:283:0:o;70335:252::-;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;70421:16:::1;:14;:16::i;:::-;;70530:49;70550:10;70563:1;70566:12;70530:11;:49::i;60867:813::-:0;-1:-1:-1;;;;;61050:23:0;;60944:4;61050:23;;;:14;:23;;;;;61279:24;;:29;;61275:70;;-1:-1:-1;61332:1:0;;60867:813;-1:-1:-1;;60867:813:0:o;61275:70::-;61593:11;;61566:24;;61539;;61566:38;;;:::i;:::-;61539:65;;61644:14;:28;;;61622:19;:50;;;;:::i;99647:1201::-;99947:5;;99741:4;;;;99947:5;;;-1:-1:-1;;;;;99947:5:0;99933:10;:19;99929:91;;99976:32;;-1:-1:-1;;;99976:32:0;;;;;;;;;;;99929:91;58772:12;100124:18;;:38;100120:110;;100186:32;;-1:-1:-1;;;100186:32:0;;;;;;;;;;;100120:110;100324:17;;;;;;;;;-1:-1:-1;;;;;100324:17:0;100301:40;;100444:20;-1:-1:-1;;;;;100444:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100436:83;;;;-1:-1:-1;;;100436:83:0;;8571:2:1;100436:83:0;;;8553:21:1;8610:2;8590:18;;;8583:30;8649;8629:18;;;8622:58;8697:18;;100436:83:0;8369:352:1;100436:83:0;100596:17;:40;;-1:-1:-1;;;;;;100596:40:0;-1:-1:-1;;;;;100596:40:0;;;;;;;;;100742:70;;;9012:15:1;;;8994:34;;9059:2;9044:18;;9037:43;;;;100742:70:0;;8929:18:1;100742:70:0;8726:360:1;28670:133:0;-1:-1:-1;;;;;;;;;;;;28759:36:0;;;;;;;;28774:19;28779:1;:10;;;28791:1;28774:4;:19::i;:::-;28759:36;;28752:43;28670:133;-1:-1:-1;;;28670:133:0:o;26254:208::-;26352:4;26369:18;26390:15;26395:1;26398:6;26390:4;:15::i;:::-;26369:36;;26423:31;26428:17;26437:7;26428:8;:17::i;:::-;26447:6;26423:4;:31::i;81652:633::-;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;81788:16:::1;:14;:16::i;:::-;;81817:10;81830:16;-1:-1:-1::0;;;;;81830:31:0::1;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81817:46:::0;-1:-1:-1;81878:17:0;;81874:227:::1;;82043:46;::::0;-1:-1:-1;;;82043:46:0;;::::1;::::0;::::1;1564:25:1::0;;;1537:18;;82043:46:0::1;1418:177:1::0;81874:227:0::1;82204:73;82225:10;82237:8;82247:11;82260:16;82204:20;:73::i;:::-;-1:-1:-1::0;;102218:11:0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;-1:-1:-1;;81652:633:0:o;87492:1932::-;87668:11;;:87;;-1:-1:-1;;;87668:87:0;;87701:4;87668:87;;;17601:34:1;-1:-1:-1;;;;;17671:15:1;;;17651:18;;;17644:43;17723:15;;;17703:18;;;17696:43;17775:15;;;17755:18;;;17748:43;17807:19;;;17800:35;;;87653:12:0;;87668:11;;:24;;17535:19:1;;87668:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87653:102;-1:-1:-1;87770:12:0;;87766:95;;87806:43;;-1:-1:-1;;;87806:43:0;;;;;1564:25:1;;;1537:18;;87806:43:0;1418:177:1;87766:95:0;87934:10;-1:-1:-1;;;;;87922:22:0;:8;-1:-1:-1;;;;;87922:22:0;;87918:98;;87968:36;;-1:-1:-1;;;87968:36:0;;;;;;;;;;;87918:98;88303:24;88330:62;88335:11;88348:43;;;;;;;;14694:6;88348:43;;;88330:4;:62::i;:::-;88303:89;-1:-1:-1;88403:26:0;88432:33;88303:89;88432:11;:33;:::i;:::-;88403:62;;88476:23;88502:45;;;;;;;;88517:28;:26;:28::i;:::-;88502:45;;88476:71;-1:-1:-1;88558:24:0;88585:53;88476:71;88618:19;88585:18;:53::i;:::-;88558:80;;88649:21;88689:19;88673:13;;:35;;;;:::i;:::-;88903:13;:32;;;88960:11;;88649:59;;-1:-1:-1;88960:33:0;;88974:19;;88960:33;:::i;:::-;88946:11;:47;-1:-1:-1;;;;;89030:23:0;;;;;;:13;:23;;;;;;:37;;89056:11;;89030:37;:::i;:::-;-1:-1:-1;;;;;89004:23:0;;;;;;;:13;:23;;;;;;:63;;;;89106:25;;;;;;;:49;;89134:21;;89106:49;:::i;:::-;-1:-1:-1;;;;;89078:25:0;;;;;;;:13;:25;;;;;;;:77;;;;89210:53;;;;;;-1:-1:-1;;;;;;;;;;;89210:53:0;;;89241:21;1564:25:1;;1552:2;1537:18;;1418:177;89210:53:0;;;;;;;;89279:54;;1564:25:1;;;89306:4:0;;-1:-1:-1;;;;;89279:54:0;;;-1:-1:-1;;;;;;;;;;;89279:54:0;1552:2:1;1537:18;89279:54:0;;;;;;;89349:67;89371:4;89378:19;89399:16;89349:67;;;;;;;;:::i;:::-;;;;;;;;87601:1823;;;;;;87492:1932;;;;:::o;74688:239::-;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;74764:16:::1;:14;:16::i;:::-;;74873:46;74893:10;74906:12;74873:11;:46::i;69801:242::-:0;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;69877:16:::1;:14;:16::i;:::-;;69986:49;70006:10;70019:12;70033:1;69986:11;:49::i;93257:838::-:0;93407:5;;93338:4;;93407:5;;;-1:-1:-1;;;;;93407:5:0;93393:10;:19;93389:87;;93436:28;;-1:-1:-1;;;93436:28:0;;;;;;;;;;;93389:87;58772:12;93561:18;;:38;93557:106;;93623:28;;-1:-1:-1;;;93623:28:0;;;;;;;;;;;93557:106;12364:4;93733:24;:51;93729:120;;;93808:29;;-1:-1:-1;;;93808:29:0;;;;;;;;;;;93729:120;93893:21;;;93925:48;;;;93991:68;;;18020:25:1;;;18076:2;18061:18;;18054:34;;;93991:68:0;;17993:18:1;93991:68:0;17846:248:1;94351:284:0;94428:4;102139:11;;;;102131:34;;;;-1:-1:-1;;;102131:34:0;;;;;;;:::i;:::-;102190:5;102176:19;;-1:-1:-1;;102176:19:0;;;94445:16:::1;:14;:16::i;:::-;;94573:28;94591:9;94573:17;:28::i;:::-;;;8333:1;94612:15;;102218:11:::0;:18;;-1:-1:-1;;102218:18:0;102232:4;102218:18;;;94351:284;;-1:-1:-1;94351:284:0:o;118150:254::-;118226:4;118277:10;-1:-1:-1;;;;;118277:18:0;;;118269:46;;;;-1:-1:-1;;;118269:46:0;;18301:2:1;118269:46:0;;;18283:21:1;18340:2;18320:18;;;18313:30;-1:-1:-1;;;18359:18:1;;;18352:45;18414:18;;118269:46:0;18099:339:1;118269:46:0;118347:6;118334:9;:19;118326:46;;;;-1:-1:-1;;;118326:46:0;;18645:2:1;118326:46:0;;;18627:21:1;18684:2;18664:18;;;18657:30;-1:-1:-1;;;18703:18:1;;;18696:44;18757:18;;118326:46:0;18443:338:1;118326:46:0;-1:-1:-1;118390:6:0;118150:254;-1:-1:-1;118150:254:0:o;29818:126::-;29877:4;29901:35;29906:17;29911:1;25213:4;29906;:17::i;:::-;29925:10;;29901:4;:35::i;25609:213::-;25791:12;;25666:4;;25791:23;;25213:4;;25791:23;:::i;78939:2319::-;79113:11;;:75;;-1:-1:-1;;;79113:75:0;;79152:4;79113:75;;;16395:34:1;-1:-1:-1;;;;;16465:15:1;;;16445:18;;;16438:43;16517:15;;;16497:18;;;16490:43;16549:18;;;16542:34;;;79034:4:0;;;;79113:11;;;:30;;16329:19:1;;79113:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79098:90;-1:-1:-1;79203:12:0;;79199:92;;79239:40;;-1:-1:-1;;;79239:40:0;;;;;1564:25:1;;;1537:18;;79239:40:0;1418:177:1;79199:92:0;58772:12;79379:18;;:38;79375:105;;79441:27;;-1:-1:-1;;;79441:27:0;;;;;;;;;;;79375:105;79572:23;79598:37;79626:8;79598:27;:37::i;:::-;79572:63;;79714:21;-1:-1:-1;;79738:11:0;:29;:64;;79791:11;79738:64;;;79770:18;79738:64;79714:88;;80376:22;80401:37;80414:5;80421:16;80401:12;:37::i;:::-;80376:62;-1:-1:-1;80699:22:0;80724:38;80376:62;80724:18;:38;:::i;:::-;80699:63;;80773:20;80811:17;80796:12;;:32;;;;:::i;:::-;-1:-1:-1;;;;;80911:24:0;;;;;;;:14;:24;;;;;;;;;:54;;;81017:11;;80976:38;;;;:52;81039:12;:30;;;81130:83;;19101:15:1;;;19083:34;;19133:18;;19126:43;;;;19185:18;;19178:34;;;19243:2;19228:18;;19221:34;;;19286:3;19271:19;;19264:35;;;81039:30:0;;-1:-1:-1;81130:83:0;;19032:3:1;19017:19;81130:83:0;;;;;;;-1:-1:-1;81233:17:0;;78939:2319;-1:-1:-1;;;;;;;;78939:2319:0:o;44950:1053::-;45083:23;;;;;45442:45;31739:2;45442:36;:45;:::i;:::-;45409:78;-1:-1:-1;45494:22:0;45519:62;45539:41;31229:2;45409:78;45539:41;:::i;:::-;45519:8;;:19;:62::i;:::-;45626:28;;;-1:-1:-1;45494:87:0;-1:-1:-1;45729:40:0;45494:87;31899:1;45729:18;:40::i;:::-;45900:34;;;;;;45825:28;;45941:56;;;-1:-1:-1;45900:34:0;;-1:-1:-1;;;;;44950:1053:0:o;118412:190::-;118575:19;;-1:-1:-1;;;;;118575:11:0;;;:19;;;;;118587:6;;118575:19;;;;118587:6;118575:11;:19;;;;;;;;;;;;;;;;;;;;;118412:190;;:::o;71147:3362::-;71264:19;;;:42;;-1:-1:-1;71287:19:0;;71264:42;71256:107;;;;-1:-1:-1;;;71256:107:0;;19512:2:1;71256:107:0;;;19494:21:1;19551:2;19531:18;;;19524:30;19590:34;19570:18;;;19563:62;-1:-1:-1;;;19641:18:1;;;19634:50;19701:19;;71256:107:0;19310:416:1;71256:107:0;71436:23;71462:46;;;;;;;;71477:28;:26;:28::i;:::-;71462:46;;71436:72;-1:-1:-1;71521:17:0;;71619:18;;71615:757;;71910:14;71895:29;;71954:48;71973:12;71987:14;71954:18;:48::i;:::-;71939:63;;71615:757;;;72282:34;72287:14;72303:12;72282:4;:34::i;:::-;72267:49;;72346:14;72331:29;;71615:757;72454:28;72522:43;;;72588:4;72609:8;72633:12;72485:171;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;72485:171:0;;;;;;;;;;;;;;-1:-1:-1;;;;;72485:171:0;-1:-1:-1;;;;;;72485:171:0;;;;;;;;;;72734:11;;72485:171;;-1:-1:-1;;;72698:108:0;;-1:-1:-1;;;;;72734:11:0;72485:171;72734:11;72698:13;:108::i;:::-;72669:137;;72819:12;72845:13;72834:36;;;;;;;;;;;;:::i;:::-;72819:51;-1:-1:-1;72885:12:0;;72881:87;;72921:35;;-1:-1:-1;;;72921:35:0;;;;;1564:25:1;;;1537:18;;72921:35:0;1418:177:1;72881:87:0;58772:12;73056:18;;:38;73052:100;;73118:22;;-1:-1:-1;;;73118:22:0;;;;;;;;;;;73052:100;73250:12;73233:14;:12;:14::i;:::-;:29;73229:99;;;73286:30;;-1:-1:-1;;;73286:30:0;;;;;;;;;;;73229:99;73686:12;73672:11;;:26;;;;:::i;:::-;73658:11;:40;-1:-1:-1;;;;;73735:23:0;;;;;;:13;:23;;;;;;:38;;73761:12;;73735:38;:::i;:::-;-1:-1:-1;;;;;73709:23:0;;;;;;:13;:23;;;;;:64;74149:37;73723:8;74173:12;74149:13;:37::i;:::-;74264:47;;1564:25:1;;;74291:4:0;;-1:-1:-1;;;;;74264:47:0;;;-1:-1:-1;;;;;;;;;;;74264:47:0;1552:2:1;1537:18;74264:47:0;;;;;;;74327:44;74334:8;74344:12;74358;74327:44;;;;;;;;:::i;:::-;;;;;;;;74424:11;;:77;;-1:-1:-1;;;74424:77:0;;74457:4;74424:77;;;20404:34:1;-1:-1:-1;;;;;20474:15:1;;;20454:18;;;20447:43;20506:18;;;20499:34;;;20549:18;;;20542:34;;;74424:11:0;;;;:24;;20338:19:1;;74424:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71245:3264;;;;;;71147:3362;;;:::o;29407:90::-;29460:4;29484:5;29488:1;29484;:5;:::i;27983:90::-;28036:4;28060:5;28064:1;28060;:5;:::i;82764:3356::-;83008:244;;;83120:4;83008:244;;;17601:34:1;-1:-1:-1;;;;;17671:15:1;;;17651:18;;;17644:43;17723:15;;;17703:18;;;17696:43;17775:15;;;17755:18;;;17748:43;17807:19;;;;17800:35;;;83008:244:0;;;;;;;;;;17535:19:1;;;;83008:244:0;;;;;;;;-1:-1:-1;;;;;83008:244:0;-1:-1:-1;;;83008:244:0;;;83330:11;;83008:244;;-1:-1:-1;;83294:108:0;;83330:11;83008:244;83330:11;83294:13;:108::i;:::-;83265:137;;83415:12;83441:13;83430:33;;;;;;;;;;;;:::i;:::-;83415:48;-1:-1:-1;83480:12:0;;83476:90;;83516:38;;-1:-1:-1;;;83516:38:0;;;;;1564:25:1;;;1537:18;;83516:38:0;1418:177:1;83476:90:0;58772:12;83654:18;;:38;83650:103;;83716:25;;-1:-1:-1;;;83716:25:0;;;;;;;;;;;83650:103;58772:12;83858:16;-1:-1:-1;;;;;83858:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:57;83854:132;;83939:35;;-1:-1:-1;;;83939:35:0;;;;;;;;;;;83854:132;84059:10;-1:-1:-1;;;;;84047:22:0;:8;-1:-1:-1;;;;;84047:22:0;;84043:93;;84093:31;;-1:-1:-1;;;84093:31:0;;;;;;;;;;;84043:93;84191:11;84206:1;84191:16;84187:84;;84231:28;;-1:-1:-1;;;84231:28:0;;;;;;;;;;;84187:84;-1:-1:-1;;84327:11:0;:29;84323:100;;84380:31;;-1:-1:-1;;;84380:31:0;;;;;;;;;;;84323:100;84476:22;84501:51;84518:10;84530:8;84540:11;84501:16;:51::i;:::-;84476:76;;84794:29;84863:59;;;84945:4;84974:16;85007:17;84826:209;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;84826:209:0;;;;;;;;;;;;;;-1:-1:-1;;;;;84826:209:0;-1:-1:-1;;;;;;84826:209:0;;;;;;;;;;85118:11;;84826:209;;-1:-1:-1;;;85078:94:0;;-1:-1:-1;;;;;85118:11:0;84826:209;85078:17;:94::i;:::-;85048:124;;85186:21;85209:16;85240:14;85229:40;;;;;;;;;;;;:::i;:::-;85185:84;;;;8333:1;85292:16;:28;85284:92;;;;-1:-1:-1;;;85284:92:0;;21039:2:1;85284:92:0;;;21021:21:1;21078:2;21058:18;;;21051:30;21117:34;21097:18;;;21090:62;-1:-1:-1;;;21168:18:1;;;21161:49;21227:19;;85284:92:0;20837:415:1;85284:92:0;85470:36;;-1:-1:-1;;;85470:36:0;;-1:-1:-1;;;;;2493:32:1;;;85470:36:0;;;2475:51:1;85510:11:0;;85470:26;;;;;;2448:18:1;;85470:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:51;;85462:88;;;;-1:-1:-1;;;85462:88:0;;21667:2:1;85462:88:0;;;21649:21:1;21706:2;21686:18;;;21679:30;21745:26;21725:18;;;21718:54;21789:18;;85462:88:0;21465:348:1;85462:88:0;85720:4;-1:-1:-1;;;;;85683:42:0;;;85679:273;;85742:63;85764:4;85771:10;85783:8;85793:11;85742:13;:63::i;:::-;85679:273;;;8333:1;85846:16;-1:-1:-1;;;;;85846:22:0;;85869:10;85881:8;85891:11;85846:57;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:69;85838:102;;;;-1:-1:-1;;;85838:102:0;;22020:2:1;85838:102:0;;;22002:21:1;22059:2;22039:18;;;22032:30;-1:-1:-1;;;22078:18:1;;;22071:50;22138:18;;85838:102:0;21818:344:1;85838:102:0;86016:96;;;-1:-1:-1;;;;;22482:15:1;;;22464:34;;22534:15;;;22529:2;22514:18;;22507:43;22566:18;;;22559:34;;;22629:15;;22624:2;22609:18;;22602:43;22676:3;22661:19;;22654:35;;;86016:96:0;;;;;;;22413:3:1;86016:96:0;;;82893:3227;;;;;;;;82764:3356;;;;:::o;28811:121::-;28870:4;25213;28894:19;28899:1;28902;:10;;;28894:4;:19::i;:::-;:30;;;;:::i;75104:2505::-;75260:28;75328:43;;;75394:4;75415:8;75439:12;75291:171;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;75291:171:0;;;;;;;;;;;;;;-1:-1:-1;;;;;75291:171:0;-1:-1:-1;;;;;;75291:171:0;;;;;;;;;;75540:11;;75291:171;;-1:-1:-1;;;75504:108:0;;-1:-1:-1;;;;;75540:11:0;75291:171;75540:11;75504:13;:108::i;:::-;75475:137;;75625:12;75651:13;75640:36;;;;;;;;;;;;:::i;:::-;75625:51;-1:-1:-1;75693:12:0;;75689:87;;75729:35;;-1:-1:-1;;;75729:35:0;;;;;1564:25:1;;;1537:18;;75729:35:0;1418:177:1;75689:87:0;58772:12;75864:18;;:38;75860:100;;75926:22;;-1:-1:-1;;;75926:22:0;;;;;;;;;;;75860:100;76069:12;76052:14;:12;:14::i;:::-;:29;76048:93;;;76105:24;;-1:-1:-1;;;76105:24:0;;;;;;;;;;;76048:93;76388:23;76414:37;76442:8;76414:27;:37::i;:::-;76388:63;-1:-1:-1;76462:22:0;76487:33;76508:12;76388:63;76487:33;:::i;:::-;76462:58;;76531:20;76569:12;76554;;:27;;;;:::i;:::-;-1:-1:-1;;;;;76912:24:0;;;;;;:14;:24;;;;;:54;;;77018:11;;76977:38;;;;:52;77040:12;:30;;;76531:50;-1:-1:-1;77442:37:0;76927:8;77466:12;77442:13;:37::i;:::-;77535:66;;;-1:-1:-1;;;;;22957:32:1;;22939:51;;23021:2;23006:18;;22999:34;;;23049:18;;;23042:34;;;23107:2;23092:18;;23085:34;;;77535:66:0;;22926:3:1;22911:19;77535:66:0;;;;;;;75179:2430;;;;;;75104:2505;;:::o;94975:1453::-;95036:4;;;;58772:12;95260:18;;:38;95256:122;;95322:44;;-1:-1:-1;;;95322:44:0;;;;;1564:25:1;;;1537:18;;95322:44:0;1418:177:1;95256:122:0;95967:35;95980:10;95992:9;95967:12;:35::i;:::-;95949:53;;96050:15;96034:13;;:31;;;;:::i;:::-;96015:50;;96158:16;96142:13;:32;;;;96263:60;96277:10;96289:15;96306:16;96263:60;;;;;;;;:::i;:::-;;;;;;;;8333:1;;96404:15;;-1:-1:-1;94975:1453:0;-1:-1:-1;;;94975:1453:0:o;30429:90::-;30482:4;30506:5;30510:1;30506;:5;:::i;36162:98::-;36220:7;36247:5;36251:1;36247;:5;:::i;46376:389::-;46511:12;46532:20;46555:32;46571:15;46555;:32::i;:::-;46532:55;;46597:12;46611:19;46641:15;-1:-1:-1;;;;;46641:20:0;46669:12;:28;;46696:1;46669:28;;;46684:9;46669:28;46699:7;46641:66;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46596:111;;;;46723:36;46743:7;46752:6;46723:19;:36::i;:::-;46716:43;46376:389;-1:-1:-1;;;;;;;46376:389:0:o;47108:335::-;47228:12;47252:20;47275:32;47291:15;47275;:32::i;:::-;47252:55;;47315:12;47329:19;47352:15;-1:-1:-1;;;;;47352:26:0;47379:7;47352:35;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47314:73;;;;47401:36;47421:7;47430:6;47401:19;:36::i;:::-;47394:43;47108:335;-1:-1:-1;;;;;;47108:335:0:o;47449:1738::-;47583:22;;47526:12;;47547:33;47646:29;:27;:29::i;:::-;47612:63;-1:-1:-1;47682:29:0;47714:51;47612:63;47714:25;:51;:::i;:::-;47682:83;-1:-1:-1;47804:8:0;47778:41;;47774:96;;;47837:25;;-1:-1:-1;;;47837:25:0;;;;;;;;;;;47774:96;47878:20;47942:15;47936:22;47925:33;;48116:21;48107:7;48100:38;48246:15;48224:20;48220:42;48297:25;48291:4;48287:36;48369:7;48347:20;48343:34;48193:431;48397:7;48391:4;48387:18;48193:431;;;48603:11;;48592:23;;48435:16;48425:27;;;;48468:25;48193:431;;;48197:189;;;48866:23;48821;48805:14;48801:44;48752:25;48730:20;48726:52;48717:7;48713:66;48690:232;49043:55;;;;49030:69;;49112:20;49014:129;48988:15;48971:181;49034:7;47449:1738;-1:-1:-1;;;47449:1738:0:o;49787:859::-;49889:12;49918:7;49913:706;;49942:6;:13;49959:1;49942:18;49938:674;;49980:34;;-1:-1:-1;;;49980:34:0;;;;;;;;;;;49938:674;50145:20;50133:33;;50127:40;-1:-1:-1;;;50203:49:0;50275:328;;;;50459:52;;-1:-1:-1;;;50459:52:0;;50409:17;50397:30;;;50459:52;;50397:30;;50459:52;;;:::i;50275:328::-;50584:6;50549:42;;-1:-1:-1;;;50549:42:0;;;;;;;;:::i;49193:588::-;49254:7;49270:30;49303:36;:34;:36::i;:::-;49270:69;;49346:25;49374:61;49412:22;49374:37;:61::i;:::-;49346:89;;;-1:-1:-1;49442:48:0;31844:1;49442:48;;:::i;:::-;;;49502:24;49497:241;49551:17;49532:16;:36;49497:241;;;49599:27;49629:47;49653:22;49629:23;:47::i;:::-;49599:77;-1:-1:-1;49685:45:0;49599:77;49685:45;;:::i;:::-;;;49590:148;49570:18;;;;;:::i;:::-;;;;49497:241;;;-1:-1:-1;49753:22:0;;49193:588;-1:-1:-1;;49193:588:0:o;14:250:1:-;99:1;109:113;123:6;120:1;117:13;109:113;;;199:11;;;193:18;180:11;;;173:39;145:2;138:10;109:113;;;-1:-1:-1;;256:1:1;238:16;;231:27;14:250::o;269:271::-;311:3;349:5;343:12;376:6;371:3;364:19;392:76;461:6;454:4;449:3;445:14;438:4;431:5;427:16;392:76;:::i;:::-;522:2;501:15;-1:-1:-1;;497:29:1;488:39;;;;529:4;484:50;;269:271;-1:-1:-1;;269:271:1:o;545:220::-;694:2;683:9;676:21;657:4;714:45;755:2;744:9;740:18;732:6;714:45;:::i;770:131::-;-1:-1:-1;;;;;845:31:1;;835:42;;825:70;;891:1;888;881:12;906:315;974:6;982;1035:2;1023:9;1014:7;1010:23;1006:32;1003:52;;;1051:1;1048;1041:12;1003:52;1090:9;1077:23;1109:31;1134:5;1109:31;:::i;:::-;1159:5;1211:2;1196:18;;;;1183:32;;-1:-1:-1;;;906:315:1:o;1600:247::-;1659:6;1712:2;1700:9;1691:7;1687:23;1683:32;1680:52;;;1728:1;1725;1718:12;1680:52;1767:9;1754:23;1786:31;1811:5;1786:31;:::i;1852:456::-;1929:6;1937;1945;1998:2;1986:9;1977:7;1973:23;1969:32;1966:52;;;2014:1;2011;2004:12;1966:52;2053:9;2040:23;2072:31;2097:5;2072:31;:::i;:::-;2122:5;-1:-1:-1;2179:2:1;2164:18;;2151:32;2192:33;2151:32;2192:33;:::i;:::-;1852:456;;2244:7;;-1:-1:-1;;;2298:2:1;2283:18;;;;2270:32;;1852:456::o;3242:180::-;3301:6;3354:2;3342:9;3333:7;3329:23;3325:32;3322:52;;;3370:1;3367;3360:12;3322:52;-1:-1:-1;3393:23:1;;3242:180;-1:-1:-1;3242:180:1:o;3427:127::-;3488:10;3483:3;3479:20;3476:1;3469:31;3519:4;3516:1;3509:15;3543:4;3540:1;3533:15;3559:719;3602:5;3655:3;3648:4;3640:6;3636:17;3632:27;3622:55;;3673:1;3670;3663:12;3622:55;3709:6;3696:20;3735:18;3772:2;3768;3765:10;3762:36;;;3778:18;;:::i;:::-;3853:2;3847:9;3821:2;3907:13;;-1:-1:-1;;3903:22:1;;;3927:2;3899:31;3895:40;3883:53;;;3951:18;;;3971:22;;;3948:46;3945:72;;;3997:18;;:::i;:::-;4037:10;4033:2;4026:22;4072:2;4064:6;4057:18;4118:3;4111:4;4106:2;4098:6;4094:15;4090:26;4087:35;4084:55;;;4135:1;4132;4125:12;4084:55;4199:2;4192:4;4184:6;4180:17;4173:4;4165:6;4161:17;4148:54;4246:1;4239:4;4234:2;4226:6;4222:15;4218:26;4211:37;4266:6;4257:15;;;;;;3559:719;;;;:::o;4283:1108::-;4458:6;4466;4474;4482;4490;4498;4551:3;4539:9;4530:7;4526:23;4522:33;4519:53;;;4568:1;4565;4558:12;4519:53;4607:9;4594:23;4626:31;4651:5;4626:31;:::i;:::-;4676:5;-1:-1:-1;4733:2:1;4718:18;;4705:32;4746:33;4705:32;4746:33;:::i;:::-;4798:7;-1:-1:-1;4852:2:1;4837:18;;4824:32;;-1:-1:-1;4907:2:1;4892:18;;4879:32;4930:18;4960:14;;;4957:34;;;4987:1;4984;4977:12;4957:34;5010:50;5052:7;5043:6;5032:9;5028:22;5010:50;:::i;:::-;5000:60;;5113:3;5102:9;5098:19;5085:33;5069:49;;5143:2;5133:8;5130:16;5127:36;;;5159:1;5156;5149:12;5127:36;;5182:52;5226:7;5215:8;5204:9;5200:24;5182:52;:::i;:::-;5172:62;;;5286:3;5275:9;5271:19;5258:33;5335:4;5326:7;5322:18;5313:7;5310:31;5300:59;;5355:1;5352;5345:12;5300:59;5378:7;5368:17;;;4283:1108;;;;;;;;:::o;5396:403::-;5479:6;5487;5540:2;5528:9;5519:7;5515:23;5511:32;5508:52;;;5556:1;5553;5546:12;5508:52;5595:9;5582:23;5614:31;5639:5;5614:31;:::i;:::-;5664:5;-1:-1:-1;5721:2:1;5706:18;;5693:32;5734:33;5693:32;5734:33;:::i;:::-;5786:7;5776:17;;;5396:403;;;;;:::o;7363:334::-;7565:2;7547:21;;;7604:2;7584:18;;;7577:30;-1:-1:-1;;;7638:2:1;7623:18;;7616:40;7688:2;7673:18;;7363:334::o;7702:380::-;7781:1;7777:12;;;;7824;;;7845:61;;7899:4;7891:6;7887:17;7877:27;;7845:61;7952:2;7944:6;7941:14;7921:18;7918:38;7915:161;;7998:10;7993:3;7989:20;7986:1;7979:31;8033:4;8030:1;8023:15;8061:4;8058:1;8051:15;8087:277;8154:6;8207:2;8195:9;8186:7;8182:23;8178:32;8175:52;;;8223:1;8220;8213:12;8175:52;8255:9;8249:16;8308:5;8301:13;8294:21;8287:5;8284:32;8274:60;;8330:1;8327;8320:12;9091:127;9152:10;9147:3;9143:20;9140:1;9133:31;9183:4;9180:1;9173:15;9207:4;9204:1;9197:15;9223:125;9288:9;;;9309:10;;;9306:36;;;9322:18;;:::i;9353:128::-;9420:9;;;9441:11;;;9438:37;;;9455:18;;:::i;9486:135::-;9525:3;9546:17;;;9543:43;;9566:18;;:::i;:::-;-1:-1:-1;9613:1:1;9602:13;;9486:135::o;11736:545::-;11838:2;11833:3;11830:11;11827:448;;;11874:1;11899:5;11895:2;11888:17;11944:4;11940:2;11930:19;12014:2;12002:10;11998:19;11995:1;11991:27;11985:4;11981:38;12050:4;12038:10;12035:20;12032:47;;;-1:-1:-1;12073:4:1;12032:47;12128:2;12123:3;12119:12;12116:1;12112:20;12106:4;12102:31;12092:41;;12183:82;12201:2;12194:5;12191:13;12183:82;;;12246:17;;;12227:1;12216:13;12183:82;;;12187:3;;;11736:545;;;:::o;12457:1352::-;12583:3;12577:10;12610:18;12602:6;12599:30;12596:56;;;12632:18;;:::i;:::-;12661:97;12751:6;12711:38;12743:4;12737:11;12711:38;:::i;:::-;12705:4;12661:97;:::i;:::-;12813:4;;12877:2;12866:14;;12894:1;12889:663;;;;13596:1;13613:6;13610:89;;;-1:-1:-1;13665:19:1;;;13659:26;13610:89;-1:-1:-1;;12414:1:1;12410:11;;;12406:24;12402:29;12392:40;12438:1;12434:11;;;12389:57;13712:81;;12859:944;;12889:663;11683:1;11676:14;;;11720:4;11707:18;;-1:-1:-1;;12925:20:1;;;13043:236;13057:7;13054:1;13051:14;13043:236;;;13146:19;;;13140:26;13125:42;;13238:27;;;;13206:1;13194:14;;;;13073:19;;13043:236;;;13047:3;13307:6;13298:7;13295:19;13292:201;;;13368:19;;;13362:26;-1:-1:-1;;13451:1:1;13447:14;;;13463:3;13443:24;13439:37;13435:42;13420:58;13405:74;;13292:201;-1:-1:-1;;;;;13539:1:1;13523:14;;;13519:22;13506:36;;-1:-1:-1;12457:1352:1:o;14138:184::-;14208:6;14261:2;14249:9;14240:7;14236:23;14232:32;14229:52;;;14277:1;14274;14267:12;14229:52;-1:-1:-1;14300:16:1;;14138:184;-1:-1:-1;14138:184:1:o;15001:375::-;-1:-1:-1;;;;;15259:15:1;;;15241:34;;15311:15;;;;15306:2;15291:18;;15284:43;15358:2;15343:18;;15336:34;;;;15191:2;15176:18;;15001:375::o;15381:345::-;-1:-1:-1;;;;;15601:32:1;;;;15583:51;;15665:2;15650:18;;15643:34;;;;15708:2;15693:18;;15686:34;15571:2;15556:18;;15381:345::o;15731:168::-;15804:9;;;15835;;15852:15;;;15846:22;;15832:37;15822:71;;15873:18;;:::i;15904:217::-;15944:1;15970;15960:132;;16014:10;16009:3;16005:20;16002:1;15995:31;16049:4;16046:1;16039:15;16077:4;16074:1;16067:15;15960:132;-1:-1:-1;16106:9:1;;15904:217::o;20587:245::-;20666:6;20674;20727:2;20715:9;20706:7;20702:23;20698:32;20695:52;;;20743:1;20740;20733:12;20695:52;-1:-1:-1;;20766:16:1;;20822:2;20807:18;;;20801:25;20766:16;;20801:25;;-1:-1:-1;20587:245:1:o;23130:287::-;23259:3;23297:6;23291:13;23313:66;23372:6;23367:3;23360:4;23352:6;23348:17;23313:66;:::i;:::-;23395:16;;;;;23130:287;-1:-1:-1;;23130:287:1:o

Swarm Source

ipfs://720e43dea4a62214f8a971deda5becee7b0947a2a48a0046d34b8191f5eb1b99
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.