Address io13nxm5dwru0rvu5fmfjc93sw097d7ljdnegpjnl

Contract Overview

Balance:
0 IOTX

IOTX Value:
$ 0

Token:
Txn Hash
Block
From
To
Value [Txn Fee]
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FToken

Compiler Version
v0.6.4+commit.1dca32f3

Optimization Enabled:
Yes with 200 runs

Other Settings:
petersburg evmVersion, None license

Contract Source Code (Solidity)

pragma experimental ABIEncoderV2;
pragma solidity 0.6.4;


// SPDX-License-Identifier: MIT
interface IInterestRateModel {
    function utilizationRate(
        uint256 cash,
        uint256 borrows,
        uint256 reserves
    ) external pure returns (uint256);

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

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

    function APR(
        uint256 cash,
        uint256 borrows,
        uint256 reserves
    ) external view returns (uint256);

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

// SPDX-License-Identifier: MIT
interface IBankController {
    function getCashPrior(address underlying) external view returns (uint256);

    function getCashAfter(address underlying, uint256 msgValue)
        external
        view
        returns (uint256);

    function getFTokeAddress(address underlying)
        external
        view
        returns (address);

    function transferToUser(
        address token,
        address payable user,
        uint256 amount
    ) external;

    function transferIn(
        address account,
        address underlying,
        uint256 amount
    ) external payable;

    function borrowCheck(
        address account,
        address underlying,
        address fToken,
        uint256 borrowAmount
    ) external;

    function repayCheck(address underlying) external;

    function liquidateBorrowCheck(
        address fTokenBorrowed,
        address fTokenCollateral,
        address borrower,
        address liquidator,
        uint256 repayAmount
    ) external;

    function liquidateTokens(
        address fTokenBorrowed,
        address fTokenCollateral,
        uint256 actualRepayAmount
    ) external view returns (uint256);

    function withdrawCheck(
        address fToken,
        address withdrawer,
        uint256 withdrawTokens
    ) external view returns (uint256);

    function transferCheck(
        address fToken,
        address src,
        address dst,
        uint256 transferTokens
    ) external;

    function marketsContains(address fToken) external view returns (bool);

    function seizeCheck(address cTokenCollateral, address cTokenBorrowed)
        external;

    function mintCheck(address underlying, address minter, uint256 amount) external;

    function addReserves(address underlying, uint256 addAmount)
        external
        payable;

    function reduceReserves(
        address underlying,
        address payable account,
        uint256 reduceAmount
    ) external;

    function calcMaxBorrowAmount(address user, address token)
        external
        view
        returns (uint256);

    function calcMaxWithdrawAmount(address user, address token)
        external
        view
        returns (uint256);

    function calcMaxCashOutAmount(address user, address token)
        external
        view
        returns (uint256);

    function calcMaxBorrowAmountWithRatio(address user, address token)
        external
        view
        returns (uint256);

    function transferEthGasCost() external view returns (uint256);

    function isFTokenValid(address fToken) external view returns (bool);

    function balance(address token) external view returns (uint256);
    function flashloanFeeBips() external view returns (uint256);
    function flashloanVault() external view returns (address);
    function transferFlashloanAsset(
        address token,
        address payable user,
        uint256 amount
    ) external;
}

// SPDX-License-Identifier: MIT
/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

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

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

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

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

        return c;
    }

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

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

        return c;
    }

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

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

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

    function abs(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a < b) {
            return b - a;
        }
        return a - b;
    }
}

// SPDX-License-Identifier: MIT
contract Exponential {
    uint256 constant expScale = 1e18;
    uint256 constant doubleScale = 1e36;
    uint256 constant halfExpScale = expScale / 2;

    using SafeMath for uint256;

    function getExp(uint256 num, uint256 denom)
        public
        pure
        returns (uint256 rational)
    {
        rational = num.mul(expScale).div(denom);
    }

    function getDiv(uint256 num, uint256 denom)
        public
        pure
        returns (uint256 rational)
    {
        rational = num.mul(expScale).div(denom);
    }

    function addExp(uint256 a, uint256 b) public pure returns (uint256 result) {
        result = a.add(b);
    }

    function subExp(uint256 a, uint256 b) public pure returns (uint256 result) {
        result = a.sub(b);
    }

    function mulExp(uint256 a, uint256 b) public pure returns (uint256) {
        uint256 doubleScaledProduct = a.mul(b);

        uint256 doubleScaledProductWithHalfScale = halfExpScale.add(
            doubleScaledProduct
        );

        return doubleScaledProductWithHalfScale.div(expScale);
    }

    function divExp(uint256 a, uint256 b) public pure returns (uint256) {
        return getDiv(a, b);
    }

    function mulExp3(
        uint256 a,
        uint256 b,
        uint256 c
    ) public pure returns (uint256) {
        return mulExp(mulExp(a, b), c);
    }

    function mulScalar(uint256 a, uint256 scalar)
        public
        pure
        returns (uint256 scaled)
    {
        scaled = a.mul(scalar);
    }

    function mulScalarTruncate(uint256 a, uint256 scalar)
        public
        pure
        returns (uint256)
    {
        uint256 product = mulScalar(a, scalar);
        return truncate(product);
    }

    function mulScalarTruncateAddUInt(
        uint256 a,
        uint256 scalar,
        uint256 addend
    ) public pure returns (uint256) {
        uint256 product = mulScalar(a, scalar);
        return truncate(product).add(addend);
    }

    function divScalarByExpTruncate(uint256 scalar, uint256 divisor)
        public
        pure
        returns (uint256)
    {
        uint256 fraction = divScalarByExp(scalar, divisor);
        return truncate(fraction);
    }

    function divScalarByExp(uint256 scalar, uint256 divisor)
        public
        pure
        returns (uint256)
    {
        uint256 numerator = expScale.mul(scalar);
        return getExp(numerator, divisor);
    }

    function divScalar(uint256 a, uint256 scalar)
        public
        pure
        returns (uint256)
    {
        return a.div(scalar);
    }

    function truncate(uint256 exp) public pure returns (uint256) {
        return exp.div(expScale);
    }
}

// SPDX-License-Identifier: MIT
/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 weiValue,
        string memory errorMessage
    ) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
library EthAddressLib {
    /**
     * @dev returns the address used within the protocol to identify ETH
     * @return the address assigned to ETH
     */
    function ethAddress() internal pure returns (address) {
        return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    }
}

// SPDX-License-Identifier: MIT
interface IFToken is IERC20 {
    function mint(address user, uint256 amount) external returns (bytes memory);

    function borrow(address borrower, uint256 borrowAmount)
        external
        returns (bytes memory);

    function withdraw(
        address payable withdrawer,
        uint256 withdrawTokensIn,
        uint256 withdrawAmountIn
    ) external returns (uint256, bytes memory);

    function underlying() external view returns (address);

    function accrueInterest() external;

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

    function MonitorEventCallback(
        address who,
        bytes32 funcName,
        bytes calldata payload
    ) external;

    //用户存借取还操作后的兑换率
    function exchangeRateCurrent() external view returns (uint256 exchangeRate);

    function repay(address borrower, uint256 repayAmount)
        external
        returns (uint256, bytes memory);

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

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

    function liquidateBorrow(
        address liquidator,
        address borrower,
        uint256 repayAmount,
        address fTokenCollateral
    ) external returns (bytes memory);

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

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

    function _reduceReserves(uint256 reduceAmount) external;

    function _addReservesFresh(uint256 addAmount) external;

    function cancellingOut(address striker)
        external
        returns (bool strikeOk, bytes memory strikeLog);

    function APR() external view returns (uint256);

    function APY() external view returns (uint256);

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

    function borrowSafeRatio() external view returns (uint256);

    function tokenCash(address token, address account)
        external
        view
        returns (uint256);

    function getBorrowRate() external view returns (uint256);

    function addTotalCash(uint256 _addAmount) external;
    function subTotalCash(uint256 _subAmount) external;

    function totalCash() external view returns (uint256);
    function totalReserves() external view returns (uint256);
    function totalBorrows() external view returns (uint256);
}

// SPDX-License-Identifier: MIT
interface IBank {
    function MonitorEventCallback(bytes32 funcName, bytes calldata payload)
        external;

    function deposit(address token, uint256 amount) external payable;

    function borrow(address token, uint256 amount) external;

    function withdraw(address underlying, uint256 withdrawTokens) external;

    function withdrawUnderlying(address underlying, uint256 amount) external;

    function repay(address token, uint256 amount) external payable;

    function liquidateBorrow(
        address borrower,
        address underlyingBorrow,
        address underlyingCollateral,
        uint256 repayAmount
    ) external payable;

    function tokenIn(address token, uint256 amountIn) external payable;

    function tokenOut(address token, uint256 amountOut) external;

    function cancellingOut(address token) external;

    function paused() external view returns (bool);
}

/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

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

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool isTopLevelCall = !initializing;
    if (isTopLevelCall) {
      initializing = true;
      initialized = true;
    }

    _;

    if (isTopLevelCall) {
      initializing = false;
    }
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    address self = address(this);
    uint256 cs;
    assembly { cs := extcodesize(self) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}

// SPDX-License-Identifier: MIT
contract FToken is Exponential, Initializable {
    using SafeERC20 for IERC20;

    uint256 public totalSupply;

    string public name;

    string public symbol;

    uint8 public decimals;

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

    uint256 public initialExchangeRate;

    address public admin;

    uint256 public totalBorrows;

    uint256 public totalReserves;

    uint256 public reserveFactor;

    uint256 public borrowIndex;

    uint256 internal constant borrowRateMax = 0.0005e16;

    uint256 public accrualBlockNumber;

    IInterestRateModel public interestRateModel;

    // 该 fToken 所代表的原生代币
    address public underlying;

    mapping(address => uint256) public accountTokens;

    IBankController public controller;

    uint256 public borrowSafeRatio;

    address public bank; // bank主合约入口地址

    bool internal _notEntered;

    uint256 public constant ONE = 1e18;

    // 借款人账户
    struct BorrowSnapshot {
        uint256 principal;
        uint256 interestIndex;
    }

    mapping(address => BorrowSnapshot) public accountBorrows;
    uint256 public totalCash;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event NewInterestRateModel(address oldIRM, uint256 oldUR, uint256 oldAPR, uint256 oldAPY, uint256 exRate1,
        address newIRM, uint256 newUR, uint256 newAPR, uint256 newAPY, uint256 exRate2
    );
    event NewInitialExchangeRate(uint256 oldInitialExchangeRate, uint256 oldUR, uint256 oldAPR, uint256 oldAPY, uint256 exRate1,
        uint256 _initialExchangeRate, uint256 newUR, uint256 newAPR, uint256 newAPY, uint256 exRate2);

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

    function initialize(
        uint256 _initialExchangeRate,
        address _controller,
        address _initialInterestRateModel,
        address _underlying,
        address _bank,
        uint256 _borrowSafeRatio,
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) public initializer {
        initialExchangeRate = _initialExchangeRate;
        controller = IBankController(_controller);
        interestRateModel = IInterestRateModel(_initialInterestRateModel);
        admin = msg.sender;
        underlying = _underlying;
        borrowSafeRatio = _borrowSafeRatio;
        accrualBlockNumber = getBlockNumber();
        borrowIndex = ONE;
        bank = _bank;
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        _notEntered = true;
    }

    modifier onlyAdmin {
        require(msg.sender == admin, "require admin");
        _;
    }

    modifier onlyBank {
        require(msg.sender == bank, "require admin");
        _;
    }

    modifier onlyController {
        require(msg.sender == address(controller), "require controller");
        _;
    }

    modifier onlyRestricted {
        require(
            msg.sender == admin ||
                msg.sender == bank ||
                msg.sender == address(controller) ||
                controller.marketsContains(msg.sender),
            "only restricted user"
        );
        _;
    }

    modifier onlyBankComponent {
        require(
            msg.sender == bank ||
                msg.sender == address(controller) ||
                msg.sender == address(this) ||
                controller.marketsContains(msg.sender),
            "only bank component"
        );
        _;
    }

    modifier whenUnpaused {
        require(!IBank(bank).paused(), "System paused");
        _;
    }

    function _setController(address _controller) external onlyAdmin {
        controller = IBankController(_controller);
    }

    function tokenCash(address token, address account)
        public
        view
        returns (uint256)
    {
        return
            token != EthAddressLib.ethAddress()
                ? IERC20(token).balanceOf(account)
                : address(account).balance;
    }

    struct TransferLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 amount_transferred;
        uint256 account_balance;
        address payee_address;
        uint256 payee_balance;
        uint256 global_token_reserved;
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     */
    function transfer(address dst, uint256 amount)
        external
        nonReentrant
        returns (bool)
    {
        // spender - src - dst
        transferTokens(msg.sender, msg.sender, dst, amount);

        TransferLogStruct memory tls = TransferLogStruct(
            msg.sender,
            underlying,
            address(this),
            amount,
            balanceOf(msg.sender),
            dst,
            balanceOf(dst),
            tokenCash(underlying, address(controller))
        );

        IBank(bank).MonitorEventCallback("Transfer", abi.encode(tls));

        return true;
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     */
    function transferFrom(
        address src,
        address dst,
        uint256 amount
    ) external nonReentrant returns (bool) {
        // spender - src - dst
        transferTokens(msg.sender, src, dst, amount);

        TransferLogStruct memory tls = TransferLogStruct(
            src,
            underlying,
            address(this),
            amount,
            balanceOf(src),
            dst,
            balanceOf(dst),
            tokenCash(underlying, address(controller))
        );

        IBank(bank).MonitorEventCallback("TransferFrom", abi.encode(tls));

        return true;
    }

    // tokens -> 转账的 fToken 的数量
    function transferTokens(
        address spender,
        address src,
        address dst,
        uint256 tokens
    ) internal whenUnpaused returns (bool) {
        //accrueInterest();
        controller.transferCheck(address(this), src, dst, mulScalarTruncate(tokens, borrowSafeRatio));

        require(src != dst, "Cannot transfer to self");

        uint256 startingAllowance = 0;
        if (spender == src) {
            startingAllowance = uint256(-1);
        } else {
            startingAllowance = transferAllowances[src][spender];
        }

        uint256 allowanceNew = startingAllowance.sub(tokens);

        accountTokens[src] = accountTokens[src].sub(tokens);
        accountTokens[dst] = accountTokens[dst].add(tokens);

        if (startingAllowance != uint256(-1)) {
            transferAllowances[src][spender] = allowanceNew;
        }

        emit Transfer(src, dst, tokens);
        return true;
    }

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

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

    struct MintLocals {
        uint256 exchangeRate;
        uint256 mintTokens;
        uint256 totalSupplyNew;
        uint256 accountTokensNew;
        uint256 actualMintAmount;
    }

    struct DepositLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 amount_deposited;
        uint256 underlying_deposited;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 account_balance;
        uint256 global_token_reserved;
    }

    // 存款记账
    function mint(address user, uint256 amount)
        external
        onlyBank
        nonReentrant
        returns (bytes memory)
    {
        accrueInterest();
        return mintInternal(user, amount);
    }

    // 存款记账
    function mintInternal(address user, uint256 amount)
        internal
        returns (bytes memory)
    {
        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");
        MintLocals memory tmp;
        controller.mintCheck(underlying, user, amount);
        tmp.exchangeRate = exchangeRateStored();
        tmp.mintTokens = divScalarByExpTruncate(amount, tmp.exchangeRate);
        tmp.totalSupplyNew = addExp(totalSupply, tmp.mintTokens);
        tmp.accountTokensNew = addExp(accountTokens[user], tmp.mintTokens);
        totalSupply = tmp.totalSupplyNew;
        accountTokens[user] = tmp.accountTokensNew;

        uint256 preCalcTokenCash = tokenCash(underlying, address(controller))
            .add(amount);

        DepositLogStruct memory dls = DepositLogStruct(
            user,
            underlying,
            address(this),
            tmp.mintTokens,
            amount,
            exchangeRateAfter(amount), //cheque_token_value, 存之后的交换率(预判)
            interestRateModel.getBorrowRate(
                preCalcTokenCash,
                totalBorrows,
                totalReserves
            ), //loan_interest_rate 借款利率,存之后的价款利率
            tokenCash(address(this), user),
            preCalcTokenCash
        );

        emit Transfer(address(0), user, tmp.mintTokens);

        return abi.encode(dls);
    }

    struct BorrowLocals {
        uint256 accountBorrows;
        uint256 accountBorrowsNew;
        uint256 totalBorrowsNew;
    }

    struct BorrowLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 amount_borrowed;
        uint256 interest_accrued;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 account_debt;
        uint256 global_token_reserved;
    }

    // 用户借钱
    function borrow(address payable borrower, uint256 borrowAmount)
        external
        onlyBank
        nonReentrant
        returns (bytes memory)
    {
        accrueInterest();
        return borrowInternal(borrower, borrowAmount);
    }

    // 用户借钱
    function borrowInternal(address payable borrower, uint256 borrowAmount)
        internal
        returns (bytes memory)
    {
        controller.borrowCheck(
            borrower,
            underlying,
            address(this),
            mulScalarTruncate(borrowAmount, borrowSafeRatio)
        );

        require(
            controller.getCashPrior(underlying) >= borrowAmount,
            "Insufficient balance"
        );

        BorrowLocals memory tmp;
        uint256 lastPrincipal = accountBorrows[borrower].principal;
        tmp.accountBorrows = borrowBalanceStoredInternal(borrower);
        tmp.accountBorrowsNew = addExp(tmp.accountBorrows, borrowAmount);
        tmp.totalBorrowsNew = addExp(totalBorrows, borrowAmount);

        accountBorrows[borrower].principal = tmp.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = tmp.totalBorrowsNew;

        controller.transferToUser(underlying, borrower, borrowAmount);
        subTotalCash(borrowAmount);

        BorrowLogStruct memory bls = BorrowLogStruct(
            borrower,
            underlying,
            address(this),
            borrowAmount,
            SafeMath.abs(tmp.accountBorrows, lastPrincipal),
            exchangeRateStored(),
            getBorrowRate(),
            accountBorrows[borrower].principal,
            tokenCash(underlying, address(controller))
        );

        return abi.encode(bls);
    }

    struct RepayLocals {
        uint256 repayAmount;
        uint256 borrowerIndex;
        uint256 accountBorrows;
        uint256 accountBorrowsNew;
        uint256 totalBorrowsNew;
        uint256 actualRepayAmount;
    }

    // 计算兑换率
    function exchangeRateStored() public view returns (uint256 exchangeRate) {
        return calcExchangeRate(totalBorrows, totalReserves);
    }

    function calcExchangeRate(uint256 _totalBorrows, uint256 _totalReserves)
        public
        view
        returns (uint256 exchangeRate)
    {
        uint256 _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            return initialExchangeRate;
        } else {
            /*
             *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
             */
            uint256 totalCash = controller.getCashPrior(underlying);
            uint256 cashPlusBorrowsMinusReserves = subExp(
                addExp(totalCash, _totalBorrows),
                _totalReserves
            );
            exchangeRate = getDiv(cashPlusBorrowsMinusReserves, _totalSupply);
        }
    }

    // 计算兑换率(预判),在实际转账之前调用,只是用于发事件,用户后端审计
    function exchangeRateAfter(uint256 transferInAmout)
        public
        view
        returns (uint256 exchangeRate)
    {
        uint256 _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            // 如果市场是初始化状态,那么返回初始兑换率
            return initialExchangeRate;
        } else {
            /*
             *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
             */
            uint256 totalCash = controller.getCashAfter(
                underlying,
                transferInAmout
            );
            uint256 cashPlusBorrowsMinusReserves = subExp(
                addExp(totalCash, totalBorrows),
                totalReserves
            );
            exchangeRate = getDiv(cashPlusBorrowsMinusReserves, _totalSupply);
        }
    }

    function balanceOfUnderlying(address owner) external returns (uint256) {
        // 获取利率
        uint256 exchangeRate = exchangeRateCurrent();
        // 利率乘余额
        uint256 balance = mulScalarTruncate(exchangeRate, accountTokens[owner]);
        return balance;
    }

    function calcBalanceOfUnderlying(address owner)
        public
        view
        returns (uint256)
    {
        (, , uint256 _totalBorrows, uint256 _trotalReserves) = peekInterest();

        uint256 _exchangeRate = calcExchangeRate(
            _totalBorrows,
            _trotalReserves
        );
        // 利率乘余额
        uint256 balance = mulScalarTruncate(
            _exchangeRate,
            accountTokens[owner]
        );
        return balance;
    }

    function exchangeRateCurrent() public nonReentrant returns (uint256) {
        accrueInterest();
        return exchangeRateStored();
    }

    // 获取账户信息
    function getAccountState(address account)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        uint256 fTokenBalance = accountTokens[account];
        uint256 borrowBalance = borrowBalanceStoredInternal(account);
        uint256 exchangeRate = exchangeRateStored();

        return (fTokenBalance, borrowBalance, exchangeRate);
    }

    struct WithdrawLocals {
        uint256 exchangeRate;
        uint256 withdrawTokens;
        uint256 withdrawAmount;
        uint256 totalSupplyNew;
        uint256 accountTokensNew;
    }

    struct WithdrawLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 amount_withdrawed;
        uint256 underlying_withdrawed;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 account_balance;
        uint256 global_token_reserved;
    }

    // todo onlyController
    function withdraw(
        address payable withdrawer,
        uint256 withdrawTokensIn,
        uint256 withdrawAmountIn
    ) external onlyBank nonReentrant returns (uint256, bytes memory) {
        accrueInterest();
        return withdrawInternal(withdrawer, withdrawTokensIn, withdrawAmountIn);
    }

    function withdrawInternal(
        address payable withdrawer,
        uint256 withdrawTokensIn,
        uint256 withdrawAmountIn
    ) internal returns (uint256, bytes memory) {
        // 一个是想要兑换 cTokens 的数量,一个是想要兑换 asset 的数量,必须有一个是 0
        require(
            withdrawTokensIn == 0 || withdrawAmountIn == 0,
            "withdraw parameter not valid"
        );
        WithdrawLocals memory tmp;

        tmp.exchangeRate = exchangeRateStored();

        if (withdrawTokensIn > 0) {
            tmp.withdrawTokens = withdrawTokensIn;
            tmp.withdrawAmount = mulScalarTruncate(
                tmp.exchangeRate,
                withdrawTokensIn
            );
        } else {
            tmp.withdrawTokens = divScalarByExpTruncate(
                withdrawAmountIn,
                tmp.exchangeRate
            );
            tmp.withdrawAmount = withdrawAmountIn;
        }

        controller.withdrawCheck(address(this), withdrawer, tmp.withdrawTokens);

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");

        tmp.totalSupplyNew = totalSupply.sub(tmp.withdrawTokens);
        tmp.accountTokensNew = accountTokens[withdrawer].sub(
            tmp.withdrawTokens
        );

        require(
            controller.getCashPrior(underlying) >= tmp.withdrawAmount,
            "Insufficient money"
        );

        controller.transferToUser(underlying, withdrawer, tmp.withdrawAmount);
        subTotalCash(tmp.withdrawAmount);

        totalSupply = tmp.totalSupplyNew;
        accountTokens[withdrawer] = tmp.accountTokensNew;

        WithdrawLogStruct memory wls = WithdrawLogStruct(
            withdrawer,
            underlying,
            address(this),
            tmp.withdrawTokens,
            tmp.withdrawAmount,
            exchangeRateStored(),
            getBorrowRate(),
            tokenCash(address(this), withdrawer),
            tokenCash(underlying, address(controller))
        );

        emit Transfer(withdrawer, address(0), tmp.withdrawTokens);

        return (tmp.withdrawAmount, abi.encode(wls));
    }

    function strikeWithdrawInternal(
        address withdrawer,
        uint256 withdrawTokensIn,
        uint256 withdrawAmountIn
    ) internal returns (uint256, bytes memory) {
        // 一个是想要兑换 cTokens 的数量,一个是想要兑换 asset 的数量,必须有一个是 0
        require(
            withdrawTokensIn == 0 || withdrawAmountIn == 0,
            "withdraw parameter not valid"
        );
        WithdrawLocals memory tmp;

        tmp.exchangeRate = exchangeRateStored();

        if (withdrawTokensIn > 0) {
            tmp.withdrawTokens = withdrawTokensIn;
            tmp.withdrawAmount = mulScalarTruncate(
                tmp.exchangeRate,
                withdrawTokensIn
            );
        } else {
            tmp.withdrawTokens = divScalarByExpTruncate(
                withdrawAmountIn,
                tmp.exchangeRate
            );
            tmp.withdrawAmount = withdrawAmountIn;
        }

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");

        tmp.totalSupplyNew = totalSupply.sub(tmp.withdrawTokens);
        tmp.accountTokensNew = accountTokens[withdrawer].sub(
            tmp.withdrawTokens
        );

        totalSupply = tmp.totalSupplyNew;
        accountTokens[withdrawer] = tmp.accountTokensNew;

        uint256 preCalcTokenCash = tokenCash(underlying, address(controller))
            .add(tmp.withdrawAmount);

        WithdrawLogStruct memory wls = WithdrawLogStruct(
            withdrawer,
            underlying,
            address(this),
            tmp.withdrawTokens,
            tmp.withdrawAmount,
            exchangeRateStored(),
            interestRateModel.getBorrowRate(
                preCalcTokenCash,
                totalBorrows,
                totalReserves
            ),
            tokenCash(address(this), withdrawer),
            preCalcTokenCash
        );

        emit Transfer(withdrawer, address(0), tmp.withdrawTokens);

        return (tmp.withdrawAmount, abi.encode(wls));
    }

    // 更新利息
    function accrueInterest() public onlyRestricted {
        uint256 currentBlockNumber = getBlockNumber();
        uint256 accrualBlockNumberPrior = accrualBlockNumber;

        // 太短 零利息
        if (accrualBlockNumberPrior == currentBlockNumber) {
            return;
        }

        uint256 cashPrior = controller.getCashPrior(underlying);
        uint256 borrowsPrior = totalBorrows;
        uint256 reservesPrior = totalReserves;
        uint256 borrowIndexPrior = borrowIndex;

        // // 计算借贷利率
        uint256 borrowRate = interestRateModel.getBorrowRate(
            cashPrior,
            borrowsPrior,
            reservesPrior
        );
        // // 不能超过最大利率
        require(borrowRate <= borrowRateMax, "borrow rate is too high");

        // // 计算块差
        uint256 blockDelta = currentBlockNumber.sub(accrualBlockNumberPrior);

        /*
         *  simpleInterestFactor = borrowRate * blockDelta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  totalBorrowsNew = interestAccumulated + totalBorrows
         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves
         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
         */

        uint256 simpleInterestFactor;
        uint256 interestAccumulated;
        uint256 totalBorrowsNew;
        uint256 totalReservesNew;
        uint256 borrowIndexNew;

        simpleInterestFactor = mulScalar(borrowRate, blockDelta);

        interestAccumulated = divExp(
            mulExp(simpleInterestFactor, borrowsPrior),
            expScale
        );

        totalBorrowsNew = addExp(interestAccumulated, borrowsPrior);

        totalReservesNew = addExp(
            divExp(mulExp(reserveFactor, interestAccumulated), expScale),
            reservesPrior
        );

        borrowIndexNew = addExp(
            divExp(mulExp(simpleInterestFactor, borrowIndexPrior), expScale),
            borrowIndexPrior
        );

        accrualBlockNumber = currentBlockNumber;
        borrowIndex = borrowIndexNew;
        totalBorrows = totalBorrowsNew;
        totalReserves = totalReservesNew;

        borrowRate = interestRateModel.getBorrowRate(
            cashPrior,
            totalBorrows,
            totalReserves
        );
        // 不能超过最大利率
        require(borrowRate <= borrowRateMax, "borrow rate is too high");
    }

    function peekInterest()
        public
        view
        returns (
            uint256 _accrualBlockNumber,
            uint256 _borrowIndex,
            uint256 _totalBorrows,
            uint256 _totalReserves
        )
    {
        _accrualBlockNumber = getBlockNumber();
        uint256 accrualBlockNumberPrior = accrualBlockNumber;

        // 太短 零利息
        if (accrualBlockNumberPrior == _accrualBlockNumber) {
            return (
                accrualBlockNumber,
                borrowIndex,
                totalBorrows,
                totalReserves
            );
        }

        uint256 cashPrior = controller.getCashPrior(underlying);
        uint256 borrowsPrior = totalBorrows;
        uint256 reservesPrior = totalReserves;
        uint256 borrowIndexPrior = borrowIndex;

        // // 计算借贷利率
        uint256 borrowRate = interestRateModel.getBorrowRate(
            cashPrior,
            borrowsPrior,
            reservesPrior
        );
        // // 不能超过最大利率
        require(borrowRate <= borrowRateMax, "borrow rate is too high");

        // // 计算块差
        uint256 blockDelta = _accrualBlockNumber.sub(accrualBlockNumberPrior);

        /*
         *  simpleInterestFactor = borrowRate * blockDelta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  totalBorrowsNew = interestAccumulated + totalBorrows
         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves
         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
         */

        uint256 simpleInterestFactor;
        uint256 interestAccumulated;
        uint256 totalBorrowsNew;
        uint256 totalReservesNew;
        uint256 borrowIndexNew;

        simpleInterestFactor = mulScalar(borrowRate, blockDelta);

        interestAccumulated = divExp(
            mulExp(simpleInterestFactor, borrowsPrior),
            expScale
        );

        totalBorrowsNew = addExp(interestAccumulated, borrowsPrior);

        totalReservesNew = addExp(
            divExp(mulExp(reserveFactor, interestAccumulated), expScale),
            reservesPrior
        );

        borrowIndexNew = addExp(
            divExp(mulExp(simpleInterestFactor, borrowIndexPrior), expScale),
            borrowIndexPrior
        );

        _borrowIndex = borrowIndexNew;
        _totalBorrows = totalBorrowsNew;
        _totalReserves = totalReservesNew;

        borrowRate = interestRateModel.getBorrowRate(
            cashPrior,
            totalBorrows,
            totalReserves
        );
        // 不能超过最大利率
        require(borrowRate <= borrowRateMax, "borrow rate is too high");
    }

    function borrowBalanceCurrent(address account)
        external
        nonReentrant
        returns (uint256)
    {
        accrueInterest();
        BorrowSnapshot memory borrowSnapshot = accountBorrows[account];
        require(borrowSnapshot.interestIndex <= borrowIndex, "borrowIndex error");

        return borrowBalanceStoredInternal(account);
    }

    function borrowBalanceStoredInternal(address user)
        internal
        view
        returns (uint256 result)
    {
        // 借贷数量
        BorrowSnapshot memory borrowSnapshot = accountBorrows[user];

        if (borrowSnapshot.principal == 0) {
            return 0;
        }

        result = mulExp(borrowSnapshot.principal, divExp(borrowIndex, borrowSnapshot.interestIndex));
    }

    function _setReserveFactorFresh(uint256 newReserveFactor)
        external
        onlyAdmin
        nonReentrant
    {
        accrueInterest();
        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");
        reserveFactor = newReserveFactor;
    }

    struct ReserveDepositLogStruct {
        address token_address;
        uint256 reserve_funded;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 global_token_reserved;
    }

    function _setInterestRateModel(IInterestRateModel newInterestRateModel)
        public
        onlyAdmin
    {
        address oldIRM = address(interestRateModel);
        uint256 oldUR = utilizationRate();
        uint256 oldAPR = APR();
        uint256 oldAPY = APY();

        uint256 exRate1 = exchangeRateStored();     
        accrueInterest();
        uint256 exRate2 = exchangeRateStored();

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");

        interestRateModel = newInterestRateModel;
        uint256 newUR = utilizationRate();
        uint256 newAPR = APR();
        uint256 newAPY = APY();

        emit NewInterestRateModel(oldIRM, oldUR, oldAPR, oldAPY, exRate1, address(newInterestRateModel), newUR, newAPR, newAPY, exRate2);

        ReserveDepositLogStruct memory rds = ReserveDepositLogStruct(
            underlying,
            0,
            exchangeRateStored(),
            getBorrowRate(),
            tokenCash(underlying, address(controller))
        );

        IBank(bank).MonitorEventCallback(
            "ReserveDeposit",
            abi.encode(rds)
        );
    }

    function _setInitialExchangeRate(uint256 _initialExchangeRate) external onlyAdmin {
        uint256 oldInitialExchangeRate = initialExchangeRate;

        uint256 oldUR = utilizationRate();
        uint256 oldAPR = APR();
        uint256 oldAPY = APY();

        uint256 exRate1 = exchangeRateStored();
        accrueInterest();
        uint256 exRate2 = exchangeRateStored();

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");

        initialExchangeRate = _initialExchangeRate;
        uint256 newUR = utilizationRate();
        uint256 newAPR = APR();
        uint256 newAPY = APY();

        emit NewInitialExchangeRate(oldInitialExchangeRate, oldUR, oldAPR, oldAPY, exRate1, initialExchangeRate, newUR, newAPR, newAPY, exRate2);

        ReserveDepositLogStruct memory rds = ReserveDepositLogStruct(
            underlying,
            0,
            exchangeRateStored(),
            getBorrowRate(),
            tokenCash(underlying, address(controller))
        );

        IBank(bank).MonitorEventCallback(
            "ReserveDeposit",
            abi.encode(rds)
        );
    }

    function getBlockNumber() internal view returns (uint256) {
        return block.number;
    }

    function repay(address borrower, uint256 repayAmount)
        external
        onlyBank
        nonReentrant
        returns (uint256, bytes memory)
    {
        accrueInterest();
        return repayInternal(borrower, repayAmount);
    }

    struct RepayLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 amount_repayed;
        uint256 interest_accrued;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 account_debt;
        uint256 global_token_reserved;
    }

    function repayInternal(address borrower, uint256 repayAmount)
        internal
        returns (uint256, bytes memory)
    {
        controller.repayCheck(underlying);
        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");

        RepayLocals memory tmp;
        uint256 lastPrincipal = accountBorrows[borrower].principal;
        tmp.borrowerIndex = accountBorrows[borrower].interestIndex;
        tmp.accountBorrows = borrowBalanceStoredInternal(borrower);

        // -1 表示还最大
        if (repayAmount == uint256(-1)) {
            tmp.repayAmount = tmp.accountBorrows;
        } else {
            tmp.repayAmount = repayAmount;
        }

        tmp.accountBorrowsNew = tmp.accountBorrows.sub(tmp.repayAmount);
        if (totalBorrows < tmp.repayAmount) {
            tmp.totalBorrowsNew = 0;
        } else {
            tmp.totalBorrowsNew = totalBorrows.sub(tmp.repayAmount);
        }

        accountBorrows[borrower].principal = tmp.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = tmp.totalBorrowsNew;

        uint256 preCalcTokenCash = tokenCash(underlying, address(controller))
            .add(tmp.repayAmount);

        RepayLogStruct memory rls = RepayLogStruct(
            borrower,
            underlying,
            address(this),
            tmp.repayAmount,
            SafeMath.abs(tmp.accountBorrows, lastPrincipal),
            exchangeRateAfter(tmp.repayAmount), //repay之后的交换率
            interestRateModel.getBorrowRate(
                preCalcTokenCash,
                totalBorrows,
                totalReserves
            ), //repay之后的借款利率
            accountBorrows[borrower].principal,
            preCalcTokenCash
        );

        return (tmp.repayAmount, abi.encode(rls));
    }

    function borrowBalanceStored(address account)
        external
        view
        returns (uint256)
    {
        return borrowBalanceStoredInternal(account);
    }

    struct LiquidateBorrowLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 debt_written_off;
        uint256 interest_accrued;
        address debtor_address;
        uint256 collateral_purchased;
        address collateral_cheque_token_address;
        uint256 debtor_balance;
        uint256 debt_remaining;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 account_balance;
        uint256 global_token_reserved;
    }

    function liquidateBorrow(
        address liquidator,
        address borrower,
        uint256 repayAmount,
        FToken fTokenCollateral
    ) public onlyBank nonReentrant returns (bytes memory) {
        require(
            controller.isFTokenValid(address(this)) &&
                controller.isFTokenValid(address(fTokenCollateral)),
            "Market not listed"
        );
        accrueInterest();
        fTokenCollateral.accrueInterest();
        uint256 lastPrincipal = accountBorrows[borrower].principal;
        uint256 newPrincipal = borrowBalanceStoredInternal(borrower);

        controller.liquidateBorrowCheck(
            address(this),
            address(fTokenCollateral),
            borrower,
            liquidator,
            repayAmount
        );

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");
        require(
            fTokenCollateral.accrualBlockNumber() == getBlockNumber(),
            "Blocknumber fails"
        );

        // 还钱
        (uint256 actualRepayAmount, ) = repayInternal(borrower, repayAmount);

        // 计算清算的质押物数量(fToken数量)
        uint256 seizeTokens = controller.liquidateTokens(
            address(this),
            address(fTokenCollateral),
            actualRepayAmount
        );

        // 借款人得要有这么多余额才行
        require(
            fTokenCollateral.balanceOf(borrower) >= seizeTokens,
            "Seize too much"
        );

        if (address(fTokenCollateral) == address(this)) {
            seizeInternal(address(this), liquidator, borrower, seizeTokens);
        } else {
            fTokenCollateral.seize(liquidator, borrower, seizeTokens);
        }

        uint256 preCalcTokenCash = tokenCash(underlying, address(controller))
            .add(actualRepayAmount);

        LiquidateBorrowLogStruct memory lbls = LiquidateBorrowLogStruct(
            liquidator,
            underlying,
            address(this),
            actualRepayAmount,
            SafeMath.abs(newPrincipal, lastPrincipal),
            borrower,
            seizeTokens,
            address(fTokenCollateral),
            tokenCash(address(fTokenCollateral), borrower),
            accountBorrows[borrower].principal, //debt_remaining
            exchangeRateAfter(actualRepayAmount),
            interestRateModel.getBorrowRate(
                preCalcTokenCash,
                totalBorrows,
                totalReserves
            ),
            tokenCash(address(fTokenCollateral), liquidator),
            preCalcTokenCash
        );

        return abi.encode(lbls);
    }

    function seize(
        address liquidator,
        address borrower,
        uint256 seizeTokens
    ) external nonReentrant {
        return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
    }

    struct CallingOutLogStruct {
        address user_address;
        address token_address;
        address cheque_token_address;
        uint256 amount_wiped_out;
        uint256 debt_cancelled_out;
        uint256 interest_accrued;
        uint256 cheque_token_value;
        uint256 loan_interest_rate;
        uint256 account_balance;
        uint256 account_debt;
        uint256 global_token_reserved;
    }

    //冲账处理
    function cancellingOut(address striker)
        public
        onlyBank
        nonReentrant
        returns (bool strikeOk, bytes memory strikeLog)
    {
        // 需要冲账时,计算利息
        if (
            borrowBalanceStoredInternal(striker) > 0 && balanceOf(striker) > 0
        ) {
            accrueInterest();
            uint256 lastPrincipal = accountBorrows[striker].principal;
            uint256 curBorrowBalance = borrowBalanceStoredInternal(striker);
            uint256 userSupplyBalance = calcBalanceOfUnderlying(striker);
            uint256 lastFtokenBalance = balanceOf(striker);
            uint256 actualRepayAmount;
            bytes memory repayLog;
            uint256 withdrawAmount;
            bytes memory withdrawLog;
            // 有借款和存款(fToken)
            if (curBorrowBalance > 0 && userSupplyBalance > 0) {
                //无实际转账的赎回(冲账赎回)
                if (userSupplyBalance > curBorrowBalance) {
                    (withdrawAmount, withdrawLog) = strikeWithdrawInternal(
                        striker,
                        0,
                        curBorrowBalance
                    );
                } else {
                    (withdrawAmount, withdrawLog) = strikeWithdrawInternal(
                        striker,
                        balanceOf(striker),
                        0
                    );
                }

                (actualRepayAmount, repayLog) = repayInternal(
                    striker,
                    withdrawAmount
                );

                CallingOutLogStruct memory cols;

                cols.user_address = striker;
                cols.token_address = underlying;
                cols.cheque_token_address = address(this);
                cols.amount_wiped_out = SafeMath.abs(
                    lastFtokenBalance,
                    balanceOf(striker)
                );
                cols.debt_cancelled_out = actualRepayAmount;
                cols.interest_accrued = SafeMath.abs(
                    curBorrowBalance,
                    lastPrincipal
                );
                cols.cheque_token_value = exchangeRateStored();
                cols.loan_interest_rate = interestRateModel.getBorrowRate(
                    tokenCash(underlying, address(controller)),
                    totalBorrows,
                    totalReserves
                );
                cols.account_balance = tokenCash(address(this), striker);
                cols.account_debt = accountBorrows[striker].principal;
                cols.global_token_reserved = tokenCash(
                    underlying,
                    address(controller)
                );

                strikeLog = abi.encode(cols);

                strikeOk = true;
            }
        }
    }

    function balanceOf(address owner) public view returns (uint256) {
        return accountTokens[owner];
    }

    function _setBorrowSafeRatio(uint256 _borrowSafeRatio) public onlyAdmin {
        borrowSafeRatio = _borrowSafeRatio;
    }

    function seizeInternal(
        address seizerToken,
        address liquidator,
        address borrower,
        uint256 seizeTokens
    ) internal {
        require(borrower != liquidator, "Liquidator cannot be borrower");
        controller.seizeCheck(address(this), seizerToken);

        accountTokens[borrower] = accountTokens[borrower].sub(seizeTokens);
        accountTokens[liquidator] = accountTokens[liquidator].add(seizeTokens);

        emit Transfer(borrower, liquidator, seizeTokens);
    }

    // onlyController
    function _reduceReserves(uint256 reduceAmount) external onlyController {
        accrueInterest();

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");
        require(
            controller.getCashPrior(underlying) >= reduceAmount,
            "Insufficient cash"
        );
        require(totalReserves >= reduceAmount, "Insufficient reserves");

        totalReserves = SafeMath.sub(
            totalReserves,
            reduceAmount,
            "reduce reserves underflow"
        );
    }

    function _addReservesFresh(uint256 addAmount) external onlyController {
        accrueInterest();

        require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails");
        totalReserves = SafeMath.add(totalReserves, addAmount);
    }

    function addTotalCash(uint256 _addAmount) public onlyBankComponent {
        totalCash = totalCash.add(_addAmount);
    }

    function subTotalCash(uint256 _subAmount) public onlyBankComponent {
        totalCash = totalCash.sub(_subAmount);
    }

    modifier nonReentrant() {
        require(_notEntered, "re-entered");
        _notEntered = false;
        _;
        _notEntered = true;
    }

    // 借款年利率
    function APR() public view returns (uint256) {
        uint256 cash = tokenCash(underlying, address(controller));
        return interestRateModel.APR(cash, totalBorrows, totalReserves);
    }

    // 存款年利率
    function APY() public view returns (uint256) {
        uint256 cash = tokenCash(underlying, address(controller));
        return
            interestRateModel.APY(
                cash,
                totalBorrows,
                totalReserves,
                reserveFactor
            );
    }

    function utilizationRate() public view returns (uint256) {
        uint256 cash = tokenCash(underlying, address(controller));
        return interestRateModel.utilizationRate(cash, totalBorrows, totalReserves);
    }

    // 借款年利率
    function getBorrowRate() public view returns (uint256) {
        uint256 cash = tokenCash(underlying, address(controller));
        return
            interestRateModel.getBorrowRate(cash, totalBorrows, totalReserves);
    }

    // 存款年利率
    function getSupplyRate() public view returns (uint256) {
        uint256 cash = tokenCash(underlying, address(controller));
        return
            interestRateModel.getSupplyRate(
                cash,
                totalBorrows,
                totalReserves,
                reserveFactor
            );
    }
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldInitialExchangeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate2","type":"uint256"}],"name":"NewInitialExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldIRM","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate1","type":"uint256"},{"indexed":false,"internalType":"address","name":"newIRM","type":"address"},{"indexed":false,"internalType":"uint256","name":"newUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate2","type":"uint256"}],"name":"NewInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"APR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"APY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"_addReservesFresh","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowSafeRatio","type":"uint256"}],"name":"_setBorrowSafeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"_setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"}],"name":"_setInitialExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IInterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactor","type":"uint256"}],"name":"_setReserveFactorFresh","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountBorrows","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"interestIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"addExp","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_addAmount","type":"uint256"}],"name":"addTotalCash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bank","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowSafeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"calcBalanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"}],"name":"calcExchangeRate","outputs":[{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"striker","type":"address"}],"name":"cancellingOut","outputs":[{"internalType":"bool","name":"strikeOk","type":"bool"},{"internalType":"bytes","name":"strikeLog","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IBankController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"divExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"}],"name":"divScalar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"scalar","type":"uint256"},{"internalType":"uint256","name":"divisor","type":"uint256"}],"name":"divScalarByExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"scalar","type":"uint256"},{"internalType":"uint256","name":"divisor","type":"uint256"}],"name":"divScalarByExpTruncate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"transferInAmout","type":"uint256"}],"name":"exchangeRateAfter","outputs":[{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountState","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"},{"internalType":"uint256","name":"denom","type":"uint256"}],"name":"getDiv","outputs":[{"internalType":"uint256","name":"rational","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"},{"internalType":"uint256","name":"denom","type":"uint256"}],"name":"getExp","outputs":[{"internalType":"uint256","name":"rational","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getSupplyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_initialInterestRateModel","type":"address"},{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"address","name":"_bank","type":"address"},{"internalType":"uint256","name":"_borrowSafeRatio","type":"uint256"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract IInterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"contract FToken","name":"fTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"mulExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"mulExp3","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"}],"name":"mulScalar","outputs":[{"internalType":"uint256","name":"scaled","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"}],"name":"mulScalarTruncate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"},{"internalType":"uint256","name":"addend","type":"uint256"}],"name":"mulScalarTruncateAddUInt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peekInterest","outputs":[{"internalType":"uint256","name":"_accrualBlockNumber","type":"uint256"},{"internalType":"uint256","name":"_borrowIndex","type":"uint256"},{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"subExp","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_subAmount","type":"uint256"}],"name":"subTotalCash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"tokenCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"exp","type":"uint256"}],"name":"truncate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"utilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"withdrawTokensIn","type":"uint256"},{"internalType":"uint256","name":"withdrawAmountIn","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}]

Contract Creation Code

608060405234801561001057600080fd5b50600436106104335760003560e01c806385cc148611610236578063ba1c5e801161013b578063d40e8f4a116100c3578063ef8bd30511610087578063ef8bd305146108c9578063f2b3abbd146108d1578063f3fdb15a146108e4578063f77c4791146108ec578063f851a440146108f457610433565b8063d40e8f4a1461085c578063d6079cc61461087d578063dd62ed3e14610890578063de32abd1146108a3578063e61de305146108b657610433565b8063bee12d531161010a578063bee12d5314610813578063c2ee3a081461081b578063c319f86614610823578063c5e9cadc14610836578063ce603aad1461084957610433565b8063ba1c5e80146107fb578063ba9316b7146105f8578063bd30558e14610803578063bd6d894d1461080b57610433565b8063a19d1460116101be578063ae8a473d1161018d578063ae8a473d1461079c578063b2a02ff1146107af578063b4ab15e7146107c2578063b507f9f9146107d5578063b5c5f672146107e857610433565b8063a19d146014610766578063a6afed9514610779578063a9059cbb14610781578063aa5af0fd1461079457610433565b806395bd6a4c1161020557806395bd6a4c1461070357806395d89b411461071657806395dd91931461071e5780639c92779c146107315780639ee2735b1461074457610433565b806385cc1486146106cd5780638de46362146106d55780638f840ddd146106e857806393508164146106f057610433565b80634751b79c1161033c5780636c540baf116102c457806370a082311161029357806370a082311461068457806376cdb03b146106975780637b94aaac1461069f57806383de424e146106b257806384bdc9a8146106c557610433565b80636c540baf1461064c5780636d019f35146106545780636f307dc31461065c5780636f4a3de91461067157610433565b80635293ff311161030b5780635293ff31146105f8578063601a0bf11461060b5780636208fc411461061e57806364fd7078146106315780636c321c8a1461064457610433565b80634751b79c146105b757806347bd3718146105ca5780634b3ac1c2146105d25780634b8a3529146105e557610433565b806323b872dd116103bf5780633af9e6691161038e5780633af9e6691461056157806340c10f19146105745780634147da13146105875780634322b7141461059a578063474a5e05146105a257610433565b806323b872dd146105135780632985fa3114610526578063313ce56714610539578063396a98cf1461054e57610433565b806315f14eaa1161040657806315f14eaa146104ae57806317bfdfbc146104cf57806318160ddd146104e2578063182df0f5146104ea57806322867d78146104f257610433565b806306fdde031461043857806308186ecf146104565780630873f15014610476578063095ea7b31461048e575b600080fd5b6104406108fc565b60405161044d9190614eda565b60405180910390f35b610469610464366004614b84565b61098a565b60405161044d919061556e565b61047e610a5b565b60405161044d94939291906155b4565b6104a161049c366004614b52565b610d41565b60405161044d9190614eb4565b6104c16104bc366004614a0d565b610daf565b60405161044d929190614ebf565b6104696104dd366004614a0d565b61107c565b61046961113d565b610469611143565b610505610500366004614b52565b611159565b60405161044d929190615577565b6104a1610521366004614ac0565b6111f1565b610469610534366004614c83565b611361565b61054161137a565b60405161044d9190615614565b61046961055c366004614c83565b611383565b61046961056f366004614a0d565b611395565b610440610582366004614b52565b6113d0565b610469610595366004614c83565b611460565b610469611472565b6105b56105b0366004614b84565b611478565b005b6104696105c5366004614c83565b6114a7565b6104696114b9565b6105b56105e0366004614b84565b6114bf565b6104406105f3366004614a29565b6116c1565b610469610606366004614c83565b611736565b6105b5610619366004614b84565b611760565b61046961062c366004614ca4565b6118c9565b61044061063f366004614b00565b6118fa565b610469611f96565b610469612049565b61046961204f565b610664612055565b60405161044d9190614d8f565b6105b561067f366004614bb4565b612064565b610469610692366004614a0d565b6121bf565b6106646121da565b6104696106ad366004614b84565b6121e9565b6105b56106c0366004614a0d565b612203565b61046961224f565b6104696122b1565b6104696106e3366004614ca4565b6122b7565b6104696122cc565b6104696106fe366004614a88565b6122d2565b6105b5610711366004614b84565b612381565b610440612469565b61046961072c366004614a0d565b6124c4565b6105b561073f366004614b84565b6124cf565b610757610752366004614a0d565b612535565b60405161044d9392919061559e565b610469610774366004614a0d565b612576565b6105b5612588565b6104a161078f366004614b52565b612900565b610469612a70565b6105b56107aa366004614b84565b612a76565b6105b56107bd366004614ac0565b612b1e565b6104696107d0366004614c83565b612b78565b6104696107e3366004614c83565b612b90565b6105056107f6366004614a54565b612b9c565b610469612c36565b610469612c93565b610469612cf0565b610469612d51565b610469612d57565b6105b5610831366004614b84565b612d63565b610469610844366004614c83565b612e45565b610469610857366004614c83565b612f0f565b61086f61086a366004614a0d565b612f36565b60405161044d929190615590565b61046961088b366004614c83565b612f4f565b61046961089e366004614a88565b612f5c565b6104696108b1366004614c83565b612f87565b6104696108c4366004614a0d565b612fca565b610469613011565b6105b56108df366004614a0d565b613073565b610664613195565b6106646131a4565b6106646131b3565b6034805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156109825780601f1061095757610100808354040283529160200191610982565b820191906000526020600020905b81548152906001019060200180831161096557829003601f168201915b505050505081565b6033546000908061099f575050603854610a56565b60425460408054905163051f87d160e51b81526000926001600160a01b039081169263a3f0fa20926109d992909116908890600401614e3e565b60206040518083038186803b1580156109f157600080fd5b505afa158015610a05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a299190614b9c565b90506000610a44610a3c83603a54611460565b603b54611383565b9050610a508184611736565b93505050505b919050565b600080600080610a696131c2565b603e5490945080851415610a9157603e54603d54603a54603b54945094509450945050610d3b565b604254604080549051639f77437b60e01b81526000926001600160a01b0390811692639f77437b92610ac99290911690600401614d8f565b60206040518083038186803b158015610ae157600080fd5b505afa158015610af5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b199190614b9c565b603a54603b54603d54603f546040516315f2405360e01b81529495509293919290916000916001600160a01b0316906315f2405390610b609088908890889060040161559e565b60206040518083038186803b158015610b7857600080fd5b505afa158015610b8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb09190614b9c565b905065048c27395000811115610be15760405162461bcd60e51b8152600401610bd8906152a9565b60405180910390fd5b6000610bf38b8863ffffffff6131c616565b90506000806000806000610c078787611361565b9450610c24610c16868c612f87565b670de0b6b3a7640000612b90565b9350610c30848b611460565b9250610c4a610c44610c16603c5487612f87565b8a611460565b9150610c62610c5c610c16878b612f87565b89611460565b9050809e50829d50819c50603f60009054906101000a90046001600160a01b03166001600160a01b03166315f240538c603a54603b546040518463ffffffff1660e01b8152600401610cb69392919061559e565b60206040518083038186803b158015610cce57600080fd5b505afa158015610ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d069190614b9c565b965065048c27395000871115610d2e5760405162461bcd60e51b8152600401610bd8906152a9565b5050505050505050505050505b90919293565b3360008181526037602090815260408083206001600160a01b03871680855292528083208590555191929182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610d9b90879061556e565b60405180910390a360019150505b92915050565b6044546000906060906001600160a01b03163314610ddf5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff16610e085760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b191690556000610e2084613208565b118015610e3557506000610e33846121bf565b115b1561106257610e42612588565b6001600160a01b03831660009081526045602052604081205490610e6585613208565b90506000610e7286612fca565b90506000610e7f876121bf565b90506000606060006060600087118015610e995750600086115b156110595786861115610ebc57610eb28b60008961326f565b9092509050610ed6565b610ed08b610ec98d6121bf565b600061326f565b90925090505b610ee08b83613512565b9094509250610eed614622565b6001600160a01b03808d1682526040805490911660208301523090820152610f1d86610f188e6121bf565b6137e1565b606082015260808101859052610f33888a6137e1565b60a0820152610f40611143565b60c0820152603f546040546042546001600160a01b03928316926315f2405392610f6e9290821691166122d2565b603a54603b546040518463ffffffff1660e01b8152600401610f929392919061559e565b60206040518083038186803b158015610faa57600080fd5b505afa158015610fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe29190614b9c565b60e0820152610ff1308d6122d2565b6101008201526001600160a01b03808d1660009081526045602052604090819020546101208401525460425461102b9291821691166122d2565b61014082015260405161104290829060200161536a565b604051602081830303815290604052995060019a50505b50505050505050505b6044805460ff60a01b1916600160a01b1790559092909150565b604454600090600160a01b900460ff166110a85760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b191690556110bd612588565b6110c5614697565b506001600160a01b03821660009081526045602090815260409182902082518084019093528054835260010154908201819052603d5410156111195760405162461bcd60e51b8152600401610bd890615036565b61112283613208565b9150506044805460ff60a01b1916600160a01b179055919050565b60335481565b6000611153603a54603b54612e45565b90505b90565b6044546000906060906001600160a01b031633146111895760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166111b25760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b191690556111c7612588565b6111d18484613512565b915091506044805460ff60a01b1916600160a01b17905590939092509050565b604454600090600160a01b900460ff1661121d5760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055611236338585856137fa565b5061123f6146b1565b60408051610100810182526001600160a01b03808816825282541660208201523091810191909152606081018490526080810161127b876121bf565b8152602001856001600160a01b03168152602001611298866121bf565b81526040546042546020909201916112bc916001600160a01b0390811691166122d2565b90526044546040519192506001600160a01b031690637bc597aa906112e5908490602001615505565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401611310919061519b565b600060405180830381600087803b15801561132a57600080fd5b505af115801561133e573d6000803e3d6000fd5b5050505060019150506044805460ff60a01b1916600160a01b1790559392505050565b6000611373838363ffffffff613a9516565b9392505050565b60365460ff1681565b6000611373838363ffffffff6131c616565b6000806113a0612cf0565b6001600160a01b038416600090815260416020526040812054919250906113c8908390612b78565b949350505050565b6044546060906001600160a01b031633146113fd5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166114265760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b1916905561143b612588565b6114458383613acf565b90506044805460ff60a01b1916600160a01b17905592915050565b6000611373838363ffffffff613d6e16565b603c5481565b6039546001600160a01b031633146114a25760405162461bcd60e51b8152600401610bd890615214565b604355565b6000611373838363ffffffff613d9316565b603a5481565b6039546001600160a01b031633146114e95760405162461bcd60e51b8152600401610bd890615214565b60385460006114f6611f96565b90506000611502612c93565b9050600061150e613011565b9050600061151a611143565b9050611524612588565b600061152e611143565b90506115386131c2565b603e54146115585760405162461bcd60e51b8152600401610bd890614fb4565b60388790556000611567611f96565b90506000611573612c93565b9050600061157f613011565b90507fcff2ff0c9e99b301907279a45536b658e0227bfa9d6fba4799b46b268e804e2789898989896038548989898d6040516115c49a999897969594939291906155cf565b60405180910390a16115d461471a565b6040805160a08101825281546001600160a01b03168152600060208201529081016115fd611143565b815260200161160a612c36565b815260405460425460209092019161162e916001600160a01b0390811691166122d2565b90526044546040519192506001600160a01b031690637bc597aa906116579084906020016154c7565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161168291906151ea565b600060405180830381600087803b15801561169c57600080fd5b505af11580156116b0573d6000803e3d6000fd5b505050505050505050505050505050565b6044546060906001600160a01b031633146116ee5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166117175760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b1916905561172c612588565b6114458383613dd5565b60006113738261175485670de0b6b3a764000063ffffffff613a9516565b9063ffffffff613d9316565b6042546001600160a01b0316331461178a5760405162461bcd60e51b8152600401610bd89061508e565b611792612588565b61179a6131c2565b603e54146117ba5760405162461bcd60e51b8152600401610bd890614fb4565b604254604080549051639f77437b60e01b815283926001600160a01b0390811692639f77437b926117f19290911690600401614d8f565b60206040518083038186803b15801561180957600080fd5b505afa15801561181d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118419190614b9c565b101561185f5760405162461bcd60e51b8152600401610bd8906152e0565b80603b5410156118815760405162461bcd60e51b8152600401610bd890614fdf565b6118c3603b54826040518060400160405280601981526020017f72656475636520726573657276657320756e646572666c6f7700000000000000815250614098565b603b5550565b6000806118d68585611361565b90506118f1836118e5836121e9565b9063ffffffff613d6e16565b95945050505050565b6044546060906001600160a01b031633146119275760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166119505760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055604254604051632a4d98cf60e01b81526001600160a01b0390911690632a4d98cf9061198d903090600401614d8f565b60206040518083038186803b1580156119a557600080fd5b505afa1580156119b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dd9190614b64565b8015611a645750604254604051632a4d98cf60e01b81526001600160a01b0390911690632a4d98cf90611a14908590600401614d8f565b60206040518083038186803b158015611a2c57600080fd5b505afa158015611a40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a649190614b64565b611a805760405162461bcd60e51b8152600401610bd890614f5b565b611a88612588565b816001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ac357600080fd5b505af1158015611ad7573d6000803e3d6000fd5b5050506001600160a01b0385166000908152604560205260408120549150611afe86613208565b604254604051633e5cd62160e11b81529192506001600160a01b031690637cb9ac4290611b3790309088908b908d908c90600401614e0b565b600060405180830381600087803b158015611b5157600080fd5b505af1158015611b65573d6000803e3d6000fd5b50505050611b716131c2565b603e5414611b915760405162461bcd60e51b8152600401610bd890614fb4565b611b996131c2565b846001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bd257600080fd5b505afa158015611be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c0a9190614b9c565b14611c275760405162461bcd60e51b8152600401610bd890614fb4565b6000611c338787613512565b506042546040516263fd3760e51b81529192506000916001600160a01b0390911690630c7fa6e090611c6d9030908a908790600401614de7565b60206040518083038186803b158015611c8557600080fd5b505afa158015611c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cbd9190614b9c565b905080866001600160a01b03166370a082318a6040518263ffffffff1660e01b8152600401611cec9190614d8f565b60206040518083038186803b158015611d0457600080fd5b505afa158015611d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3c9190614b9c565b1015611d5a5760405162461bcd60e51b8152600401610bd89061500e565b6001600160a01b038616301415611d7c57611d77308a8a846140c4565b611ddf565b60405163b2a02ff160e01b81526001600160a01b0387169063b2a02ff190611dac908c908c908690600401614de7565b600060405180830381600087803b158015611dc657600080fd5b505af1158015611dda573d6000803e3d6000fd5b505050505b604054604254600091611e049185916118e5916001600160a01b0391821691166122d2565b9050611e0e614752565b604080516101c0810182526001600160a01b03808e168252825416602082015230918101919091526060810185905260808101611e4b87896137e1565b81526020018b6001600160a01b03168152602001848152602001896001600160a01b03168152602001611e7e8a8d6122d2565b81526001600160a01b038c16600090815260456020908152604091829020549083015201611eab8661098a565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f2405392611ee992899260040161559e565b60206040518083038186803b158015611f0157600080fd5b505afa158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f399190614b9c565b8152602001611f488a8e6122d2565b815260200183815250905080604051602001611f649190615400565b60405160208183030381529060405296505050505050506044805460ff60a01b1916600160a01b179055949350505050565b6040546042546000918291611fb7916001600160a01b0390811691166122d2565b603f54603a54603b54604051630dce3c5b60e31b81529394506001600160a01b0390921692636e71e2d892611ff392869290919060040161559e565b60206040518083038186803b15801561200b57600080fd5b505afa15801561201f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120439190614b9c565b91505090565b603e5481565b60385481565b6040546001600160a01b031681565b600054610100900460ff168061207d575061207d614206565b8061208b575060005460ff16155b6120a75760405162461bcd60e51b8152600401610bd89061514d565b600054610100900460ff161580156120d2576000805460ff1961ff0019909116610100171660011790555b60388a9055604280546001600160a01b03808c166001600160a01b031992831617909255603f80548b84169083161790556039805482163317905560408054928a1692909116919091179055604385905561212b6131c2565b603e55670de0b6b3a7640000603d55604480546001600160a01b0319166001600160a01b03881617905583516121689060349060208701906147ee565b50825161217c9060359060208601906147ee565b506036805460ff841660ff199091161790556044805460ff60a01b1916600160a01b17905580156121b3576000805461ff00191690555b50505050505050505050565b6001600160a01b031660009081526041602052604090205490565b6044546001600160a01b031681565b6000610da982670de0b6b3a764000063ffffffff613d9316565b6039546001600160a01b0316331461222d5760405162461bcd60e51b8152600401610bd890615214565b604280546001600160a01b0319166001600160a01b0392909216919091179055565b6040546042546000918291612270916001600160a01b0390811691166122d2565b603f54603a54603b54603c54604051635c0b440b60e11b81529495506001600160a01b039093169363b816881693611ff393879390929091906004016155b4565b60435481565b60006113c86122c68585612f87565b83612f87565b603b5481565b60006122dc61420c565b6001600160a01b0316836001600160a01b0316141561230557816001600160a01b031631611373565b6040516370a0823160e01b81526001600160a01b038416906370a0823190612331908590600401614d8f565b60206040518083038186803b15801561234957600080fd5b505afa15801561235d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113739190614b9c565b6044546001600160a01b03163314806123a457506042546001600160a01b031633145b806123ae57503330145b806124345750604254604051639deec7cb60e01b81526001600160a01b0390911690639deec7cb906123e4903390600401614d8f565b60206040518083038186803b1580156123fc57600080fd5b505afa158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614b64565b6124505760405162461bcd60e51b8152600401610bd890615061565b604654612463908263ffffffff613d6e16565b60465550565b6035805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156109825780601f1061095757610100808354040283529160200191610982565b6000610da982613208565b6042546001600160a01b031633146124f95760405162461bcd60e51b8152600401610bd89061508e565b612501612588565b6125096131c2565b603e54146125295760405162461bcd60e51b8152600401610bd890614fb4565b6118c3603b5482613d6e565b6001600160a01b038116600090815260416020526040812054819081908161255c86613208565b90506000612568611143565b929791965091945092505050565b60416020526000908152604090205481565b6039546001600160a01b03163314806125ab57506044546001600160a01b031633145b806125c057506042546001600160a01b031633145b806126465750604254604051639deec7cb60e01b81526001600160a01b0390911690639deec7cb906125f6903390600401614d8f565b60206040518083038186803b15801561260e57600080fd5b505afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190614b64565b6126625760405162461bcd60e51b8152600401610bd89061511f565b600061266c6131c2565b603e54909150808214156126815750506128fe565b604254604080549051639f77437b60e01b81526000926001600160a01b0390811692639f77437b926126b99290911690600401614d8f565b60206040518083038186803b1580156126d157600080fd5b505afa1580156126e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127099190614b9c565b603a54603b54603d54603f546040516315f2405360e01b81529495509293919290916000916001600160a01b0316906315f24053906127509088908890889060040161559e565b60206040518083038186803b15801561276857600080fd5b505afa15801561277c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a09190614b9c565b905065048c273950008111156127c85760405162461bcd60e51b8152600401610bd8906152a9565b60006127da888863ffffffff6131c616565b905060008060008060006127ee8787611361565b94506127fd610c16868c612f87565b9350612809848b611460565b925061281d610c44610c16603c5487612f87565b915061282f610c5c610c16878b612f87565b603e8e9055603d819055603a849055603b839055603f546040516315f2405360e01b81529192506001600160a01b0316906315f2405390612878908e908790879060040161559e565b60206040518083038186803b15801561289057600080fd5b505afa1580156128a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c89190614b9c565b965065048c273950008711156128f05760405162461bcd60e51b8152600401610bd8906152a9565b505050505050505050505050505b565b604454600090600160a01b900460ff1661292c5760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612945338085856137fa565b5061294e6146b1565b60408051610100810182523380825282546001600160a01b0316602083015230928201929092526060810185905290608082019061298b906121bf565b8152602001856001600160a01b031681526020016129a8866121bf565b81526040546042546020909201916129cc916001600160a01b0390811691166122d2565b90526044546040519192506001600160a01b031690637bc597aa906129f5908490602001615505565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401612a20919061530b565b600060405180830381600087803b158015612a3a57600080fd5b505af1158015612a4e573d6000803e3d6000fd5b5050505060019150506044805460ff60a01b1916600160a01b17905592915050565b603d5481565b6039546001600160a01b03163314612aa05760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff16612ac95760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612ade612588565b612ae66131c2565b603e5414612b065760405162461bcd60e51b8152600401610bd890614fb4565b603c556044805460ff60a01b1916600160a01b179055565b604454600160a01b900460ff16612b475760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612b60338484846140c4565b50506044805460ff60a01b1916600160a01b17905550565b600080612b858484611361565b90506113c8816121e9565b60006113738383611736565b6044546000906060906001600160a01b03163314612bcc5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff16612bf55760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612c0a612588565b612c15858585614224565b915091506044805460ff60a01b1916600160a01b1790559094909350915050565b6040546042546000918291612c57916001600160a01b0390811691166122d2565b603f54603a54603b546040516315f2405360e01b81529394506001600160a01b03909216926315f2405392611ff392869290919060040161559e565b6040546042546000918291612cb4916001600160a01b0390811691166122d2565b603f54603a54603b5460405163ca9cdd1b60e01b81529394506001600160a01b039092169263ca9cdd1b92611ff392869290919060040161559e565b604454600090600160a01b900460ff16612d1c5760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612d31612588565b612d39611143565b90506044805460ff60a01b1916600160a01b17905590565b60465481565b670de0b6b3a764000081565b6044546001600160a01b0316331480612d8657506042546001600160a01b031633145b80612d9057503330145b80612e165750604254604051639deec7cb60e01b81526001600160a01b0390911690639deec7cb90612dc6903390600401614d8f565b60206040518083038186803b158015612dde57600080fd5b505afa158015612df2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e169190614b64565b612e325760405162461bcd60e51b8152600401610bd890615061565b604654612463908263ffffffff6131c616565b60335460009080612e5a575050603854610da9565b604254604080549051639f77437b60e01b81526000926001600160a01b0390811692639f77437b92612e929290911690600401614d8f565b60206040518083038186803b158015612eaa57600080fd5b505afa158015612ebe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ee29190614b9c565b90506000612ef9612ef38388611460565b86611383565b9050612f058184611736565b9695505050505050565b600080612f2a670de0b6b3a76400008563ffffffff613a9516565b90506113c88184611736565b6045602052600090815260409020805460019091015482565b600080612b858484612f0f565b6001600160a01b03918216600090815260376020908152604080832093909416825291909152205490565b600080612f9a848463ffffffff613a9516565b90506000612fb06706f05b59d3b2000083613d6e565b90506118f181670de0b6b3a764000063ffffffff613d9316565b6000806000612fd7610a5b565b9350935050506000612fe98383612e45565b6001600160a01b03861660009081526041602052604081205491925090612f05908390612b78565b6040546042546000918291613032916001600160a01b0390811691166122d2565b603f54603a54603b54603c5460405163ae8b520f60e01b81529495506001600160a01b039093169363ae8b520f93611ff393879390929091906004016155b4565b6039546001600160a01b0316331461309d5760405162461bcd60e51b8152600401610bd890615214565b603f546001600160a01b031660006130b3611f96565b905060006130bf612c93565b905060006130cb613011565b905060006130d7611143565b90506130e1612588565b60006130eb611143565b90506130f56131c2565b603e54146131155760405162461bcd60e51b8152600401610bd890614fb4565b603f80546001600160a01b0319166001600160a01b038916179055600061313a611f96565b90506000613146612c93565b90506000613152613011565b90507fdeb648bcaeacc8fe85ac80af712d28507d5040e38de659e3981835f7732b580e89898989898f8989898d6040516115c49a99989796959493929190614e57565b603f546001600160a01b031681565b6042546001600160a01b031681565b6039546001600160a01b031681565b4390565b600061137383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614098565b6000613212614697565b506001600160a01b0382166000908152604560209081526040918290208251808401909352805480845260019091015491830191909152613257576000915050610a56565b61137381600001516108b1603d548460200151612b90565b6000606083158061327e575082155b61329a5760405162461bcd60e51b8152600401610bd890614eed565b6132a261486c565b6132aa611143565b815284156132cf576020810185905280516132c59086612b78565b60408201526132ea565b6132dd848260000151612f4f565b6020820152604081018490525b6132f26131c2565b603e54146133125760405162461bcd60e51b8152600401610bd890614fb4565b60208101516033546133299163ffffffff6131c616565b60608201526020808201516001600160a01b0388166000908152604190925260409091205461335d9163ffffffff6131c616565b6080820181905260608201516033556001600160a01b038088166000908152604160205260408082209390935582840151925460425491936133a89390926118e592821691166122d2565b90506133b261489b565b60408051610120810182526001600160a01b03808b1682528254166020808301919091523082840152850151606082015290840151608082015260a081016133f8611143565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f240539261343692899260040161559e565b60206040518083038186803b15801561344e57600080fd5b505afa158015613462573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134869190614b9c565b8152602001613495308b6122d2565b815260200183815250905060006001600160a01b0316886001600160a01b031660008051602061563b83398151915285602001516040516134d6919061556e565b60405180910390a38260400151816040516020016134f4919061535b565b60405160208183030381529060405294509450505050935093915050565b60425460408054905163227a5a8360e11b81526000926060926001600160a01b03918216926344f4b5069261354b921690600401614d8f565b600060405180830381600087803b15801561356557600080fd5b505af1158015613579573d6000803e3d6000fd5b505050506135856131c2565b603e54146135a55760405162461bcd60e51b8152600401610bd890614fb4565b6135ad614902565b6001600160a01b03851660009081526045602090815260409091208054600190910154918301919091526135e086613208565b60408301526000198514156135fb57604082015182526135ff565b8482525b815160408301516136159163ffffffff6131c616565b60608301528151603a541015613631576000608083015261364b565b8151603a546136459163ffffffff6131c616565b60808301525b60608201516001600160a01b03808816600090815260456020526040808220938455603d546001909401939093556080850151603a5584519254604254919361369d9390926118e592821691166122d2565b90506136a761489b565b60408051610120810182526001600160a01b03808b16825282541660208201523081830152855160608201529085015160808201906136e690866137e1565b81526020016136f8866000015161098a565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f240539261373692899260040161559e565b60206040518083038186803b15801561374e57600080fd5b505afa158015613762573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137869190614b9c565b81526001600160a01b038a16600090815260456020908152604091829020548184015291810185905286519051929350916137c39184910161535b565b60405160208183030381529060405295509550505050509250929050565b6000818310156137f45750818103610da9565b50900390565b60445460408051635c975abb60e01b815290516000926001600160a01b031691635c975abb916004808301926020929190829003018186803b15801561383f57600080fd5b505afa158015613853573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138779190614b64565b156138945760405162461bcd60e51b8152600401610bd8906151c3565b604260009054906101000a90046001600160a01b03166001600160a01b031663d38120c93086866138c787604354612b78565b6040518563ffffffff1660e01b81526004016138e69493929190614da3565b600060405180830381600087803b15801561390057600080fd5b505af1158015613914573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316141561394a5760405162461bcd60e51b8152600401610bd890615272565b60006001600160a01b0386811690861614156139695750600019613991565b506001600160a01b038085166000908152603760209081526040808320938916835292905220545b60006139a3828563ffffffff6131c616565b6001600160a01b0387166000908152604160205260409020549091506139cf908563ffffffff6131c616565b6001600160a01b038088166000908152604160205260408082209390935590871681522054613a04908563ffffffff613d6e16565b6001600160a01b0386166000908152604160205260409020556000198214613a4f576001600160a01b038087166000908152603760209081526040808320938b168352929052208190555b846001600160a01b0316866001600160a01b031660008051602061563b83398151915286604051613a80919061556e565b60405180910390a35060019695505050505050565b600082613aa457506000610da9565b82820282848281613ab157fe5b04146113735760405162461bcd60e51b8152600401610bd8906150ba565b6060613ad96131c2565b603e5414613af95760405162461bcd60e51b8152600401610bd890614fb4565b613b0161486c565b604254604080549051631f3c14ef60e11b81526001600160a01b0392831692633e7829de92613b399291169088908890600401614de7565b600060405180830381600087803b158015613b5357600080fd5b505af1158015613b67573d6000803e3d6000fd5b50505050613b73611143565b808252613b81908490612f4f565b60208201819052603354613b9491611460565b6040808301919091526001600160a01b0385166000908152604160209081529190205490820151613bc59190611460565b606082018190526040808301516033556001600160a01b0380871660009081526041602052828120939093559054604254613c0a9287926118e59290821691166122d2565b9050613c1461489b565b60408051610120810182526001600160a01b03808916825282541660208083019190915230928201929092529084015160608201526080810186905260a08101613c5d8761098a565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f2405392613c9b92899260040161559e565b60206040518083038186803b158015613cb357600080fd5b505afa158015613cc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ceb9190614b9c565b8152602001613cfa30896122d2565b8152602001838152509050856001600160a01b031660006001600160a01b031660008051602061563b8339815191528560200151604051613d3b919061556e565b60405180910390a380604051602001613d54919061535b565b604051602081830303815290604052935050505092915050565b6000828201838110156113735760405162461bcd60e51b8152600401610bd890614f24565b600061137383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506145eb565b6042546040546043546060926001600160a01b03908116926396a13b32928792909116903090613e06908890612b78565b6040518563ffffffff1660e01b8152600401613e259493929190614da3565b600060405180830381600087803b158015613e3f57600080fd5b505af1158015613e53573d6000803e3d6000fd5b5050604254604080549051639f77437b60e01b81528694506001600160a01b039283169350639f77437b92613e8c921690600401614d8f565b60206040518083038186803b158015613ea457600080fd5b505afa158015613eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613edc9190614b9c565b1015613efa5760405162461bcd60e51b8152600401610bd890614f86565b613f02614938565b6001600160a01b038416600090815260456020526040902054613f2485613208565b808352613f319085611460565b6020830152603a54613f439085611460565b60408084019182526020808501516001600160a01b03808a166000908152604590935291839020908155603d546001909101559151603a556042548154915163fa93b2a560e01b81529083169263fa93b2a592613fa99291169089908990600401614de7565b600060405180830381600087803b158015613fc357600080fd5b505af1158015613fd7573d6000803e3d6000fd5b50505050613fe484612d63565b613fec61489b565b60408051610120810182526001600160a01b03808916825282541660208201523091810191909152606081018690528351608082019061402c90856137e1565b8152602001614039611143565b8152602001614046612c36565b81526001600160a01b038089166000908152604560209081526040918290205490840152805460425491909301926140829290811691166122d2565b815250905080604051602001613d54919061535b565b600081848411156140bc5760405162461bcd60e51b8152600401610bd89190614eda565b505050900390565b826001600160a01b0316826001600160a01b031614156140f65760405162461bcd60e51b8152600401610bd89061523b565b604254604051637ceb4c9760e01b81526001600160a01b0390911690637ceb4c97906141289030908890600401614dcd565b600060405180830381600087803b15801561414257600080fd5b505af1158015614156573d6000803e3d6000fd5b5050506001600160a01b03831660009081526041602052604090205461418391508263ffffffff6131c616565b6001600160a01b0380841660009081526041602052604080822093909355908516815220546141b8908263ffffffff613d6e16565b6001600160a01b03808516600081815260416020526040908190209390935591519084169060008051602061563b833981519152906141f890859061556e565b60405180910390a350505050565b303b1590565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90565b60006060831580614233575082155b61424f5760405162461bcd60e51b8152600401610bd890614eed565b61425761486c565b61425f611143565b815284156142845760208101859052805161427a9086612b78565b604082015261429f565b614292848260000151612f4f565b6020820152604081018490525b6042546020820151604051635798612960e01b81526001600160a01b03909216916357986129916142d69130918b91600401614de7565b60206040518083038186803b1580156142ee57600080fd5b505afa158015614302573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143269190614b9c565b5061432f6131c2565b603e541461434f5760405162461bcd60e51b8152600401610bd890614fb4565b60208101516033546143669163ffffffff6131c616565b60608201526020808201516001600160a01b0388166000908152604190925260409091205461439a9163ffffffff6131c616565b608082015260408082015160425482549251639f77437b60e01b815291926001600160a01b0391821692639f77437b926143d8921690600401614d8f565b60206040518083038186803b1580156143f057600080fd5b505afa158015614404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144289190614b9c565b10156144465760405162461bcd60e51b8152600401610bd89061532f565b6042546040805483820151915163fa93b2a560e01b81526001600160a01b039384169363fa93b2a59361448293909116918b9190600401614de7565b600060405180830381600087803b15801561449c57600080fd5b505af11580156144b0573d6000803e3d6000fd5b505050506144c18160400151612d63565b606081015160335560808101516001600160a01b0387166000908152604160205260409020556144ef61489b565b60408051610120810182526001600160a01b03808a1682528254166020808301919091523082840152840151606082015290830151608082015260a08101614535611143565b8152602001614542612c36565b8152602001614551308a6122d2565b8152604054604254602090920191614575916001600160a01b0390811691166122d2565b815250905060006001600160a01b0316876001600160a01b031660008051602061563b83398151915284602001516040516145b0919061556e565b60405180910390a38160400151816040516020016145ce919061535b565b604051602081830303815290604052935093505050935093915050565b6000818361460c5760405162461bcd60e51b8152600401610bd89190614eda565b50600083858161461857fe5b0495945050505050565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b6040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b604051806101c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061482f57805160ff191683800117855561485c565b8280016001018555821561485c579182015b8281111561485c578251825591602001919060010190614841565b50614868929150614959565b5090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180610120016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b61115691905b80821115614868576000815560010161495f565b8035610da981615622565b600082601f83011261498e578081fd5b813567ffffffffffffffff808211156149a5578283fd5b604051601f8301601f1916810160200182811182821017156149c5578485fd5b6040528281529250828483016020018610156149e057600080fd5b8260208601602083013760006020848301015250505092915050565b803560ff81168114610da957600080fd5b600060208284031215614a1e578081fd5b813561137381615622565b60008060408385031215614a3b578081fd5b8235614a4681615622565b946020939093013593505050565b600080600060608486031215614a68578081fd5b8335614a7381615622565b95602085013595506040909401359392505050565b60008060408385031215614a9a578182fd5b8235614aa581615622565b91506020830135614ab581615622565b809150509250929050565b600080600060608486031215614ad4578283fd5b8335614adf81615622565b92506020840135614aef81615622565b929592945050506040919091013590565b60008060008060808587031215614b15578081fd5b8435614b2081615622565b93506020850135614b3081615622565b9250604085013591506060850135614b4781615622565b939692955090935050565b60008060408385031215614a3b578182fd5b600060208284031215614b75578081fd5b81518015158114611373578182fd5b600060208284031215614b95578081fd5b5035919050565b600060208284031215614bad578081fd5b5051919050565b60008060008060008060008060006101208a8c031215614bd2578485fd5b8935985060208a0135614be481615622565b975060408a0135614bf481615622565b9650614c038b60608c01614973565b9550614c128b60808c01614973565b945060a08a0135935060c08a013567ffffffffffffffff80821115614c35578485fd5b614c418d838e0161497e565b945060e08c0135915080821115614c56578384fd5b50614c638c828d0161497e565b925050614c748b6101008c016149fc565b90509295985092959850929598565b60008060408385031215614c95578081fd5b50508035926020909101359150565b600080600060608486031215614cb8578081fd5b505081359360208301359350604090920135919050565b6001600160a01b03169052565b60008151808452815b81811015614d0157602081850181015186830182015201614ce5565b81811115614d125782602083870101525b50601f01601f19169290920160200192915050565b60018060a01b0380825116835280602083015116602084015280604083015116604084015250606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039586168152938516602085015291841660408401529092166060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039a8b1681526020810199909952604089019790975260608801959095526080870193909352951660a085015260c084019490945260e08301939093526101008201929092526101208101919091526101400190565b901515815260200190565b60008315158252604060208301526113c86040830184614cdc565b6000602082526113736020830184614cdc565b6020808252601c908201527f776974686472617720706172616d65746572206e6f742076616c696400000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526011908201527013585c9ad95d081b9bdd081b1a5cdd1959607a1b604082015260600190565b602080825260149082015273496e73756666696369656e742062616c616e636560601b604082015260600190565b602080825260119082015270426c6f636b6e756d626572206661696c7360781b604082015260600190565b602080825260159082015274496e73756666696369656e7420726573657276657360581b604082015260600190565b6020808252600e908201526d0a6cad2f4ca40e8dede40daeac6d60931b604082015260600190565b6020808252601190820152703137b93937bba4b73232bc1032b93937b960791b604082015260600190565b6020808252601390820152721bdb9b1e4818985b9ac818dbdb5c1bdb995b9d606a1b604082015260600190565b6020808252601290820152713932b8bab4b9329031b7b73a3937b63632b960711b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252600a90820152691c994b595b9d195c995960b21b604082015260600190565b60208082526014908201527337b7363c903932b9ba3934b1ba32b2103ab9b2b960611b604082015260600190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b60006b5472616e7366657246726f6d60a01b8252604060208301526113736040830184614cdc565b6020808252600d908201526c14de5cdd195b481c185d5cd959609a1b604082015260600190565b60006d14995cd95c9d9951195c1bdcda5d60921b8252604060208301526113736040830184614cdc565b6020808252600d908201526c3932b8bab4b9329030b236b4b760991b604082015260600190565b6020808252601d908201527f4c697175696461746f722063616e6e6f7420626520626f72726f776572000000604082015260600190565b60208082526017908201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604082015260600190565b60208082526017908201527f626f72726f77207261746520697320746f6f2068696768000000000000000000604082015260600190565b602080825260119082015270092dce6eaccccd2c6d2cadce840c6c2e6d607b1b604082015260600190565b6000672a3930b739b332b960c11b8252604060208301526113736040830184614cdc565b602080825260129082015271496e73756666696369656e74206d6f6e657960701b604082015260600190565b6101208101610da98284614d27565b60006101608201905061537e828451614ccf565b60208301516153906020840182614ccf565b5060408301516153a36040840182614ccf565b50606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151818401525092915050565b60006101c082019050615414828451614ccf565b60208301516154266020840182614ccf565b5060408301516154396040840182614ccf565b50606083015160608301526080830151608083015260a083015161546060a0840182614ccf565b5060c083015160c083015260e083015161547d60e0840182614ccf565b50610100838101519083015261012080840151908301526101408084015190830152610160808401519083015261018080840151908301526101a092830151929091019190915290565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080918201519181019190915260a00190565b60006101008201905060018060a01b0380845116835280602085015116602084015280604085015116604084015260608401516060840152608084015160808401528060a08501511660a08401525060c083015160c083015260e083015160e083015292915050565b90815260200190565b6000838252604060208301526113c86040830184614cdc565b918252602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b998a5260208a019890985260408901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400190565b60ff91909116815260200190565b6001600160a01b038116811461563757600080fd5b5056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220b4a3535465e8afd15762e942628abf29ac8304f5de6aa713dae5948dd4e1784f64736f6c63430006040033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.