ETH Price: $3,270.09 (-2.53%)
Gas: 1.69 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
_transfer Admin118735842021-02-17 9:40:221445 days ago1613554822IN
Hifi Finance: Balance Sheet
0 ETH0.0027720390.001

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BalanceSheet

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU LGPLv3 license

Contract Source Code (Solidity Multiple files format)

File 1 of 23: BalanceSheet.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./Admin.sol";
import "./Exponential.sol";
import "./Erc20Interface.sol";
import "./SafeErc20.sol";
import "./ReentrancyGuard.sol";

import "./BalanceSheetInterface.sol";
import "./FintrollerInterface.sol";
import "./FyTokenInterface.sol";
import "./ChainlinkOperatorInterface.sol";

/**
 * @title BalanceSheet
 * @author Hifi
 * @notice Manages the debt vault for all fyTokens.
 */
contract BalanceSheet is
    ReentrancyGuard, /* no depedency */
    BalanceSheetInterface, /* one dependency */
    Admin, /* two dependencies */
    Exponential /* two dependencies */
{
    using SafeErc20 for Erc20Interface;

    modifier isVaultOpenForMsgSender(FyTokenInterface fyToken) {
        require(vaults[address(fyToken)][msg.sender].isOpen, "ERR_VAULT_NOT_OPEN");
        _;
    }

    /**
     * @param fintroller_ The address of the Fintroller contract.
     */
    constructor(FintrollerInterface fintroller_) Admin() {
        /* Set the fyToken contract and sanity check it. */
        fintroller = fintroller_;
        fintroller.isFintroller();
    }

    /**
     * CONSTANT FUNCTIONS
     */

    struct GetClutchableCollateralLocalVars {
        MathError mathErr;
        Exp clutchableCollateralAmountUpscaled;
        uint256 clutchableCollateralAmount;
        uint256 collateralPrecisionScalar;
        uint256 collateralPriceUpscaled;
        uint256 liquidationIncentiveMantissa;
        Exp numerator;
        uint256 oraclePricePrecisionScalar;
        uint256 underlyingPriceUpscaled;
    }

    /**
     * @notice Determines the amount of collateral that can be clutched when liquidating a borrow.
     *
     * @dev The formula applied:
     * clutchedCollateral = repayAmount * liquidationIncentive * underlyingPriceUsd / collateralPriceUsd
     *
     * Requirements:
     *
     * - `repayAmount` must be non-zero.
     *
     * @param fyToken The fyToken to make the query against.
     * @param repayAmount The amount of fyTokens to repay.
     * @return The amount of clutchable collateral as uint256, specified in the collateral's decimal system.
     */
    function getClutchableCollateral(FyTokenInterface fyToken, uint256 repayAmount)
        external
        view
        override
        returns (uint256)
    {
        GetClutchableCollateralLocalVars memory vars;

        /* Avoid the zero edge cases. */
        require(repayAmount > 0, "ERR_GET_CLUTCHABLE_COLLATERAL_ZERO");

        /* When the liquidation incentive is zero, the end result would be zero anyways. */
        vars.liquidationIncentiveMantissa = fintroller.liquidationIncentiveMantissa();
        if (vars.liquidationIncentiveMantissa == 0) {
            return 0;
        }

        /* Grab the upscaled USD price of the underlying. */
        ChainlinkOperatorInterface oracle = fintroller.oracle();
        vars.underlyingPriceUpscaled = oracle.getAdjustedPrice(fyToken.underlying().symbol());

        /* Grab the upscaled USD price of the collateral. */
        vars.collateralPriceUpscaled = oracle.getAdjustedPrice(fyToken.collateral().symbol());

        /* Calculate the top part of the equation. */
        (vars.mathErr, vars.numerator) = mulExp3(
            Exp({ mantissa: repayAmount }),
            Exp({ mantissa: vars.liquidationIncentiveMantissa }),
            Exp({ mantissa: vars.underlyingPriceUpscaled })
        );
        require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_CLUTCHABLE_COLLATERAL_MATH_ERROR");

        /* Calculate the mantissa form of the clutched collateral amount. */
        (vars.mathErr, vars.clutchableCollateralAmountUpscaled) = divExp(
            vars.numerator,
            Exp({ mantissa: vars.collateralPriceUpscaled })
        );
        require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_CLUTCHABLE_COLLATERAL_MATH_ERROR");

        /* If the precision scalar is not 1, calculate the final form of the clutched collateral amount. */
        vars.collateralPrecisionScalar = fyToken.collateralPrecisionScalar();
        if (vars.collateralPrecisionScalar != 1) {
            (vars.mathErr, vars.clutchableCollateralAmount) = divUInt(
                vars.clutchableCollateralAmountUpscaled.mantissa,
                vars.collateralPrecisionScalar
            );
            require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_CLUTCHABLE_COLLATERAL_MATH_ERROR");
        } else {
            vars.clutchableCollateralAmount = vars.clutchableCollateralAmountUpscaled.mantissa;
        }

        return vars.clutchableCollateralAmount;
    }

    /**
     * @notice Determines the current collateralization ratio for the given borrower account.
     * @param fyToken The fyToken to make the query against.
     * @param borrower The borrower account to make the query against.
     * @return A quotient if locked collateral is non-zero, otherwise zero.
     */
    function getCurrentCollateralizationRatio(FyTokenInterface fyToken, address borrower)
        public
        view
        override
        returns (uint256)
    {
        Vault memory vault = vaults[address(fyToken)][borrower];
        return getHypotheticalCollateralizationRatio(fyToken, borrower, vault.lockedCollateral, vault.debt);
    }

    struct GetHypotheticalAccountLiquidityLocalVars {
        MathError mathErr;
        uint256 collateralPriceUpscaled;
        uint256 collateralPrecisionScalar;
        uint256 collateralizationRatioMantissa;
        Exp debtValueUsd;
        Exp hypotheticalCollateralizationRatio;
        Exp lockedCollateralValueUsd;
        uint256 lockedCollateralUpscaled;
        uint256 oraclePricePrecisionScalar;
        uint256 underlyingPriceUpscaled;
        uint256 underlyingPrecisionScalar;
    }

    /**
     * @notice Determines the hypothetical collateralization ratio for the given locked
     * collateral and debt, at the current prices provided by the oracle.
     *
     * @dev The formula applied: collateralizationRatio = lockedCollateralValueUsd / debtValueUsd
     *
     * Requirements:
     *
     * - The vault must be open.
     * - `debt` must be non-zero.
     * - The oracle prices must be non-zero.
     *
     * @param fyToken The fyToken for which to make the query against.
     * @param borrower The borrower account for which to make the query against.
     * @param lockedCollateral The hypothetical locked collateral.
     * @param debt The hypothetical debt.
     * @return The hypothetical collateralization ratio as a percentage mantissa if locked
     * collateral is non-zero, otherwise zero.
     */
    function getHypotheticalCollateralizationRatio(
        FyTokenInterface fyToken,
        address borrower,
        uint256 lockedCollateral,
        uint256 debt
    ) public view override returns (uint256) {
        GetHypotheticalAccountLiquidityLocalVars memory vars;

        /* If the vault is not open, a hypothetical collateralization ratio cannot be calculated. */
        require(vaults[address(fyToken)][borrower].isOpen, "ERR_VAULT_NOT_OPEN");

        /* Avoid the zero edge cases. */
        if (lockedCollateral == 0) {
            return 0;
        }
        require(debt > 0, "ERR_GET_HYPOTHETICAL_COLLATERALIZATION_RATIO_DEBT_ZERO");

        /* Grab the upscaled USD price of the collateral. */
        ChainlinkOperatorInterface oracle = fintroller.oracle();
        vars.collateralPriceUpscaled = oracle.getAdjustedPrice(fyToken.collateral().symbol());

        /* Grab the upscaled USD price of the underlying. */
        vars.underlyingPriceUpscaled = oracle.getAdjustedPrice(fyToken.underlying().symbol());

        /* Upscale the collateral, which can have any precision, to mantissa precision. */
        vars.collateralPrecisionScalar = fyToken.collateralPrecisionScalar();
        if (vars.collateralPrecisionScalar != 1) {
            (vars.mathErr, vars.lockedCollateralUpscaled) = mulUInt(lockedCollateral, vars.collateralPrecisionScalar);
            require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_HYPOTHETICAL_COLLATERALIZATION_RATIO_MATH_ERROR");
        } else {
            vars.lockedCollateralUpscaled = lockedCollateral;
        }

        /* Calculate the USD value of the collateral. */
        (vars.mathErr, vars.lockedCollateralValueUsd) = mulExp(
            Exp({ mantissa: vars.lockedCollateralUpscaled }),
            Exp({ mantissa: vars.collateralPriceUpscaled })
        );
        require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_HYPOTHETICAL_COLLATERALIZATION_RATIO_MATH_ERROR");

        /* Calculate the USD value of the debt. */
        (vars.mathErr, vars.debtValueUsd) = mulExp(
            Exp({ mantissa: debt }),
            Exp({ mantissa: vars.underlyingPriceUpscaled })
        );
        require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_HYPOTHETICAL_COLLATERALIZATION_RATIO_MATH_ERROR");

        /**
         * Calculate the collateralization ratio by dividing the USD value of the hypothetical locked collateral by
         * the USD value of the debt.
         */
        (vars.mathErr, vars.hypotheticalCollateralizationRatio) = divExp(
            vars.lockedCollateralValueUsd,
            vars.debtValueUsd
        );
        require(vars.mathErr == MathError.NO_ERROR, "ERR_GET_HYPOTHETICAL_COLLATERALIZATION_RATIO_MATH_ERROR");

        return vars.hypotheticalCollateralizationRatio.mantissa;
    }

    /**
     * @notice Reads the storage properties of a vault.
     * @return (uint256 debt, uint256 freeCollateral, uint256 lockedCollateral, bool isOpen).
     */
    function getVault(FyTokenInterface fyToken, address borrower)
        external
        view
        override
        returns (
            uint256,
            uint256,
            uint256,
            bool
        )
    {
        return (
            vaults[address(fyToken)][borrower].debt,
            vaults[address(fyToken)][borrower].freeCollateral,
            vaults[address(fyToken)][borrower].lockedCollateral,
            vaults[address(fyToken)][borrower].isOpen
        );
    }

    /**
     * @notice Reads the debt held by the given account.
     * @return The debt held by the borrower, as an uint256.
     */
    function getVaultDebt(FyTokenInterface fyToken, address borrower) external view override returns (uint256) {
        return vaults[address(fyToken)][borrower].debt;
    }

    /**
     * @notice Reads the amount of collateral that the given borrower account locked in the vault.
     * @return The collateral locked in the vault by the borrower, as an uint256.
     */
    function getVaultLockedCollateral(FyTokenInterface fyToken, address borrower)
        external
        view
        override
        returns (uint256)
    {
        return vaults[address(fyToken)][borrower].lockedCollateral;
    }

    /**
     * @notice Checks whether the borrower account can be liquidated or not.
     * @param fyToken The fyToken for which to make the query against.
     * @param borrower The borrower account for which to make the query against.
     * @return bool true = is underwater, otherwise not.
     */
    function isAccountUnderwater(FyTokenInterface fyToken, address borrower) external view override returns (bool) {
        Vault memory vault = vaults[address(fyToken)][borrower];
        if (!vault.isOpen || vault.debt == 0) {
            return false;
        }
        uint256 currentCollateralizationRatioMantissa = getCurrentCollateralizationRatio(fyToken, borrower);
        uint256 thresholdCollateralizationRatioMantissa = fintroller.getBondCollateralizationRatio(fyToken);
        return currentCollateralizationRatioMantissa < thresholdCollateralizationRatioMantissa;
    }

    /**
     * @notice Checks whether the borrower account has a vault opened for a particular fyToken.
     */
    function isVaultOpen(FyTokenInterface fyToken, address borrower) external view override returns (bool) {
        return vaults[address(fyToken)][borrower].isOpen;
    }

    /**
     * NON-CONSTANT FUNCTIONS
     */

    /**
     * @notice Transfers the collateral from the borrower's vault to the liquidator account.
     *
     * @dev Emits a {ClutchCollateral} event.
     *
     * Requirements:
     *
     * - Can only be called by the fyToken.
     * - There must be enough collateral in the borrower's vault.
     *
     * @param fyToken The address of the fyToken contract.
     * @param liquidator The account who repays the borrower's debt and receives the collateral.
     * @param borrower The account who fell underwater and is liquidated.
     * @param collateralAmount The amount of collateral to clutch, specified in the collateral's decimal system.
     * @return bool true = success, otherwise it reverts.
     */
    function clutchCollateral(
        FyTokenInterface fyToken,
        address liquidator,
        address borrower,
        uint256 collateralAmount
    ) external override nonReentrant returns (bool) {
        /* Checks: the caller is the fyToken. */
        require(msg.sender == address(fyToken), "ERR_CLUTCH_COLLATERAL_NOT_AUTHORIZED");

        /* Checks: there is enough clutchable collateral in the vault. */
        uint256 lockedCollateral = vaults[address(fyToken)][borrower].lockedCollateral;
        require(lockedCollateral >= collateralAmount, "ERR_INSUFFICIENT_LOCKED_COLLATERAL");

        /* Calculate the new locked collateral amount. */
        MathError mathErr;
        uint256 newLockedCollateral;
        (mathErr, newLockedCollateral) = subUInt(lockedCollateral, collateralAmount);
        assert(mathErr == MathError.NO_ERROR);

        /* Effects: update the vault. */
        vaults[address(fyToken)][borrower].lockedCollateral = newLockedCollateral;

        /* Interactions: transfer the collateral. */
        fyToken.collateral().safeTransfer(liquidator, collateralAmount);

        emit ClutchCollateral(fyToken, liquidator, borrower, collateralAmount);

        return true;
    }

    /**
     * @notice Deposits collateral into the account's vault.
     *
     * @dev Emits a {DepositCollateral} event.
     *
     * Requirements:
     *
     * - The vault must be open.
     * - The amount to deposit cannot be zero.
     * - The Fintroller must allow this action to be performed.
     * - The caller must have allowed this contract to spend `collateralAmount` tokens.
     *
     * @param fyToken The address of the fyToken contract.
     * @param collateralAmount The amount of collateral to deposit.
     * @return bool true = success, otherwise it reverts.
     */
    function depositCollateral(FyTokenInterface fyToken, uint256 collateralAmount)
        external
        override
        isVaultOpenForMsgSender(fyToken)
        nonReentrant
        returns (bool)
    {
        /* Checks: the zero edge case. */
        require(collateralAmount > 0, "ERR_DEPOSIT_COLLATERAL_ZERO");

        /* Checks: the Fintroller allows this action to be performed. */
        require(fintroller.getDepositCollateralAllowed(fyToken), "ERR_DEPOSIT_COLLATERAL_NOT_ALLOWED");

        /* Effects: update storage. */
        MathError mathErr;
        uint256 hypotheticalFreeCollateral;
        (mathErr, hypotheticalFreeCollateral) = addUInt(
            vaults[address(fyToken)][msg.sender].freeCollateral,
            collateralAmount
        );
        require(mathErr == MathError.NO_ERROR, "ERR_DEPOSIT_COLLATERAL_MATH_ERROR");
        vaults[address(fyToken)][msg.sender].freeCollateral = hypotheticalFreeCollateral;

        /* Interactions: perform the Erc20 transfer. */
        fyToken.collateral().safeTransferFrom(msg.sender, address(this), collateralAmount);

        emit DepositCollateral(fyToken, msg.sender, collateralAmount);

        return true;
    }

    struct FreeCollateralLocalVars {
        MathError mathErr;
        uint256 collateralizationRatioMantissa;
        uint256 hypotheticalCollateralizationRatioMantissa;
        uint256 newFreeCollateral;
        uint256 newLockedCollateral;
    }

    /**
     * @notice Frees a portion or all of the locked collateral.
     * @dev Emits a {FreeCollateral} event.
     *
     * Requirements:
     *
     * - The vault must be open.
     * - The amount to free cannot be zero.
     * - There must be enough locked collateral.
     * - The borrower account cannot fall below the collateralization ratio.
     *
     * @param fyToken The address of the fyToken contract.
     * @param collateralAmount The amount of locked collateral to free.
     * @return bool true = success, otherwise it reverts.
     */
    function freeCollateral(FyTokenInterface fyToken, uint256 collateralAmount)
        external
        override
        isVaultOpenForMsgSender(fyToken)
        returns (bool)
    {
        FreeCollateralLocalVars memory vars;

        /* Checks: the zero edge case. */
        require(collateralAmount > 0, "ERR_FREE_COLLATERAL_ZERO");

        /* Checks: enough locked collateral. */
        Vault memory vault = vaults[address(fyToken)][msg.sender];
        require(vault.lockedCollateral >= collateralAmount, "ERR_INSUFFICIENT_LOCKED_COLLATERAL");

        /* This operation can't fail because of the first `require` in this function. */
        (vars.mathErr, vars.newLockedCollateral) = subUInt(vault.lockedCollateral, collateralAmount);
        assert(vars.mathErr == MathError.NO_ERROR);

        /* Checks: the hypothetical collateralization ratio is above the threshold. */
        if (vault.debt > 0) {
            vars.hypotheticalCollateralizationRatioMantissa = getHypotheticalCollateralizationRatio(
                fyToken,
                msg.sender,
                vars.newLockedCollateral,
                vault.debt
            );
            vars.collateralizationRatioMantissa = fintroller.getBondCollateralizationRatio(fyToken);
            require(
                vars.hypotheticalCollateralizationRatioMantissa >= vars.collateralizationRatioMantissa,
                "ERR_BELOW_COLLATERALIZATION_RATIO"
            );
        }

        /* Effects: update storage. */
        vaults[address(fyToken)][msg.sender].lockedCollateral = vars.newLockedCollateral;
        (vars.mathErr, vars.newFreeCollateral) = addUInt(vault.freeCollateral, collateralAmount);
        require(vars.mathErr == MathError.NO_ERROR, "ERR_FREE_COLLATERAL_MATH_ERROR");
        vaults[address(fyToken)][msg.sender].freeCollateral = vars.newFreeCollateral;

        emit FreeCollateral(fyToken, msg.sender, collateralAmount);

        return true;
    }

    /**
     * @notice Locks a portion or all of the free collateral to make it eligible for borrowing.
     * @dev Emits a {LockCollateral} event.
     *
     * Requirements:
     *
     * - The vault must be open.
     * - The amount to lock cannot be zero.
     * - There must be enough free collateral.
     *
     * @param fyToken The address of the fyToken contract.
     * @param collateralAmount The amount of free collateral to lock.
     * @return bool true = success, otherwise it reverts.
     */
    function lockCollateral(FyTokenInterface fyToken, uint256 collateralAmount)
        external
        override
        isVaultOpenForMsgSender(fyToken)
        returns (bool)
    {
        /* Avoid the zero edge case. */
        require(collateralAmount > 0, "ERR_LOCK_COLLATERAL_ZERO");

        Vault memory vault = vaults[address(fyToken)][msg.sender];
        require(vault.freeCollateral >= collateralAmount, "ERR_INSUFFICIENT_FREE_COLLATERAL");

        MathError mathErr;
        uint256 newLockedCollateral;
        (mathErr, newLockedCollateral) = addUInt(vault.lockedCollateral, collateralAmount);
        require(mathErr == MathError.NO_ERROR, "ERR_LOCK_COLLATERAL_MATH_ERROR");
        vaults[address(fyToken)][msg.sender].lockedCollateral = newLockedCollateral;

        /* This operation can't fail because of the first `require` in this function. */
        uint256 hypotheticalFreeCollateral;
        (mathErr, hypotheticalFreeCollateral) = subUInt(vault.freeCollateral, collateralAmount);
        assert(mathErr == MathError.NO_ERROR);
        vaults[address(fyToken)][msg.sender].freeCollateral = hypotheticalFreeCollateral;

        emit LockCollateral(fyToken, msg.sender, collateralAmount);

        return true;
    }

    /**
     * @notice Opens a Vault for the caller.
     * @dev Emits an {OpenVault} event.
     *
     * Requirements:
     *
     * - The vault cannot be already open.
     * - The fyToken must pass the inspection.
     *
     * @param fyToken The address of the fyToken contract for which to open the vault.
     * @return bool true = success, otherwise it reverts.
     */
    function openVault(FyTokenInterface fyToken) external override returns (bool) {
        require(fyToken.isFyToken(), "ERR_OPEN_VAULT_FYTOKEN_INSPECTION");
        require(vaults[address(fyToken)][msg.sender].isOpen == false, "ERR_VAULT_OPEN");
        vaults[address(fyToken)][msg.sender].isOpen = true;
        emit OpenVault(fyToken, msg.sender);
        return true;
    }

    /**
     * @notice Updates the debt accrued by a particular borrower account.
     *
     * @dev Emits a {SetVaultDebt} event.
     *
     * Requirements:
     *
     * - Can only be called by the fyToken.
     *
     * @param fyToken The address of the fyToken contract.
     * @param borrower The borrower account for which to update the debt.
     * @param newVaultDebt The new debt to assign to the borrower account.
     * @return bool=true success, otherwise it reverts.
     */
    function setVaultDebt(
        FyTokenInterface fyToken,
        address borrower,
        uint256 newVaultDebt
    ) external override returns (bool) {
        /* Checks: the caller is the fyToken. */
        require(msg.sender == address(fyToken), "ERR_SET_VAULT_DEBT_NOT_AUTHORIZED");

        /* Effects: update storage. */
        uint256 oldVaultDebt = vaults[address(fyToken)][borrower].debt;
        vaults[address(fyToken)][borrower].debt = newVaultDebt;

        emit SetVaultDebt(fyToken, borrower, oldVaultDebt, newVaultDebt);

        return true;
    }

    /**
     * @notice Withdraws a portion or all of the free collateral.
     *
     * @dev Emits a {WithdrawCollateral} event.
     *
     * Requirements:
     *
     * - The vault must be open.
     * - The amount to withdraw cannot be zero.
     * - There must be enough free collateral in the vault.
     *
     * @param fyToken The address of the fyToken contract.
     * @param collateralAmount The amount of collateral to withdraw.
     * @return bool true = success, otherwise it reverts.
     */
    function withdrawCollateral(FyTokenInterface fyToken, uint256 collateralAmount)
        external
        override
        isVaultOpenForMsgSender(fyToken)
        nonReentrant
        returns (bool)
    {
        /* Checks: the zero edge case. */
        require(collateralAmount > 0, "ERR_WITHDRAW_COLLATERAL_ZERO");

        /* Checks: there is enough free collateral. */
        require(
            vaults[address(fyToken)][msg.sender].freeCollateral >= collateralAmount,
            "ERR_INSUFFICIENT_FREE_COLLATERAL"
        );

        /* Effects: update storage. */
        MathError mathErr;
        uint256 newFreeCollateral;
        (mathErr, newFreeCollateral) = subUInt(vaults[address(fyToken)][msg.sender].freeCollateral, collateralAmount);
        /* This operation can't fail because of the first `require` in this function. */
        assert(mathErr == MathError.NO_ERROR);
        vaults[address(fyToken)][msg.sender].freeCollateral = newFreeCollateral;

        /* Interactions: perform the Erc20 transfer. */
        fyToken.collateral().safeTransfer(msg.sender, collateralAmount);

        emit WithdrawCollateral(fyToken, msg.sender, collateralAmount);

        return true;
    }
}

File 2 of 23: Address.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

/**
 * @title Address
 * @author Paul Razvan Berg
 * @notice Collection of functions related to the address type.
 * @dev Forked from OpenZeppelin
 * https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v3.1.0/contracts/utils/Address.sol
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`.
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        /* solhint-disable-next-line no-inline-assembly */
        assembly {
            codehash := extcodehash(account)
        }
        return (codehash != accountHash && codehash != 0x0);
    }
}

File 3 of 23: Admin.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

import "./AdminInterface.sol";

/**
 * @title Admin
 * @author Paul Razvan Berg
 * @notice Contract module which provides a basic access control mechanism, where there is
 * an account (an admin) that can be granted exclusive access to specific functions.
 *
 * By default, the admin account will be the one that deploys the contract. This can later
 * be changed with {transferAdmin}.
 *
 * This module is used through inheritance. It will make available the modifier `onlyAdmin`,
 * which can be applied to your functions to restrict their use to the admin.
 *
 * @dev Forked from OpenZeppelin
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/access/Ownable.sol
 */
abstract contract Admin is AdminInterface {
    /**
     * @notice Throws if called by any account other than the admin.
     */
    modifier onlyAdmin() {
        require(admin == msg.sender, "ERR_NOT_ADMIN");
        _;
    }

    /**
     * @notice Initializes the contract setting the deployer as the initial admin.
     */
    constructor() {
        address msgSender = msg.sender;
        admin = msgSender;
        emit TransferAdmin(address(0x00), msgSender);
    }

    /**
     * @notice Leaves the contract without admin, so it will not be possible to call
     * `onlyAdmin` functions anymore.
     *
     * Requirements:
     *
     * - The caller must be the administrator.
     *
     * WARNING: Doing this will leave the contract without an admin,
     * thereby removing any functionality that is only available to the admin.
     */
    function _renounceAdmin() external virtual override onlyAdmin {
        emit TransferAdmin(admin, address(0x00));
        admin = address(0x00);
    }

    /**
     * @notice Transfers the admin of the contract to a new account (`newAdmin`).
     * Can only be called by the current admin.
     * @param newAdmin The acount of the new admin.
     */
    function _transferAdmin(address newAdmin) external virtual override onlyAdmin {
        require(newAdmin != address(0x00), "ERR_SET_ADMIN_ZERO_ADDRESS");
        emit TransferAdmin(admin, newAdmin);
        admin = newAdmin;
    }
}

File 4 of 23: AdminInterface.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

import "./AdminStorage.sol";

/**
 * @title AdminInterface
 * @author Paul Razvan Berg
 */
abstract contract AdminInterface is AdminStorage {
    /**
     * NON-CONSTANT FUNCTIONS
     */
    function _renounceAdmin() external virtual;

    function _transferAdmin(address newAdmin) external virtual;

    /**
     * EVENTS
     */
    event TransferAdmin(address indexed oldAdmin, address indexed newAdmin);
}

File 5 of 23: AdminStorage.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

abstract contract AdminStorage {
    /**
     * @notice The address of the administrator account or contract.
     */
    address public admin;
}

File 6 of 23: AggregatorV3Interface.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

/**
 * @title AggregatorV3Interface
 * @author Hifi
 * @dev Forked from Chainlink
 * https://github.com/smartcontractkit/chainlink/blob/v0.9.9/evm-contracts/src/v0.7/interfaces/AggregatorV3Interface.sol
 */
interface AggregatorV3Interface {
    function decimals() external view returns (uint8);

    function description() external view returns (string memory);

    function version() external view returns (uint256);

    /*
     * getRoundData and latestRoundData should both raise "No data present"
     * if they do not have data to report, instead of returning unset values
     * which could be misinterpreted as actual reported values.
     */
    function getRoundData(uint80 _roundId)
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}

File 7 of 23: BalanceSheetInterface.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./BalanceSheetStorage.sol";

/**
 * @title BalanceSheetInterface
 * @author Hifi
 */
abstract contract BalanceSheetInterface is BalanceSheetStorage {
    /**
     * CONSTANT FUNCTIONS
     */
    function getClutchableCollateral(FyTokenInterface fyToken, uint256 repayAmount)
        external
        view
        virtual
        returns (uint256);

    function getCurrentCollateralizationRatio(FyTokenInterface fyToken, address borrower)
        public
        view
        virtual
        returns (uint256);

    function getHypotheticalCollateralizationRatio(
        FyTokenInterface fyToken,
        address borrower,
        uint256 lockedCollateral,
        uint256 debt
    ) public view virtual returns (uint256);

    function getVault(FyTokenInterface fyToken, address borrower)
        external
        view
        virtual
        returns (
            uint256,
            uint256,
            uint256,
            bool
        );

    function getVaultDebt(FyTokenInterface fyToken, address borrower) external view virtual returns (uint256);

    function getVaultLockedCollateral(FyTokenInterface fyToken, address borrower)
        external
        view
        virtual
        returns (uint256);

    function isAccountUnderwater(FyTokenInterface fyToken, address borrower) external view virtual returns (bool);

    function isVaultOpen(FyTokenInterface fyToken, address borrower) external view virtual returns (bool);

    /**
     * NON-CONSTANT FUNCTIONS
     */

    function clutchCollateral(
        FyTokenInterface fyToken,
        address liquidator,
        address borrower,
        uint256 clutchedCollateralAmount
    ) external virtual returns (bool);

    function depositCollateral(FyTokenInterface fyToken, uint256 collateralAmount) external virtual returns (bool);

    function freeCollateral(FyTokenInterface fyToken, uint256 collateralAmount) external virtual returns (bool);

    function lockCollateral(FyTokenInterface fyToken, uint256 collateralAmount) external virtual returns (bool);

    function openVault(FyTokenInterface fyToken) external virtual returns (bool);

    function setVaultDebt(
        FyTokenInterface fyToken,
        address borrower,
        uint256 newVaultDebt
    ) external virtual returns (bool);

    function withdrawCollateral(FyTokenInterface fyToken, uint256 collateralAmount) external virtual returns (bool);

    /**
     * EVENTS
     */

    event ClutchCollateral(
        FyTokenInterface indexed fyToken,
        address indexed liquidator,
        address indexed borrower,
        uint256 clutchedCollateralAmount
    );

    event DepositCollateral(FyTokenInterface indexed fyToken, address indexed borrower, uint256 collateralAmount);

    event FreeCollateral(FyTokenInterface indexed fyToken, address indexed borrower, uint256 collateralAmount);

    event LockCollateral(FyTokenInterface indexed fyToken, address indexed borrower, uint256 collateralAmount);

    event OpenVault(FyTokenInterface indexed fyToken, address indexed borrower);

    event SetVaultDebt(FyTokenInterface indexed fyToken, address indexed borrower, uint256 oldDebt, uint256 newDebt);

    event WithdrawCollateral(FyTokenInterface indexed fyToken, address indexed borrower, uint256 collateralAmount);
}

File 8 of 23: BalanceSheetStorage.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./FyTokenInterface.sol";

/**
 * @title BalanceSheetStorage
 * @author Hifi
 */
abstract contract BalanceSheetStorage {
    struct Vault {
        uint256 debt;
        uint256 freeCollateral;
        uint256 lockedCollateral;
        bool isOpen;
    }

    /**
     * @notice The unique Fintroller associated with this contract.
     */
    FintrollerInterface public fintroller;

    /**
     * @dev One vault for each fyToken for each account.
     */
    mapping(address => mapping(address => Vault)) internal vaults;

    /**
     * @notice Indicator that this is a BalanceSheet contract, for inspection.
     */
    bool public constant isBalanceSheet = true;
}

File 9 of 23: CarefulMath.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

/**
 * @notice Possible error codes that can be returned.
 */
enum MathError { NO_ERROR, DIVISION_BY_ZERO, INTEGER_OVERFLOW, INTEGER_UNDERFLOW, MODULO_BY_ZERO }

/**
 * @title CarefulMath
 * @author Paul Razvan Berg
 * @notice Exponential module for storing fixed-precision decimals.
 * @dev Forked from Compound
 * https://github.com/compound-finance/compound-protocol/blob/v2.8.1/contracts/CarefulMath.sol
 */
abstract contract CarefulMath {
    /**
     * @notice Adds two numbers, returns an error on overflow.
     */
    function addUInt(uint256 a, uint256 b) internal pure returns (MathError, uint256) {
        uint256 c = a + b;

        if (c >= a) {
            return (MathError.NO_ERROR, c);
        } else {
            return (MathError.INTEGER_OVERFLOW, 0);
        }
    }

    /**
     * @notice Add `a` and `b` and then subtract `c`.
     */
    function addThenSubUInt(
        uint256 a,
        uint256 b,
        uint256 c
    ) internal pure returns (MathError, uint256) {
        (MathError err0, uint256 sum) = addUInt(a, b);

        if (err0 != MathError.NO_ERROR) {
            return (err0, 0);
        }

        return subUInt(sum, c);
    }

    /**
     * @notice Integer division of two numbers, truncating the quotient.
     */
    function divUInt(uint256 a, uint256 b) internal pure returns (MathError, uint256) {
        if (b == 0) {
            return (MathError.DIVISION_BY_ZERO, 0);
        }

        return (MathError.NO_ERROR, a / b);
    }

    /**
     * @notice Returns the remainder of dividing two numbers.
     * @dev 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).
     */
    function modUInt(uint256 a, uint256 b) internal pure returns (MathError, uint256) {
        if (b == 0) {
            return (MathError.MODULO_BY_ZERO, 0);
        }

        return (MathError.NO_ERROR, a % b);
    }

    /**
     * @notice Multiplies two numbers, returns an error on overflow.
     */
    function mulUInt(uint256 a, uint256 b) internal pure returns (MathError, uint256) {
        if (a == 0) {
            return (MathError.NO_ERROR, 0);
        }

        uint256 c = a * b;

        if (c / a != b) {
            return (MathError.INTEGER_OVERFLOW, 0);
        } else {
            return (MathError.NO_ERROR, c);
        }
    }

    /**
     * @notice Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
     */
    function subUInt(uint256 a, uint256 b) internal pure returns (MathError, uint256) {
        if (b <= a) {
            return (MathError.NO_ERROR, a - b);
        } else {
            return (MathError.INTEGER_UNDERFLOW, 0);
        }
    }
}

File 10 of 23: ChainlinkOperatorInterface.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./CarefulMath.sol";
import "./Erc20Interface.sol";

import "./ChainlinkOperatorStorage.sol";
import "./AggregatorV3Interface.sol";

/**
 * @title ChainlinkOperatorInterface
 * @author Hifi
 */
abstract contract ChainlinkOperatorInterface is ChainlinkOperatorStorage {
    /**
     * EVENTS
     */
    event DeleteFeed(Erc20Interface indexed asset, AggregatorV3Interface indexed feed);

    event SetFeed(Erc20Interface indexed asset, AggregatorV3Interface indexed feed);

    /**
     * CONSTANT FUNCTIONS.
     */
    function getAdjustedPrice(string memory symbol) external view virtual returns (uint256);

    function getFeed(string memory symbol)
        external
        view
        virtual
        returns (
            Erc20Interface,
            AggregatorV3Interface,
            bool
        );

    function getPrice(string memory symbol) public view virtual returns (uint256);

    /**
     * NON-CONSTANT FUNCTIONS.
     */
    function deleteFeed(string memory symbol) external virtual returns (bool);

    function setFeed(Erc20Interface asset, AggregatorV3Interface feed) external virtual returns (bool);
}

File 11 of 23: ChainlinkOperatorStorage.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./Erc20Interface.sol";

import "./AggregatorV3Interface.sol";

/**
 * @title ChainlinkOperatorStorage
 * @author Hifi
 */
abstract contract ChainlinkOperatorStorage {
    struct Feed {
        Erc20Interface asset;
        AggregatorV3Interface id;
        bool isSet;
    }

    /**
     * @dev Mapping between Erc20 symbols and Feed structs.
     */
    mapping(string => Feed) internal feeds;

    /**
     * @notice Chainlink price precision for USD-quoted data.
     */
    uint256 public constant pricePrecision = 8;

    /**
     * @notice The ratio between mantissa precision (1e18) and the Chainlink price precision (1e8).
     */
    uint256 public constant pricePrecisionScalar = 1.0e10;
}

File 12 of 23: Erc20Interface.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

import "./Erc20Storage.sol";

/**
 * @title Erc20Interface
 * @author Paul Razvan Berg
 * @notice Interface of the Erc20 standard
 * @dev Forked from OpenZeppelin
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.2.0/contracts/token/ERC20/IERC20.sol
 */
abstract contract Erc20Interface is Erc20Storage {
    /**
     * CONSTANT FUNCTIONS
     */
    function allowance(address owner, address spender) external view virtual returns (uint256);

    function balanceOf(address account) external view virtual returns (uint256);

    /**
     * NON-CONSTANT FUNCTIONS
     */
    function approve(address spender, uint256 amount) external virtual returns (bool);

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

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external virtual returns (bool);

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

    event Burn(address indexed holder, uint256 burnAmount);

    event Mint(address indexed beneficiary, uint256 mintAmount);

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

File 13 of 23: Erc20Storage.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

/**
 * @title ExponentialStorage
 * @author Paul Razvan Berg
 * @notice The storage interface ancillary to an Erc20 contract.
 */
abstract contract Erc20Storage {
    /**
     * @notice Returns the number of decimals used to get its user representation.
     */
    uint8 public decimals;

    /**
     * @notice Returns the name of the token.
     */
    string public name;

    /**
     * @notice Returns the symbol of the token, usually a shorter version of
     * the name.
     */
    string public symbol;

    /**
     * @notice Returns the amount of tokens in existence.
     */
    uint256 public totalSupply;

    mapping(address => mapping(address => uint256)) internal allowances;

    mapping(address => uint256) internal balances;
}

File 14 of 23: Exponential.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

import "./CarefulMath.sol";
import "./ExponentialStorage.sol";

/**
 * @title Exponential module for storing fixed-precision decimals.
 * @author Paul Razvan Berg
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: `Exp({mantissa: 5100000000000000000})`.
 * @dev Forked from Compound
 * https://github.com/compound-finance/compound-protocol/blob/v2.6/contracts/Exponential.sol
 */
abstract contract Exponential is
    CarefulMath, /* no dependency */
    ExponentialStorage /* no dependency */
{
    /**
     * @dev Adds two exponentials, returning a new exponential.
     */
    function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        (MathError error, uint256 result) = addUInt(a.mantissa, b.mantissa);

        return (error, Exp({ mantissa: result }));
    }

    /**
     * @dev Divides two exponentials, returning a new exponential.
     * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b.
     * NOTE: Returns an error if (`num` * 10e18) > MAX_INT, or if `denom` is zero.
     */
    function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        (MathError err0, uint256 scaledNumerator) = mulUInt(a.mantissa, expScale);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }

        (MathError err1, uint256 rational) = divUInt(scaledNumerator, b.mantissa);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({ mantissa: 0 }));
        }

        return (MathError.NO_ERROR, Exp({ mantissa: rational }));
    }

    /**
     * @dev Multiplies two exponentials, returning a new exponential.
     */
    function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        (MathError err0, uint256 doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }

        /*
         * We add half the scale before dividing so that we get rounding instead of truncation.
         * See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
         * Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
         */
        (MathError err1, uint256 doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({ mantissa: 0 }));
        }

        (MathError err2, uint256 product) = divUInt(doubleScaledProductWithHalfScale, expScale);
        /* The only possible error `div` is MathError.DIVISION_BY_ZERO but we control `expScale` and it's not zero. */
        assert(err2 == MathError.NO_ERROR);

        return (MathError.NO_ERROR, Exp({ mantissa: product }));
    }

    /**
     * @dev Multiplies three exponentials, returning a new exponential.
     */
    function mulExp3(
        Exp memory a,
        Exp memory b,
        Exp memory c
    ) internal pure returns (MathError, Exp memory) {
        (MathError err, Exp memory ab) = mulExp(a, b);
        if (err != MathError.NO_ERROR) {
            return (err, ab);
        }
        return mulExp(ab, c);
    }

    /**
     * @dev Subtracts two exponentials, returning a new exponential.
     */
    function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        (MathError error, uint256 result) = subUInt(a.mantissa, b.mantissa);

        return (error, Exp({ mantissa: result }));
    }
}

File 15 of 23: ExponentialStorage.sol
/* SPDX-License-Identifier: LPGL-3.0-or-later */
pragma solidity ^0.7.0;

/**
 * @title ExponentialStorage
 * @author Paul Razvan Berg
 * @notice The storage interface ancillary to an Exponential contract.
 */
abstract contract ExponentialStorage {
    struct Exp {
        uint256 mantissa;
    }

    /**
     * @dev In Exponential denomination, 1e18 is 1.
     */
    uint256 internal constant expScale = 1e18;
    uint256 internal constant halfExpScale = expScale / 2;
    uint256 internal constant mantissaOne = expScale;
}

File 16 of 23: FintrollerInterface.sol
/* SPDX-License-Identifier: LPGL-3.0-or-later */
pragma solidity ^0.7.0;

import "./FintrollerStorage.sol";
import "./FyTokenInterface.sol";
import "./ChainlinkOperatorInterface.sol";

abstract contract FintrollerInterface is FintrollerStorage {
    /**
     * CONSTANT FUNCTIONS
     */

    function getBond(FyTokenInterface fyToken)
        external
        view
        virtual
        returns (
            uint256 debtCeiling,
            uint256 collateralizationRatioMantissa,
            bool isBorrowAllowed,
            bool isDepositCollateralAllowed,
            bool isLiquidateBorrowAllowed,
            bool isListed,
            bool isRedeemFyTokenAllowed,
            bool isRepayBorrowAllowed,
            bool isSupplyUnderlyingAllowed
        );

    function getBorrowAllowed(FyTokenInterface fyToken) external view virtual returns (bool);

    function getBondCollateralizationRatio(FyTokenInterface fyToken) external view virtual returns (uint256);

    function getBondDebtCeiling(FyTokenInterface fyToken) external view virtual returns (uint256);

    function getDepositCollateralAllowed(FyTokenInterface fyToken) external view virtual returns (bool);

    function getLiquidateBorrowAllowed(FyTokenInterface fyToken) external view virtual returns (bool);

    function getRedeemFyTokensAllowed(FyTokenInterface fyToken) external view virtual returns (bool);

    function getRepayBorrowAllowed(FyTokenInterface fyToken) external view virtual returns (bool);

    function getSupplyUnderlyingAllowed(FyTokenInterface fyToken) external view virtual returns (bool);

    /**
     * NON-CONSTANT FUNCTIONS
     */

    function listBond(FyTokenInterface fyToken) external virtual returns (bool);

    function setBondCollateralizationRatio(FyTokenInterface fyToken, uint256 newCollateralizationRatioMantissa)
        external
        virtual
        returns (bool);

    function setBondDebtCeiling(FyTokenInterface fyToken, uint256 newDebtCeiling) external virtual returns (bool);

    function setBorrowAllowed(FyTokenInterface fyToken, bool state) external virtual returns (bool);

    function setDepositCollateralAllowed(FyTokenInterface fyToken, bool state) external virtual returns (bool);

    function setLiquidateBorrowAllowed(FyTokenInterface fyToken, bool state) external virtual returns (bool);

    function setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external virtual returns (bool);

    function setOracle(ChainlinkOperatorInterface newOracle) external virtual returns (bool);

    function setRedeemFyTokensAllowed(FyTokenInterface fyToken, bool state) external virtual returns (bool);

    function setRepayBorrowAllowed(FyTokenInterface fyToken, bool state) external virtual returns (bool);

    function setSupplyUnderlyingAllowed(FyTokenInterface fyToken, bool state) external virtual returns (bool);

    /**
     * EVENTS
     */
    event ListBond(address indexed admin, FyTokenInterface indexed fyToken);

    event SetBorrowAllowed(address indexed admin, FyTokenInterface indexed fyToken, bool state);

    event SetBondCollateralizationRatio(
        address indexed admin,
        FyTokenInterface indexed fyToken,
        uint256 oldCollateralizationRatio,
        uint256 newCollateralizationRatio
    );

    event SetBondDebtCeiling(
        address indexed admin,
        FyTokenInterface indexed fyToken,
        uint256 oldDebtCeiling,
        uint256 newDebtCeiling
    );

    event SetDepositCollateralAllowed(address indexed admin, FyTokenInterface indexed fyToken, bool state);

    event SetLiquidateBorrowAllowed(address indexed admin, FyTokenInterface indexed fyToken, bool state);

    event SetLiquidationIncentive(
        address indexed admin,
        uint256 oldLiquidationIncentive,
        uint256 newLiquidationIncentive
    );

    event SetRedeemFyTokensAllowed(address indexed admin, FyTokenInterface indexed fyToken, bool state);

    event SetRepayBorrowAllowed(address indexed admin, FyTokenInterface indexed fyToken, bool state);

    event SetOracle(address indexed admin, address oldOracle, address newOracle);

    event SetSupplyUnderlyingAllowed(address indexed admin, FyTokenInterface indexed fyToken, bool state);
}

File 17 of 23: FintrollerStorage.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./Exponential.sol";

import "./FyTokenInterface.sol";
import "./ChainlinkOperatorInterface.sol";

/**
 * @title FintrollerStorage
 * @author Hifi
 */
abstract contract FintrollerStorage is Exponential {
    struct Bond {
        Exp collateralizationRatio;
        uint256 debtCeiling;
        bool isBorrowAllowed;
        bool isDepositCollateralAllowed;
        bool isLiquidateBorrowAllowed;
        bool isListed;
        bool isRedeemFyTokenAllowed;
        bool isRepayBorrowAllowed;
        bool isSupplyUnderlyingAllowed;
    }

    /**
     * @dev Maps the fyToken address to the Bond structs.
     */
    mapping(FyTokenInterface => Bond) internal bonds;

    /**
     * @notice The contract that provides price data for the collateral and the underlying asset.
     */
    ChainlinkOperatorInterface public oracle;

    /**
     * @notice Multiplier representing the discount on collateral that a liquidator receives.
     */
    uint256 public liquidationIncentiveMantissa;

    /**
     * @dev The threshold below which the collateralization ratio cannot be set, equivalent to 100%.
     */
    uint256 internal constant collateralizationRatioLowerBoundMantissa = 1.0e18;

    /**
     * @dev The threshold above which the collateralization ratio cannot be set, equivalent to 10,000%.
     */
    uint256 internal constant collateralizationRatioUpperBoundMantissa = 1.0e20;

    /**
     * @dev The dafault collateralization ratio set when a new bond is listed, equivalent to 150%.
     */
    uint256 internal constant defaultCollateralizationRatioMantissa = 1.5e18;

    /**
     * @dev The threshold below which the liquidation incentive cannot be set, equivalent to 100%.
     */
    uint256 internal constant liquidationIncentiveLowerBoundMantissa = 1.0e18;

    /**
     * @dev The threshold above which the liquidation incentive cannot be set, equivalent to 150%.
     */
    uint256 internal constant liquidationIncentiveUpperBoundMantissa = 1.5e18;

    /**
     * @notice Indicator that this is a Fintroller contract, for inspection.
     */
    bool public constant isFintroller = true;
}

File 18 of 23: FyTokenInterface.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./Erc20Interface.sol";
import "./FyTokenStorage.sol";

/**
 * @title FyTokenInterface
 * @author Hifi
 */
abstract contract FyTokenInterface is
    FyTokenStorage, /* no dependency */
    Erc20Interface /* one dependency */
{
    /**
     * CONSTANT FUNCTIONS
     */
    function isMatured() public view virtual returns (bool);

    /**
     * NON-CONSTANT FUNCTIONS
     */
    function borrow(uint256 borrowAmount) external virtual returns (bool);

    function burn(address holder, uint256 burnAmount) external virtual returns (bool);

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

    function mint(address beneficiary, uint256 mintAmount) external virtual returns (bool);

    function repayBorrow(uint256 repayAmount) external virtual returns (bool);

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

    function _setFintroller(FintrollerInterface newFintroller) external virtual returns (bool);

    /**
     * EVENTS
     */
    event Borrow(address indexed borrower, uint256 borrowAmount);

    event LiquidateBorrow(
        address indexed liquidator,
        address indexed borrower,
        uint256 repayAmount,
        uint256 clutchedCollateralAmount
    );

    event RepayBorrow(address indexed payer, address indexed borrower, uint256 repayAmount, uint256 newDebt);

    event SetFintroller(address indexed admin, FintrollerInterface oldFintroller, FintrollerInterface newFintroller);
}

File 19 of 23: FyTokenStorage.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./Erc20Interface.sol";
import "./BalanceSheetInterface.sol";
import "./FintrollerInterface.sol";
import "./RedemptionPoolInterface.sol";

/**
 * @title FyTokenStorage
 * @author Hifi
 */
abstract contract FyTokenStorage {
    /**
     * STORAGE PROPERTIES
     */

    /**
     * @notice The global debt registry.
     */
    BalanceSheetInterface public balanceSheet;

    /**
     * @notice The Erc20 asset that backs the borrows of this fyToken.
     */
    Erc20Interface public collateral;

    /**
     * @notice The ratio between mantissa precision (1e18) and the collateral precision.
     */
    uint256 public collateralPrecisionScalar;

    /**
     * @notice Unix timestamp in seconds for when this token expires.
     */
    uint256 public expirationTime;

    /**
     * @notice The unique Fintroller associated with this contract.
     */
    FintrollerInterface public fintroller;

    /**
     * @notice The unique Redemption Pool associated with this contract.
     */
    RedemptionPoolInterface public redemptionPool;

    /**
     * @notice The Erc20 underlying, or target, asset for this fyToken.
     */
    Erc20Interface public underlying;

    /**
     * @notice The ratio between mantissa precision (1e18) and the underlying precision.
     */
    uint256 public underlyingPrecisionScalar;

    /**
     * @notice Indicator that this is a FyToken contract, for inspection.
     */
    bool public constant isFyToken = true;
}

File 20 of 23: RedemptionPoolInterface.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./RedemptionPoolStorage.sol";

/**
 * @title RedemptionPoolInterface
 * @author Hifi
 */
abstract contract RedemptionPoolInterface is RedemptionPoolStorage {
    /**
     * NON-CONSTANT FUNCTIONS
     */
    function redeemFyTokens(uint256 fyTokenAmount) external virtual returns (bool);

    function supplyUnderlying(uint256 underlyingAmount) external virtual returns (bool);

    /**
     * EVENTS
     */
    event RedeemFyTokens(address indexed account, uint256 fyTokenAmount, uint256 underlyingAmount);

    event SupplyUnderlying(address indexed account, uint256 underlyingAmount, uint256 fyTokenAmount);
}

File 21 of 23: RedemptionPoolStorage.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

import "./FintrollerInterface.sol";
import "./FyTokenInterface.sol";

/**
 * @title RedemptionPoolStorage
 * @author Hifi
 */
abstract contract RedemptionPoolStorage {
    /**
     * @notice The unique Fintroller associated with this contract.
     */
    FintrollerInterface public fintroller;

    /**
     * @notice The amount of the underlying asset available to be redeemed after maturation.
     */
    uint256 public totalUnderlyingSupply;

    /**
     * The unique fyToken associated with this Redemption Pool.
     */
    FyTokenInterface public fyToken;

    /**
     * @notice Indicator that this is a Redemption Pool contract, for inspection.
     */
    bool public constant isRedemptionPool = true;
}

File 22 of 23: ReentrancyGuard.sol
/* SPDX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.7.0;

/**
 * @title ReentrancyGuard
 * @author Paul Razvan Berg
 * @notice 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.
 *
 * @dev Forked from OpenZeppelin
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/math/ReentrancyGuard.sol
 */
abstract contract ReentrancyGuard {
    bool private notEntered;

    /*
     * Storing an initial 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 percetange 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.
     */
    constructor() {
        notEntered = true;
    }

    /**
     * @notice Prevents a contract from calling itself, directly or indirectly.
     * @dev 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(notEntered, "ERR_REENTRANT_CALL");

        /* Any calls to nonReentrant after this point will fail. */
        notEntered = false;

        _;

        /*
         * By storing the original value once again, a refund is triggered (see
         * https://eips.ethereum.org/EIPS/eip-2200).
         */
        notEntered = true;
    }
}

File 23 of 23: SafeErc20.sol
/* SPDX-License-Identifier: MIT */
pragma solidity ^0.7.0;

import "./Erc20Interface.sol";
import "./Address.sol";

/**
 * @title SafeErc20.sol
 * @author Paul Razvan Berg
 * @notice Wraps 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 Erc20Interface;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 *
 * @dev Forked from OpenZeppelin
 * https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v3.1.0/contracts/utils/Address.sol
 */
library SafeErc20 {
    using Address for address;

    /**
     * INTERNAL FUNCTIONS
     */

    function safeTransfer(
        Erc20Interface token,
        address to,
        uint256 amount
    ) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, amount));
    }

    function safeTransferFrom(
        Erc20Interface token,
        address from,
        address to,
        uint256 amount
    ) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, amount));
    }

    /**
     * PRIVATE FUNCTIONS
     */

    /**
     * @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 cannot 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(Erc20Interface 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 = functionCall(address(token), data, "ERR_SAFE_ERC20_LOW_LEVEL_CALL");
        if (returndata.length > 0) {
            /* Return data is optional. */
            require(abi.decode(returndata, (bool)), "ERR_SAFE_ERC20_ERC20_OPERATION");
        }
    }

    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) private returns (bytes memory) {
        require(target.isContract(), "ERR_SAFE_ERC20_CALL_TO_NON_CONTRACT");

        /* solhint-disable-next-line avoid-low-level-calls */
        (bool success, bytes memory returndata) = target.call(data);
        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);
            }
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract FintrollerInterface","name":"fintroller_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"clutchedCollateralAmount","type":"uint256"}],"name":"ClutchCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"DepositCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"FreeCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"LockCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"}],"name":"OpenVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDebt","type":"uint256"}],"name":"SetVaultDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"TransferAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"WithdrawCollateral","type":"event"},{"inputs":[],"name":"_renounceAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"_transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"clutchCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"depositCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fintroller","outputs":[{"internalType":"contract FintrollerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"freeCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"getClutchableCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getCurrentCollateralizationRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"lockedCollateral","type":"uint256"},{"internalType":"uint256","name":"debt","type":"uint256"}],"name":"getHypotheticalCollateralizationRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getVault","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getVaultDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"getVaultLockedCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"isAccountUnderwater","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBalanceSheet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"name":"isVaultOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"lockCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"}],"name":"openVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"newVaultDebt","type":"uint256"}],"name":"setVaultDebt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract FyTokenInterface","name":"fyToken","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"withdrawCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620034f4380380620034f4833981810160405260208110156200003757600080fd5b50516000805460ff19166001178155600280546001600160a01b03191633908117909155604051909182917fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80908290a35080600060016101000a8154816001600160a01b0302191690836001600160a01b03160217905550600060019054906101000a90046001600160a01b03166001600160a01b03166358f25c506040518163ffffffff1660e01b815260040160206040518083038186803b158015620000fe57600080fd5b505afa15801562000113573d6000803e3d6000fd5b505050506040513d60208110156200012a57600080fd5b5050506133b7806200013d6000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063a5d5db0c116100ad578063d8e51dfb11610071578063d8e51dfb146103eb578063e2ad6fe014610427578063e6abb5ae14610455578063ede4c0cc1461047b578063f851a4401461049f5761012c565b8063a5d5db0c146102fb578063b4f2a9cc14610327578063b9d2cc3014610355578063bbd7edc51461038b578063bfa25308146103e15761012c565b8063464b0485116100f4578063464b04851461023f57806347a7d1071461026b5780636321e20c146102975780638a0695fd1461029f5780639ee91d1f146102cd5761012c565b80630e496ef3146101315780631a7a4eb4146101815780632abaf14e146101c1578063318e7028146101ed578063350c35e914610213575b600080fd5b61016d6004803603608081101561014757600080fd5b506001600160a01b038135811691602081013582169160408201351690606001356104a7565b604080519115158252519081900360200190f35b6101af6004803603604081101561019757600080fd5b506001600160a01b03813581169160200135166106e9565b60408051918252519081900360200190f35b61016d600480360360408110156101d757600080fd5b506001600160a01b038135169060200135610719565b61016d6004803603602081101561020357600080fd5b50356001600160a01b0316610add565b61016d6004803603604081101561022957600080fd5b506001600160a01b038135169060200135610c4f565b6101af6004803603604081101561025557600080fd5b506001600160a01b038135169060200135610eea565b61016d6004803603604081101561028157600080fd5b506001600160a01b038135169060200135611761565b61016d611a06565b6101af600480360360408110156102b557600080fd5b506001600160a01b0381358116916020013516611a0b565b61016d600480360360408110156102e357600080fd5b506001600160a01b0381358116916020013516611a36565b61016d6004803603604081101561031157600080fd5b506001600160a01b038135169060200135611b47565b61016d6004803603604081101561033d57600080fd5b506001600160a01b0381358116916020013516611ea8565b61016d6004803603606081101561036b57600080fd5b506001600160a01b03813581169160208101359091169060400135611ed9565b6103b9600480360360408110156103a157600080fd5b506001600160a01b0381358116916020013516611f97565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b6103e9611fdc565b005b6101af6004803603608081101561040157600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135612075565b6101af6004803603604081101561043d57600080fd5b506001600160a01b038135811691602001351661295c565b6103e96004803603602081101561046b57600080fd5b50356001600160a01b03166129c3565b610483612ac9565b604080516001600160a01b039092168252519081900360200190f35b610483612add565b6000805460ff166104f4576040805162461bcd60e51b815260206004820152601260248201527111549497d4915153951490539517d0d0531360721b604482015290519081900360640190fd5b6000805460ff19169055336001600160a01b038616146105455760405162461bcd60e51b81526004018080602001828103825260248152602001806132786024913960400191505060405180910390fd5b6001600160a01b03808616600090815260016020908152604080832093871683529290522060020154828110156105ad5760405162461bcd60e51b81526004018080602001828103825260228152602001806131ff6022913960400191505060405180910390fd5b6000806105ba8386612aec565b909250905060008260048111156105cd57fe5b146105d457fe5b6001600160a01b038089166000818152600160209081526040808320948b16835293815290839020600201849055825163d8dfeb4560e01b81529251610678938b938a93909263d8dfeb45926004808201939291829003018186803b15801561063c57600080fd5b505afa158015610650573d6000803e3d6000fd5b505050506040513d602081101561066657600080fd5b50516001600160a01b03169190612b12565b856001600160a01b0316876001600160a01b0316896001600160a01b03167f01d76d96d07104485e19bcce9463bb051a46eaa5d8cce043a1a9cbaeb2a7228e886040518082815260200191505060405180910390a4600193505050506000805460ff19166001179055949350505050565b6001600160a01b038083166000908152600160209081526040808320938516835292905220600201545b92915050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff1661078b576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b6107936130d7565b600084116107e8576040805162461bcd60e51b815260206004820152601860248201527f4552525f465245455f434f4c4c41544552414c5f5a45524f0000000000000000604482015290519081900360640190fd5b6001600160a01b0385166000908152600160208181526040808420338552825292839020835160808101855281548152928101549183019190915260028101549282018390526003015460ff16151560608201529085111561087b5760405162461bcd60e51b81526004018080602001828103825260228152602001806131ff6022913960400191505060405180910390fd5b610889816040015186612aec565b608084018190528382600481111561089d57fe5b60048111156108a857fe5b90525060009050825160048111156108bc57fe5b146108c357fe5b8051156109ac576108de863384608001518460000151612075565b604083810191909152600054815163351da44160e21b81526001600160a01b03898116600483015292516101009092049092169163d4769104916024808301926020929190829003018186803b15801561093757600080fd5b505afa15801561094b573d6000803e3d6000fd5b505050506040513d602081101561096157600080fd5b505160208301819052604083015110156109ac5760405162461bcd60e51b81526004018080602001828103825260218152602001806131bc6021913960400191505060405180910390fd5b60808201516001600160a01b03871660009081526001602090815260408083203384528252909120600201919091558101516109e89086612b69565b60608401819052838260048111156109fc57fe5b6004811115610a0757fe5b9052506000905082516004811115610a1b57fe5b14610a6d576040805162461bcd60e51b815260206004820152601e60248201527f4552525f465245455f434f4c4c41544552414c5f4d4154485f4552524f520000604482015290519081900360640190fd5b60608201516001600160a01b03871660008181526001602081815260408084203380865290835293819020909201949094558051898152905191937f1eb814d29363ba0d496e4eeb821d6f2537310b83b36c70fb97ae141b41fa733c92918290030190a350600195945050505050565b6000816001600160a01b031663cab364f16040518163ffffffff1660e01b815260040160206040518083038186803b158015610b1857600080fd5b505afa158015610b2c573d6000803e3d6000fd5b505050506040513d6020811015610b4257600080fd5b5051610b7f5760405162461bcd60e51b815260040180806020018281038252602181526020018061332a6021913960400191505060405180910390fd5b6001600160a01b038216600090815260016020908152604080832033845290915290206003015460ff1615610bec576040805162461bcd60e51b815260206004820152600e60248201526d22a9292fab20aaa62a2fa7a822a760911b604482015290519081900360640190fd5b6001600160a01b0382166000818152600160208181526040808420338086529252808420600301805460ff191690931790925590519092917fbe36feaa49d1f66b249db1d112a47d32073d1ce484020276d73790cad02be89091a3506001919050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff16610cc1576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b60005460ff16610d0d576040805162461bcd60e51b815260206004820152601260248201527111549497d4915153951490539517d0d0531360721b604482015290519081900360640190fd5b6000805460ff1916905582610d69576040805162461bcd60e51b815260206004820152601c60248201527f4552525f57495448445241575f434f4c4c41544552414c5f5a45524f00000000604482015290519081900360640190fd5b6001600160a01b03841660009081526001602081815260408084203385529091529091200154831115610de3576040805162461bcd60e51b815260206004820181905260248201527f4552525f494e53554646494349454e545f465245455f434f4c4c41544552414c604482015290519081900360640190fd5b6001600160a01b0384166000908152600160208181526040808420338552909152822001548190610e149086612aec565b90925090506000826004811115610e2757fe5b14610e2e57fe5b6001600160a01b03861660008181526001602081815260408084203380865290835293819020909201859055815163d8dfeb4560e01b81529151610e90948a93909263d8dfeb4592600480840193829003018186803b15801561063c57600080fd5b60408051868152905133916001600160a01b038916917f1607da8e9144035d8537941425741e9e3569c81d34a7f8e0c5c44635dc7169219181900360200190a3600193505050506000805460ff1916600117905592915050565b6000610ef4613108565b60008311610f335760405162461bcd60e51b815260040180806020018281038252602281526020018061329c6022913960400191505060405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b0316634ada90af6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f8157600080fd5b505afa158015610f95573d6000803e3d6000fd5b505050506040513d6020811015610fab57600080fd5b505160a08201819052610fc2576000915050610713565b60008060019054906101000a90046001600160a01b03166001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561101157600080fd5b505afa158015611025573d6000803e3d6000fd5b505050506040513d602081101561103b57600080fd5b505160408051636f307dc360e01b815290519192506001600160a01b038084169263f8d71a119291891691636f307dc3916004808301926020929190829003018186803b15801561108b57600080fd5b505afa15801561109f573d6000803e3d6000fd5b505050506040513d60208110156110b557600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b1580156110f957600080fd5b505afa15801561110d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561113657600080fd5b8101908080516040519392919084600160201b82111561115557600080fd5b90830190602082018581111561116a57600080fd5b8251600160201b81118282018810171561118357600080fd5b82525081516020918201929091019080838360005b838110156111b0578181015183820152602001611198565b50505050905090810190601f1680156111dd5780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611230578181015183820152602001611218565b50505050905090810190601f16801561125d5780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b15801561127a57600080fd5b505afa15801561128e573d6000803e3d6000fd5b505050506040513d60208110156112a457600080fd5b50516101008301526040805163d8dfeb4560e01b815290516001600160a01b038084169263f8d71a11929189169163d8dfeb4591600480820192602092909190829003018186803b1580156112f857600080fd5b505afa15801561130c573d6000803e3d6000fd5b505050506040513d602081101561132257600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b15801561136657600080fd5b505afa15801561137a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156113a357600080fd5b8101908080516040519392919084600160201b8211156113c257600080fd5b9083019060208201858111156113d757600080fd5b8251600160201b8111828201881017156113f057600080fd5b82525081516020918201929091019080838360005b8381101561141d578181015183820152602001611405565b50505050905090810190601f16801561144a5780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561149d578181015183820152602001611485565b50505050905090810190601f1680156114ca5780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b1580156114e757600080fd5b505afa1580156114fb573d6000803e3d6000fd5b505050506040513d602081101561151157600080fd5b5051608083015260408051602081810183528682528251808201845260a086015181528351918201909352610100850151815261154e9290612b8f565b60c084018190528382600481111561156257fe5b600481111561156d57fe5b905250600090508251600481111561158157fe5b146115bd5760405162461bcd60e51b81526004018080602001828103825260288152602001806132e16028913960400191505060405180910390fd5b6115dd8260c0015160405180602001604052808560800151815250612be1565b60208401819052838260048111156115f157fe5b60048111156115fc57fe5b905250600090508251600481111561161057fe5b1461164c5760405162461bcd60e51b81526004018080602001828103825260288152602001806132e16028913960400191505060405180910390fd5b846001600160a01b031663b2bc5ef96040518163ffffffff1660e01b815260040160206040518083038186803b15801561168557600080fd5b505afa158015611699573d6000803e3d6000fd5b505050506040513d60208110156116af57600080fd5b505160608301819052600114611749576116d58260200151600001518360600151612c9a565b60408401819052838260048111156116e957fe5b60048111156116f457fe5b905250600090508251600481111561170857fe5b146117445760405162461bcd60e51b81526004018080602001828103825260288152602001806132e16028913960400191505060405180910390fd5b611755565b60208201515160408301525b50604001519392505050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff166117d3576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b60008311611828576040805162461bcd60e51b815260206004820152601860248201527f4552525f4c4f434b5f434f4c4c41544552414c5f5a45524f0000000000000000604482015290519081900360640190fd5b6001600160a01b03841660009081526001602081815260408084203385528252928390208351608081018552815481529281015491830182905260028101549383019390935260039092015460ff1615156060820152908411156118d3576040805162461bcd60e51b815260206004820181905260248201527f4552525f494e53554646494349454e545f465245455f434f4c4c41544552414c604482015290519081900360640190fd5b6000806118e4836040015187612b69565b909250905060008260048111156118f757fe5b14611949576040805162461bcd60e51b815260206004820152601e60248201527f4552525f4c4f434b5f434f4c4c41544552414c5f4d4154485f4552524f520000604482015290519081900360640190fd5b6001600160a01b03871660009081526001602090815260408083203384528252822060020183905584015161197e9088612aec565b9093509050600083600481111561199157fe5b1461199857fe5b6001600160a01b0388166000818152600160208181526040808420338086529083529381902090920185905581518b815291519293927f5dece52d6e464edb81a56c0ff16f6db48378690286920d6db39d387000064de69281900390910190a3506001979650505050505050565b600181565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0380831660009081526001602081815260408084209486168452938152838320845160808101865281548152928101549183019190915260028101549382019390935260039092015460ff16158015606084015290919080611a9e57508051155b15611aad576000915050610713565b6000611ab9858561295c565b600080546040805163351da44160e21b81526001600160a01b038a8116600483015291519495509293610100909204169163d4769104916024808301926020929190829003018186803b158015611b0f57600080fd5b505afa158015611b23573d6000803e3d6000fd5b505050506040513d6020811015611b3957600080fd5b505190911095945050505050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff16611bb9576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b60005460ff16611c05576040805162461bcd60e51b815260206004820152601260248201527111549497d4915153951490539517d0d0531360721b604482015290519081900360640190fd5b6000805460ff1916905582611c61576040805162461bcd60e51b815260206004820152601b60248201527f4552525f4445504f5349545f434f4c4c41544552414c5f5a45524f0000000000604482015290519081900360640190fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663ce8f6d3e856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015611cc357600080fd5b505afa158015611cd7573d6000803e3d6000fd5b505050506040513d6020811015611ced57600080fd5b5051611d2a5760405162461bcd60e51b81526004018080602001828103825260228152602001806131dd6022913960400191505060405180910390fd5b6001600160a01b0384166000908152600160208181526040808420338552909152822001548190611d5b9086612b69565b90925090506000826004811115611d6e57fe5b14611daa5760405162461bcd60e51b81526004018080602001828103825260218152602001806132576021913960400191505060405180910390fd5b6001600160a01b03861660008181526001602081815260408084203380865290835293819020909201859055815163d8dfeb4560e01b81529151611e4e9430938b93919263d8dfeb4592600480840193919291829003018186803b158015611e1157600080fd5b505afa158015611e25573d6000803e3d6000fd5b505050506040513d6020811015611e3b57600080fd5b50516001600160a01b0316929190612cc5565b60408051868152905133916001600160a01b038916917fef12f18e2b6578b91b3c852c423ca8ee530f65f20f770e62a7ce8aa08e1ab7779181900360200190a3600193505050506000805460ff1916600117905592915050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152206003015460ff1690565b6000336001600160a01b03851614611f225760405162461bcd60e51b81526004018080602001828103825260218152602001806133096021913960400191505060405180910390fd5b6001600160a01b0384811660008181526001602090815260408083209488168084529482529182902080549087905582518181529182018790528251909493927ff2d27c8f0e872c6ed429c5d25278ae6023ae9cc5f788a0fd39b66fb738f8f45c928290030190a360019150505b9392505050565b6001600160a01b039182166000908152600160208181526040808420949095168352929092529190912080549181015460028201546003909201549293909260ff1690565b6002546001600160a01b0316331461202b576040805162461bcd60e51b815260206004820152600d60248201526c22a9292fa727aa2fa0a226a4a760991b604482015290519081900360640190fd5b6002546040516000916001600160a01b0316907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80908390a3600280546001600160a01b0319169055565b600061207f613161565b6001600160a01b0380871660009081526001602090815260408083209389168352929052206003015460ff166120f1576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b83612100576000915050612954565b6000831161213f5760405162461bcd60e51b81526004018080602001828103825260368152602001806132216036913960400191505060405180910390fd5b60008060019054906101000a90046001600160a01b03166001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561218e57600080fd5b505afa1580156121a2573d6000803e3d6000fd5b505050506040513d60208110156121b857600080fd5b50516040805163d8dfeb4560e01b815290519192506001600160a01b038084169263f8d71a1192918b169163d8dfeb45916004808301926020929190829003018186803b15801561220857600080fd5b505afa15801561221c573d6000803e3d6000fd5b505050506040513d602081101561223257600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b15801561227657600080fd5b505afa15801561228a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156122b357600080fd5b8101908080516040519392919084600160201b8211156122d257600080fd5b9083019060208201858111156122e757600080fd5b8251600160201b81118282018810171561230057600080fd5b82525081516020918201929091019080838360005b8381101561232d578181015183820152602001612315565b50505050905090810190601f16801561235a5780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156123ad578181015183820152602001612395565b50505050905090810190601f1680156123da5780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b1580156123f757600080fd5b505afa15801561240b573d6000803e3d6000fd5b505050506040513d602081101561242157600080fd5b505160208381019190915260408051636f307dc360e01b815290516001600160a01b038085169363f8d71a1193918c1692636f307dc3926004808201939291829003018186803b15801561247457600080fd5b505afa158015612488573d6000803e3d6000fd5b505050506040513d602081101561249e57600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b1580156124e257600080fd5b505afa1580156124f6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561251f57600080fd5b8101908080516040519392919084600160201b82111561253e57600080fd5b90830190602082018581111561255357600080fd5b8251600160201b81118282018810171561256c57600080fd5b82525081516020918201929091019080838360005b83811015612599578181015183820152602001612581565b50505050905090810190601f1680156125c65780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612619578181015183820152602001612601565b50505050905090810190601f1680156126465780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b15801561266357600080fd5b505afa158015612677573d6000803e3d6000fd5b505050506040513d602081101561268d57600080fd5b50516101208301526040805163b2bc5ef960e01b815290516001600160a01b0389169163b2bc5ef9916004808301926020929190829003018186803b1580156126d557600080fd5b505afa1580156126e9573d6000803e3d6000fd5b505050506040513d60208110156126ff57600080fd5b5051604083018190526001146127915761271d858360400151612d25565b60e084018190528382600481111561273157fe5b600481111561273c57fe5b905250600090508251600481111561275057fe5b1461278c5760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b612799565b60e082018590525b604080516020808201835260e08501518252825180820190935284015182526127c191612d64565b60c08401819052838260048111156127d557fe5b60048111156127e057fe5b90525060009050825160048111156127f457fe5b146128305760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b61285b6040518060200160405280868152506040518060200160405280856101200151815250612d64565b608084018190528382600481111561286f57fe5b600481111561287a57fe5b905250600090508251600481111561288e57fe5b146128ca5760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b6128dc8260c001518360800151612be1565b60a08401819052838260048111156128f057fe5b60048111156128fb57fe5b905250600090508251600481111561290f57fe5b1461294b5760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b5060a001515190505b949350505050565b6001600160a01b038083166000908152600160208181526040808420948616845293815283832084516080810186528154808252938201549281019290925260028101549482018590526003015460ff161515606082015291926129549186918691612075565b6002546001600160a01b03163314612a12576040805162461bcd60e51b815260206004820152600d60248201526c22a9292fa727aa2fa0a226a4a760991b604482015290519081900360640190fd5b6001600160a01b038116612a6d576040805162461bcd60e51b815260206004820152601a60248201527f4552525f5345545f41444d494e5f5a45524f5f41444452455353000000000000604482015290519081900360640190fd5b6002546040516001600160a01b038084169216907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf8090600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b60005461010090046001600160a01b031681565b6002546001600160a01b031681565b600080838311612b03575060009050818303612b0b565b506003905060005b9250929050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612b64908490612e4e565b505050565b600080838301848110612b8157600092509050612b0b565b600260009250925050612b0b565b6000612b996131a8565b600080612ba68787612d64565b90925090506000826004811115612bb957fe5b14612bc8579092509050612bd9565b612bd28186612d64565b9350935050505b935093915050565b6000612beb6131a8565b600080612c048660000151670de0b6b3a7640000612d25565b90925090506000826004811115612c1757fe5b14612c3657506040805160208101909152600081529092509050612b0b565b600080612c47838860000151612c9a565b90925090506000826004811115612c5a57fe5b14612c7d5781604051806020016040528060008152509550955050505050612b0b565b604080516020810190915290815260009890975095505050505050565b60008082612cae5750600190506000612b0b565b6000838581612cb957fe5b04915091509250929050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612d1f908590612e4e565b50505050565b60008083612d3857506000905080612b0b565b83830283858281612d4557fe5b0414612d5957600260009250925050612b0b565b600092509050612b0b565b6000612d6e6131a8565b600080612d8386600001518660000151612d25565b90925090506000826004811115612d9657fe5b14612db557506040805160208101909152600081529092509050612b0b565b600080612dca6706f05b59d3b2000084612b69565b90925090506000826004811115612ddd57fe5b14612e005781604051806020016040528060008152509550955050505050612b0b565b600080612e1583670de0b6b3a7640000612c9a565b90925090506000826004811115612e2857fe5b14612e2f57fe5b604080516020810190915290815260009a909950975050505050505050565b6000612e9083836040518060400160405280601d81526020017f4552525f534146455f45524332305f4c4f575f4c4556454c5f43414c4c000000815250612f02565b805190915015612b6457808060200190516020811015612eaf57600080fd5b5051612b64576040805162461bcd60e51b815260206004820152601e60248201527f4552525f534146455f45524332305f45524332305f4f5045524154494f4e0000604482015290519081900360640190fd5b6060612f16846001600160a01b031661309e565b612f515760405162461bcd60e51b81526004018080602001828103825260238152602001806132be6023913960400191505060405180910390fd5b600080856001600160a01b0316856040518082805190602001908083835b60208310612f8e5780518252601f199092019160209182019101612f6f565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612ff0576040519150601f19603f3d011682016040523d82523d6000602084013e612ff5565b606091505b50915091508115613009579150611f909050565b8051156130195780518082602001fd5b8360405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561306357818101518382015260200161304b565b50505050905090810190601f1680156130905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612954575050151592915050565b6040805160a081019091528060005b8152602001600081526020016000815260200160008152602001600081525090565b60408051610120810190915280600081526020016131246131a8565b81526020016000815260200160008152602001600081526020016000815260200161314d6131a8565b815260200160008152602001600081525090565b60408051610160810190915280600081526020016000815260200160008152602001600081526020016131926131a8565b815260200161319f6131a8565b81526020016130e65b604051806020016040528060008152509056fe4552525f42454c4f575f434f4c4c41544552414c495a4154494f4e5f524154494f4552525f4445504f5349545f434f4c4c41544552414c5f4e4f545f414c4c4f5745444552525f494e53554646494349454e545f4c4f434b45445f434f4c4c41544552414c4552525f4745545f4859504f544845544943414c5f434f4c4c41544552414c495a4154494f4e5f524154494f5f444542545f5a45524f4552525f4445504f5349545f434f4c4c41544552414c5f4d4154485f4552524f524552525f434c555443485f434f4c4c41544552414c5f4e4f545f415554484f52495a45444552525f4745545f434c5554434841424c455f434f4c4c41544552414c5f5a45524f4552525f534146455f45524332305f43414c4c5f544f5f4e4f4e5f434f4e54524143544552525f4745545f434c5554434841424c455f434f4c4c41544552414c5f4d4154485f4552524f524552525f5345545f5641554c545f444542545f4e4f545f415554484f52495a45444552525f4f50454e5f5641554c545f4659544f4b454e5f494e5350454354494f4e4552525f4745545f4859504f544845544943414c5f434f4c4c41544552414c495a4154494f4e5f524154494f5f4d4154485f4552524f52a2646970667358221220928357a59c778e5f8d069b600a19b817e5393c5184a7792ffe7f0903b50afcd064736f6c63430007060033000000000000000000000000ed4348fc8b1b634b3a0eadabfd32530046b89c60

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061012c5760003560e01c8063a5d5db0c116100ad578063d8e51dfb11610071578063d8e51dfb146103eb578063e2ad6fe014610427578063e6abb5ae14610455578063ede4c0cc1461047b578063f851a4401461049f5761012c565b8063a5d5db0c146102fb578063b4f2a9cc14610327578063b9d2cc3014610355578063bbd7edc51461038b578063bfa25308146103e15761012c565b8063464b0485116100f4578063464b04851461023f57806347a7d1071461026b5780636321e20c146102975780638a0695fd1461029f5780639ee91d1f146102cd5761012c565b80630e496ef3146101315780631a7a4eb4146101815780632abaf14e146101c1578063318e7028146101ed578063350c35e914610213575b600080fd5b61016d6004803603608081101561014757600080fd5b506001600160a01b038135811691602081013582169160408201351690606001356104a7565b604080519115158252519081900360200190f35b6101af6004803603604081101561019757600080fd5b506001600160a01b03813581169160200135166106e9565b60408051918252519081900360200190f35b61016d600480360360408110156101d757600080fd5b506001600160a01b038135169060200135610719565b61016d6004803603602081101561020357600080fd5b50356001600160a01b0316610add565b61016d6004803603604081101561022957600080fd5b506001600160a01b038135169060200135610c4f565b6101af6004803603604081101561025557600080fd5b506001600160a01b038135169060200135610eea565b61016d6004803603604081101561028157600080fd5b506001600160a01b038135169060200135611761565b61016d611a06565b6101af600480360360408110156102b557600080fd5b506001600160a01b0381358116916020013516611a0b565b61016d600480360360408110156102e357600080fd5b506001600160a01b0381358116916020013516611a36565b61016d6004803603604081101561031157600080fd5b506001600160a01b038135169060200135611b47565b61016d6004803603604081101561033d57600080fd5b506001600160a01b0381358116916020013516611ea8565b61016d6004803603606081101561036b57600080fd5b506001600160a01b03813581169160208101359091169060400135611ed9565b6103b9600480360360408110156103a157600080fd5b506001600160a01b0381358116916020013516611f97565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b6103e9611fdc565b005b6101af6004803603608081101561040157600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135612075565b6101af6004803603604081101561043d57600080fd5b506001600160a01b038135811691602001351661295c565b6103e96004803603602081101561046b57600080fd5b50356001600160a01b03166129c3565b610483612ac9565b604080516001600160a01b039092168252519081900360200190f35b610483612add565b6000805460ff166104f4576040805162461bcd60e51b815260206004820152601260248201527111549497d4915153951490539517d0d0531360721b604482015290519081900360640190fd5b6000805460ff19169055336001600160a01b038616146105455760405162461bcd60e51b81526004018080602001828103825260248152602001806132786024913960400191505060405180910390fd5b6001600160a01b03808616600090815260016020908152604080832093871683529290522060020154828110156105ad5760405162461bcd60e51b81526004018080602001828103825260228152602001806131ff6022913960400191505060405180910390fd5b6000806105ba8386612aec565b909250905060008260048111156105cd57fe5b146105d457fe5b6001600160a01b038089166000818152600160209081526040808320948b16835293815290839020600201849055825163d8dfeb4560e01b81529251610678938b938a93909263d8dfeb45926004808201939291829003018186803b15801561063c57600080fd5b505afa158015610650573d6000803e3d6000fd5b505050506040513d602081101561066657600080fd5b50516001600160a01b03169190612b12565b856001600160a01b0316876001600160a01b0316896001600160a01b03167f01d76d96d07104485e19bcce9463bb051a46eaa5d8cce043a1a9cbaeb2a7228e886040518082815260200191505060405180910390a4600193505050506000805460ff19166001179055949350505050565b6001600160a01b038083166000908152600160209081526040808320938516835292905220600201545b92915050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff1661078b576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b6107936130d7565b600084116107e8576040805162461bcd60e51b815260206004820152601860248201527f4552525f465245455f434f4c4c41544552414c5f5a45524f0000000000000000604482015290519081900360640190fd5b6001600160a01b0385166000908152600160208181526040808420338552825292839020835160808101855281548152928101549183019190915260028101549282018390526003015460ff16151560608201529085111561087b5760405162461bcd60e51b81526004018080602001828103825260228152602001806131ff6022913960400191505060405180910390fd5b610889816040015186612aec565b608084018190528382600481111561089d57fe5b60048111156108a857fe5b90525060009050825160048111156108bc57fe5b146108c357fe5b8051156109ac576108de863384608001518460000151612075565b604083810191909152600054815163351da44160e21b81526001600160a01b03898116600483015292516101009092049092169163d4769104916024808301926020929190829003018186803b15801561093757600080fd5b505afa15801561094b573d6000803e3d6000fd5b505050506040513d602081101561096157600080fd5b505160208301819052604083015110156109ac5760405162461bcd60e51b81526004018080602001828103825260218152602001806131bc6021913960400191505060405180910390fd5b60808201516001600160a01b03871660009081526001602090815260408083203384528252909120600201919091558101516109e89086612b69565b60608401819052838260048111156109fc57fe5b6004811115610a0757fe5b9052506000905082516004811115610a1b57fe5b14610a6d576040805162461bcd60e51b815260206004820152601e60248201527f4552525f465245455f434f4c4c41544552414c5f4d4154485f4552524f520000604482015290519081900360640190fd5b60608201516001600160a01b03871660008181526001602081815260408084203380865290835293819020909201949094558051898152905191937f1eb814d29363ba0d496e4eeb821d6f2537310b83b36c70fb97ae141b41fa733c92918290030190a350600195945050505050565b6000816001600160a01b031663cab364f16040518163ffffffff1660e01b815260040160206040518083038186803b158015610b1857600080fd5b505afa158015610b2c573d6000803e3d6000fd5b505050506040513d6020811015610b4257600080fd5b5051610b7f5760405162461bcd60e51b815260040180806020018281038252602181526020018061332a6021913960400191505060405180910390fd5b6001600160a01b038216600090815260016020908152604080832033845290915290206003015460ff1615610bec576040805162461bcd60e51b815260206004820152600e60248201526d22a9292fab20aaa62a2fa7a822a760911b604482015290519081900360640190fd5b6001600160a01b0382166000818152600160208181526040808420338086529252808420600301805460ff191690931790925590519092917fbe36feaa49d1f66b249db1d112a47d32073d1ce484020276d73790cad02be89091a3506001919050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff16610cc1576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b60005460ff16610d0d576040805162461bcd60e51b815260206004820152601260248201527111549497d4915153951490539517d0d0531360721b604482015290519081900360640190fd5b6000805460ff1916905582610d69576040805162461bcd60e51b815260206004820152601c60248201527f4552525f57495448445241575f434f4c4c41544552414c5f5a45524f00000000604482015290519081900360640190fd5b6001600160a01b03841660009081526001602081815260408084203385529091529091200154831115610de3576040805162461bcd60e51b815260206004820181905260248201527f4552525f494e53554646494349454e545f465245455f434f4c4c41544552414c604482015290519081900360640190fd5b6001600160a01b0384166000908152600160208181526040808420338552909152822001548190610e149086612aec565b90925090506000826004811115610e2757fe5b14610e2e57fe5b6001600160a01b03861660008181526001602081815260408084203380865290835293819020909201859055815163d8dfeb4560e01b81529151610e90948a93909263d8dfeb4592600480840193829003018186803b15801561063c57600080fd5b60408051868152905133916001600160a01b038916917f1607da8e9144035d8537941425741e9e3569c81d34a7f8e0c5c44635dc7169219181900360200190a3600193505050506000805460ff1916600117905592915050565b6000610ef4613108565b60008311610f335760405162461bcd60e51b815260040180806020018281038252602281526020018061329c6022913960400191505060405180910390fd5b600060019054906101000a90046001600160a01b03166001600160a01b0316634ada90af6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f8157600080fd5b505afa158015610f95573d6000803e3d6000fd5b505050506040513d6020811015610fab57600080fd5b505160a08201819052610fc2576000915050610713565b60008060019054906101000a90046001600160a01b03166001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561101157600080fd5b505afa158015611025573d6000803e3d6000fd5b505050506040513d602081101561103b57600080fd5b505160408051636f307dc360e01b815290519192506001600160a01b038084169263f8d71a119291891691636f307dc3916004808301926020929190829003018186803b15801561108b57600080fd5b505afa15801561109f573d6000803e3d6000fd5b505050506040513d60208110156110b557600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b1580156110f957600080fd5b505afa15801561110d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561113657600080fd5b8101908080516040519392919084600160201b82111561115557600080fd5b90830190602082018581111561116a57600080fd5b8251600160201b81118282018810171561118357600080fd5b82525081516020918201929091019080838360005b838110156111b0578181015183820152602001611198565b50505050905090810190601f1680156111dd5780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611230578181015183820152602001611218565b50505050905090810190601f16801561125d5780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b15801561127a57600080fd5b505afa15801561128e573d6000803e3d6000fd5b505050506040513d60208110156112a457600080fd5b50516101008301526040805163d8dfeb4560e01b815290516001600160a01b038084169263f8d71a11929189169163d8dfeb4591600480820192602092909190829003018186803b1580156112f857600080fd5b505afa15801561130c573d6000803e3d6000fd5b505050506040513d602081101561132257600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b15801561136657600080fd5b505afa15801561137a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156113a357600080fd5b8101908080516040519392919084600160201b8211156113c257600080fd5b9083019060208201858111156113d757600080fd5b8251600160201b8111828201881017156113f057600080fd5b82525081516020918201929091019080838360005b8381101561141d578181015183820152602001611405565b50505050905090810190601f16801561144a5780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561149d578181015183820152602001611485565b50505050905090810190601f1680156114ca5780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b1580156114e757600080fd5b505afa1580156114fb573d6000803e3d6000fd5b505050506040513d602081101561151157600080fd5b5051608083015260408051602081810183528682528251808201845260a086015181528351918201909352610100850151815261154e9290612b8f565b60c084018190528382600481111561156257fe5b600481111561156d57fe5b905250600090508251600481111561158157fe5b146115bd5760405162461bcd60e51b81526004018080602001828103825260288152602001806132e16028913960400191505060405180910390fd5b6115dd8260c0015160405180602001604052808560800151815250612be1565b60208401819052838260048111156115f157fe5b60048111156115fc57fe5b905250600090508251600481111561161057fe5b1461164c5760405162461bcd60e51b81526004018080602001828103825260288152602001806132e16028913960400191505060405180910390fd5b846001600160a01b031663b2bc5ef96040518163ffffffff1660e01b815260040160206040518083038186803b15801561168557600080fd5b505afa158015611699573d6000803e3d6000fd5b505050506040513d60208110156116af57600080fd5b505160608301819052600114611749576116d58260200151600001518360600151612c9a565b60408401819052838260048111156116e957fe5b60048111156116f457fe5b905250600090508251600481111561170857fe5b146117445760405162461bcd60e51b81526004018080602001828103825260288152602001806132e16028913960400191505060405180910390fd5b611755565b60208201515160408301525b50604001519392505050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff166117d3576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b60008311611828576040805162461bcd60e51b815260206004820152601860248201527f4552525f4c4f434b5f434f4c4c41544552414c5f5a45524f0000000000000000604482015290519081900360640190fd5b6001600160a01b03841660009081526001602081815260408084203385528252928390208351608081018552815481529281015491830182905260028101549383019390935260039092015460ff1615156060820152908411156118d3576040805162461bcd60e51b815260206004820181905260248201527f4552525f494e53554646494349454e545f465245455f434f4c4c41544552414c604482015290519081900360640190fd5b6000806118e4836040015187612b69565b909250905060008260048111156118f757fe5b14611949576040805162461bcd60e51b815260206004820152601e60248201527f4552525f4c4f434b5f434f4c4c41544552414c5f4d4154485f4552524f520000604482015290519081900360640190fd5b6001600160a01b03871660009081526001602090815260408083203384528252822060020183905584015161197e9088612aec565b9093509050600083600481111561199157fe5b1461199857fe5b6001600160a01b0388166000818152600160208181526040808420338086529083529381902090920185905581518b815291519293927f5dece52d6e464edb81a56c0ff16f6db48378690286920d6db39d387000064de69281900390910190a3506001979650505050505050565b600181565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0380831660009081526001602081815260408084209486168452938152838320845160808101865281548152928101549183019190915260028101549382019390935260039092015460ff16158015606084015290919080611a9e57508051155b15611aad576000915050610713565b6000611ab9858561295c565b600080546040805163351da44160e21b81526001600160a01b038a8116600483015291519495509293610100909204169163d4769104916024808301926020929190829003018186803b158015611b0f57600080fd5b505afa158015611b23573d6000803e3d6000fd5b505050506040513d6020811015611b3957600080fd5b505190911095945050505050565b6001600160a01b0382166000908152600160209081526040808320338452909152812060030154839060ff16611bb9576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b60005460ff16611c05576040805162461bcd60e51b815260206004820152601260248201527111549497d4915153951490539517d0d0531360721b604482015290519081900360640190fd5b6000805460ff1916905582611c61576040805162461bcd60e51b815260206004820152601b60248201527f4552525f4445504f5349545f434f4c4c41544552414c5f5a45524f0000000000604482015290519081900360640190fd5b600060019054906101000a90046001600160a01b03166001600160a01b031663ce8f6d3e856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015611cc357600080fd5b505afa158015611cd7573d6000803e3d6000fd5b505050506040513d6020811015611ced57600080fd5b5051611d2a5760405162461bcd60e51b81526004018080602001828103825260228152602001806131dd6022913960400191505060405180910390fd5b6001600160a01b0384166000908152600160208181526040808420338552909152822001548190611d5b9086612b69565b90925090506000826004811115611d6e57fe5b14611daa5760405162461bcd60e51b81526004018080602001828103825260218152602001806132576021913960400191505060405180910390fd5b6001600160a01b03861660008181526001602081815260408084203380865290835293819020909201859055815163d8dfeb4560e01b81529151611e4e9430938b93919263d8dfeb4592600480840193919291829003018186803b158015611e1157600080fd5b505afa158015611e25573d6000803e3d6000fd5b505050506040513d6020811015611e3b57600080fd5b50516001600160a01b0316929190612cc5565b60408051868152905133916001600160a01b038916917fef12f18e2b6578b91b3c852c423ca8ee530f65f20f770e62a7ce8aa08e1ab7779181900360200190a3600193505050506000805460ff1916600117905592915050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152206003015460ff1690565b6000336001600160a01b03851614611f225760405162461bcd60e51b81526004018080602001828103825260218152602001806133096021913960400191505060405180910390fd5b6001600160a01b0384811660008181526001602090815260408083209488168084529482529182902080549087905582518181529182018790528251909493927ff2d27c8f0e872c6ed429c5d25278ae6023ae9cc5f788a0fd39b66fb738f8f45c928290030190a360019150505b9392505050565b6001600160a01b039182166000908152600160208181526040808420949095168352929092529190912080549181015460028201546003909201549293909260ff1690565b6002546001600160a01b0316331461202b576040805162461bcd60e51b815260206004820152600d60248201526c22a9292fa727aa2fa0a226a4a760991b604482015290519081900360640190fd5b6002546040516000916001600160a01b0316907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80908390a3600280546001600160a01b0319169055565b600061207f613161565b6001600160a01b0380871660009081526001602090815260408083209389168352929052206003015460ff166120f1576040805162461bcd60e51b815260206004820152601260248201527122a9292fab20aaa62a2fa727aa2fa7a822a760711b604482015290519081900360640190fd5b83612100576000915050612954565b6000831161213f5760405162461bcd60e51b81526004018080602001828103825260368152602001806132216036913960400191505060405180910390fd5b60008060019054906101000a90046001600160a01b03166001600160a01b0316637dc0d1d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561218e57600080fd5b505afa1580156121a2573d6000803e3d6000fd5b505050506040513d60208110156121b857600080fd5b50516040805163d8dfeb4560e01b815290519192506001600160a01b038084169263f8d71a1192918b169163d8dfeb45916004808301926020929190829003018186803b15801561220857600080fd5b505afa15801561221c573d6000803e3d6000fd5b505050506040513d602081101561223257600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b15801561227657600080fd5b505afa15801561228a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156122b357600080fd5b8101908080516040519392919084600160201b8211156122d257600080fd5b9083019060208201858111156122e757600080fd5b8251600160201b81118282018810171561230057600080fd5b82525081516020918201929091019080838360005b8381101561232d578181015183820152602001612315565b50505050905090810190601f16801561235a5780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156123ad578181015183820152602001612395565b50505050905090810190601f1680156123da5780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b1580156123f757600080fd5b505afa15801561240b573d6000803e3d6000fd5b505050506040513d602081101561242157600080fd5b505160208381019190915260408051636f307dc360e01b815290516001600160a01b038085169363f8d71a1193918c1692636f307dc3926004808201939291829003018186803b15801561247457600080fd5b505afa158015612488573d6000803e3d6000fd5b505050506040513d602081101561249e57600080fd5b5051604080516395d89b4160e01b815290516001600160a01b03909216916395d89b4191600480820192600092909190829003018186803b1580156124e257600080fd5b505afa1580156124f6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561251f57600080fd5b8101908080516040519392919084600160201b82111561253e57600080fd5b90830190602082018581111561255357600080fd5b8251600160201b81118282018810171561256c57600080fd5b82525081516020918201929091019080838360005b83811015612599578181015183820152602001612581565b50505050905090810190601f1680156125c65780820380516001836020036101000a031916815260200191505b506040525050506040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612619578181015183820152602001612601565b50505050905090810190601f1680156126465780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b15801561266357600080fd5b505afa158015612677573d6000803e3d6000fd5b505050506040513d602081101561268d57600080fd5b50516101208301526040805163b2bc5ef960e01b815290516001600160a01b0389169163b2bc5ef9916004808301926020929190829003018186803b1580156126d557600080fd5b505afa1580156126e9573d6000803e3d6000fd5b505050506040513d60208110156126ff57600080fd5b5051604083018190526001146127915761271d858360400151612d25565b60e084018190528382600481111561273157fe5b600481111561273c57fe5b905250600090508251600481111561275057fe5b1461278c5760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b612799565b60e082018590525b604080516020808201835260e08501518252825180820190935284015182526127c191612d64565b60c08401819052838260048111156127d557fe5b60048111156127e057fe5b90525060009050825160048111156127f457fe5b146128305760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b61285b6040518060200160405280868152506040518060200160405280856101200151815250612d64565b608084018190528382600481111561286f57fe5b600481111561287a57fe5b905250600090508251600481111561288e57fe5b146128ca5760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b6128dc8260c001518360800151612be1565b60a08401819052838260048111156128f057fe5b60048111156128fb57fe5b905250600090508251600481111561290f57fe5b1461294b5760405162461bcd60e51b815260040180806020018281038252603781526020018061334b6037913960400191505060405180910390fd5b5060a001515190505b949350505050565b6001600160a01b038083166000908152600160208181526040808420948616845293815283832084516080810186528154808252938201549281019290925260028101549482018590526003015460ff161515606082015291926129549186918691612075565b6002546001600160a01b03163314612a12576040805162461bcd60e51b815260206004820152600d60248201526c22a9292fa727aa2fa0a226a4a760991b604482015290519081900360640190fd5b6001600160a01b038116612a6d576040805162461bcd60e51b815260206004820152601a60248201527f4552525f5345545f41444d494e5f5a45524f5f41444452455353000000000000604482015290519081900360640190fd5b6002546040516001600160a01b038084169216907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf8090600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b60005461010090046001600160a01b031681565b6002546001600160a01b031681565b600080838311612b03575060009050818303612b0b565b506003905060005b9250929050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612b64908490612e4e565b505050565b600080838301848110612b8157600092509050612b0b565b600260009250925050612b0b565b6000612b996131a8565b600080612ba68787612d64565b90925090506000826004811115612bb957fe5b14612bc8579092509050612bd9565b612bd28186612d64565b9350935050505b935093915050565b6000612beb6131a8565b600080612c048660000151670de0b6b3a7640000612d25565b90925090506000826004811115612c1757fe5b14612c3657506040805160208101909152600081529092509050612b0b565b600080612c47838860000151612c9a565b90925090506000826004811115612c5a57fe5b14612c7d5781604051806020016040528060008152509550955050505050612b0b565b604080516020810190915290815260009890975095505050505050565b60008082612cae5750600190506000612b0b565b6000838581612cb957fe5b04915091509250929050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612d1f908590612e4e565b50505050565b60008083612d3857506000905080612b0b565b83830283858281612d4557fe5b0414612d5957600260009250925050612b0b565b600092509050612b0b565b6000612d6e6131a8565b600080612d8386600001518660000151612d25565b90925090506000826004811115612d9657fe5b14612db557506040805160208101909152600081529092509050612b0b565b600080612dca6706f05b59d3b2000084612b69565b90925090506000826004811115612ddd57fe5b14612e005781604051806020016040528060008152509550955050505050612b0b565b600080612e1583670de0b6b3a7640000612c9a565b90925090506000826004811115612e2857fe5b14612e2f57fe5b604080516020810190915290815260009a909950975050505050505050565b6000612e9083836040518060400160405280601d81526020017f4552525f534146455f45524332305f4c4f575f4c4556454c5f43414c4c000000815250612f02565b805190915015612b6457808060200190516020811015612eaf57600080fd5b5051612b64576040805162461bcd60e51b815260206004820152601e60248201527f4552525f534146455f45524332305f45524332305f4f5045524154494f4e0000604482015290519081900360640190fd5b6060612f16846001600160a01b031661309e565b612f515760405162461bcd60e51b81526004018080602001828103825260238152602001806132be6023913960400191505060405180910390fd5b600080856001600160a01b0316856040518082805190602001908083835b60208310612f8e5780518252601f199092019160209182019101612f6f565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612ff0576040519150601f19603f3d011682016040523d82523d6000602084013e612ff5565b606091505b50915091508115613009579150611f909050565b8051156130195780518082602001fd5b8360405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561306357818101518382015260200161304b565b50505050905090810190601f1680156130905780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612954575050151592915050565b6040805160a081019091528060005b8152602001600081526020016000815260200160008152602001600081525090565b60408051610120810190915280600081526020016131246131a8565b81526020016000815260200160008152602001600081526020016000815260200161314d6131a8565b815260200160008152602001600081525090565b60408051610160810190915280600081526020016000815260200160008152602001600081526020016131926131a8565b815260200161319f6131a8565b81526020016130e65b604051806020016040528060008152509056fe4552525f42454c4f575f434f4c4c41544552414c495a4154494f4e5f524154494f4552525f4445504f5349545f434f4c4c41544552414c5f4e4f545f414c4c4f5745444552525f494e53554646494349454e545f4c4f434b45445f434f4c4c41544552414c4552525f4745545f4859504f544845544943414c5f434f4c4c41544552414c495a4154494f4e5f524154494f5f444542545f5a45524f4552525f4445504f5349545f434f4c4c41544552414c5f4d4154485f4552524f524552525f434c555443485f434f4c4c41544552414c5f4e4f545f415554484f52495a45444552525f4745545f434c5554434841424c455f434f4c4c41544552414c5f5a45524f4552525f534146455f45524332305f43414c4c5f544f5f4e4f4e5f434f4e54524143544552525f4745545f434c5554434841424c455f434f4c4c41544552414c5f4d4154485f4552524f524552525f5345545f5641554c545f444542545f4e4f545f415554484f52495a45444552525f4f50454e5f5641554c545f4659544f4b454e5f494e5350454354494f4e4552525f4745545f4859504f544845544943414c5f434f4c4c41544552414c495a4154494f4e5f524154494f5f4d4154485f4552524f52a2646970667358221220928357a59c778e5f8d069b600a19b817e5393c5184a7792ffe7f0903b50afcd064736f6c63430007060033

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

000000000000000000000000ed4348fc8b1b634b3a0eadabfd32530046b89c60

-----Decoded View---------------
Arg [0] : fintroller_ (address): 0xED4348fC8B1B634b3A0eadabFD32530046B89C60

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ed4348fc8b1b634b3a0eadabfd32530046b89c60


Deployed Bytecode Sourcemap

464:23318:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12730:1212;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;12730:1212:5;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;10557:230;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;10557:230:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;16543:1950;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;16543:1950:5;;;;;;;;:::i;20630:375::-;;;;;;;;;;;;;;;;-1:-1:-1;20630:375:5;-1:-1:-1;;;;;20630:375:5;;:::i;22578:1202::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;22578:1202:5;;;;;;;;:::i;2166:2418::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2166:2418:5;;;;;;;;:::i;19008:1238::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;19008:1238:5;;;;;;;;:::i;705:42:7:-;;;:::i;10184:170:5:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;10184:170:5;;;;;;;;;;:::i;11095:581::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;11095:581:5;;;;;;;;;;:::i;14538:1190::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;14538:1190:5;;;;;;;;:::i;11794:168::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;11794:168:5;;;;;;;;;;:::i;21500:566::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;21500:566:5;;;;;;;;;;;;;;;;;:::i;9553:491::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;9553:491:5;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1615:150:1;;;:::i;:::-;;6594:2787:5;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;6594:2787:5;;;;;;;;;;;;;;;;;;;;;;:::i;4908:342::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;4908:342:5;;;;;;;;;;:::i;1969:230:1:-;;;;;;;;;;;;;;;;-1:-1:-1;1969:230:1;-1:-1:-1;;;;;1969:230:1;;:::i;425:37:7:-;;;:::i;:::-;;;;-1:-1:-1;;;;;425:37:7;;;;;;;;;;;;;;182:20:3;;;:::i;12730:1212:5:-;12924:4;1817:10:21;;;;1809:41;;;;;-1:-1:-1;;;1809:41:21;;;;;;;;;;;;-1:-1:-1;;;1809:41:21;;;;;;;;;;;;;;;1942:5;1929:18;;-1:-1:-1;;1929:18:21;;;12997:10:5::1;-1:-1:-1::0;;;;;12997:30:5;::::1;;12989:79;;;;-1:-1:-1::0;;;12989:79:5::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;13180:24:5;;::::1;13153;13180::::0;;;:6:::1;:24;::::0;;;;;;;:34;;::::1;::::0;;;;;;:51:::1;;::::0;13249:36;;::::1;;13241:83;;;;-1:-1:-1::0;;;13241:83:5::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13393:17;13420:27:::0;13490:43:::1;13498:16;13516;13490:7;:43::i;:::-;13457:76:::0;;-1:-1:-1;13457:76:5;-1:-1:-1;13561:18:5::1;13550:7;:29;;;;;;;;;13543:37;;;;-1:-1:-1::0;;;;;13632:24:5;;::::1;;::::0;;;:6:::1;:24;::::0;;;;;;;:34;;::::1;::::0;;;;;;;;;:51:::1;;:73:::0;;;13769:20;;-1:-1:-1;;;13769:20:5;;;;:63:::1;::::0;13803:10;;13815:16;;13632:24;;13769:18:::1;::::0;:20:::1;::::0;;::::1;::::0;13632:24;13769:20;;;;;;13632:24;13769:20;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;13769:20:5;-1:-1:-1;;;;;13769:33:5::1;::::0;:63;:33:::1;:63::i;:::-;13886:8;-1:-1:-1::0;;;;;13848:65:5::1;13874:10;-1:-1:-1::0;;;;;13848:65:5::1;13865:7;-1:-1:-1::0;;;;;13848:65:5::1;;13896:16;13848:65;;;;;;;;;;;;;;;;;;13931:4;13924:11;;;;;2126:10:21::0;:17;;-1:-1:-1;;2126:17:21;2139:4;2126:17;;;12730:1212:5;;-1:-1:-1;;;;12730:1212:5:o;10557:230::-;-1:-1:-1;;;;;10729:24:5;;;10699:7;10729:24;;;:6;:24;;;;;;;;:34;;;;;;;;;:51;;;10557:230;;;;;:::o;16543:1950::-;-1:-1:-1;;;;;774:24:5;;16711:4;774:24;;;:6;:24;;;;;;;;799:10;774:36;;;;;;;:43;;;16685:7;;774:43;;766:74;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;;;;16731:35:::1;;:::i;:::-;16846:1;16827:16;:20;16819:57;;;::::0;;-1:-1:-1;;;16819:57:5;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;-1:-1:-1::0;;;;;16956:24:5;::::1;16935:18;16956:24:::0;;;:6:::1;:24;::::0;;;;;;;16981:10:::1;16956:36:::0;;;;;;;;16935:57;;::::1;::::0;::::1;::::0;;;;;;;;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;;;;::::1;;::::0;::::1;;;;::::0;;;;;17010:42;-1:-1:-1;17010:42:5::1;17002:89;;;;-1:-1:-1::0;;;17002:89:5::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17234:49;17242:5;:22;;;17266:16;17234:7;:49::i;:::-;17206:24;::::0;::::1;17191:92:::0;;;17192:4;17191:92;::::1;::::0;::::1;;;;;;;;;;;;;;::::0;;-1:-1:-1;17316:18:5::1;::::0;-1:-1:-1;17300:12:5;;:34:::1;::::0;::::1;;;;;;;17293:42;;;;17437:10:::0;;:14;17433:562:::1;;17517:174;17572:7;17597:10;17625:4;:24;;;17667:5;:10;;;17517:37;:174::i;:::-;17467:47;::::0;;::::1;:224:::0;;;;17743:10:::1;::::0;:49;;-1:-1:-1;;;17743:49:5;;-1:-1:-1;;;;;17743:49:5;;::::1;;::::0;::::1;::::0;;;:10:::1;::::0;;::::1;::::0;;::::1;::::0;:40:::1;::::0;:49;;;;;::::1;::::0;;;;;;;;:10;:49;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;17743:49:5;::::1;17705:35:::0;::::1;:87:::0;;;17831:47:::1;::::0;::::1;::::0;:86:::1;;17806:178;;;;-1:-1:-1::0;;;17806:178:5::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:24;::::0;::::1;::::0;-1:-1:-1;;;;;18044:24:5;::::1;;::::0;;;:6:::1;:24;::::0;;;;;;;18069:10:::1;18044:36:::0;;;;;;;:53:::1;;:80:::0;;;;18183:20;::::1;::::0;18175:47:::1;::::0;18205:16;18175:7:::1;:47::i;:::-;18149:22;::::0;::::1;18134:88:::0;;;18135:4;18134:88;::::1;::::0;::::1;;;;;;;;;;;;;;::::0;;-1:-1:-1;18256:18:5::1;::::0;-1:-1:-1;18240:12:5;;:34:::1;::::0;::::1;;;;;;;18232:77;;;::::0;;-1:-1:-1;;;18232:77:5;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;18373:22;::::0;::::1;::::0;-1:-1:-1;;;;;18319:24:5;::::1;;::::0;;;:6:::1;:24;::::0;;;;;;;18344:10:::1;18319:36:::0;;;;;;;;;;:51;;::::1;:76:::0;;;;18411:53;;;;;;;18344:10;;18411:53:::1;::::0;;;;;;;::::1;-1:-1:-1::0;18482:4:5::1;::::0;16543:1950;-1:-1:-1;;;;;16543:1950:5:o;20630:375::-;20702:4;20726:7;-1:-1:-1;;;;;20726:17:5;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;20726:19:5;20718:65;;;;-1:-1:-1;;;20718:65:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;20801:24:5;;;;;;:6;:24;;;;;;;;20826:10;20801:36;;;;;;;:43;;;;;:52;20793:79;;;;;-1:-1:-1;;;20793:79:5;;;;;;;;;;;;-1:-1:-1;;;20793:79:5;;;;;;;;;;;;;;;-1:-1:-1;;;;;20882:24:5;;;;;;20928:4;20882:24;;;;;;;;20907:10;20882:36;;;;;;;;:43;;:50;;-1:-1:-1;;20882:50:5;;;;;;;20947:30;;20907:10;;20882:24;20947:30;;;-1:-1:-1;20994:4:5;20630:375;;;:::o;22578:1202::-;-1:-1:-1;;;;;774:24:5;;22771:4;774:24;;;:6;:24;;;;;;;;799:10;774:36;;;;;;;:43;;;22724:7;;774:43;;766:74;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;;;;1817:10:21::1;::::0;::::1;;1809:41;;;::::0;;-1:-1:-1;;;1809:41:21;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;1809:41:21;;;;;;;;;;;;;::::1;;1942:5;1929:18:::0;;-1:-1:-1;;1929:18:21::1;::::0;;22841:20:5;22833:61:::2;;;::::0;;-1:-1:-1;;;22833:61:5;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;-1:-1:-1::0;;;;;22981:24:5;::::2;;::::0;;;:6:::2;:24;::::0;;;;;;;23006:10:::2;22981:36:::0;;;;;;;;:51:::2;::::0;:71;-1:-1:-1;22981:71:5::2;22960:150;;;::::0;;-1:-1:-1;;;22960:150:5;;::::2;;::::0;::::2;::::0;;;;;;;::::2;::::0;;;;;;;;;;;;;::::2;;-1:-1:-1::0;;;;;23261:24:5;::::2;23160:17;23261:24:::0;;;:6:::2;:24;::::0;;;;;;;23286:10:::2;23261:36:::0;;;;;;;:51:::2;::::0;23160:17;;23253:78:::2;::::0;23314:16;23253:7:::2;:78::i;:::-;23222:109:::0;;-1:-1:-1;23222:109:5;-1:-1:-1;23448:18:5::2;23437:7;:29;;;;;;;;;23430:37;;;;-1:-1:-1::0;;;;;23477:24:5;::::2;;::::0;;;:6:::2;:24;::::0;;;;;;;23502:10:::2;23477:36:::0;;;;;;;;;;:51;;::::2;:71:::0;;;23615:20;;-1:-1:-1;;;23615:20:5;;;;:63:::2;::::0;23661:16;;23477:24;;23615:18:::2;::::0;:20:::2;::::0;;::::2;::::0;;;;;;23477:24;23615:20;::::2;;::::0;::::2;;;;::::0;::::2;:63;23694:57;::::0;;;;;;;23722:10:::2;::::0;-1:-1:-1;;;;;23694:57:5;::::2;::::0;::::2;::::0;;;;::::2;::::0;;::::2;23769:4;23762:11;;;;-1:-1:-1::0;2126:10:21::1;:17:::0;;-1:-1:-1;;2126:17:21::1;2139:4;2126:17;::::0;;22578:1202:5;;-1:-1:-1;;22578:1202:5:o;2166:2418::-;2310:7;2333:44;;:::i;:::-;2451:1;2437:11;:15;2429:62;;;;-1:-1:-1;;;2429:62:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2630:10;;;;;;;;;-1:-1:-1;;;;;2630:10:5;-1:-1:-1;;;;;2630:39:5;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2630:41:5;2594:33;;;:77;;;2681;;2746:1;2739:8;;;;;2681:77;2829:33;2865:10;;;;;;;;;-1:-1:-1;;;;;2865:10:5;-1:-1:-1;;;;;2865:17:5;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2865:19:5;2949:20;;;-1:-1:-1;;;2949:20:5;;;;2865:19;;-1:-1:-1;;;;;;2925:23:5;;;;;;2949:18;;;;;;:20;;;;;2865:19;;2949:20;;;;;;;:18;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2949:20:5;:29;;;-1:-1:-1;;;2949:29:5;;;;-1:-1:-1;;;;;2949:27:5;;;;;;:29;;;;;;;;;;;;;;;:27;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2949:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2949:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2949:29:5;;;;;;-1:-1:-1;2949:29:5;;;;;;;;;;-1:-1:-1;2949:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2925:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2925:54:5;2894:28;;;:85;3106:20;;;-1:-1:-1;;;3106:20:5;;;;-1:-1:-1;;;;;3082:23:5;;;;;;3106:18;;;;;;:20;;;;;2925:54;;3106:20;;;;;;;;:18;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3106:20:5;:29;;;-1:-1:-1;;;3106:29:5;;;;-1:-1:-1;;;;;3106:27:5;;;;;;:29;;;;;;;;;;;;;;;:27;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3106:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;3106:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;3106:29:5;;;;;;-1:-1:-1;3106:29:5;;;;;;;;;;-1:-1:-1;3106:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3082:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3082:54:5;3051:28;;;:85;3255:30;;;3082:54;3255:30;;;;;;;;3299:52;;;;;;;3315:33;;;;3299:52;;3365:47;;;;;;;;3381:28;;;;3365:47;;3234:188;;3299:52;3234:7;:188::i;:::-;3216:14;;;3201:221;;;3202:4;3201:221;;;;;;;;;;;;;;;;;;;-1:-1:-1;3456:18:5;;-1:-1:-1;3440:12:5;;:34;;;;;;;;;3432:87;;;;-1:-1:-1;;;3432:87:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3665:105;3685:4;:14;;;3713:47;;;;;;;;3729:4;:28;;;3713:47;;;3665:6;:105::i;:::-;3622:39;;;3607:163;;;3608:4;3607:163;;;;;;;;;;;;;;;;;;;-1:-1:-1;3804:18:5;;-1:-1:-1;3788:12:5;;:34;;;;;;;;;3780:87;;;;-1:-1:-1;;;3780:87:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4019:7;-1:-1:-1;;;;;4019:33:5;;:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4019:35:5;3986:30;;;:68;;;4102:1;4068:35;4064:465;;4169:135;4194:4;:39;;;:48;;;4260:4;:30;;;4169:7;:135::i;:::-;4134:31;;;4119:185;;;4120:4;4119:185;;;;;;;;;;;;;;;;;;;-1:-1:-1;4342:18:5;;-1:-1:-1;4326:12:5;;:34;;;;;;;;;4318:87;;;;-1:-1:-1;;;4318:87:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4064:465;;;4470:39;;;;:48;4436:31;;;:82;4064:465;-1:-1:-1;4546:31:5;;;;2166:2418;-1:-1:-1;;;2166:2418:5:o;19008:1238::-;-1:-1:-1;;;;;774:24:5;;19176:4;774:24;;;:6;:24;;;;;;;;799:10;774:36;;;;;;;:43;;;19150:7;;774:43;;766:74;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;;;;19263:1:::1;19244:16;:20;19236:57;;;::::0;;-1:-1:-1;;;19236:57:5;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;-1:-1:-1::0;;;;;19325:24:5;::::1;19304:18;19325:24:::0;;;:6:::1;:24;::::0;;;;;;;19350:10:::1;19325:36:::0;;;;;;;;19304:57;;::::1;::::0;::::1;::::0;;;;;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;;;;;::::1;::::0;;::::1;::::0;::::1;;;;::::0;;;;;19379:40;-1:-1:-1;19379:40:5::1;19371:85;;;::::0;;-1:-1:-1;;;19371:85:5;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;;;;;::::1;;19467:17;19494:27:::0;19564:49:::1;19572:5;:22;;;19596:16;19564:7;:49::i;:::-;19531:82:::0;;-1:-1:-1;19531:82:5;-1:-1:-1;19642:18:5::1;19631:7;:29;;;;;;;;;19623:72;;;::::0;;-1:-1:-1;;;19623:72:5;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;-1:-1:-1::0;;;;;19705:24:5;::::1;;::::0;;;:6:::1;:24;::::0;;;;;;;19730:10:::1;19705:36:::0;;;;;;:53:::1;;:75:::0;;;19972:20;::::1;::::0;19964:47:::1;::::0;19994:16;19964:7:::1;:47::i;:::-;19924:87:::0;;-1:-1:-1;19924:87:5;-1:-1:-1;20039:18:5::1;20028:7;:29;;;;;;;;;20021:37;;;;-1:-1:-1::0;;;;;20068:24:5;::::1;;::::0;;;:6:::1;:24;::::0;;;;;;;20093:10:::1;20068:36:::0;;;;;;;;;;:51;;::::1;:80:::0;;;20164:53;;;;;;;20093:10;;20068:24;20164:53:::1;::::0;;;;;;;;::::1;-1:-1:-1::0;20235:4:5::1;::::0;19008:1238;-1:-1:-1;;;;;;;19008:1238:5:o;705:42:7:-;743:4;705:42;:::o;10184:170:5:-;-1:-1:-1;;;;;10308:24:5;;;10282:7;10308:24;;;:6;:24;;;;;;;;:34;;;;;;;;;;;:39;;10184:170::o;11095:581::-;-1:-1:-1;;;;;11237:24:5;;;11200:4;11237:24;;;:6;:24;;;;;;;;:34;;;;;;;;;;;11216:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11200:4;;11216:55;;11285:32;;-1:-1:-1;11302:10:5;;:15;11285:32;11281:75;;;11340:5;11333:12;;;;;11281:75;11365:45;11413:51;11446:7;11455:8;11413:32;:51::i;:::-;11474:47;11524:10;;:49;;;-1:-1:-1;;;11524:49:5;;-1:-1:-1;;;;;11524:49:5;;;;;;;;;11365:99;;-1:-1:-1;11474:47:5;;11524:10;;;;;;:40;;:49;;;;;;;;;;;;;;:10;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11524:49:5;11590:79;;;;11095:581;-1:-1:-1;;;;;11095:581:5:o;14538:1190::-;-1:-1:-1;;;;;774:24:5;;14730:4;774:24;;;:6;:24;;;;;;;;799:10;774:36;;;;;;;:43;;;14683:7;;774:43;;766:74;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;-1:-1:-1;;;766:74:5;;;;;;;;;;;;;;;1817:10:21::1;::::0;::::1;;1809:41;;;::::0;;-1:-1:-1;;;1809:41:21;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;1809:41:21;;;;;;;;;;;;;::::1;;1942:5;1929:18:::0;;-1:-1:-1;;1929:18:21::1;::::0;;14800:20:5;14792:60:::2;;;::::0;;-1:-1:-1;;;14792:60:5;;::::2;;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;;;;;;;;;;;;::::2;;14944:10;;;;;;;;;-1:-1:-1::0;;;;;14944:10:5::2;-1:-1:-1::0;;;;;14944:38:5::2;;14983:7;14944:47;;;;;;;;;;;;;-1:-1:-1::0;;;;;14944:47:5::2;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;::::0;::::2;;-1:-1:-1::0;14944:47:5;14936:94:::2;;;;-1:-1:-1::0;;;14936:94:5::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;15212:24:5;::::2;15080:17;15212:24:::0;;;:6:::2;:24;::::0;;;;;;;15237:10:::2;15212:36:::0;;;;;;;:51:::2;::::0;15080:17;;15191:112:::2;::::0;15277:16;15191:7:::2;:112::i;:::-;15151:152:::0;;-1:-1:-1;15151:152:5;-1:-1:-1;15332:18:5::2;15321:7;:29;;;;;;;;;15313:75;;;;-1:-1:-1::0;;;15313:75:5::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;15398:24:5;::::2;;::::0;;;:6:::2;:24;::::0;;;;;;;15423:10:::2;15398:36:::0;;;;;;;;;;:51;;::::2;:80:::0;;;15545:20;;-1:-1:-1;;;15545:20:5;;;;:82:::2;::::0;15603:4:::2;::::0;15610:16;;15398:24;;15545:18:::2;::::0;:20:::2;::::0;;::::2;::::0;15398:24;;15545:20;;;;;;15398:24;15545:20;::::2;;::::0;::::2;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;::::0;::::2;;-1:-1:-1::0;15545:20:5;-1:-1:-1;;;;;15545:37:5::2;::::0;:82;;:37:::2;:82::i;:::-;15643:56;::::0;;;;;;;15670:10:::2;::::0;-1:-1:-1;;;;;15643:56:5;::::2;::::0;::::2;::::0;;;;::::2;::::0;;::::2;15717:4;15710:11;;;;-1:-1:-1::0;2126:10:21::1;:17:::0;;-1:-1:-1;;2126:17:21::1;2139:4;2126:17;::::0;;14538:1190:5;;-1:-1:-1;;14538:1190:5:o;11794:168::-;-1:-1:-1;;;;;11914:24:5;;;11891:4;11914:24;;;:6;:24;;;;;;;;:34;;;;;;;;;;;:41;;;;;;11794:168::o;21500:566::-;21645:4;21718:10;-1:-1:-1;;;;;21718:30:5;;;21710:76;;;;-1:-1:-1;;;21710:76:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;21859:24:5;;;21836:20;21859:24;;;:6;:24;;;;;;;;:34;;;;;;;;;;;;;:39;;21908:54;;;;21978:59;;;;;;;;;;;;;21859:39;;:34;:24;21978:59;;;;;;;;22055:4;22048:11;;;21500:566;;;;;;:::o;9553:491::-;-1:-1:-1;;;;;9805:24:5;;;9692:7;9805:24;;;:6;:24;;;;;;;;:34;;;;;;;;;;;;;;:39;;9858:49;;;;9921:51;;;;9986:41;;;;;9805:39;;9858:49;;9986:41;;;9553:491::o;1615:150:1:-;931:5;;-1:-1:-1;;;;;931:5:1;940:10;931:19;923:45;;;;;-1:-1:-1;;;923:45:1;;;;;;;;;;;;-1:-1:-1;;;923:45:1;;;;;;;;;;;;;;;1706:5:::1;::::0;1692:35:::1;::::0;1721:4:::1;::::0;-1:-1:-1;;;;;1706:5:1::1;::::0;1692:35:::1;::::0;1721:4;;1692:35:::1;1737:5;:21:::0;;-1:-1:-1;;;;;;1737:21:1::1;::::0;;1615:150::o;6594:2787:5:-;6793:7;6812:52;;:::i;:::-;-1:-1:-1;;;;;6984:24:5;;;;;;;:6;:24;;;;;;;;:34;;;;;;;;;:41;;;;;6976:72;;;;;-1:-1:-1;;;6976:72:5;;;;;;;;;;;;-1:-1:-1;;;6976:72:5;;;;;;;;;;;;;;;7104:21;7100:60;;7148:1;7141:8;;;;;7100:60;7184:1;7177:4;:8;7169:75;;;;-1:-1:-1;;;7169:75:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7316:33;7352:10;;;;;;;;;-1:-1:-1;;;;;7352:10:5;-1:-1:-1;;;;;7352:17:5;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7352:19:5;7436:20;;;-1:-1:-1;;;7436:20:5;;;;7352:19;;-1:-1:-1;;;;;;7412:23:5;;;;;;7436:18;;;;;;:20;;;;;7352:19;;7436:20;;;;;;;:18;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7436:20:5;:29;;;-1:-1:-1;;;7436:29:5;;;;-1:-1:-1;;;;;7436:27:5;;;;;;:29;;;;;;;;;;;;;;;:27;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;7436:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;7436:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;7436:29:5;;;;;;-1:-1:-1;7436:29:5;;;;;;;;;;-1:-1:-1;7436:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7412:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7412:54:5;;7381:28;;;:85;;;;7593:20;;;-1:-1:-1;;;7593:20:5;;;;-1:-1:-1;;;;;7569:23:5;;;;;;7593:18;;;;;;:20;;;;;7412:54;7593:20;;;;;;:18;:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7593:20:5;:29;;;-1:-1:-1;;;7593:29:5;;;;-1:-1:-1;;;;;7593:27:5;;;;;;:29;;;;;;;;;;;;;;;:27;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;7593:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;7593:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;7593:29:5;;;;;;-1:-1:-1;7593:29:5;;;;;;;;;;-1:-1:-1;7593:29:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7569:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7569:54:5;7538:28;;;:85;7758:35;;;-1:-1:-1;;;7758:35:5;;;;-1:-1:-1;;;;;7758:33:5;;;;;:35;;;;;7569:54;;7758:35;;;;;;;:33;:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7758:35:5;7725:30;;;:68;;;7841:1;7807:35;7803:366;;7906:57;7914:16;7932:4;:30;;;7906:7;:57::i;:::-;7873:29;;;7858:105;;;7859:4;7858:105;;;;;;;;;;;;;;;;;;;-1:-1:-1;8001:18:5;;-1:-1:-1;7985:12:5;;:34;;;;;;;;;7977:102;;;;-1:-1:-1;;;7977:102:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7803:366;;;8110:29;;;:48;;;7803:366;8304:48;;;;;;;;;8320:29;;;;8304:48;;8366:47;;;;;;;;8382:28;;;8366:47;;8284:139;;:6;:139::i;:::-;8251:29;;;8236:187;;;8237:4;8236:187;;;;;;;;;;;;;;;;;;;-1:-1:-1;8457:18:5;;-1:-1:-1;8441:12:5;;:34;;;;;;;;;8433:102;;;;-1:-1:-1;;;8433:102:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8633:114;8653:23;;;;;;;;8669:4;8653:23;;;8690:47;;;;;;;;8706:4;:28;;;8690:47;;;8633:6;:114::i;:::-;8612:17;;;8597:150;;;8598:4;8597:150;;;;;;;;;;;;;;;;;;;-1:-1:-1;8781:18:5;;-1:-1:-1;8765:12:5;;:34;;;;;;;;;8757:102;;;;-1:-1:-1;;;8757:102:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9106:90;9126:4;:29;;;9169:4;:17;;;9106:6;:90::i;:::-;9063:39;;;9048:148;;;9049:4;9048:148;;;;;;;;;;;;;;;;;;;-1:-1:-1;9230:18:5;;-1:-1:-1;9214:12:5;;:34;;;;;;;;;9206:102;;;;-1:-1:-1;;;9206:102:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9326:39:5;;;:48;;-1:-1:-1;6594:2787:5;;;;;;;:::o;4908:342::-;-1:-1:-1;;;;;5100:24:5;;;5056:7;5100:24;;;:6;:24;;;;;;;;:34;;;;;;;;;;;5079:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5056:7;;5151:92;;5115:7;;5125:8;;5151:37;:92::i;1969:230:1:-;931:5;;-1:-1:-1;;;;;931:5:1;940:10;931:19;923:45;;;;;-1:-1:-1;;;923:45:1;;;;;;;;;;;;-1:-1:-1;;;923:45:1;;;;;;;;;;;;;;;-1:-1:-1;;;;;2065:25:1;::::1;2057:64;;;::::0;;-1:-1:-1;;;2057:64:1;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;2150:5;::::0;2136:30:::1;::::0;-1:-1:-1;;;;;2136:30:1;;::::1;::::0;2150:5:::1;::::0;2136:30:::1;::::0;2150:5:::1;::::0;2136:30:::1;2176:5;:16:::0;;-1:-1:-1;;;;;;2176:16:1::1;-1:-1:-1::0;;;;;2176:16:1;;;::::1;::::0;;;::::1;::::0;;1969:230::o;425:37:7:-;;;;;;-1:-1:-1;;;;;425:37:7;;:::o;182:20:3:-;;;-1:-1:-1;;;;;182:20:3;;:::o;2701:239:8:-;2763:9;2774:7;2802:1;2797;:6;2793:141;;-1:-1:-1;2827:18:8;;-1:-1:-1;2847:5:8;;;2819:34;;2793:141;-1:-1:-1;2892:27:8;;-1:-1:-1;2921:1:8;2793:141;2701:239;;;;;:::o;857:214:22:-;1004:59;;;-1:-1:-1;;;;;1004:59:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1004:59:22;-1:-1:-1;;;1004:59:22;;;978:86;;997:5;;978:18;:86::i;:::-;857:214;;;:::o;587:262:8:-;649:9;;691:5;;;711:6;;;707:136;;741:18;;-1:-1:-1;761:1:8;-1:-1:-1;733:30:8;;707:136;802:26;830:1;794:38;;;;;;;3089:308:13;3201:9;3212:10;;:::i;:::-;3235:13;3250;3267:12;3274:1;3277;3267:6;:12::i;:::-;3234:45;;-1:-1:-1;3234:45:13;-1:-1:-1;3300:18:13;3293:3;:25;;;;;;;;;3289:72;;3342:3;;-1:-1:-1;3347:2:13;-1:-1:-1;3334:16:13;;3289:72;3377:13;3384:2;3388:1;3377:6;:13::i;:::-;3370:20;;;;;;3089:308;;;;;;;:::o;1218:533::-;1285:9;1296:10;;:::i;:::-;1319:14;1335:23;1362:29;1370:1;:10;;;408:4:14;1362:7:13;:29::i;:::-;1318:73;;-1:-1:-1;1318:73:13;-1:-1:-1;1413:18:13;1405:4;:26;;;;;;;;;1401:92;;-1:-1:-1;1461:20:13;;;;;;;;;-1:-1:-1;1461:20:13;;1455:4;;-1:-1:-1;1461:20:13;-1:-1:-1;1447:35:13;;1401:92;1504:14;1520:16;1540:36;1548:15;1565:1;:10;;;1540:7;:36::i;:::-;1503:73;;-1:-1:-1;1503:73:13;-1:-1:-1;1598:18:13;1590:4;:26;;;;;;;;;1586:92;;1640:4;1646:20;;;;;;;;1662:1;1646:20;;;1632:35;;;;;;;;;;1586:92;1716:27;;;;;;;;;;;;-1:-1:-1;;1716:27:13;;-1:-1:-1;1218:533:13;-1:-1:-1;;;;;;1218:533:13:o;1328:218:8:-;1390:9;;1424:6;1420:75;;-1:-1:-1;1454:26:8;;-1:-1:-1;1482:1:8;1446:38;;1420:75;1513:18;1537:1;1533;:5;;;;;;1505:34;;;;1328:218;;;;;:::o;1077:250:22:-;1250:69;;;-1:-1:-1;;;;;1250:69:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1250:69:22;-1:-1:-1;;;1250:69:22;;;1224:96;;1243:5;;1224:18;:96::i;:::-;1077:250;;;;:::o;2223:343:8:-;2285:9;;2319:6;2315:67;;-1:-1:-1;2349:18:8;;-1:-1:-1;2349:18:8;2341:30;;2315:67;2404:5;;;2408:1;2404;:5;:1;2424:5;;;;;:10;2420:140;;2458:26;2486:1;2450:38;;;;;;;2420:140;2527:18;;-1:-1:-1;2547:1:8;-1:-1:-1;2519:30:8;;1843:1152:13;1910:9;1921:10;;:::i;:::-;1944:14;1960:27;1991:31;1999:1;:10;;;2011:1;:10;;;1991:7;:31::i;:::-;1943:79;;-1:-1:-1;1943:79:13;-1:-1:-1;2044:18:13;2036:4;:26;;;;;;;;;2032:92;;-1:-1:-1;2092:20:13;;;;;;;;;-1:-1:-1;2092:20:13;;2086:4;;-1:-1:-1;2092:20:13;-1:-1:-1;2078:35:13;;2032:92;2458:14;;2518:42;459:12:14;2540:19:13;2518:7;:42::i;:::-;2457:103;;-1:-1:-1;2457:103:13;-1:-1:-1;2582:18:13;2574:4;:26;;;;;;;;;2570:92;;2624:4;2630:20;;;;;;;;2646:1;2630:20;;;2616:35;;;;;;;;;;2570:92;2673:14;2689:15;2708:51;2716:32;408:4:14;2708:7:13;:51::i;:::-;2672:87;;-1:-1:-1;2672:87:13;-1:-1:-1;2903:18:13;2895:4;:26;;;;;;;;;2888:34;;;;2961:26;;;;;;;;;;;;-1:-1:-1;;2961:26:13;;-1:-1:-1;1843:1152:13;-1:-1:-1;;;;;;;;1843:1152:13:o;1750:702:22:-;2175:23;2201:67;2222:5;2230:4;2201:67;;;;;;;;;;;;;;;;;:12;:67::i;:::-;2282:17;;2175:93;;-1:-1:-1;2282:21:22;2278:168;;2381:10;2370:30;;;;;;;;;;;;;;;-1:-1:-1;2370:30:22;2362:73;;;;;-1:-1:-1;;;2362:73:22;;;;;;;;;;;;;;;;;;;;;;;;;;;2458:961;2590:12;2622:19;:6;-1:-1:-1;;;;;2622:17:22;;:19::i;:::-;2614:67;;;;-1:-1:-1;;;2614:67:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2755:12;2769:23;2796:6;-1:-1:-1;;;;;2796:11:22;2808:4;2796:17;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;2796:17:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2754:59;;;;2827:7;2823:590;;;2857:10;-1:-1:-1;2850:17:22;;-1:-1:-1;2850:17:22;2823:590;2971:17;;:21;2967:436;;3236:10;3230:17;3296:15;3283:10;3279:2;3275:19;3268:44;3185:145;3375:12;3368:20;;-1:-1:-1;;;3368:20:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;911:634:0;971:4;1448:20;;1278:66;1495:23;;;;;;:42;;-1:-1:-1;;1522:15:0;;;1487:51;-1:-1:-1;;911:634:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

ipfs://928357a59c778e5f8d069b600a19b817e5393c5184a7792ffe7f0903b50afcd0

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.