ETH Price: $2,399.63 (-0.24%)

Contract

0xe227d81DA324136670E6203AdF20306E48DC3112
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Initialize119320992021-02-26 9:46:401287 days ago1614332800IN
0xe227d81D...E48DC3112
0 ETH0.03837864120
0x60806040119273222021-02-25 16:06:101288 days ago1614269170IN
 Create: iToken
0 ETH0.90071197230

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
iToken

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : iToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol";

import "./TokenBase/Base.sol";

/**
 * @title dForce's Lending Protocol Contract.
 * @notice iTokens which wrap an EIP-20 underlying.
 * @author dForce Team.
 */
contract iToken is Base {
    using SafeERC20Upgradeable for IERC20Upgradeable;

    /**
     * @notice Expects to call only once to initialize a new market.
     * @param _underlyingToken The underlying token address.
     * @param _name Token name.
     * @param _symbol Token symbol.
     * @param _controller Core controller contract address.
     * @param _interestRateModel Token interest rate model contract address.
     */
    function initialize(
        address _underlyingToken,
        string memory _name,
        string memory _symbol,
        IControllerInterface _controller,
        IInterestRateModelInterface _interestRateModel
    ) external initializer {
        _initialize(
            _name,
            _symbol,
            ERC20(_underlyingToken).decimals(),
            _controller,
            _interestRateModel
        );

        underlying = IERC20Upgradeable(_underlyingToken);
    }

    /**
     * @notice In order to support deflationary token, returns the changed amount.
     * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom`.
     */
    function _doTransferIn(address _spender, uint256 _amount)
        internal
        override
        returns (uint256)
    {
        uint256 _balanceBefore = underlying.balanceOf(address(this));
        underlying.safeTransferFrom(_spender, address(this), _amount);
        return underlying.balanceOf(address(this)).sub(_balanceBefore);
    }

    /**
     * @dev Similar to EIP20 transfer, except it handles a False result from `transfer`.
     */
    function _doTransferOut(address payable _recipient, uint256 _amount)
        internal
        override
    {
        underlying.safeTransfer(_recipient, _amount);
    }

    /**
     * @dev Gets balance of this contract in terms of the underlying
     */
    function _getCurrentCash() internal view override returns (uint256) {
        return underlying.balanceOf(address(this));
    }

    /**
     * @dev Caller deposits assets into the market and `_recipient` receives iToken in exchange.
     * @param _recipient The account that would receive the iToken.
     * @param _mintAmount The amount of the underlying token to deposit.
     */
    function mint(address _recipient, uint256 _mintAmount)
        external
        nonReentrant
        settleInterest
    {
        _mintInternal(_recipient, _mintAmount);
    }

    /**
     * @dev Caller redeems specified iToken from `_from` to get underlying token.
     * @param _from The account that would burn the iToken.
     * @param _redeemiToken The number of iToken to redeem.
     */
    function redeem(address _from, uint256 _redeemiToken)
        external
        nonReentrant
        settleInterest
    {
        _redeemInternal(
            _from,
            _redeemiToken,
            _redeemiToken.rmul(_exchangeRateInternal())
        );
    }

    /**
     * @dev Caller redeems specified underlying from `_from` to get underlying token.
     * @param _from The account that would burn the iToken.
     * @param _redeemUnderlying The number of underlying to redeem.
     */
    function redeemUnderlying(address _from, uint256 _redeemUnderlying)
        external
        nonReentrant
        settleInterest
    {
        _redeemInternal(
            _from,
            _redeemUnderlying.rdivup(_exchangeRateInternal()),
            _redeemUnderlying
        );
    }

    /**
     * @dev Caller borrows tokens from the protocol to their own address.
     * @param _borrowAmount The amount of the underlying token to borrow.
     */
    function borrow(uint256 _borrowAmount)
        external
        nonReentrant
        settleInterest
    {
        _borrowInternal(msg.sender, _borrowAmount);
    }

    /**
     * @dev Caller repays their own borrow.
     * @param _repayAmount The amount to repay.
     */
    function repayBorrow(uint256 _repayAmount)
        external
        nonReentrant
        settleInterest
    {
        _repayInternal(msg.sender, msg.sender, _repayAmount);
    }

    /**
     * @dev Caller repays a borrow belonging to borrower.
     * @param _borrower the account with the debt being payed off.
     * @param _repayAmount The amount to repay.
     */
    function repayBorrowBehalf(address _borrower, uint256 _repayAmount)
        external
        nonReentrant
        settleInterest
    {
        _repayInternal(msg.sender, _borrower, _repayAmount);
    }

    /**
     * @dev The caller liquidates the borrowers collateral.
     * @param _borrower The account whose borrow should be liquidated.
     * @param _assetCollateral The market in which to seize collateral from the borrower.
     * @param _repayAmount The amount to repay.
     */
    function liquidateBorrow(
        address _borrower,
        uint256 _repayAmount,
        address _assetCollateral
    ) external nonReentrant settleInterest {
        _liquidateBorrowInternal(_borrower, _repayAmount, _assetCollateral);
    }

    /**
     * @dev Transfers this tokens to the liquidator.
     * @param _liquidator The account receiving seized collateral.
     * @param _borrower The account having collateral seized.
     * @param _seizeTokens The number of iTokens to seize.
     */
    function seize(
        address _liquidator,
        address _borrower,
        uint256 _seizeTokens
    ) external override nonReentrant {
        _seizeInternal(msg.sender, _liquidator, _borrower, _seizeTokens);
    }

    /**
     * @notice Calculates interest and update total borrows and reserves.
     * @dev Updates total borrows and reserves with any accumulated interest.
     */
    function updateInterest() external override returns (bool) {
        _updateInterest();
        return true;
    }

    /**
     * @dev Gets the newest exchange rate by accruing interest.
     */
    function exchangeRateCurrent() external returns (uint256) {
        // Accrues interest.
        _updateInterest();

        return _exchangeRateInternal();
    }

    /**
     * @dev Calculates the exchange rate without accruing interest.
     */
    function exchangeRateStored() external view override returns (uint256) {
        return _exchangeRateInternal();
    }

    /**
     * @dev Gets the underlying balance of the `_account`.
     * @param _account The address of the account to query.
     */
    function balanceOfUnderlying(address _account) external returns (uint256) {
        // Accrues interest.
        _updateInterest();

        return _exchangeRateInternal().rmul(balanceOf[_account]);
    }

    /**
     * @dev Gets the user's borrow balance with the latest `borrowIndex`.
     */
    function borrowBalanceCurrent(address _account)
        external
        nonReentrant
        returns (uint256)
    {
        // Accrues interest.
        _updateInterest();

        return _borrowBalanceInternal(_account);
    }

    /**
     * @dev Gets the borrow balance of user without accruing interest.
     */
    function borrowBalanceStored(address _account)
        external
        view
        override
        returns (uint256)
    {
        return _borrowBalanceInternal(_account);
    }

    /**
     * @dev Gets user borrowing information.
     */
    function borrowSnapshot(address _account)
        external
        view
        returns (uint256, uint256)
    {
        return (
            accountBorrows[_account].principal,
            accountBorrows[_account].interestIndex
        );
    }

    /**
     * @dev Gets the current total borrows by accruing interest.
     */
    function totalBorrowsCurrent() external returns (uint256) {
        // Accrues interest.
        _updateInterest();

        return totalBorrows;
    }

    /**
     * @dev Returns the current per-block borrow interest rate.
     */
    function borrowRatePerBlock() public view returns (uint256) {
        return
            interestRateModel.getBorrowRate(
                _getCurrentCash(),
                totalBorrows,
                totalReserves
            );
    }

    /**
     * @dev Returns the current per-block supply interest rate.
     *  Calculates the supply rate:
     *  underlying = totalSupply × exchangeRate
     *  borrowsPer = totalBorrows ÷ underlying
     *  supplyRate = borrowRate × (1-reserveFactor) × borrowsPer
     */
    function supplyRatePerBlock() external view returns (uint256) {
        // `_underlyingScaled` is scaled by 1e36.
        uint256 _underlyingScaled = totalSupply.mul(_exchangeRateInternal());
        if (_underlyingScaled == 0) return 0;
        uint256 _totalBorrowsScaled = totalBorrows.mul(BASE);

        return
            borrowRatePerBlock().tmul(
                BASE.sub(reserveRatio),
                _totalBorrowsScaled.rdiv(_underlyingScaled)
            );
    }

    /**
     * @dev Get cash balance of this iToken in the underlying token.
     */
    function getCash() external view returns (uint256) {
        return _getCurrentCash();
    }
}

File 2 of 18 : SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20Upgradeable.sol";
import "../../math/SafeMathUpgradeable.sol";
import "../../utils/AddressUpgradeable.sol";

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

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

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

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

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

    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

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

File 3 of 18 : Base.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "../interface/IFlashloanExecutor.sol";
import "../library/SafeRatioMath.sol";

import "./TokenERC20.sol";

/**
 * @title dForce's lending Base Contract
 * @author dForce
 */
abstract contract Base is TokenERC20 {
    using SafeRatioMath for uint256;

    /**
     * @notice Expects to call only once to create a new lending market.
     * @param _name Token name.
     * @param _symbol Token symbol.
     * @param _controller Core controller contract address.
     * @param _interestRateModel Token interest rate model contract address.
     */
    function _initialize(
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        IControllerInterface _controller,
        IInterestRateModelInterface _interestRateModel
    ) internal virtual {
        controller = _controller;
        interestRateModel = _interestRateModel;
        accrualBlockNumber = block.number;
        borrowIndex = BASE;
        flashloanFeeRatio = 0.0008e18;
        protocolFeeRatio = 0.25e18;
        __Ownable_init();
        __ERC20_init(_name, _symbol, _decimals);
        __ReentrancyGuard_init();

        uint256 chainId;

        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                ),
                keccak256(bytes(_name)),
                keccak256(bytes("1")),
                chainId,
                address(this)
            )
        );
    }

    /*********************************/
    /******** Security Check *********/
    /*********************************/

    /**
     * @notice Ensure this is a iToken contract.
     */
    function isiToken() external pure returns (bool) {
        return true;
    }

    //----------------------------------
    //******** Main calculation ********
    //----------------------------------

    struct InterestLocalVars {
        uint256 borrowRate;
        uint256 currentBlockNumber;
        uint256 currentCash;
        uint256 totalBorrows;
        uint256 totalReserves;
        uint256 borrowIndex;
        uint256 blockDelta;
        uint256 simpleInterestFactor;
        uint256 interestAccumulated;
        uint256 newTotalBorrows;
        uint256 newTotalReserves;
        uint256 newBorrowIndex;
    }

    /**
     * @notice Calculates interest and update total borrows and reserves.
     * @dev Updates total borrows and reserves with any accumulated interest.
     */
    function _updateInterest() internal virtual override {
        InterestLocalVars memory _vars;
        _vars.currentCash = _getCurrentCash();
        _vars.totalBorrows = totalBorrows;
        _vars.totalReserves = totalReserves;

        // Gets the current borrow interest rate.
        _vars.borrowRate = interestRateModel.getBorrowRate(
            _vars.currentCash,
            _vars.totalBorrows,
            _vars.totalReserves
        );
        require(
            _vars.borrowRate <= maxBorrowRate,
            "_updateInterest: Borrow rate is too high!"
        );

        // Records the current block number.
        _vars.currentBlockNumber = block.number;

        // Calculates the number of blocks elapsed since the last accrual.
        _vars.blockDelta = _vars.currentBlockNumber.sub(accrualBlockNumber);

        /**
         * Calculates the interest accumulated into borrows and reserves and the new index:
         *  simpleInterestFactor = borrowRate * blockDelta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  newTotalBorrows = interestAccumulated + totalBorrows
         *  newTotalReserves = interestAccumulated * reserveFactor + totalReserves
         *  newBorrowIndex = simpleInterestFactor * borrowIndex + borrowIndex
         */
        _vars.simpleInterestFactor = _vars.borrowRate.mul(_vars.blockDelta);
        _vars.interestAccumulated = _vars.simpleInterestFactor.rmul(
            _vars.totalBorrows
        );
        _vars.newTotalBorrows = _vars.interestAccumulated.add(
            _vars.totalBorrows
        );
        _vars.newTotalReserves = reserveRatio
            .rmul(_vars.interestAccumulated)
            .add(_vars.totalReserves);

        _vars.borrowIndex = borrowIndex;
        _vars.newBorrowIndex = _vars
            .simpleInterestFactor
            .rmul(_vars.borrowIndex)
            .add(_vars.borrowIndex);

        // Writes the previously calculated values into storage.
        accrualBlockNumber = _vars.currentBlockNumber;
        borrowIndex = _vars.newBorrowIndex;
        totalBorrows = _vars.newTotalBorrows;
        totalReserves = _vars.newTotalReserves;

        // Emits an `UpdateInterest` event.
        emit UpdateInterest(
            _vars.currentBlockNumber,
            _vars.interestAccumulated,
            _vars.newBorrowIndex,
            _vars.currentCash,
            _vars.newTotalBorrows,
            _vars.newTotalReserves
        );
    }

    struct MintLocalVars {
        uint256 exchangeRate;
        uint256 mintTokens;
        uint256 actualMintAmout;
    }

    /**
     * @dev User deposits token into the market and `_recipient` gets iToken.
     * @param _recipient The address of the user to get iToken.
     * @param _mintAmount The amount of the underlying token to deposit.
     */
    function _mintInternal(address _recipient, uint256 _mintAmount)
        internal
        virtual
    {
        controller.beforeMint(address(this), _recipient, _mintAmount);

        MintLocalVars memory _vars;

        /**
         * Gets the current exchange rate and calculate the number of iToken to be minted:
         *  mintTokens = mintAmount / exchangeRate
         */
        _vars.exchangeRate = _exchangeRateInternal();

        // Transfers `_mintAmount` from caller to contract, and returns the actual amount the contract
        // get, cause some tokens may be charged.

        _vars.actualMintAmout = _doTransferIn(msg.sender, _mintAmount);

        // Supports deflationary tokens.
        _vars.mintTokens = _vars.actualMintAmout.rdiv(_vars.exchangeRate);

        // Mints `mintTokens` iToken to `_recipient`.
        _mint(_recipient, _vars.mintTokens);

        controller.afterMint(
            address(this),
            _recipient,
            _mintAmount,
            _vars.mintTokens
        );

        emit Mint(msg.sender, _recipient, _mintAmount, _vars.mintTokens);
    }

    /**
     * @notice This is a common function to redeem, so only one of `_redeemiTokenAmount` or
     *         `_redeemUnderlyingAmount` may be non-zero.
     * @dev Caller redeems undelying token based on the input amount of iToken or underlying token.
     * @param _from The address of the account which will spend underlying token.
     * @param _redeemiTokenAmount The number of iTokens to redeem into underlying.
     * @param _redeemUnderlyingAmount The number of underlying tokens to receive.
     */
    function _redeemInternal(
        address _from,
        uint256 _redeemiTokenAmount,
        uint256 _redeemUnderlyingAmount
    ) internal virtual {
        require(
            _redeemiTokenAmount > 0,
            "_redeemInternal: Redeem iToken amount should be greater than zero!"
        );

        controller.beforeRedeem(address(this), _from, _redeemiTokenAmount);

        if (msg.sender != _from)
            _approve(
                _from,
                msg.sender,
                allowance[_from][msg.sender].sub(_redeemiTokenAmount)
            );

        _burn(_from, _redeemiTokenAmount);

        /**
         * Transfers `_redeemUnderlyingAmount` underlying token to caller.
         */
        _doTransferOut(msg.sender, _redeemUnderlyingAmount);

        controller.afterRedeem(
            address(this),
            _from,
            _redeemiTokenAmount,
            _redeemUnderlyingAmount
        );

        emit Redeem(
            _from,
            msg.sender,
            _redeemiTokenAmount,
            _redeemUnderlyingAmount
        );
    }

    /**
     * @dev Caller borrows assets from the protocol.
     * @param _borrower The account that will borrow tokens.
     * @param _borrowAmount The amount of the underlying asset to borrow.
     */
    function _borrowInternal(address payable _borrower, uint256 _borrowAmount)
        internal
        virtual
    {
        controller.beforeBorrow(address(this), _borrower, _borrowAmount);

        // Calculates the new borrower and total borrow balances:
        //  newAccountBorrows = accountBorrows + borrowAmount
        //  newTotalBorrows = totalBorrows + borrowAmount
        BorrowSnapshot storage borrowSnapshot = accountBorrows[_borrower];
        borrowSnapshot.principal = _borrowBalanceInternal(_borrower).add(
            _borrowAmount
        );
        borrowSnapshot.interestIndex = borrowIndex;
        totalBorrows = totalBorrows.add(_borrowAmount);

        // Transfers token to borrower.
        _doTransferOut(_borrower, _borrowAmount);

        controller.afterBorrow(address(this), _borrower, _borrowAmount);

        emit Borrow(
            _borrower,
            _borrowAmount,
            borrowSnapshot.principal,
            borrowSnapshot.interestIndex,
            totalBorrows
        );
    }

    /**
     * @notice Please approve enough amount at first!!! If not,
     *         maybe you will get an error: `SafeMath: subtraction overflow`
     * @dev `_payer` repays `_repayAmount` tokens for `_borrower`.
     * @param _payer The account to pay for the borrowed.
     * @param _borrower The account with the debt being payed off.
     * @param _repayAmount The amount to repay (or -1 for max).
     */
    function _repayInternal(
        address _payer,
        address _borrower,
        uint256 _repayAmount
    ) internal virtual returns (uint256) {
        controller.beforeRepayBorrow(
            address(this),
            _payer,
            _borrower,
            _repayAmount
        );

        // Calculates the latest borrowed amount by the new market borrowed index.
        uint256 _accountBorrows = _borrowBalanceInternal(_borrower);

        // Transfers the token into the market to repay.
        uint256 _actualRepayAmount =
            _doTransferIn(
                _payer,
                _repayAmount > _accountBorrows ? _accountBorrows : _repayAmount
            );

        // Calculates the `_borrower` new borrow balance and total borrow balances:
        //  accountBorrows[_borrower].principal = accountBorrows - actualRepayAmount
        //  newTotalBorrows = totalBorrows - actualRepayAmount

        // Saves borrower updates.
        BorrowSnapshot storage borrowSnapshot = accountBorrows[_borrower];
        borrowSnapshot.principal = _accountBorrows.sub(_actualRepayAmount);
        borrowSnapshot.interestIndex = borrowIndex;

        totalBorrows = totalBorrows < _actualRepayAmount
            ? 0
            : totalBorrows.sub(_actualRepayAmount);

        // Defense hook.
        controller.afterRepayBorrow(
            address(this),
            _payer,
            _borrower,
            _actualRepayAmount
        );

        emit RepayBorrow(
            _payer,
            _borrower,
            _actualRepayAmount,
            borrowSnapshot.principal,
            borrowSnapshot.interestIndex,
            totalBorrows
        );

        return _actualRepayAmount;
    }

    /**
     * @dev The caller repays some of borrow and receive collateral.
     * @param _borrower The account whose borrow should be liquidated.
     * @param _repayAmount The amount to repay.
     * @param _assetCollateral The market in which to seize collateral from the borrower.
     */
    function _liquidateBorrowInternal(
        address _borrower,
        uint256 _repayAmount,
        address _assetCollateral
    ) internal virtual {
        require(
            msg.sender != _borrower,
            "_liquidateBorrowInternal: Liquidator can not be borrower!"
        );
        // According to the parameter `_repayAmount` to see what is the exact error.
        require(
            _repayAmount != 0,
            "_liquidateBorrowInternal: Liquidate amount should be greater than 0!"
        );

        // Accrues interest for collateral asset.
        Base _dlCollateral = Base(_assetCollateral);
        _dlCollateral.updateInterest();

        controller.beforeLiquidateBorrow(
            address(this),
            _assetCollateral,
            msg.sender,
            _borrower,
            _repayAmount
        );

        require(
            _dlCollateral.accrualBlockNumber() == block.number,
            "_liquidateBorrowInternal: Failed to update block number in collateral asset!"
        );

        uint256 _actualRepayAmount =
            _repayInternal(msg.sender, _borrower, _repayAmount);

        // Calculates the number of collateral tokens that will be seized
        uint256 _seizeTokens =
            controller.liquidateCalculateSeizeTokens(
                address(this),
                _assetCollateral,
                _actualRepayAmount
            );

        // If this is also the collateral, calls seizeInternal to avoid re-entrancy,
        // otherwise make an external call.
        if (_assetCollateral == address(this)) {
            _seizeInternal(address(this), msg.sender, _borrower, _seizeTokens);
        } else {
            _dlCollateral.seize(msg.sender, _borrower, _seizeTokens);
        }

        controller.afterLiquidateBorrow(
            address(this),
            _assetCollateral,
            msg.sender,
            _borrower,
            _actualRepayAmount,
            _seizeTokens
        );

        emit LiquidateBorrow(
            msg.sender,
            _borrower,
            _actualRepayAmount,
            _assetCollateral,
            _seizeTokens
        );
    }

    /**
     * @dev Transfers this token to the liquidator.
     * @param _seizerToken The contract seizing the collateral.
     * @param _liquidator The account receiving seized collateral.
     * @param _borrower The account having collateral seized.
     * @param _seizeTokens The number of iTokens to seize.
     */
    function _seizeInternal(
        address _seizerToken,
        address _liquidator,
        address _borrower,
        uint256 _seizeTokens
    ) internal virtual {
        require(
            _borrower != _liquidator,
            "seize: Liquidator can not be borrower!"
        );

        controller.beforeSeize(
            address(this),
            _seizerToken,
            _liquidator,
            _borrower,
            _seizeTokens
        );

        /**
         * Calculates the new _borrower and _liquidator token balances,
         * that is transfer `_seizeTokens` iToken from `_borrower` to `_liquidator`.
         */
        _transfer(_borrower, _liquidator, _seizeTokens);

        // Hook checks.
        controller.afterSeize(
            address(this),
            _seizerToken,
            _liquidator,
            _borrower,
            _seizeTokens
        );
    }

    /**
     * @param _account The address whose balance should be calculated.
     */
    function _borrowBalanceInternal(address _account)
        internal
        view
        virtual
        returns (uint256)
    {
        // Gets stored borrowed data of the `_account`.
        BorrowSnapshot storage borrowSnapshot = accountBorrows[_account];

        // If borrowBalance = 0, return 0 directly.
        if (borrowSnapshot.principal == 0 || borrowSnapshot.interestIndex == 0)
            return 0;

        // Calculate new borrow balance with market new borrow index:
        //   recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
        return
            borrowSnapshot.principal.mul(borrowIndex).divup(
                borrowSnapshot.interestIndex
            );
    }

    /**
     * @dev Calculates the exchange rate from the underlying token to the iToken.
     */
    function _exchangeRateInternal() internal view virtual returns (uint256) {
        if (totalSupply == 0) {
            // This is the first time to mint, so current exchange rate is equal to initial exchange rate.
            return initialExchangeRate;
        } else {
            // exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
            return
                _getCurrentCash().add(totalBorrows).sub(totalReserves).rdiv(
                    totalSupply
                );
        }
    }

    function updateInterest() external virtual returns (bool);

    /**
     * @dev EIP2612 permit function. For more details, please look at here:
     * https://eips.ethereum.org/EIPS/eip-2612
     * @param _owner The owner of the funds.
     * @param _spender The spender.
     * @param _value The amount.
     * @param _deadline The deadline timestamp, type(uint256).max for max deadline.
     * @param _v Signature param.
     * @param _s Signature param.
     * @param _r Signature param.
     */
    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        require(_deadline >= block.timestamp, "permit: EXPIRED!");
        uint256 _currentNonce = nonces[_owner];
        bytes32 _digest =
            keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR,
                    keccak256(
                        abi.encode(
                            PERMIT_TYPEHASH,
                            _owner,
                            _spender,
                            _value,
                            _currentNonce,
                            _deadline
                        )
                    )
                )
            );
        address _recoveredAddress = ecrecover(_digest, _v, _r, _s);
        require(
            _recoveredAddress != address(0) && _recoveredAddress == _owner,
            "permit: INVALID_SIGNATURE!"
        );
        nonces[_owner] = _currentNonce.add(1);
        _approve(_owner, _spender, _value);
    }

    /**
     * @dev Transfers this tokens to the liquidator.
     * @param _liquidator The account receiving seized collateral.
     * @param _borrower The account having collateral seized.
     * @param _seizeTokens The number of iTokens to seize.
     */
    function seize(
        address _liquidator,
        address _borrower,
        uint256 _seizeTokens
    ) external virtual;

    /**
     * @notice Users are expected to have enough allowance and balance before calling.
     * @dev Transfers asset in.
     */
    function _doTransferIn(address _spender, uint256 _amount)
        internal
        virtual
        returns (uint256);

    function exchangeRateStored() external view virtual returns (uint256);

    function borrowBalanceStored(address _account)
        external
        view
        virtual
        returns (uint256);
}

File 4 of 18 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 5 of 18 : SafeMathUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMathUpgradeable {
    /**
     * @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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @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 sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @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) {
        // 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 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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 mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 6 of 18 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 7 of 18 : IFlashloanExecutor.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

interface IFlashloanExecutor {
    function executeOperation(
        address reserve,
        uint256 amount,
        uint256 fee,
        bytes memory data
    ) external;
}

File 8 of 18 : SafeRatioMath.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

library SafeRatioMath {
    using SafeMathUpgradeable for uint256;

    uint256 private constant BASE = 10**18;
    uint256 private constant DOUBLE = 10**36;

    function divup(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x.add(y.sub(1)).div(y);
    }

    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x.mul(y).div(BASE);
    }

    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x.mul(BASE).div(y);
    }

    function rdivup(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x.mul(BASE).add(y.sub(1)).div(y);
    }

    function tmul(
        uint256 x,
        uint256 y,
        uint256 z
    ) internal pure returns (uint256 result) {
        result = x.mul(y).mul(z).div(DOUBLE);
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 base
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
                case 0 {
                    switch n
                        case 0 {
                            z := base
                        }
                        default {
                            z := 0
                        }
                }
                default {
                    switch mod(n, 2)
                        case 0 {
                            z := base
                        }
                        default {
                            z := x
                        }
                    let half := div(base, 2) // for rounding.

                    for {
                        n := div(n, 2)
                    } n {
                        n := div(n, 2)
                    } {
                        let xx := mul(x, x)
                        if iszero(eq(div(xx, x), x)) {
                            revert(0, 0)
                        }
                        let xxRound := add(xx, half)
                        if lt(xxRound, xx) {
                            revert(0, 0)
                        }
                        x := div(xxRound, base)
                        if mod(n, 2) {
                            let zx := mul(z, x)
                            if and(
                                iszero(iszero(x)),
                                iszero(eq(div(zx, x), z))
                            ) {
                                revert(0, 0)
                            }
                            let zxRound := add(zx, half)
                            if lt(zxRound, zx) {
                                revert(0, 0)
                            }
                            z := div(zxRound, base)
                        }
                    }
                }
        }
    }
}

File 9 of 18 : TokenERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./TokenAdmin.sol";

/**
 * @title dForce's lending Token ERC20 Contract
 * @author dForce
 */
abstract contract TokenERC20 is TokenAdmin {
    /**
     * @dev Transfers `_amount` tokens from `_spender` to `_recipient`.
     * @param _spender The address of the source account.
     * @param _recipient The address of the destination account.
     * @param _amount The number of tokens to transfer.
     */
    function _transferTokens(
        address _spender,
        address _recipient,
        uint256 _amount
    ) internal returns (bool) {
        require(
            _spender != _recipient,
            "_transferTokens: Do not self-transfer!"
        );

        controller.beforeTransfer(
            address(this),
            msg.sender,
            _recipient,
            _amount
        );

        _transfer(_spender, _recipient, _amount);

        controller.afterTransfer(address(this), _spender, _recipient, _amount);

        return true;
    }

    //----------------------------------
    //********* ERC20 Actions **********
    //----------------------------------

    /**
     * @notice Cause iToken is an ERC20 token, so users can `transfer` them,
     *         but this action is only allowed when after transferring tokens, the caller
     *         does not have a shortfall.
     * @dev Moves `_amount` tokens from caller to `_recipient`.
     * @param _recipient The address of the destination account.
     * @param _amount The number of tokens to transfer.
     */
    function transfer(address _recipient, uint256 _amount)
        public
        virtual
        override
        nonReentrant
        returns (bool)
    {
        return _transferTokens(msg.sender, _recipient, _amount);
    }

    /**
     * @notice Cause iToken is an ERC20 token, so users can `transferFrom` them,
     *         but this action is only allowed when after transferring tokens, the `_spender`
     *         does not have a shortfall.
     * @dev Moves `_amount` tokens from `_spender` to `_recipient`.
     * @param _spender The address of the source account.
     * @param _recipient The address of the destination account.
     * @param _amount The number of tokens to transfer.
     */
    function transferFrom(
        address _spender,
        address _recipient,
        uint256 _amount
    ) public virtual override nonReentrant returns (bool) {
        _approve(
            _spender,
            msg.sender,
            allowance[_spender][msg.sender].sub(_amount)
        );
        return _transferTokens(_spender, _recipient, _amount);
    }
}

File 10 of 18 : TokenAdmin.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./TokenEvent.sol";

/**
 * @title dForce's lending Token admin Contract
 * @author dForce
 */
abstract contract TokenAdmin is TokenEvent {
    //----------------------------------
    //********* Owner Actions **********
    //----------------------------------

    modifier settleInterest() {
        // Accrues interest.
        _updateInterest();
        require(
            accrualBlockNumber == block.number,
            "settleInterest: Fail to accrue interest!"
        );
        _;
    }

    /**
     * @dev Sets a new controller.
     */
    function _setController(IControllerInterface _newController)
        external
        virtual
        onlyOwner
    {
        IControllerInterface _oldController = controller;
        // Ensures the input address is a controller contract.
        require(
            _newController.isController(),
            "_setController: This is not the controller contract!"
        );

        // Sets to new controller.
        controller = _newController;

        emit NewController(_oldController, _newController);
    }

    /**
     * @dev Sets a new interest rate model.
     * @param _newInterestRateModel The new interest rate model.
     */
    function _setInterestRateModel(
        IInterestRateModelInterface _newInterestRateModel
    ) external virtual onlyOwner settleInterest {
        // Gets current interest rate model.
        IInterestRateModelInterface _oldInterestRateModel = interestRateModel;

        // Ensures the input address is the interest model contract.
        require(
            _newInterestRateModel.isInterestRateModel(),
            "_setInterestRateModel: This is not the rate model contract!"
        );

        // Set to the new interest rate model.
        interestRateModel = _newInterestRateModel;

        emit NewInterestRateModel(_oldInterestRateModel, _newInterestRateModel);
    }

    /**
     * @dev Sets a new reserve ratio.
     */
    function _setNewReserveRatio(uint256 _newReserveRatio)
        external
        virtual
        onlyOwner
        settleInterest
    {
        require(
            _newReserveRatio <= maxReserveRatio,
            "_setNewReserveRatio: New reserve ratio too large!"
        );

        // Gets current reserve ratio.
        uint256 _oldReserveRatio = reserveRatio;

        // Sets new reserve ratio.
        reserveRatio = _newReserveRatio;

        emit NewReserveRatio(_oldReserveRatio, _newReserveRatio);
    }

    /**
     * @dev Sets a new flashloan fee ratio.
     */
    function _setNewFlashloanFeeRatio(uint256 _newFlashloanFeeRatio)
        external
        virtual
        onlyOwner
        settleInterest
    {
        require(
            _newFlashloanFeeRatio <= BASE,
            "setNewFlashloanFeeRatio: New flashloan ratio too large!"
        );

        // Gets current reserve ratio.
        uint256 _oldFlashloanFeeRatio = flashloanFeeRatio;

        // Sets new reserve ratio.
        flashloanFeeRatio = _newFlashloanFeeRatio;

        emit NewFlashloanFeeRatio(_oldFlashloanFeeRatio, _newFlashloanFeeRatio);
    }

    /**
     * @dev Sets a new protocol fee ratio.
     */
    function _setNewProtocolFeeRatio(uint256 _newProtocolFeeRatio)
        external
        virtual
        onlyOwner
        settleInterest
    // nonReentrant
    {
        require(
            _newProtocolFeeRatio <= BASE,
            "_setNewProtocolFeeRatio: New protocol ratio too large!"
        );

        // Gets current reserve ratio.
        uint256 _oldProtocolFeeRatio = protocolFeeRatio;

        // Sets new reserve ratio.
        protocolFeeRatio = _newProtocolFeeRatio;

        emit NewProtocolFeeRatio(_oldProtocolFeeRatio, _newProtocolFeeRatio);
    }

    /**
     * @dev Admin withdraws `_withdrawAmount` of the iToken.
     * @param _withdrawAmount Amount of reserves to withdraw.
     */
    function _withdrawReserves(uint256 _withdrawAmount)
        external
        virtual
        onlyOwner
        settleInterest
    // nonReentrant
    {
        require(
            _withdrawAmount <= totalReserves &&
                _withdrawAmount <= _getCurrentCash(),
            "_withdrawReserves: Invalid withdraw amount and do not have enough cash!"
        );

        uint256 _oldTotalReserves = totalReserves;
        // Updates total amount of the reserves.
        totalReserves = totalReserves.sub(_withdrawAmount);

        // Transfers reserve to the owner.
        _doTransferOut(owner, _withdrawAmount);

        emit ReservesWithdrawn(
            owner,
            _withdrawAmount,
            totalReserves,
            _oldTotalReserves
        );
    }

    /**
     * @notice Calculates interest and update total borrows and reserves.
     * @dev Updates total borrows and reserves with any accumulated interest.
     */
    function _updateInterest() internal virtual;

    /**
     * @dev Transfers underlying token out.
     */
    function _doTransferOut(address payable _recipient, uint256 _amount)
        internal
        virtual;

    /**
     * @dev Total amount of reserves owned by this contract.
     */
    function _getCurrentCash() internal view virtual returns (uint256);
}

File 11 of 18 : TokenEvent.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./TokenStorage.sol";

/**
 * @title dForce's lending Token event Contract
 * @author dForce
 */
contract TokenEvent is TokenStorage {
    //----------------------------------
    //********** User Events ***********
    //----------------------------------

    event UpdateInterest(
        uint256 currentBlockNumber,
        uint256 interestAccumulated,
        uint256 borrowIndex,
        uint256 cash,
        uint256 totalBorrows,
        uint256 totalReserves
    );

    event Mint(
        address spender,
        address recipient,
        uint256 mintAmount,
        uint256 mintTokens
    );

    event Redeem(
        address from,
        address recipient,
        uint256 redeemiTokenAmount,
        uint256 redeemUnderlyingAmount
    );

    /**
     * @dev Emits when underlying is borrowed.
     */
    event Borrow(
        address borrower,
        uint256 borrowAmount,
        uint256 accountBorrows,
        uint256 accountInterestIndex,
        uint256 totalBorrows
    );

    event RepayBorrow(
        address payer,
        address borrower,
        uint256 repayAmount,
        uint256 accountBorrows,
        uint256 accountInterestIndex,
        uint256 totalBorrows
    );

    event LiquidateBorrow(
        address liquidator,
        address borrower,
        uint256 repayAmount,
        address iTokenCollateral,
        uint256 seizeTokens
    );

    event Flashloan(
        address loaner,
        uint256 loanAmount,
        uint256 flashloanFee,
        uint256 protocolFee,
        uint256 timestamp
    );

    //----------------------------------
    //********** Owner Events **********
    //----------------------------------

    event NewReserveRatio(uint256 oldReserveRatio, uint256 newReserveRatio);
    event NewFlashloanFeeRatio(
        uint256 oldFlashloanFeeRatio,
        uint256 newFlashloanFeeRatio
    );
    event NewProtocolFeeRatio(
        uint256 oldProtocolFeeRatio,
        uint256 newProtocolFeeRatio
    );
    event NewFlashloanFee(
        uint256 oldFlashloanFeeRatio,
        uint256 newFlashloanFeeRatio,
        uint256 oldProtocolFeeRatio,
        uint256 newProtocolFeeRatio
    );

    event NewInterestRateModel(
        IInterestRateModelInterface oldInterestRateModel,
        IInterestRateModelInterface newInterestRateModel
    );

    event NewController(
        IControllerInterface oldController,
        IControllerInterface newController
    );

    event ReservesWithdrawn(
        address admin,
        uint256 amount,
        uint256 newTotalReserves,
        uint256 oldTotalReserves
    );
}

File 12 of 18 : TokenStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

import "../library/Initializable.sol";
import "../library/ReentrancyGuard.sol";
import "../library/Ownable.sol";
import "../library/ERC20.sol";

import "../interface/IInterestRateModelInterface.sol";
import "../interface/IControllerInterface.sol";

/**
 * @title dForce's lending Token storage Contract
 * @author dForce
 */
contract TokenStorage is Initializable, ReentrancyGuard, Ownable, ERC20 {
    //----------------------------------
    //********* Token Storage **********
    //----------------------------------

    uint256 constant BASE = 1e18;

    /**
     * @dev Whether this token is supported in the market or not.
     */
    bool public constant isSupported = true;

    /**
     * @dev Maximum borrow rate(0.1% per block, scaled by 1e18).
     */
    uint256 constant maxBorrowRate = 0.001e18;

    /**
     * @dev Interest ratio set aside for reserves(scaled by 1e18).
     */
    uint256 public reserveRatio;

    /**
     * @dev Maximum interest ratio that can be set aside for reserves(scaled by 1e18).
     */
    uint256 constant maxReserveRatio = 1e18;

    /**
     * @notice This ratio is relative to the total flashloan fee.
     * @dev Flash loan fee rate(scaled by 1e18).
     */
    uint256 public flashloanFeeRatio;

    /**
     * @notice This ratio is relative to the total flashloan fee.
     * @dev Protocol fee rate when a flashloan happens(scaled by 1e18);
     */
    uint256 public protocolFeeRatio;

    /**
     * @dev Underlying token address.
     */
    IERC20Upgradeable public underlying;

    /**
     * @dev Current interest rate model contract.
     */
    IInterestRateModelInterface public interestRateModel;

    /**
     * @dev Core control of the contract.
     */
    IControllerInterface public controller;

    /**
     * @dev Initial exchange rate(scaled by 1e18).
     */
    uint256 constant initialExchangeRate = 1e18;

    /**
     * @dev The interest index for borrows of asset as of blockNumber.
     */
    uint256 public borrowIndex;

    /**
     * @dev Block number that interest was last accrued at.
     */
    uint256 public accrualBlockNumber;

    /**
     * @dev Total amount of this reserve borrowed.
     */
    uint256 public totalBorrows;

    /**
     * @dev Total amount of this reserves accrued.
     */
    uint256 public totalReserves;

    /**
     * @dev Container for user balance information written to storage.
     * @param principal User total balance with accrued interest after applying the user's most recent balance-changing action.
     * @param interestIndex The total interestIndex as calculated after applying the user's most recent balance-changing action.
     */
    struct BorrowSnapshot {
        uint256 principal;
        uint256 interestIndex;
    }

    /**
     * @dev 2-level map: userAddress -> assetAddress -> balance for borrows.
     */
    mapping(address => BorrowSnapshot) internal accountBorrows;

    bytes32 public DOMAIN_SEPARATOR;
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    mapping(address => uint256) public nonces;
}

File 13 of 18 : Initializable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(
            !_initialized,
            "Initializable: contract is already initialized"
        );

        _;

        _initialized = true;
    }
}

File 14 of 18 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

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

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

    uint256 private _status;

    function __ReentrancyGuard_init() internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 15 of 18 : Ownable.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {_setPendingOwner} and {_acceptOwner}.
 */
contract Ownable {
    /**
     * @dev Returns the address of the current owner.
     */
    address payable public owner;

    /**
     * @dev Returns the address of the current pending owner.
     */
    address payable public pendingOwner;

    event NewOwner(address indexed previousOwner, address indexed newOwner);
    event NewPendingOwner(
        address indexed oldPendingOwner,
        address indexed newPendingOwner
    );

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner == msg.sender, "onlyOwner: caller is not the owner");
        _;
    }

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal {
        owner = msg.sender;
        emit NewOwner(address(0), msg.sender);
    }

    /**
     * @notice Base on the inputing parameter `newPendingOwner` to check the exact error reason.
     * @dev Transfer contract control to a new owner. The newPendingOwner must call `_acceptOwner` to finish the transfer.
     * @param newPendingOwner New pending owner.
     */
    function _setPendingOwner(address payable newPendingOwner)
        external
        onlyOwner
    {
        require(
            newPendingOwner != address(0) && newPendingOwner != pendingOwner,
            "_setPendingOwner: New owenr can not be zero address and owner has been set!"
        );

        // Gets current owner.
        address oldPendingOwner = pendingOwner;

        // Sets new pending owner.
        pendingOwner = newPendingOwner;

        emit NewPendingOwner(oldPendingOwner, newPendingOwner);
    }

    /**
     * @dev Accepts the admin rights, but only for pendingOwenr.
     */
    function _acceptOwner() external {
        require(
            msg.sender == pendingOwner,
            "_acceptOwner: Only for pending owner!"
        );

        // Gets current values for events.
        address oldOwner = owner;
        address oldPendingOwner = pendingOwner;

        // Set the new contract owner.
        owner = pendingOwner;

        // Clear the pendingOwner.
        pendingOwner = address(0);

        emit NewOwner(oldOwner, owner);
        emit NewPendingOwner(oldPendingOwner, pendingOwner);
    }

    uint256[50] private __gap;
}

File 16 of 18 : ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 {
    using SafeMathUpgradeable for uint256;

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

    string public name;
    string public symbol;
    uint8 public decimals;

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(
        string memory name_,
        string memory symbol_,
        uint8 decimals_
    ) internal {
        name = name_;
        symbol = symbol_;
        decimals = decimals_;
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount)
        public
        virtual
        returns (bool)
    {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount)
        public
        virtual
        returns (bool)
    {
        _approve(msg.sender, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, allowance[sender][msg.sender].sub(amount));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue)
        public
        virtual
        returns (bool)
    {
        _approve(
            msg.sender,
            spender,
            allowance[msg.sender][spender].add(addedValue)
        );
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue)
        public
        virtual
        returns (bool)
    {
        _approve(
            msg.sender,
            spender,
            allowance[msg.sender][spender].sub(subtractedValue)
        );
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        balanceOf[sender] = balanceOf[sender].sub(amount);
        balanceOf[recipient] = balanceOf[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        totalSupply = totalSupply.add(amount);
        balanceOf[account] = balanceOf[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        balanceOf[account] = balanceOf[account].sub(amount);
        totalSupply = totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        allowance[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    uint256[50] private __gap;
}

File 17 of 18 : IInterestRateModelInterface.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

/**
 * @title dForce Lending Protocol's InterestRateModel Interface.
 * @author dForce Team.
 */
interface IInterestRateModelInterface {
    function isInterestRateModel() external view returns (bool);

    /**
     * @dev 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.
     * @param reserves The total amnount of reserves the market has.
     * @return The borrow rate per block (as a percentage, and scaled by 1e18).
     */
    function getBorrowRate(
        uint256 cash,
        uint256 borrows,
        uint256 reserves
    ) external view returns (uint256);

    /**
     * @dev 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.
     * @param reserves The total amnount of reserves the market has.
     * @param reserveRatio The current reserve factor the market has.
     * @return The supply rate per block (as a percentage, and scaled by 1e18).
     */
    function getSupplyRate(
        uint256 cash,
        uint256 borrows,
        uint256 reserves,
        uint256 reserveRatio
    ) external view returns (uint256);
}

File 18 of 18 : IControllerInterface.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

interface IControllerAdminInterface {
    /// @notice Emitted when an admin supports a market
    event MarketAdded(
        address iToken,
        uint256 collateralFactor,
        uint256 borrowFactor,
        uint256 supplyCapacity,
        uint256 borrowCapacity,
        uint256 distributionFactor
    );

    function _addMarket(
        address _iToken,
        uint256 _collateralFactor,
        uint256 _borrowFactor,
        uint256 _supplyCapacity,
        uint256 _borrowCapacity,
        uint256 _distributionFactor
    ) external;

    /// @notice Emitted when new price oracle is set
    event NewPriceOracle(address oldPriceOracle, address newPriceOracle);

    function _setPriceOracle(address newOracle) external;

    /// @notice Emitted when close factor is changed by admin
    event NewCloseFactor(
        uint256 oldCloseFactorMantissa,
        uint256 newCloseFactorMantissa
    );

    function _setCloseFactor(uint256 newCloseFactorMantissa) external;

    /// @notice Emitted when liquidation incentive is changed by admin
    event NewLiquidationIncentive(
        uint256 oldLiquidationIncentiveMantissa,
        uint256 newLiquidationIncentiveMantissa
    );

    function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa)
        external;

    /// @notice Emitted when iToken's collateral factor is changed by admin
    event NewCollateralFactor(
        address iToken,
        uint256 oldCollateralFactorMantissa,
        uint256 newCollateralFactorMantissa
    );

    function _setCollateralFactor(
        address iToken,
        uint256 newCollateralFactorMantissa
    ) external;

    /// @notice Emitted when iToken's borrow factor is changed by admin
    event NewBorrowFactor(
        address iToken,
        uint256 oldBorrowFactorMantissa,
        uint256 newBorrowFactorMantissa
    );

    function _setBorrowFactor(address iToken, uint256 newBorrowFactorMantissa)
        external;

    /// @notice Emitted when iToken's borrow capacity is changed by admin
    event NewBorrowCapacity(
        address iToken,
        uint256 oldBorrowCapacity,
        uint256 newBorrowCapacity
    );

    function _setBorrowCapacity(address iToken, uint256 newBorrowCapacity)
        external;

    /// @notice Emitted when iToken's supply capacity is changed by admin
    event NewSupplyCapacity(
        address iToken,
        uint256 oldSupplyCapacity,
        uint256 newSupplyCapacity
    );

    function _setSupplyCapacity(address iToken, uint256 newSupplyCapacity)
        external;

    /// @notice Emitted when pause guardian is changed by admin
    event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);

    function _setPauseGuardian(address newPauseGuardian) external;

    /// @notice Emitted when mint is paused/unpaused by admin or pause guardian
    event MintPaused(address iToken, bool paused);

    function _setMintPaused(address iToken, bool paused) external;

    function _setAllMintPaused(bool paused) external;

    /// @notice Emitted when redeem is paused/unpaused by admin or pause guardian
    event RedeemPaused(address iToken, bool paused);

    function _setRedeemPaused(address iToken, bool paused) external;

    function _setAllRedeemPaused(bool paused) external;

    /// @notice Emitted when borrow is paused/unpaused by admin or pause guardian
    event BorrowPaused(address iToken, bool paused);

    function _setBorrowPaused(address iToken, bool paused) external;

    function _setAllBorrowPaused(bool paused) external;

    /// @notice Emitted when transfer is paused/unpaused by admin or pause guardian
    event TransferPaused(bool paused);

    function _setTransferPaused(bool paused) external;

    /// @notice Emitted when seize is paused/unpaused by admin or pause guardian
    event SeizePaused(bool paused);

    function _setSeizePaused(bool paused) external;

    function _setiTokenPaused(address iToken, bool paused) external;

    function _setProtocolPaused(bool paused) external;

    event NewRewardDistributor(
        address oldRewardDistributor,
        address _newRewardDistributor
    );

    function _setRewardDistributor(address _newRewardDistributor) external;
}

interface IControllerPolicyInterface {
    function beforeMint(
        address iToken,
        address account,
        uint256 mintAmount
    ) external;

    function afterMint(
        address iToken,
        address minter,
        uint256 mintAmount,
        uint256 mintedAmount
    ) external;

    function beforeRedeem(
        address iToken,
        address redeemer,
        uint256 redeemAmount
    ) external;

    function afterRedeem(
        address iToken,
        address redeemer,
        uint256 redeemAmount,
        uint256 redeemedAmount
    ) external;

    function beforeBorrow(
        address iToken,
        address borrower,
        uint256 borrowAmount
    ) external;

    function afterBorrow(
        address iToken,
        address borrower,
        uint256 borrowedAmount
    ) external;

    function beforeRepayBorrow(
        address iToken,
        address payer,
        address borrower,
        uint256 repayAmount
    ) external;

    function afterRepayBorrow(
        address iToken,
        address payer,
        address borrower,
        uint256 repayAmount
    ) external;

    function beforeLiquidateBorrow(
        address iTokenBorrowed,
        address iTokenCollateral,
        address liquidator,
        address borrower,
        uint256 repayAmount
    ) external;

    function afterLiquidateBorrow(
        address iTokenBorrowed,
        address iTokenCollateral,
        address liquidator,
        address borrower,
        uint256 repaidAmount,
        uint256 seizedAmount
    ) external;

    function beforeSeize(
        address iTokenBorrowed,
        address iTokenCollateral,
        address liquidator,
        address borrower,
        uint256 seizeAmount
    ) external;

    function afterSeize(
        address iTokenBorrowed,
        address iTokenCollateral,
        address liquidator,
        address borrower,
        uint256 seizedAmount
    ) external;

    function beforeTransfer(
        address iToken,
        address from,
        address to,
        uint256 amount
    ) external;

    function afterTransfer(
        address iToken,
        address from,
        address to,
        uint256 amount
    ) external;

    function beforeFlashloan(
        address iToken,
        address to,
        uint256 amount
    ) external;

    function afterFlashloan(
        address iToken,
        address to,
        uint256 amount
    ) external;
}

interface IControllerAccountEquityInterface {
    function calcAccountEquity(address account)
        external
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        );

    function liquidateCalculateSeizeTokens(
        address iTokenBorrowed,
        address iTokenCollateral,
        uint256 actualRepayAmount
    ) external view returns (uint256);
}

interface IControllerAccountInterface {
    function hasEnteredMarket(address account, address iToken)
        external
        view
        returns (bool);

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

    /// @notice Emitted when an account enters a market
    event MarketEntered(address iToken, address account);

    function enterMarkets(address[] calldata iTokens)
        external
        returns (bool[] memory);

    /// @notice Emitted when an account exits a market
    event MarketExited(address iToken, address account);

    function exitMarkets(address[] calldata iTokens)
        external
        returns (bool[] memory);

    /// @notice Emitted when an account add a borrow asset
    event BorrowedAdded(address iToken, address account);

    /// @notice Emitted when an account remove a borrow asset
    event BorrowedRemoved(address iToken, address account);

    function hasBorrowed(address account, address iToken)
        external
        view
        returns (bool);

    function getBorrowedAssets(address account)
        external
        view
        returns (address[] memory);
}

interface IControllerInterface is
    IControllerAdminInterface,
    IControllerPolicyInterface,
    IControllerAccountEquityInterface,
    IControllerAccountInterface
{
    /**
     * @notice Security checks when updating the comptroller of a market, always expect to return true.
     */
    function isController() external view returns (bool);

    /**
     * @notice Return all of the iTokens
     * @return The list of iToken addresses
     */
    function getAlliTokens() external view returns (address[] memory);

    /**
     * @notice Check whether a iToken is listed in controller
     * @param _iToken The iToken to check for
     * @return true if the iToken is listed otherwise false
     */
    function hasiToken(address _iToken) external view returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","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":"accountInterestIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loaner","type":"address"},{"indexed":false,"internalType":"uint256","name":"loanAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flashloanFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Flashloan","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":"iTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","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":"contract IControllerInterface","name":"oldController","type":"address"},{"indexed":false,"internalType":"contract IControllerInterface","name":"newController","type":"address"}],"name":"NewController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFlashloanFeeRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFlashloanFeeRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldProtocolFeeRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newProtocolFeeRatio","type":"uint256"}],"name":"NewFlashloanFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFlashloanFeeRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFlashloanFeeRatio","type":"uint256"}],"name":"NewFlashloanFeeRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IInterestRateModelInterface","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract IInterestRateModelInterface","name":"newInterestRateModel","type":"address"}],"name":"NewInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPendingOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"NewPendingOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldProtocolFeeRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newProtocolFeeRatio","type":"uint256"}],"name":"NewProtocolFeeRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveRatio","type":"uint256"}],"name":"NewReserveRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemiTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemUnderlyingAmount","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":"accountInterestIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldTotalReserves","type":"uint256"}],"name":"ReservesWithdrawn","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":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currentBlockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cash","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalReserves","type":"uint256"}],"name":"UpdateInterest","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_acceptOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IControllerInterface","name":"_newController","type":"address"}],"name":"_setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IInterestRateModelInterface","name":"_newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFlashloanFeeRatio","type":"uint256"}],"name":"_setNewFlashloanFeeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newProtocolFeeRatio","type":"uint256"}],"name":"_setNewProtocolFeeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newReserveRatio","type":"uint256"}],"name":"_setNewReserveRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingOwner","type":"address"}],"name":"_setPendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawAmount","type":"uint256"}],"name":"_withdrawReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","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":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowAmount","type":"uint256"}],"name":"borrow","outputs":[],"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":[{"internalType":"address","name":"_account","type":"address"}],"name":"borrowSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IControllerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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":"flashloanFeeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"contract IControllerInterface","name":"_controller","type":"address"},{"internalType":"contract IInterestRateModelInterface","name":"_interestRateModel","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract IInterestRateModelInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isiToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_repayAmount","type":"uint256"},{"internalType":"address","name":"_assetCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_mintAmount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolFeeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_redeemiToken","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_redeemUnderlying","type":"uint256"}],"name":"redeemUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_repayAmount","type":"uint256"}],"name":"repayBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"uint256","name":"_repayAmount","type":"uint256"}],"name":"repayBorrowBehalf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveRatio","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":[],"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":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateInterest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b506145dc806100206000396000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c806373acee98116101de578063b2a02ff11161010f578063dd62ed3e116100ad578063f5e3c4621161007c578063f5e3c46214610ada578063f77c479114610b10578063f8f9da2814610b18578063fc4d33f914610b2057610383565b8063dd62ed3e14610a76578063e30c397814610aa4578063f2b3abbd14610aac578063f3fdb15a14610ad257610383565b8063c5ebeaec116100e9578063c5ebeaec146109e3578063c9f30e5314610a00578063d148279114610a1d578063d505accf14610a2557610383565b8063b2a02ff114610988578063b3efd5b4146109be578063bd6d894d146109db57610383565b806395d89b411161017c578063a457c2d711610156578063a457c2d714610920578063a9059cbb1461094c578063aa5af0fd14610978578063ae9d70b01461098057610383565b806395d89b41146108c657806395dd9193146108ce57806396294178146108f457610383565b80637ecebe00116101b85780637ecebe001461086a57806383de424e146108905780638da5cb5b146108b65780638f840ddd146108be57610383565b806373acee9814610852578063744279371461085a5780637a27d9f61461086257610383565b80633644e515116102b8578063508fe21f116102565780636cf1dbed116102305780636cf1dbed1461068f5780636e96dfd7146107e25780636f307dc31461080857806370a082311461082c57610383565b8063508fe21f14610662578063621fd5071461067f5780636c540baf1461068757610383565b80633af9e669116102925780633af9e669146106005780633b1d21a21461062657806340c10f191461062e57806347bd37181461065a57610383565b80633644e5151461058d57806337d336181461059557806339509351146105d457610383565b8063197523f8116103255780632608f818116102ff5780632608f8181461051e578063269aafee1461054a57806330adf81f14610567578063313ce5671461056f57610383565b8063197523f8146104b45780631e9a6950146104bc57806323b872dd146104e857610383565b80630e752702116103615780630e7527021461045f57806317bfdfbc1461047e57806318160ddd146104a4578063182df0f5146104ac57610383565b806306fdde0314610388578063095ea7b3146104055780630c7d5cd814610445575b600080fd5b610390610b28565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103ca5781810151838201526020016103b2565b50505050905090810190601f1680156103f75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104316004803603604081101561041b57600080fd5b506001600160a01b038135169060200135610bb6565b604080519115158252519081900360200190f35b61044d610bcd565b60408051918252519081900360200190f35b61047c6004803603602081101561047557600080fd5b5035610bd3565b005b61044d6004803603602081101561049457600080fd5b50356001600160a01b0316610c79565b61044d610ce1565b61044d610ce7565b61044d610cf7565b61047c600480360360408110156104d257600080fd5b506001600160a01b038135169060200135610cfd565b610431600480360360608110156104fe57600080fd5b506001600160a01b03813581169160208101359091169060400135610dac565b61047c6004803603604081101561053457600080fd5b506001600160a01b038135169060200135610e4a565b61047c6004803603602081101561056057600080fd5b5035610ef1565b61044d611010565b610577611034565b6040805160ff9092168252519081900360200190f35b61044d61103d565b6105bb600480360360208110156105ab57600080fd5b50356001600160a01b0316611043565b6040805192835260208301919091528051918290030190f35b610431600480360360408110156105ea57600080fd5b506001600160a01b038135169060200135611066565b61044d6004803603602081101561061657600080fd5b50356001600160a01b031661109c565b61044d6110d9565b61047c6004803603604081101561064457600080fd5b506001600160a01b0381351690602001356110e3565b61044d611180565b61047c6004803603602081101561067857600080fd5b5035611186565b6104316112a5565b61044d6112aa565b61047c600480360360a08110156106a557600080fd5b6001600160a01b0382351691908101906040810160208201356401000000008111156106d057600080fd5b8201836020820111156106e257600080fd5b8035906020019184600183028401116401000000008311171561070457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929594936020810193503591505064010000000081111561075757600080fd5b82018360208201111561076957600080fd5b8035906020019184600183028401116401000000008311171561078b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550506001600160a01b0383358116945060209093013590921691506112b09050565b61047c600480360360208110156107f857600080fd5b50356001600160a01b0316611397565b610810611493565b604080516001600160a01b039092168252519081900360200190f35b61044d6004803603602081101561084257600080fd5b50356001600160a01b03166114a2565b61044d6114b4565b6104316114c5565b61044d6114ca565b61044d6004803603602081101561088057600080fd5b50356001600160a01b03166114d0565b61047c600480360360208110156108a657600080fd5b50356001600160a01b03166114e2565b610810611639565b61044d611648565b61039061164e565b61044d600480360360208110156108e457600080fd5b50356001600160a01b03166116a9565b61047c6004803603604081101561090a57600080fd5b506001600160a01b0381351690602001356116b4565b6104316004803603604081101561093657600080fd5b506001600160a01b038135169060200135611763565b6104316004803603604081101561096257600080fd5b506001600160a01b038135169060200135611799565b61044d6117fc565b61044d611802565b61047c6004803603606081101561099e57600080fd5b506001600160a01b03813581169160208101359091169060400135611884565b61047c600480360360208110156109d457600080fd5b50356118db565b61044d611a41565b61047c600480360360208110156109f957600080fd5b5035611a53565b61047c60048036036020811015610a1657600080fd5b5035611af7565b610431611c16565b61047c600480360360e0811015610a3b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611c26565b61044d60048036036040811015610a8c57600080fd5b506001600160a01b0381358116916020013516611e48565b610810611e65565b61047c60048036036020811015610ac257600080fd5b50356001600160a01b0316611e74565b610810612013565b61047c60048036036060811015610af057600080fd5b506001600160a01b03813581169160208101359160409091013516612022565b6108106120c0565b61044d6120cf565b61047c612164565b606a805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610bae5780601f10610b8357610100808354040283529160200191610bae565b820191906000526020600020905b815481529060010190602001808311610b9157829003601f168201915b505050505081565b6000610bc333848461224b565b5060015b92915050565b609f5481565b60026001541415610c19576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610c26612337565b4360a65414610c665760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c71333383612560565b505060018055565b600060026001541415610cc1576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610cce612337565b610cd782612745565b6001805592915050565b60695481565b6000610cf161279b565b90505b90565b60a05481565b60026001541415610d43576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610d50612337565b4360a65414610d905760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c718282610da7610da061279b565b85906127e4565b612802565b600060026001541415610df4576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b60026001556001600160a01b038416600090815260686020908152604080832033808552925290912054610e33918691610e2e90866129e5565b61224b565b610e3e848484612a27565b60018055949350505050565b60026001541415610e90576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610e9d612337565b4360a65414610edd5760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610ee8338383612560565b50506001805550565b6033546001600160a01b03163314610f3a5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b610f42612337565b4360a65414610f825760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b670de0b6b3a7640000811115610fc95760405162461bcd60e51b81526004018080602001828103825260368152602001806142d56036913960400191505060405180910390fd5b60a1805490829055604080518281526020810184905281517f1f6917c8223f142d2549d7531b9897b963f67c4cd1d266e9771080a608ebe188929181900390910190a15050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b606c5460ff1681565b60aa5481565b6001600160a01b0316600090815260a96020526040902080546001909101549091565b3360008181526068602090815260408083206001600160a01b03871684529091528120549091610bc3918590610e2e9086612b83565b60006110a6612337565b6001600160a01b0382166000908152606760205260409020546110d1906110cb61279b565b906127e4565b90505b919050565b6000610cf1612bdd565b60026001541415611129576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155611136612337565b4360a654146111765760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c718282612c28565b60a75481565b6033546001600160a01b031633146111cf5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b6111d7612337565b4360a654146112175760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b670de0b6b3a764000081111561125e5760405162461bcd60e51b81526004018080602001828103825260378152602001806143ca6037913960400191505060405180910390fd5b60a0805490829055604080518281526020810184905281517fcc8d29bd7a6ccb34210e5349873398367afa955e6b745621430e8152677d7c75929181900390910190a15050565b600190565b60a65481565b60005460ff16156112f25760405162461bcd60e51b815260040180806020018281038252602e815260200180614333602e913960400191505060405180910390fd5b6113638484876001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561133057600080fd5b505afa158015611344573d6000803e3d6000fd5b505050506040513d602081101561135a57600080fd5b50518585612db9565b505060a280546001600160a01b0319166001600160a01b03949094169390931790925550506000805460ff19166001179055565b6033546001600160a01b031633146113e05760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b6001600160a01b0381161580159061140657506034546001600160a01b03828116911614155b6114415760405162461bcd60e51b815260040180806020018281038252604b815260200180614148604b913960600191505060405180910390fd5b603480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b60a2546001600160a01b031681565b60676020526000908152604090205481565b60006114be612337565b5060a75490565b600181565b60a15481565b60ab6020526000908152604090205481565b6033546001600160a01b0316331461152b5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b60a45460408051634e1647fb60e01b815290516001600160a01b0392831692841691634e1647fb916004808301926020929190829003018186803b15801561157257600080fd5b505afa158015611586573d6000803e3d6000fd5b505050506040513d602081101561159c57600080fd5b50516115d95760405162461bcd60e51b81526004018080602001828103825260348152602001806140f46034913960400191505060405180910390fd5b60a480546001600160a01b0319166001600160a01b03848116918217909255604080519284168352602083019190915280517ff9b6a28700579d5c8fab50f0ac2dcaa52109b85c369c4f511fcc873330ab6cbb9281900390910190a15050565b6033546001600160a01b031681565b60a85481565b606b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610bae5780601f10610b8357610100808354040283529160200191610bae565b60006110d182612745565b600260015414156116fa576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155611707612337565b4360a654146117475760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c718261175d61175661279b565b8490612ecf565b83612802565b3360008181526068602090815260408083206001600160a01b03871684529091528120549091610bc3918590610e2e90866129e5565b6000600260015414156117e1576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b60026001556117f1338484612a27565b600180559392505050565b60a55481565b60008061181961181061279b565b60695490612ef1565b90508061182a576000915050610cf4565b60a75460009061184290670de0b6b3a7640000612ef1565b905061187d611864609f54670de0b6b3a76400006129e590919063ffffffff16565b61186e8385612f4a565b6118766120cf565b9190612f62565b9250505090565b600260015414156118ca576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610ee833848484612f93565b6033546001600160a01b031633146119245760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b61192c612337565b4360a6541461196c5760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b60a85481111580156119855750611981612bdd565b8111155b6119c05760405162461bcd60e51b81526004018080602001828103825260478152602001806144016047913960600191505060405180910390fd5b60a8546119cd81836129e5565b60a8556033546119e6906001600160a01b0316836130f9565b60335460a854604080516001600160a01b039093168352602083018590528281019190915260608201839052517f2e8843ddc3123732d720f1cb17a6e81d71d5bb90a346f13498b87c5639d474409181900360800190a15050565b6000611a4b612337565b610cf161279b565b60026001541415611a99576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155611aa6612337565b4360a65414611ae65760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b611af03382613114565b5060018055565b6033546001600160a01b03163314611b405760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b611b48612337565b4360a65414611b885760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b670de0b6b3a7640000811115611bcf5760405162461bcd60e51b81526004018080602001828103825260318152602001806142a46031913960400191505060405180910390fd5b609f805490829055604080518281526020810184905281517f619970c7b73e9bc2b93e0fc379d50dbf7eced564f397fba395b2e7efc0b4894d929181900390910190a15050565b6000611c20612337565b50600190565b42841015611c6e576040805162461bcd60e51b815260206004820152601060248201526f7065726d69743a20455850495245442160801b604482015290519081900360640190fd5b6001600160a01b03808816600081815260ab602090815260408083205460aa5482517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958c166060860152608085018b905260a0850181905260c08086018b90528251808703909101815260e08601835280519084012061190160f01b6101008701526101028601969096526101228086019690965281518086039096018652610142850180835286519684019690962095849052610162850180835286905260ff89166101828601526101a285018890526101c2850187905290519094936001926101e2808301939192601f198301929081900390910190855afa158015611d86573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611dbc5750896001600160a01b0316816001600160a01b0316145b611e0d576040805162461bcd60e51b815260206004820152601a60248201527f7065726d69743a20494e56414c49445f5349474e415455524521000000000000604482015290519081900360640190fd5b611e18836001612b83565b6001600160a01b038b16600090815260ab6020526040902055611e3c8a8a8a61224b565b50505050505050505050565b606860209081526000928352604080842090915290825290205481565b6034546001600160a01b031681565b6033546001600160a01b03163314611ebd5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b611ec5612337565b4360a65414611f055760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b60a354604080516310c8fc9560e11b815290516001600160a01b0392831692841691632191f92a916004808301926020929190829003018186803b158015611f4c57600080fd5b505afa158015611f60573d6000803e3d6000fd5b505050506040513d6020811015611f7657600080fd5b5051611fb35760405162461bcd60e51b815260040180806020018281038252603b81526020018061448e603b913960400191505060405180910390fd5b60a380546001600160a01b0319166001600160a01b03848116918217909255604080519284168352602083019190915280517feb5cc99f497dc2d7106563bb080e06c9b09e3d81a38623ac4d0839575658d1fa9281900390910190a15050565b60a3546001600160a01b031681565b60026001541415612068576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155612075612337565b4360a654146120b55760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610ee88383836132a9565b60a4546001600160a01b031681565b60a3546000906001600160a01b03166315f240536120eb612bdd565b60a75460a8546040518463ffffffff1660e01b815260040180848152602001838152602001828152602001935050505060206040518083038186803b15801561213357600080fd5b505afa158015612147573d6000803e3d6000fd5b505050506040513d602081101561215d57600080fd5b5051905090565b6034546001600160a01b031633146121ad5760405162461bcd60e51b81526004018080602001828103825260258152602001806145586025913960400191505060405180910390fd5b60338054603480546001600160a01b038082166001600160a01b031980861682179687905590921690925560405192821693909291169083907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236490600090a36034546040516001600160a01b03918216918316907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b6001600160a01b0383166122905760405162461bcd60e51b81526004018080602001828103825260248152602001806144c96024913960400191505060405180910390fd5b6001600160a01b0382166122d55760405162461bcd60e51b81526004018080602001828103825260228152602001806141936022913960400191505060405180910390fd5b6001600160a01b03808416600081815260686020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b61233f613fbb565b612347612bdd565b604080830182905260a7546060840181905260a8546080850181905260a35483516315f2405360e01b815260048101959095526024850192909252604484015290516001600160a01b03909116916315f24053916064808301926020929190829003018186803b1580156123ba57600080fd5b505afa1580156123ce573d6000803e3d6000fd5b505050506040513d60208110156123e457600080fd5b505180825266038d7ea4c68000101561242e5760405162461bcd60e51b815260040180806020018281038252602981526020018061452f6029913960400191505060405180910390fd5b436020820181905260a65461244391906129e5565b60c08201819052815161245591612ef1565b60e08201819052606082015161246b91906127e4565b610100820181905260608201516124829190612b83565b6101208201526080810151610100820151609f546124ab92916124a591906127e4565b90612b83565b61014082015260a55460a0820181905260e08201516124cf91906124a590826127e4565b610160820181905260208083015160a681905560a583905561012084015160a781905561014085015160a8819055610100860151604080880151815195865295850191909152838101959095526060830193909352608082015260a081019190915290517f59693255bedc2974b761b077cd2fdb47b3bde759f64b247f599c6941525655e19181900360c00190a150565b60a45460408051631637eefd60e01b81523060048201526001600160a01b03868116602483015285811660448301526064820185905291516000939290921691631637eefd91608480820192869290919082900301818387803b1580156125c657600080fd5b505af11580156125da573d6000803e3d6000fd5b5050505060006125e984612745565b90506000612605868386116125fe5785612600565b835b6136d2565b6001600160a01b038616600090815260a96020526040902090915061262a83836129e5565b815560a554600182015560a754821161264f5760a75461264a90836129e5565b612652565b60005b60a75560a4546040805163783ca10560e11b81523060048201526001600160a01b038a811660248301528981166044830152606482018690529151919092169163f079420a91608480830192600092919082900301818387803b1580156126b857600080fd5b505af11580156126cc573d6000803e3d6000fd5b50508254600184015460a754604080516001600160a01b03808f1682528d1660208201528082018990526060810194909452608084019290925260a0830152517f6fadbf7329d21f278e724fa0d4511001a158f2a97ee35c5bc4cf8b64417399ef93509081900360c0019150a1509150505b9392505050565b6001600160a01b038116600090815260a9602052604081208054158061276d57506001810154155b1561277c5760009150506110d4565b600181015460a554825461273e92916127959190612ef1565b906137ec565b6000606954600014156127b75750670de0b6b3a7640000610cf4565b6127dd6069546127d760a8546127d160a7546124a5612bdd565b906129e5565b90612f4a565b9050610cf4565b600061273e670de0b6b3a76400006127fc8585612ef1565b90613807565b600082116128415760405162461bcd60e51b81526004018080602001828103825260428152602001806144ed6042913960600191505060405180910390fd5b60a4546040805163af505ad960e01b81523060048201526001600160a01b038681166024830152604482018690529151919092169163af505ad991606480830192600092919082900301818387803b15801561289c57600080fd5b505af11580156128b0573d6000803e3d6000fd5b50505050826001600160a01b0316336001600160a01b031614612902576001600160a01b038316600090815260686020908152604080832033808552925290912054612902918591610e2e90866129e5565b61290c8383613849565b61291633826130f9565b60a4546040805163a2ddeb8560e01b81523060048201526001600160a01b03868116602483015260448201869052606482018590529151919092169163a2ddeb8591608480830192600092919082900301818387803b15801561297857600080fd5b505af115801561298c573d6000803e3d6000fd5b5050604080516001600160a01b03871681523360208201528082018690526060810185905290517f3f693fff038bb8a046aa76d9516190ac7444f7d69cf952c4cbdc086fdef2d6fc9350908190036080019150a1505050565b600061273e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061391f565b6000826001600160a01b0316846001600160a01b03161415612a7a5760405162461bcd60e51b81526004018080602001828103825260268152602001806143826026913960400191505060405180910390fd5b60a4546040805163395a182560e11b81523060048201523360248201526001600160a01b03868116604483015260648201869052915191909216916372b4304a91608480830192600092919082900301818387803b158015612adb57600080fd5b505af1158015612aef573d6000803e3d6000fd5b50505050612afe8484846139b6565b60a4546040805163719d7a4560e11b81523060048201526001600160a01b0387811660248301528681166044830152606482018690529151919092169163e33af48a91608480830192600092919082900301818387803b158015612b6157600080fd5b505af1158015612b75573d6000803e3d6000fd5b506001979650505050505050565b60008282018381101561273e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60a254604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561213357600080fd5b60a454604080516386b8418760e01b81523060048201526001600160a01b03858116602483015260448201859052915191909216916386b8418791606480830192600092919082900301818387803b158015612c8357600080fd5b505af1158015612c97573d6000803e3d6000fd5b50505050612ca361401c565b612cab61279b565b8152612cb733836136d2565b604082018190528151612cca9190612f4a565b60208201819052612cdc908490613aee565b60a45460208201516040805163de65f41b60e01b81523060048201526001600160a01b0387811660248301526044820187905260648201939093529051919092169163de65f41b91608480830192600092919082900301818387803b158015612d4457600080fd5b505af1158015612d58573d6000803e3d6000fd5b505050602080830151604080513381526001600160a01b038816938101939093528281018690526060830191909152517f2f00e3cdd69a77be7ed215ec7b2a36784dd158f921fca79ac29deffa353fe6ee92509081900360800190a1505050565b60a480546001600160a01b038085166001600160a01b03199283161790925560a38054928416929091169190911790554360a655670de0b6b3a764000060a5556602d79883d2000060a0556703782dace9d9000060a155612e18613bd4565b612e23858585613c16565b612e2b613c56565b5050825160209384012060408051808201825260018152603160f81b9086015280517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81870152808201929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528151808403909101815260c09092019052805193019290922060aa555050565b600061273e826127fc612ee38260016129e5565b6124a587670de0b6b3a76400005b600082612f0057506000610bc7565b82820282848281612f0d57fe5b041461273e5760405162461bcd60e51b81526004018080602001828103825260218152602001806143616021913960400191505060405180910390fd5b600061273e826127fc85670de0b6b3a7640000612ef1565b6000612f8b6ec097ce7bc90715b34b9f10000000006127fc84612f858888612ef1565b90612ef1565b949350505050565b826001600160a01b0316826001600160a01b03161415612fe45760405162461bcd60e51b815260040180806020018281038252602681526020018061427e6026913960400191505060405180910390fd5b60a48054604080516332db6c6760e21b81523060048201526001600160a01b03888116602483015287811660448301528681166064830152608482018690529151919092169263cb6db19c9280820192600092909182900301818387803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050506130718284836139b6565b60a48054604080516306bfb3d160e11b81523060048201526001600160a01b038881166024830152878116604483015286811660648301526084820186905291519190921692630d7f67a29280820192600092909182900301818387803b1580156130db57600080fd5b505af11580156130ef573d6000803e3d6000fd5b5050505050505050565b60a254613110906001600160a01b03168383613c5c565b5050565b60a454604080516315caa9e760e11b81523060048201526001600160a01b0385811660248301526044820185905291519190921691632b9553ce91606480830192600092919082900301818387803b15801561316f57600080fd5b505af1158015613183573d6000803e3d6000fd5b505050506001600160a01b038216600090815260a9602052604090206131ac826124a585612745565b815560a554600182015560a7546131c39083612b83565b60a7556131d083836130f9565b60a45460408051636524c56b60e11b81523060048201526001600160a01b038681166024830152604482018690529151919092169163ca498ad691606480830192600092919082900301818387803b15801561322b57600080fd5b505af115801561323f573d6000803e3d6000fd5b50508254600184015460a754604080516001600160a01b038a168152602081018990528082019490945260608401929092526080830152517f2dd79f4fccfd18c360ce7f9132f3621bf05eee18f995224badb32d17f172df7393509081900360a0019150a1505050565b336001600160a01b03841614156132f15760405162461bcd60e51b81526004018080602001828103825260398152602001806142456039913960400191505060405180910390fd5b8161332d5760405162461bcd60e51b81526004018080602001828103825260448152602001806141b56044913960600191505060405180910390fd5b6000819050806001600160a01b031663d14827916040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561336d57600080fd5b505af1158015613381573d6000803e3d6000fd5b505050506040513d602081101561339757600080fd5b505060a480546040805163030b416f60e11b81523060048201526001600160a01b0386811660248301523360448301528881166064830152608482018890529151919092169263061682de9280820192600092909182900301818387803b15801561340157600080fd5b505af1158015613415573d6000803e3d6000fd5b5050505043816001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b15801561345357600080fd5b505afa158015613467573d6000803e3d6000fd5b505050506040513d602081101561347d57600080fd5b5051146134bb5760405162461bcd60e51b815260040180806020018281038252604c8152602001806141f9604c913960600191505060405180910390fd5b60006134c8338686612560565b60a4546040805163c488847b60e01b81523060048201526001600160a01b038781166024830152604482018590529151939450600093919092169163c488847b916064808301926020929190829003018186803b15801561352857600080fd5b505afa15801561353c573d6000803e3d6000fd5b505050506040513d602081101561355257600080fd5b505190506001600160a01b0384163014156135785761357330338884612f93565b6135e9565b6040805163b2a02ff160e01b81523360048201526001600160a01b0388811660248301526044820184905291519185169163b2a02ff19160648082019260009290919082900301818387803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b505050505b60a4805460408051632fbde00360e11b81523060048201526001600160a01b0388811660248301523360448301528a811660648301526084820187905293810185905290519290911691635f7bc0069160c48082019260009290919082900301818387803b15801561365a57600080fd5b505af115801561366e573d6000803e3d6000fd5b5050604080513381526001600160a01b03808b166020830152818301879052881660608201526080810185905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb5293509081900360a0019150a1505050505050565b60a254604080516370a0823160e01b8152306004820152905160009283926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b15801561372257600080fd5b505afa158015613736573d6000803e3d6000fd5b505050506040513d602081101561374c57600080fd5b505160a254909150613769906001600160a01b0316853086613cb3565b60a254604080516370a0823160e01b81523060048201529051612f8b9284926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b1580156137ba57600080fd5b505afa1580156137ce573d6000803e3d6000fd5b505050506040513d60208110156137e457600080fd5b5051906129e5565b600061273e826127fc6138008260016129e5565b8690612b83565b600061273e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613d13565b6001600160a01b03821661388e5760405162461bcd60e51b81526004018080602001828103825260218152602001806144486021913960400191505060405180910390fd5b6001600160a01b0382166000908152606760205260409020546138b190826129e5565b6001600160a01b0383166000908152606760205260409020556069546138d790826129e5565b6069556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600081848411156139ae5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561397357818101518382015260200161395b565b50505050905090810190601f1680156139a05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b0383166139fb5760405162461bcd60e51b81526004018080602001828103825260258152602001806144696025913960400191505060405180910390fd5b6001600160a01b038216613a405760405162461bcd60e51b81526004018080602001828103825260238152602001806140d16023913960400191505060405180910390fd5b6001600160a01b038316600090815260676020526040902054613a6390826129e5565b6001600160a01b038085166000908152606760205260408082209390935590841681522054613a929082612b83565b6001600160a01b0380841660008181526067602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6001600160a01b038216613b49576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b606954613b569082612b83565b6069556001600160a01b038216600090815260676020526040902054613b7c9082612b83565b6001600160a01b03831660008181526067602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b603380546001600160a01b031916339081179091556040516000907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b2364908290a3565b8251613c2990606a90602086019061403d565b508151613c3d90606b90602085019061403d565b50606c805460ff191660ff929092169190911790555050565b60018055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613cae908490613d78565b505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052613d0d908590613d78565b50505050565b60008183613d625760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561397357818101518382015260200161395b565b506000838581613d6e57fe5b0495945050505050565b6060613dcd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e299092919063ffffffff16565b805190915015613cae57808060200190516020811015613dec57600080fd5b5051613cae5760405162461bcd60e51b815260040180806020018281038252602a81526020018061457d602a913960400191505060405180910390fd5b6060612f8b848460008585613e3d85613f4f565b613e8e576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613ecd5780518252601f199092019160209182019101613eae565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613f2f576040519150601f19603f3d011682016040523d82523d6000602084013e613f34565b606091505b5091509150613f44828286613f55565b979650505050505050565b3b151590565b60608315613f6457508161273e565b825115613f745782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561397357818101518382015260200161395b565b6040518061018001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061407e57805160ff19168380011785556140ab565b828001600101855582156140ab579182015b828111156140ab578251825591602001919060010190614090565b506140b79291506140bb565b5090565b5b808211156140b757600081556001016140bc56fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573735f736574436f6e74726f6c6c65723a2054686973206973206e6f742074686520636f6e74726f6c6c657220636f6e7472616374215265656e7472616e637947756172643a207265656e7472616e742063616c6c005f73657450656e64696e674f776e65723a204e6577206f77656e722063616e206e6f74206265207a65726f206164647265737320616e64206f776e657220686173206265656e207365742145524332303a20617070726f766520746f20746865207a65726f20616464726573735f6c6971756964617465426f72726f77496e7465726e616c3a204c697175696461746520616d6f756e742073686f756c642062652067726561746572207468616e2030215f6c6971756964617465426f72726f77496e7465726e616c3a204661696c656420746f2075706461746520626c6f636b206e756d62657220696e20636f6c6c61746572616c206173736574215f6c6971756964617465426f72726f77496e7465726e616c3a204c697175696461746f722063616e206e6f7420626520626f72726f776572217365697a653a204c697175696461746f722063616e206e6f7420626520626f72726f776572215f7365744e657752657365727665526174696f3a204e6577207265736572766520726174696f20746f6f206c61726765215f7365744e657750726f746f636f6c466565526174696f3a204e65772070726f746f636f6c20726174696f20746f6f206c6172676521736574746c65496e7465726573743a204661696c20746f2061636372756520696e74657265737421496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775f7472616e73666572546f6b656e733a20446f206e6f742073656c662d7472616e73666572216f6e6c794f776e65723a2063616c6c6572206973206e6f7420746865206f776e65727365744e6577466c6173686c6f616e466565526174696f3a204e657720666c6173686c6f616e20726174696f20746f6f206c61726765215f776974686472617752657365727665733a20496e76616c696420776974686472617720616d6f756e7420616e6420646f206e6f74206861766520656e6f75676820636173682145524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f20616464726573735f736574496e746572657374526174654d6f64656c3a2054686973206973206e6f74207468652072617465206d6f64656c20636f6e74726163742145524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735f72656465656d496e7465726e616c3a2052656465656d2069546f6b656e20616d6f756e742073686f756c642062652067726561746572207468616e207a65726f215f757064617465496e7465726573743a20426f72726f77207261746520697320746f6f2068696768215f6163636570744f776e65723a204f6e6c7920666f722070656e64696e67206f776e6572215361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a264697066735822122009e62d963fc629d459d1145ba5cc285e0fa4fd15399d39f54653802c478a728364736f6c634300060c0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103835760003560e01c806373acee98116101de578063b2a02ff11161010f578063dd62ed3e116100ad578063f5e3c4621161007c578063f5e3c46214610ada578063f77c479114610b10578063f8f9da2814610b18578063fc4d33f914610b2057610383565b8063dd62ed3e14610a76578063e30c397814610aa4578063f2b3abbd14610aac578063f3fdb15a14610ad257610383565b8063c5ebeaec116100e9578063c5ebeaec146109e3578063c9f30e5314610a00578063d148279114610a1d578063d505accf14610a2557610383565b8063b2a02ff114610988578063b3efd5b4146109be578063bd6d894d146109db57610383565b806395d89b411161017c578063a457c2d711610156578063a457c2d714610920578063a9059cbb1461094c578063aa5af0fd14610978578063ae9d70b01461098057610383565b806395d89b41146108c657806395dd9193146108ce57806396294178146108f457610383565b80637ecebe00116101b85780637ecebe001461086a57806383de424e146108905780638da5cb5b146108b65780638f840ddd146108be57610383565b806373acee9814610852578063744279371461085a5780637a27d9f61461086257610383565b80633644e515116102b8578063508fe21f116102565780636cf1dbed116102305780636cf1dbed1461068f5780636e96dfd7146107e25780636f307dc31461080857806370a082311461082c57610383565b8063508fe21f14610662578063621fd5071461067f5780636c540baf1461068757610383565b80633af9e669116102925780633af9e669146106005780633b1d21a21461062657806340c10f191461062e57806347bd37181461065a57610383565b80633644e5151461058d57806337d336181461059557806339509351146105d457610383565b8063197523f8116103255780632608f818116102ff5780632608f8181461051e578063269aafee1461054a57806330adf81f14610567578063313ce5671461056f57610383565b8063197523f8146104b45780631e9a6950146104bc57806323b872dd146104e857610383565b80630e752702116103615780630e7527021461045f57806317bfdfbc1461047e57806318160ddd146104a4578063182df0f5146104ac57610383565b806306fdde0314610388578063095ea7b3146104055780630c7d5cd814610445575b600080fd5b610390610b28565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103ca5781810151838201526020016103b2565b50505050905090810190601f1680156103f75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104316004803603604081101561041b57600080fd5b506001600160a01b038135169060200135610bb6565b604080519115158252519081900360200190f35b61044d610bcd565b60408051918252519081900360200190f35b61047c6004803603602081101561047557600080fd5b5035610bd3565b005b61044d6004803603602081101561049457600080fd5b50356001600160a01b0316610c79565b61044d610ce1565b61044d610ce7565b61044d610cf7565b61047c600480360360408110156104d257600080fd5b506001600160a01b038135169060200135610cfd565b610431600480360360608110156104fe57600080fd5b506001600160a01b03813581169160208101359091169060400135610dac565b61047c6004803603604081101561053457600080fd5b506001600160a01b038135169060200135610e4a565b61047c6004803603602081101561056057600080fd5b5035610ef1565b61044d611010565b610577611034565b6040805160ff9092168252519081900360200190f35b61044d61103d565b6105bb600480360360208110156105ab57600080fd5b50356001600160a01b0316611043565b6040805192835260208301919091528051918290030190f35b610431600480360360408110156105ea57600080fd5b506001600160a01b038135169060200135611066565b61044d6004803603602081101561061657600080fd5b50356001600160a01b031661109c565b61044d6110d9565b61047c6004803603604081101561064457600080fd5b506001600160a01b0381351690602001356110e3565b61044d611180565b61047c6004803603602081101561067857600080fd5b5035611186565b6104316112a5565b61044d6112aa565b61047c600480360360a08110156106a557600080fd5b6001600160a01b0382351691908101906040810160208201356401000000008111156106d057600080fd5b8201836020820111156106e257600080fd5b8035906020019184600183028401116401000000008311171561070457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929594936020810193503591505064010000000081111561075757600080fd5b82018360208201111561076957600080fd5b8035906020019184600183028401116401000000008311171561078b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550506001600160a01b0383358116945060209093013590921691506112b09050565b61047c600480360360208110156107f857600080fd5b50356001600160a01b0316611397565b610810611493565b604080516001600160a01b039092168252519081900360200190f35b61044d6004803603602081101561084257600080fd5b50356001600160a01b03166114a2565b61044d6114b4565b6104316114c5565b61044d6114ca565b61044d6004803603602081101561088057600080fd5b50356001600160a01b03166114d0565b61047c600480360360208110156108a657600080fd5b50356001600160a01b03166114e2565b610810611639565b61044d611648565b61039061164e565b61044d600480360360208110156108e457600080fd5b50356001600160a01b03166116a9565b61047c6004803603604081101561090a57600080fd5b506001600160a01b0381351690602001356116b4565b6104316004803603604081101561093657600080fd5b506001600160a01b038135169060200135611763565b6104316004803603604081101561096257600080fd5b506001600160a01b038135169060200135611799565b61044d6117fc565b61044d611802565b61047c6004803603606081101561099e57600080fd5b506001600160a01b03813581169160208101359091169060400135611884565b61047c600480360360208110156109d457600080fd5b50356118db565b61044d611a41565b61047c600480360360208110156109f957600080fd5b5035611a53565b61047c60048036036020811015610a1657600080fd5b5035611af7565b610431611c16565b61047c600480360360e0811015610a3b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611c26565b61044d60048036036040811015610a8c57600080fd5b506001600160a01b0381358116916020013516611e48565b610810611e65565b61047c60048036036020811015610ac257600080fd5b50356001600160a01b0316611e74565b610810612013565b61047c60048036036060811015610af057600080fd5b506001600160a01b03813581169160208101359160409091013516612022565b6108106120c0565b61044d6120cf565b61047c612164565b606a805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610bae5780601f10610b8357610100808354040283529160200191610bae565b820191906000526020600020905b815481529060010190602001808311610b9157829003601f168201915b505050505081565b6000610bc333848461224b565b5060015b92915050565b609f5481565b60026001541415610c19576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610c26612337565b4360a65414610c665760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c71333383612560565b505060018055565b600060026001541415610cc1576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610cce612337565b610cd782612745565b6001805592915050565b60695481565b6000610cf161279b565b90505b90565b60a05481565b60026001541415610d43576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610d50612337565b4360a65414610d905760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c718282610da7610da061279b565b85906127e4565b612802565b600060026001541415610df4576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b60026001556001600160a01b038416600090815260686020908152604080832033808552925290912054610e33918691610e2e90866129e5565b61224b565b610e3e848484612a27565b60018055949350505050565b60026001541415610e90576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610e9d612337565b4360a65414610edd5760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610ee8338383612560565b50506001805550565b6033546001600160a01b03163314610f3a5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b610f42612337565b4360a65414610f825760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b670de0b6b3a7640000811115610fc95760405162461bcd60e51b81526004018080602001828103825260368152602001806142d56036913960400191505060405180910390fd5b60a1805490829055604080518281526020810184905281517f1f6917c8223f142d2549d7531b9897b963f67c4cd1d266e9771080a608ebe188929181900390910190a15050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b606c5460ff1681565b60aa5481565b6001600160a01b0316600090815260a96020526040902080546001909101549091565b3360008181526068602090815260408083206001600160a01b03871684529091528120549091610bc3918590610e2e9086612b83565b60006110a6612337565b6001600160a01b0382166000908152606760205260409020546110d1906110cb61279b565b906127e4565b90505b919050565b6000610cf1612bdd565b60026001541415611129576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155611136612337565b4360a654146111765760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c718282612c28565b60a75481565b6033546001600160a01b031633146111cf5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b6111d7612337565b4360a654146112175760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b670de0b6b3a764000081111561125e5760405162461bcd60e51b81526004018080602001828103825260378152602001806143ca6037913960400191505060405180910390fd5b60a0805490829055604080518281526020810184905281517fcc8d29bd7a6ccb34210e5349873398367afa955e6b745621430e8152677d7c75929181900390910190a15050565b600190565b60a65481565b60005460ff16156112f25760405162461bcd60e51b815260040180806020018281038252602e815260200180614333602e913960400191505060405180910390fd5b6113638484876001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561133057600080fd5b505afa158015611344573d6000803e3d6000fd5b505050506040513d602081101561135a57600080fd5b50518585612db9565b505060a280546001600160a01b0319166001600160a01b03949094169390931790925550506000805460ff19166001179055565b6033546001600160a01b031633146113e05760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b6001600160a01b0381161580159061140657506034546001600160a01b03828116911614155b6114415760405162461bcd60e51b815260040180806020018281038252604b815260200180614148604b913960600191505060405180910390fd5b603480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b60a2546001600160a01b031681565b60676020526000908152604090205481565b60006114be612337565b5060a75490565b600181565b60a15481565b60ab6020526000908152604090205481565b6033546001600160a01b0316331461152b5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b60a45460408051634e1647fb60e01b815290516001600160a01b0392831692841691634e1647fb916004808301926020929190829003018186803b15801561157257600080fd5b505afa158015611586573d6000803e3d6000fd5b505050506040513d602081101561159c57600080fd5b50516115d95760405162461bcd60e51b81526004018080602001828103825260348152602001806140f46034913960400191505060405180910390fd5b60a480546001600160a01b0319166001600160a01b03848116918217909255604080519284168352602083019190915280517ff9b6a28700579d5c8fab50f0ac2dcaa52109b85c369c4f511fcc873330ab6cbb9281900390910190a15050565b6033546001600160a01b031681565b60a85481565b606b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610bae5780601f10610b8357610100808354040283529160200191610bae565b60006110d182612745565b600260015414156116fa576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155611707612337565b4360a654146117475760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610c718261175d61175661279b565b8490612ecf565b83612802565b3360008181526068602090815260408083206001600160a01b03871684529091528120549091610bc3918590610e2e90866129e5565b6000600260015414156117e1576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b60026001556117f1338484612a27565b600180559392505050565b60a55481565b60008061181961181061279b565b60695490612ef1565b90508061182a576000915050610cf4565b60a75460009061184290670de0b6b3a7640000612ef1565b905061187d611864609f54670de0b6b3a76400006129e590919063ffffffff16565b61186e8385612f4a565b6118766120cf565b9190612f62565b9250505090565b600260015414156118ca576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155610ee833848484612f93565b6033546001600160a01b031633146119245760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b61192c612337565b4360a6541461196c5760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b60a85481111580156119855750611981612bdd565b8111155b6119c05760405162461bcd60e51b81526004018080602001828103825260478152602001806144016047913960600191505060405180910390fd5b60a8546119cd81836129e5565b60a8556033546119e6906001600160a01b0316836130f9565b60335460a854604080516001600160a01b039093168352602083018590528281019190915260608201839052517f2e8843ddc3123732d720f1cb17a6e81d71d5bb90a346f13498b87c5639d474409181900360800190a15050565b6000611a4b612337565b610cf161279b565b60026001541415611a99576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155611aa6612337565b4360a65414611ae65760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b611af03382613114565b5060018055565b6033546001600160a01b03163314611b405760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b611b48612337565b4360a65414611b885760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b670de0b6b3a7640000811115611bcf5760405162461bcd60e51b81526004018080602001828103825260318152602001806142a46031913960400191505060405180910390fd5b609f805490829055604080518281526020810184905281517f619970c7b73e9bc2b93e0fc379d50dbf7eced564f397fba395b2e7efc0b4894d929181900390910190a15050565b6000611c20612337565b50600190565b42841015611c6e576040805162461bcd60e51b815260206004820152601060248201526f7065726d69743a20455850495245442160801b604482015290519081900360640190fd5b6001600160a01b03808816600081815260ab602090815260408083205460aa5482517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958c166060860152608085018b905260a0850181905260c08086018b90528251808703909101815260e08601835280519084012061190160f01b6101008701526101028601969096526101228086019690965281518086039096018652610142850180835286519684019690962095849052610162850180835286905260ff89166101828601526101a285018890526101c2850187905290519094936001926101e2808301939192601f198301929081900390910190855afa158015611d86573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611dbc5750896001600160a01b0316816001600160a01b0316145b611e0d576040805162461bcd60e51b815260206004820152601a60248201527f7065726d69743a20494e56414c49445f5349474e415455524521000000000000604482015290519081900360640190fd5b611e18836001612b83565b6001600160a01b038b16600090815260ab6020526040902055611e3c8a8a8a61224b565b50505050505050505050565b606860209081526000928352604080842090915290825290205481565b6034546001600160a01b031681565b6033546001600160a01b03163314611ebd5760405162461bcd60e51b81526004018080602001828103825260228152602001806143a86022913960400191505060405180910390fd5b611ec5612337565b4360a65414611f055760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b60a354604080516310c8fc9560e11b815290516001600160a01b0392831692841691632191f92a916004808301926020929190829003018186803b158015611f4c57600080fd5b505afa158015611f60573d6000803e3d6000fd5b505050506040513d6020811015611f7657600080fd5b5051611fb35760405162461bcd60e51b815260040180806020018281038252603b81526020018061448e603b913960400191505060405180910390fd5b60a380546001600160a01b0319166001600160a01b03848116918217909255604080519284168352602083019190915280517feb5cc99f497dc2d7106563bb080e06c9b09e3d81a38623ac4d0839575658d1fa9281900390910190a15050565b60a3546001600160a01b031681565b60026001541415612068576040805162461bcd60e51b815260206004820152601f6024820152600080516020614128833981519152604482015290519081900360640190fd5b6002600155612075612337565b4360a654146120b55760405162461bcd60e51b815260040180806020018281038252602881526020018061430b6028913960400191505060405180910390fd5b610ee88383836132a9565b60a4546001600160a01b031681565b60a3546000906001600160a01b03166315f240536120eb612bdd565b60a75460a8546040518463ffffffff1660e01b815260040180848152602001838152602001828152602001935050505060206040518083038186803b15801561213357600080fd5b505afa158015612147573d6000803e3d6000fd5b505050506040513d602081101561215d57600080fd5b5051905090565b6034546001600160a01b031633146121ad5760405162461bcd60e51b81526004018080602001828103825260258152602001806145586025913960400191505060405180910390fd5b60338054603480546001600160a01b038082166001600160a01b031980861682179687905590921690925560405192821693909291169083907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236490600090a36034546040516001600160a01b03918216918316907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b6001600160a01b0383166122905760405162461bcd60e51b81526004018080602001828103825260248152602001806144c96024913960400191505060405180910390fd5b6001600160a01b0382166122d55760405162461bcd60e51b81526004018080602001828103825260228152602001806141936022913960400191505060405180910390fd5b6001600160a01b03808416600081815260686020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b61233f613fbb565b612347612bdd565b604080830182905260a7546060840181905260a8546080850181905260a35483516315f2405360e01b815260048101959095526024850192909252604484015290516001600160a01b03909116916315f24053916064808301926020929190829003018186803b1580156123ba57600080fd5b505afa1580156123ce573d6000803e3d6000fd5b505050506040513d60208110156123e457600080fd5b505180825266038d7ea4c68000101561242e5760405162461bcd60e51b815260040180806020018281038252602981526020018061452f6029913960400191505060405180910390fd5b436020820181905260a65461244391906129e5565b60c08201819052815161245591612ef1565b60e08201819052606082015161246b91906127e4565b610100820181905260608201516124829190612b83565b6101208201526080810151610100820151609f546124ab92916124a591906127e4565b90612b83565b61014082015260a55460a0820181905260e08201516124cf91906124a590826127e4565b610160820181905260208083015160a681905560a583905561012084015160a781905561014085015160a8819055610100860151604080880151815195865295850191909152838101959095526060830193909352608082015260a081019190915290517f59693255bedc2974b761b077cd2fdb47b3bde759f64b247f599c6941525655e19181900360c00190a150565b60a45460408051631637eefd60e01b81523060048201526001600160a01b03868116602483015285811660448301526064820185905291516000939290921691631637eefd91608480820192869290919082900301818387803b1580156125c657600080fd5b505af11580156125da573d6000803e3d6000fd5b5050505060006125e984612745565b90506000612605868386116125fe5785612600565b835b6136d2565b6001600160a01b038616600090815260a96020526040902090915061262a83836129e5565b815560a554600182015560a754821161264f5760a75461264a90836129e5565b612652565b60005b60a75560a4546040805163783ca10560e11b81523060048201526001600160a01b038a811660248301528981166044830152606482018690529151919092169163f079420a91608480830192600092919082900301818387803b1580156126b857600080fd5b505af11580156126cc573d6000803e3d6000fd5b50508254600184015460a754604080516001600160a01b03808f1682528d1660208201528082018990526060810194909452608084019290925260a0830152517f6fadbf7329d21f278e724fa0d4511001a158f2a97ee35c5bc4cf8b64417399ef93509081900360c0019150a1509150505b9392505050565b6001600160a01b038116600090815260a9602052604081208054158061276d57506001810154155b1561277c5760009150506110d4565b600181015460a554825461273e92916127959190612ef1565b906137ec565b6000606954600014156127b75750670de0b6b3a7640000610cf4565b6127dd6069546127d760a8546127d160a7546124a5612bdd565b906129e5565b90612f4a565b9050610cf4565b600061273e670de0b6b3a76400006127fc8585612ef1565b90613807565b600082116128415760405162461bcd60e51b81526004018080602001828103825260428152602001806144ed6042913960600191505060405180910390fd5b60a4546040805163af505ad960e01b81523060048201526001600160a01b038681166024830152604482018690529151919092169163af505ad991606480830192600092919082900301818387803b15801561289c57600080fd5b505af11580156128b0573d6000803e3d6000fd5b50505050826001600160a01b0316336001600160a01b031614612902576001600160a01b038316600090815260686020908152604080832033808552925290912054612902918591610e2e90866129e5565b61290c8383613849565b61291633826130f9565b60a4546040805163a2ddeb8560e01b81523060048201526001600160a01b03868116602483015260448201869052606482018590529151919092169163a2ddeb8591608480830192600092919082900301818387803b15801561297857600080fd5b505af115801561298c573d6000803e3d6000fd5b5050604080516001600160a01b03871681523360208201528082018690526060810185905290517f3f693fff038bb8a046aa76d9516190ac7444f7d69cf952c4cbdc086fdef2d6fc9350908190036080019150a1505050565b600061273e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061391f565b6000826001600160a01b0316846001600160a01b03161415612a7a5760405162461bcd60e51b81526004018080602001828103825260268152602001806143826026913960400191505060405180910390fd5b60a4546040805163395a182560e11b81523060048201523360248201526001600160a01b03868116604483015260648201869052915191909216916372b4304a91608480830192600092919082900301818387803b158015612adb57600080fd5b505af1158015612aef573d6000803e3d6000fd5b50505050612afe8484846139b6565b60a4546040805163719d7a4560e11b81523060048201526001600160a01b0387811660248301528681166044830152606482018690529151919092169163e33af48a91608480830192600092919082900301818387803b158015612b6157600080fd5b505af1158015612b75573d6000803e3d6000fd5b506001979650505050505050565b60008282018381101561273e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60a254604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561213357600080fd5b60a454604080516386b8418760e01b81523060048201526001600160a01b03858116602483015260448201859052915191909216916386b8418791606480830192600092919082900301818387803b158015612c8357600080fd5b505af1158015612c97573d6000803e3d6000fd5b50505050612ca361401c565b612cab61279b565b8152612cb733836136d2565b604082018190528151612cca9190612f4a565b60208201819052612cdc908490613aee565b60a45460208201516040805163de65f41b60e01b81523060048201526001600160a01b0387811660248301526044820187905260648201939093529051919092169163de65f41b91608480830192600092919082900301818387803b158015612d4457600080fd5b505af1158015612d58573d6000803e3d6000fd5b505050602080830151604080513381526001600160a01b038816938101939093528281018690526060830191909152517f2f00e3cdd69a77be7ed215ec7b2a36784dd158f921fca79ac29deffa353fe6ee92509081900360800190a1505050565b60a480546001600160a01b038085166001600160a01b03199283161790925560a38054928416929091169190911790554360a655670de0b6b3a764000060a5556602d79883d2000060a0556703782dace9d9000060a155612e18613bd4565b612e23858585613c16565b612e2b613c56565b5050825160209384012060408051808201825260018152603160f81b9086015280517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81870152808201929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528151808403909101815260c09092019052805193019290922060aa555050565b600061273e826127fc612ee38260016129e5565b6124a587670de0b6b3a76400005b600082612f0057506000610bc7565b82820282848281612f0d57fe5b041461273e5760405162461bcd60e51b81526004018080602001828103825260218152602001806143616021913960400191505060405180910390fd5b600061273e826127fc85670de0b6b3a7640000612ef1565b6000612f8b6ec097ce7bc90715b34b9f10000000006127fc84612f858888612ef1565b90612ef1565b949350505050565b826001600160a01b0316826001600160a01b03161415612fe45760405162461bcd60e51b815260040180806020018281038252602681526020018061427e6026913960400191505060405180910390fd5b60a48054604080516332db6c6760e21b81523060048201526001600160a01b03888116602483015287811660448301528681166064830152608482018690529151919092169263cb6db19c9280820192600092909182900301818387803b15801561304e57600080fd5b505af1158015613062573d6000803e3d6000fd5b505050506130718284836139b6565b60a48054604080516306bfb3d160e11b81523060048201526001600160a01b038881166024830152878116604483015286811660648301526084820186905291519190921692630d7f67a29280820192600092909182900301818387803b1580156130db57600080fd5b505af11580156130ef573d6000803e3d6000fd5b5050505050505050565b60a254613110906001600160a01b03168383613c5c565b5050565b60a454604080516315caa9e760e11b81523060048201526001600160a01b0385811660248301526044820185905291519190921691632b9553ce91606480830192600092919082900301818387803b15801561316f57600080fd5b505af1158015613183573d6000803e3d6000fd5b505050506001600160a01b038216600090815260a9602052604090206131ac826124a585612745565b815560a554600182015560a7546131c39083612b83565b60a7556131d083836130f9565b60a45460408051636524c56b60e11b81523060048201526001600160a01b038681166024830152604482018690529151919092169163ca498ad691606480830192600092919082900301818387803b15801561322b57600080fd5b505af115801561323f573d6000803e3d6000fd5b50508254600184015460a754604080516001600160a01b038a168152602081018990528082019490945260608401929092526080830152517f2dd79f4fccfd18c360ce7f9132f3621bf05eee18f995224badb32d17f172df7393509081900360a0019150a1505050565b336001600160a01b03841614156132f15760405162461bcd60e51b81526004018080602001828103825260398152602001806142456039913960400191505060405180910390fd5b8161332d5760405162461bcd60e51b81526004018080602001828103825260448152602001806141b56044913960600191505060405180910390fd5b6000819050806001600160a01b031663d14827916040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561336d57600080fd5b505af1158015613381573d6000803e3d6000fd5b505050506040513d602081101561339757600080fd5b505060a480546040805163030b416f60e11b81523060048201526001600160a01b0386811660248301523360448301528881166064830152608482018890529151919092169263061682de9280820192600092909182900301818387803b15801561340157600080fd5b505af1158015613415573d6000803e3d6000fd5b5050505043816001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b15801561345357600080fd5b505afa158015613467573d6000803e3d6000fd5b505050506040513d602081101561347d57600080fd5b5051146134bb5760405162461bcd60e51b815260040180806020018281038252604c8152602001806141f9604c913960600191505060405180910390fd5b60006134c8338686612560565b60a4546040805163c488847b60e01b81523060048201526001600160a01b038781166024830152604482018590529151939450600093919092169163c488847b916064808301926020929190829003018186803b15801561352857600080fd5b505afa15801561353c573d6000803e3d6000fd5b505050506040513d602081101561355257600080fd5b505190506001600160a01b0384163014156135785761357330338884612f93565b6135e9565b6040805163b2a02ff160e01b81523360048201526001600160a01b0388811660248301526044820184905291519185169163b2a02ff19160648082019260009290919082900301818387803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b505050505b60a4805460408051632fbde00360e11b81523060048201526001600160a01b0388811660248301523360448301528a811660648301526084820187905293810185905290519290911691635f7bc0069160c48082019260009290919082900301818387803b15801561365a57600080fd5b505af115801561366e573d6000803e3d6000fd5b5050604080513381526001600160a01b03808b166020830152818301879052881660608201526080810185905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb5293509081900360a0019150a1505050505050565b60a254604080516370a0823160e01b8152306004820152905160009283926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b15801561372257600080fd5b505afa158015613736573d6000803e3d6000fd5b505050506040513d602081101561374c57600080fd5b505160a254909150613769906001600160a01b0316853086613cb3565b60a254604080516370a0823160e01b81523060048201529051612f8b9284926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b1580156137ba57600080fd5b505afa1580156137ce573d6000803e3d6000fd5b505050506040513d60208110156137e457600080fd5b5051906129e5565b600061273e826127fc6138008260016129e5565b8690612b83565b600061273e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613d13565b6001600160a01b03821661388e5760405162461bcd60e51b81526004018080602001828103825260218152602001806144486021913960400191505060405180910390fd5b6001600160a01b0382166000908152606760205260409020546138b190826129e5565b6001600160a01b0383166000908152606760205260409020556069546138d790826129e5565b6069556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b600081848411156139ae5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561397357818101518382015260200161395b565b50505050905090810190601f1680156139a05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b0383166139fb5760405162461bcd60e51b81526004018080602001828103825260258152602001806144696025913960400191505060405180910390fd5b6001600160a01b038216613a405760405162461bcd60e51b81526004018080602001828103825260238152602001806140d16023913960400191505060405180910390fd5b6001600160a01b038316600090815260676020526040902054613a6390826129e5565b6001600160a01b038085166000908152606760205260408082209390935590841681522054613a929082612b83565b6001600160a01b0380841660008181526067602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6001600160a01b038216613b49576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b606954613b569082612b83565b6069556001600160a01b038216600090815260676020526040902054613b7c9082612b83565b6001600160a01b03831660008181526067602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b603380546001600160a01b031916339081179091556040516000907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b2364908290a3565b8251613c2990606a90602086019061403d565b508151613c3d90606b90602085019061403d565b50606c805460ff191660ff929092169190911790555050565b60018055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613cae908490613d78565b505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052613d0d908590613d78565b50505050565b60008183613d625760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561397357818101518382015260200161395b565b506000838581613d6e57fe5b0495945050505050565b6060613dcd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e299092919063ffffffff16565b805190915015613cae57808060200190516020811015613dec57600080fd5b5051613cae5760405162461bcd60e51b815260040180806020018281038252602a81526020018061457d602a913960400191505060405180910390fd5b6060612f8b848460008585613e3d85613f4f565b613e8e576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310613ecd5780518252601f199092019160209182019101613eae565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613f2f576040519150601f19603f3d011682016040523d82523d6000602084013e613f34565b606091505b5091509150613f44828286613f55565b979650505050505050565b3b151590565b60608315613f6457508161273e565b825115613f745782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561397357818101518382015260200161395b565b6040518061018001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061407e57805160ff19168380011785556140ab565b828001600101855582156140ab579182015b828111156140ab578251825591602001919060010190614090565b506140b79291506140bb565b5090565b5b808211156140b757600081556001016140bc56fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573735f736574436f6e74726f6c6c65723a2054686973206973206e6f742074686520636f6e74726f6c6c657220636f6e7472616374215265656e7472616e637947756172643a207265656e7472616e742063616c6c005f73657450656e64696e674f776e65723a204e6577206f77656e722063616e206e6f74206265207a65726f206164647265737320616e64206f776e657220686173206265656e207365742145524332303a20617070726f766520746f20746865207a65726f20616464726573735f6c6971756964617465426f72726f77496e7465726e616c3a204c697175696461746520616d6f756e742073686f756c642062652067726561746572207468616e2030215f6c6971756964617465426f72726f77496e7465726e616c3a204661696c656420746f2075706461746520626c6f636b206e756d62657220696e20636f6c6c61746572616c206173736574215f6c6971756964617465426f72726f77496e7465726e616c3a204c697175696461746f722063616e206e6f7420626520626f72726f776572217365697a653a204c697175696461746f722063616e206e6f7420626520626f72726f776572215f7365744e657752657365727665526174696f3a204e6577207265736572766520726174696f20746f6f206c61726765215f7365744e657750726f746f636f6c466565526174696f3a204e65772070726f746f636f6c20726174696f20746f6f206c6172676521736574746c65496e7465726573743a204661696c20746f2061636372756520696e74657265737421496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775f7472616e73666572546f6b656e733a20446f206e6f742073656c662d7472616e73666572216f6e6c794f776e65723a2063616c6c6572206973206e6f7420746865206f776e65727365744e6577466c6173686c6f616e466565526174696f3a204e657720666c6173686c6f616e20726174696f20746f6f206c61726765215f776974686472617752657365727665733a20496e76616c696420776974686472617720616d6f756e7420616e6420646f206e6f74206861766520656e6f75676820636173682145524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f20616464726573735f736574496e746572657374526174654d6f64656c3a2054686973206973206e6f74207468652072617465206d6f64656c20636f6e74726163742145524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735f72656465656d496e7465726e616c3a2052656465656d2069546f6b656e20616d6f756e742073686f756c642062652067726561746572207468616e207a65726f215f757064617465496e7465726573743a20426f72726f77207261746520697320746f6f2068696768215f6163636570744f776e65723a204f6e6c7920666f722070656e64696e67206f776e6572215361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a264697066735822122009e62d963fc629d459d1145ba5cc285e0fa4fd15399d39f54653802c478a728364736f6c634300060c0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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