Address io1psh4jgtgrf7aj4hzy0awthpr2q4uks7d4qdfjy

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:
Bank

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
/**
 * @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
/**
 * @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
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 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
enum RewardType {
    DefaultType,
    Deposit,
    Borrow,
    Withdraw,
    Repay,
    Liquidation,
    TokenIn, //入金,为还款和存款的组合
    TokenOut //出金, 为取款和借款的组合
}

// 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;
    }
}

/**
 * @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
/**
* @title IFlashLoanReceiver interface
* @notice Interface for the Aave fee IFlashLoanReceiver.
* @author Aave
* @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract
**/
interface IFlashLoanReceiver {
    function executeOperation(address token, uint256 amount, uint256 fee, bytes calldata params) external;
}

// SPDX-License-Identifier: MIT
// 入口合约
contract Bank is Initializable {
    using SafeMath for uint256;

    bool public paused;

    address public mulSig;

    //monitor event
    event MonitorEvent(bytes32 indexed funcName, bytes payload);
    event FlashLoan(
        address indexed receiver,
        address indexed token,
        uint256 amount,
        uint256 fee
    );

    modifier onlyFToken(address fToken) {
        require(
            controller.marketsContains(fToken) ||
                msg.sender == address(controller),
            "only supported ftoken or controller"
        );
        _;
    }

    function MonitorEventCallback(bytes32 funcName, bytes calldata payload)
        external
        onlyFToken(msg.sender)
    {
        emit MonitorEvent(funcName, payload);
    }

    // bank controller 实例
    IBankController public controller;

    address public admin;

    address public proposedAdmin;
    address public pauser;

    bool private loaning;
    modifier nonSelfLoan() {
        require(!loaning, "re-loaning");
        loaning = true;
        _;
        loaning = false;
    }

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

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

    modifier onlyMulSig {
        require(msg.sender == mulSig, "require mulsig");
        _;
    }

    modifier onlySelf {
        require(msg.sender == address(this), "require self");
        _;
    }

    modifier onlyPauser {
        require(msg.sender == pauser, "require pauser");
        _;
    }

    // 初始化,只能初始化一次
    function initialize(address _controller, address _mulSig)
        public
        initializer
    {
        controller = IBankController(_controller);
        mulSig = _mulSig;
        paused = false;
        admin = msg.sender;
    }

    function setController(address _controller) public onlyAdmin {
        controller = IBankController(_controller);
    }

    function setPaused() public onlyPauser {
        paused = true;
    }

    function setUnpaused() public onlyPauser {
        paused = false;
    }

    function setPauser(address _pauser) public onlyAdmin {
        pauser = _pauser;
    }

    function proposeNewAdmin(address admin_) external onlyMulSig {
        proposedAdmin = admin_;
    }

    function claimAdministration() external {
        require(msg.sender == proposedAdmin, "Not proposed admin.");
        admin = proposedAdmin;
        proposedAdmin = address(0);
    }

    // 用户存款
    function deposit(address token, uint256 amount)
        public
        payable
        whenUnpaused
    {
        return this._deposit{value: msg.value}(token, amount, msg.sender);
    }

    // 用户存款
    function _deposit(
        address token,
        uint256 amount,
        address account
    ) external payable whenUnpaused onlySelf nonSelfLoan {
        IFToken fToken = IFToken(controller.getFTokeAddress(token));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        bytes memory flog = fToken.mint(account, amount);
        controller.transferIn{value: msg.value}(account, token, amount);

        fToken.addTotalCash(amount);

        emit MonitorEvent("Deposit", flog);
    }

    // 用户借款
    function borrow(address underlying, uint256 borrowAmount)
        public
        whenUnpaused
        nonSelfLoan
    {
        IFToken fToken = IFToken(controller.getFTokeAddress(underlying));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        bytes memory flog = fToken.borrow(msg.sender, borrowAmount);
        emit MonitorEvent("Borrow", flog);
    }

    // 用户取款 取 fToken 的数量
    function withdraw(address underlying, uint256 withdrawTokens)
        public
        whenUnpaused
        nonSelfLoan
        returns (uint256)
    {
        IFToken fToken = IFToken(controller.getFTokeAddress(underlying));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        (uint256 amount, bytes memory flog) = fToken.withdraw(
            msg.sender,
            withdrawTokens,
            0
        );
        emit MonitorEvent("Withdraw", flog);
        return amount;
    }

    // 用户取款 取底层 token 的数量
    function withdrawUnderlying(address underlying, uint256 withdrawAmount)
        public
        whenUnpaused
        nonSelfLoan
        returns (uint256)
    {
        IFToken fToken = IFToken(controller.getFTokeAddress(underlying));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        (uint256 amount, bytes memory flog) = fToken.withdraw(
            msg.sender,
            0,
            withdrawAmount
        );
        emit MonitorEvent("WithdrawUnderlying", flog);
        return amount;
    }

    // 用户还款
    function repay(address token, uint256 repayAmount)
        public
        payable
        whenUnpaused
        returns (uint256)
    {
        return this._repay{value: msg.value}(token, repayAmount, msg.sender);
    }

    // 用户还款
    function _repay(
        address token,
        uint256 repayAmount,
        address account
    ) public payable whenUnpaused onlySelf nonSelfLoan returns (uint256) {
        IFToken fToken = IFToken(controller.getFTokeAddress(token));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        (uint256 actualRepayAmount, bytes memory flog) = fToken.repay(
            account,
            repayAmount
        );
        controller.transferIn{value: msg.value}(
            account,
            token,
            actualRepayAmount
        );

        fToken.addTotalCash(actualRepayAmount);

        emit MonitorEvent("Repay", flog);
        return actualRepayAmount;
    }

    // 用户清算
    function liquidateBorrow(
        address borrower,
        address underlyingBorrow,
        address underlyingCollateral,
        uint256 repayAmount
    ) public payable whenUnpaused nonSelfLoan {
        require(msg.sender != borrower, "Liquidator cannot be borrower");
        require(repayAmount > 0, "Liquidate amount not valid");

        IFToken fTokenBorrow = IFToken(
            controller.getFTokeAddress(underlyingBorrow)
        );
        IFToken fTokenCollateral = IFToken(
            controller.getFTokeAddress(underlyingCollateral)
        );
        bytes memory flog = fTokenBorrow.liquidateBorrow(
            msg.sender,
            borrower,
            repayAmount,
            address(fTokenCollateral)
        );
        controller.transferIn{value: msg.value}(
            msg.sender,
            underlyingBorrow,
            repayAmount
        );

        fTokenBorrow.addTotalCash(repayAmount);

        emit MonitorEvent("LiquidateBorrow", flog);
    }

    // 入金token in, 为还款和存款的组合
    //没有借款时,无需还款,有借款时,先还款,单独写一个进行入金,而不是直接调用mint和repay,原因在于在ETH存款时会有bug,msg.value会复用。
    function tokenIn(address token, uint256 amountIn)
        public
        payable
        whenUnpaused
    {
        IFToken fToken = IFToken(controller.getFTokeAddress(token));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        //先进行冲账操作
        cancellingOut(token);
        uint256 curBorrowBalance = fToken.borrowBalanceCurrent(msg.sender);
        uint256 actualRepayAmount;

        //还清欠款
        if (amountIn == uint256(-1)) {
            require(curBorrowBalance > 0, "no debt to repay");
            if (token != EthAddressLib.ethAddress()) {
                require(
                    msg.value == 0,
                    "msg.value should be 0 for ERC20 repay"
                );
                actualRepayAmount = this._repay{value: 0}(
                    token,
                    amountIn,
                    msg.sender
                );
            } else {
                require(
                    msg.value >= curBorrowBalance,
                    "msg.value need great or equal than current debt"
                );
                actualRepayAmount = this._repay{value: curBorrowBalance}(
                    token,
                    amountIn,
                    msg.sender
                );
                if (msg.value > actualRepayAmount) {
                    (bool result, ) = msg.sender.call{
                        value: msg.value.sub(actualRepayAmount),
                        gas: controller.transferEthGasCost()
                    }("");
                    require(result, "Transfer of exceed ETH failed");
                }
            }

            emit MonitorEvent("TokenIn", abi.encode(token, actualRepayAmount));
        } else {
            if (curBorrowBalance > 0) {
                uint256 repayEthValue = SafeMath.min(
                    curBorrowBalance,
                    amountIn
                );
                if (token != EthAddressLib.ethAddress()) {
                    repayEthValue = 0;
                }
                actualRepayAmount = this._repay{value: repayEthValue}(
                    token,
                    SafeMath.min(curBorrowBalance, amountIn),
                    msg.sender
                );
            }

            // 还款数量有剩余,转为存款
            if (actualRepayAmount < amountIn) {
                uint256 exceedAmout = SafeMath.sub(amountIn, actualRepayAmount);
                if (token != EthAddressLib.ethAddress()) {
                    exceedAmout = 0;
                }
                this._deposit{value: exceedAmout}(
                    token,
                    SafeMath.sub(amountIn, actualRepayAmount),
                    msg.sender
                );
            }

            emit MonitorEvent("TokenIn", abi.encode(token, amountIn));
        }
    }

    // 出金token out, 为取款和借款的组合,
    // 取款如果该用户有对应的存款(有对应的ftoken),完全可取出,剩余的部分采用借的逻辑,
    function tokenOut(address token, uint256 amountOut) external whenUnpaused {
        IFToken fToken = IFToken(controller.getFTokeAddress(token));
        require(
            controller.marketsContains(address(fToken)),
            "unsupported token"
        );

        //先进行冲账操作
        cancellingOut(token);

        uint256 supplyAmount = 0;
        if (amountOut == uint256(-1)) {
            uint256 fBalance = fToken.balanceOf(msg.sender);
            require(fBalance > 0, "no asset to withdraw");
            supplyAmount = withdraw(token, fBalance);

            emit MonitorEvent("TokenOut", abi.encode(token, supplyAmount));
        } else {
            uint256 userSupplyBalance = fToken.calcBalanceOfUnderlying(
                msg.sender
            );
            if (userSupplyBalance > 0) {
                if (userSupplyBalance < amountOut) {
                    supplyAmount = withdraw(
                        token,
                        fToken.balanceOf(msg.sender)
                    );
                } else {
                    supplyAmount = withdrawUnderlying(
                        token,
                        amountOut
                    );
                }
            }

            if (supplyAmount < amountOut) {
                borrow(token, amountOut.sub(supplyAmount));
            }

            emit MonitorEvent("TokenOut", abi.encode(token, amountOut));
        }
    }

    function cancellingOut(address token) public whenUnpaused nonSelfLoan {
        IFToken fToken = IFToken(controller.getFTokeAddress(token));
        //先进行冲账操作
        (bool strikeOk, bytes memory strikeLog) = fToken.cancellingOut(
            msg.sender
        );
        if (strikeOk) {
            emit MonitorEvent("CancellingOut", strikeLog);
        }
    }

    function flashloan(
        address receiver,
        address token,
        uint256 amount,
        bytes memory params
    ) public whenUnpaused nonSelfLoan {
        uint256 balanceBefore = controller.balance(token);
        require(amount > 0 && amount <= balanceBefore, "insufficient flashloan liquidity");

        uint256 fee = amount.mul(controller.flashloanFeeBips()).div(10000);
        address payable _receiver = address(uint160(receiver));

        controller.transferFlashloanAsset(token, _receiver, amount); 
        IFlashLoanReceiver(_receiver).executeOperation(token, amount, fee, params);

        uint256 balanceAfter = controller.balance(token);
        require(balanceAfter >= balanceBefore.add(fee), "invalid flashloan payback amount");

        address payable vault = address(uint160(controller.flashloanVault()));
        controller.transferFlashloanAsset(token, vault, fee);

        emit FlashLoan(receiver, token, amount, fee);
    }
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FlashLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"funcName","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"}],"name":"MonitorEvent","type":"event"},{"inputs":[{"internalType":"bytes32","name":"funcName","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"MonitorEventCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"_deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"_repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"cancellingOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAdministration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IBankController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"params","type":"bytes"}],"name":"flashloan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_mulSig","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"underlyingBorrow","type":"address"},{"internalType":"address","name":"underlyingCollateral","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mulSig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin_","type":"address"}],"name":"proposeNewAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposedAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pauser","type":"address"}],"name":"setPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setUnpaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"tokenIn","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"tokenOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint256","name":"withdrawTokens","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

Contract Creation Code

6080604052600436106101815760003560e01c806363ad2c41116100d1578063a63767461161008a578063f3fef3a311610064578063f3fef3a3146103dd578063f77c4791146103fd578063f851a44014610412578063fdb872521461042757610181565b8063a637674614610395578063ad2cb239146103b5578063e61604cf146103ca57610181565b806363ad2c41146102fa5780637bc597aa1461031a5780637f51975f1461033a57806392eefe9b1461034d578063942389291461036d5780639fd0506d1461038057610181565b80633c89edce1161013e578063485cc95511610118578063485cc955146102835780634b8a3529146102a35780635c975abb146102c357806362757215146102e557610181565b80633c89edce146102485780633e62cd3f1461025d57806347e7ef241461027057610181565b806315f14eaa146101865780631beb7f5c146101a857806322867d78146101c85780632d88af4a146101f157806332f751ec1461021157806337a66d8514610233575b600080fd5b34801561019257600080fd5b506101a66101a1366004612bfe565b610447565b005b3480156101b457600080fd5b506101a66101c3366004612d64565b61060d565b6101db6101d6366004612d64565b6109fd565b6040516101e891906134e5565b60405180910390f35b3480156101fd57600080fd5b506101a661020c366004612bfe565b610aa7565b34801561021d57600080fd5b50610226610af3565b6040516101e89190612f61565b34801561023f57600080fd5b506101a6610b02565b34801561025457600080fd5b506101a6610b3b565b6101db61026b366004612d8f565b610b71565b6101a661027e366004612d64565b610ea8565b34801561028f57600080fd5b506101a661029e366004612c36565b610f2a565b3480156102af57600080fd5b506101a66102be366004612d64565b610ffc565b3480156102cf57600080fd5b506102d861122a565b6040516101e89190613058565b3480156102f157600080fd5b50610226611233565b34801561030657600080fd5b506101a6610315366004612cbe565b611247565b34801561032657600080fd5b506101a6610335366004612e3b565b6116cc565b6101a6610348366004612d64565b6117ab565b34801561035957600080fd5b506101a6610368366004612bfe565b611dfc565b6101a661037b366004612d8f565b611e48565b34801561038c57600080fd5b50610226612177565b3480156103a157600080fd5b506101a66103b0366004612bfe565b612186565b3480156103c157600080fd5b506101a66121d7565b6101a66103d8366004612c6e565b612228565b3480156103e957600080fd5b506101db6103f8366004612d64565b612579565b34801561040957600080fd5b506102266127d0565b34801561041e57600080fd5b506102266127df565b34801561043357600080fd5b506101db610442366004612d64565b6127ee565b60335460ff16156104735760405162461bcd60e51b815260040161046a90613363565b60405180910390fd5b603754600160a01b900460ff161561049d5760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce708906104e1908590600401612f61565b60206040518083038186803b1580156104f957600080fd5b505afa15801561050d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105319190612c1a565b905060006060826001600160a01b03166315f14eaa336040518263ffffffff1660e01b81526004016105639190612f61565b600060405180830381600087803b15801561057d57600080fd5b505af1158015610591573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105b99190810190612dec565b9150915081156105fa576c10d85b98d95b1b1a5b99d3dd5d609a1b60008051602061359a833981519152826040516105f19190613092565b60405180910390a25b50506037805460ff60a01b191690555050565b60335460ff16156106305760405162461bcd60e51b815260040161046a90613363565b603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce70890610661908690600401612f61565b60206040518083038186803b15801561067957600080fd5b505afa15801561068d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b19190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb906106e2908490600401612f61565b60206040518083038186803b1580156106fa57600080fd5b505afa15801561070e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190612dd0565b61074e5760405162461bcd60e51b815260040161046a9061317f565b61075783610447565b6000600019831415610866576040516370a0823160e01b81526000906001600160a01b038416906370a0823190610792903390600401612f61565b60206040518083038186803b1580156107aa57600080fd5b505afa1580156107be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e29190612eeb565b9050600081116108045760405162461bcd60e51b815260040161046a90613237565b61080e8582612579565b915067151bdad95b93dd5d60c21b60008051602061359a833981519152868460405160200161083e929190612fe5565b60408051601f198184030181529082905261085891613092565b60405180910390a2506109f7565b60405163e61de30560e01b81526000906001600160a01b0384169063e61de30590610895903390600401612f61565b60206040518083038186803b1580156108ad57600080fd5b505afa1580156108c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e59190612eeb565b90508015610989578381101561097c5761097585846001600160a01b03166370a08231336040518263ffffffff1660e01b81526004016109259190612f61565b60206040518083038186803b15801561093d57600080fd5b505afa158015610951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f89190612eeb565b9150610989565b61098685856127ee565b91505b838210156109a5576109a5856102be868563ffffffff612a3116565b67151bdad95b93dd5d60c21b60008051602061359a83398151915286866040516020016109d3929190612fe5565b60408051601f19818403018152908290526109ed91613092565b60405180910390a2505b50505050565b60335460009060ff1615610a235760405162461bcd60e51b815260040161046a90613363565b604051633e62cd3f60e01b81523090633e62cd3f903490610a4c90879087903390600401612ffe565b6020604051808303818588803b158015610a6557600080fd5b505af1158015610a79573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a9e9190612eeb565b90505b92915050565b6035546001600160a01b03163314610ad15760405162461bcd60e51b815260040161046a906131df565b603780546001600160a01b0319166001600160a01b0392909216919091179055565b6036546001600160a01b031681565b6037546001600160a01b03163314610b2c5760405162461bcd60e51b815260040161046a90613157565b6033805460ff19166001179055565b6037546001600160a01b03163314610b655760405162461bcd60e51b815260040161046a90613157565b6033805460ff19169055565b60335460009060ff1615610b975760405162461bcd60e51b815260040161046a90613363565b333014610bb65760405162461bcd60e51b815260040161046a90613131565b603754600160a01b900460ff1615610be05760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce70890610c24908890600401612f61565b60206040518083038186803b158015610c3c57600080fd5b505afa158015610c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c749190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb90610ca5908490600401612f61565b60206040518083038186803b158015610cbd57600080fd5b505afa158015610cd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf59190612dd0565b610d115760405162461bcd60e51b815260040161046a9061317f565b60006060826001600160a01b03166322867d7886886040518363ffffffff1660e01b8152600401610d43929190612fe5565b600060405180830381600087803b158015610d5d57600080fd5b505af1158015610d71573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d999190810190612f03565b60345460405163e4652f4960e01b81529294509092506001600160a01b03169063e4652f49903490610dd39089908c908890600401612f75565b6000604051808303818588803b158015610dec57600080fd5b505af1158015610e00573d6000803e3d6000fd5b505060405163256f5a9360e21b81526001600160a01b03871693506395bd6a4c9250610e31915085906004016134e5565b600060405180830381600087803b158015610e4b57600080fd5b505af1158015610e5f573d6000803e3d6000fd5b5050505064526570617960d81b60008051602061359a83398151915282604051610e899190613092565b60405180910390a2506037805460ff60a01b1916905595945050505050565b60335460ff1615610ecb5760405162461bcd60e51b815260040161046a90613363565b604051639423892960e01b815230906394238929903490610ef490869086903390600401612ffe565b6000604051808303818588803b158015610f0d57600080fd5b505af1158015610f21573d6000803e3d6000fd5b50505050505050565b600054610100900460ff1680610f435750610f43612a73565b80610f51575060005460ff16155b610f6d5760405162461bcd60e51b815260040161046a906132eb565b600054610100900460ff16158015610f98576000805460ff1961ff0019909116610100171660011790555b603480546001600160a01b038086166001600160a01b0319928316179092556033805460ff1993861661010002610100600160a81b0319909116179290921690915560358054909116331790558015610ff7576000805461ff00191690555b505050565b60335460ff161561101f5760405162461bcd60e51b815260040161046a90613363565b603754600160a01b900460ff16156110495760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce7089061108d908690600401612f61565b60206040518083038186803b1580156110a557600080fd5b505afa1580156110b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110dd9190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb9061110e908490600401612f61565b60206040518083038186803b15801561112657600080fd5b505afa15801561113a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115e9190612dd0565b61117a5760405162461bcd60e51b815260040161046a9061317f565b604051634b8a352960e01b81526060906001600160a01b03831690634b8a3529906111ab9033908790600401612fe5565b600060405180830381600087803b1580156111c557600080fd5b505af11580156111d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112019190810190612eb0565b905065426f72726f7760d01b60008051602061359a833981519152826040516105f19190613092565b60335460ff1681565b60335461010090046001600160a01b031681565b60335460ff161561126a5760405162461bcd60e51b815260040161046a90613363565b603754600160a01b900460ff16156112945760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b17905560345460405163e3d670d760e01b81526000916001600160a01b03169063e3d670d7906112d8908790600401612f61565b60206040518083038186803b1580156112f057600080fd5b505afa158015611304573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113289190612eeb565b905060008311801561133a5750808311155b6113565760405162461bcd60e51b815260040161046a906131aa565b60006114006127106113f4603460009054906101000a90046001600160a01b03166001600160a01b0316631289155b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113af57600080fd5b505afa1580156113c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e79190612eeb565b879063ffffffff612a7916565b9063ffffffff612ab316565b603454604051635502c98d60e11b815291925087916001600160a01b039091169063aa05931a9061143990899085908a90600401612f75565b600060405180830381600087803b15801561145357600080fd5b505af1158015611467573d6000803e3d6000fd5b5050604051631dd0e4ab60e31b81526001600160a01b038416925063ee872558915061149d908990899087908a90600401613021565b600060405180830381600087803b1580156114b757600080fd5b505af11580156114cb573d6000803e3d6000fd5b505060345460405163e3d670d760e01b8152600093506001600160a01b03909116915063e3d670d790611502908a90600401612f61565b60206040518083038186803b15801561151a57600080fd5b505afa15801561152e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115529190612eeb565b9050611564848463ffffffff612af516565b8110156115835760405162461bcd60e51b815260040161046a90613202565b60345460408051636bfbcfa960e11b815290516000926001600160a01b03169163d7f79f52916004808301926020929190829003018186803b1580156115c857600080fd5b505afa1580156115dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116009190612c1a565b603454604051635502c98d60e11b81529192506001600160a01b03169063aa05931a90611635908b9085908990600401612f75565b600060405180830381600087803b15801561164f57600080fd5b505af1158015611663573d6000803e3d6000fd5b50505050876001600160a01b0316896001600160a01b03167f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f089876040516116ac9291906134ee565b60405180910390a350506037805460ff60a01b1916905550505050505050565b603454604051639deec7cb60e01b815233916001600160a01b031690639deec7cb906116fc908490600401612f61565b60206040518083038186803b15801561171457600080fd5b505afa158015611728573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174c9190612dd0565b8061176157506034546001600160a01b031633145b61177d5760405162461bcd60e51b815260040161046a906133c1565b8360008051602061359a833981519152848460405161179d929190613063565b60405180910390a250505050565b60335460ff16156117ce5760405162461bcd60e51b815260040161046a90613363565b603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce708906117ff908690600401612f61565b60206040518083038186803b15801561181757600080fd5b505afa15801561182b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184f9190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb90611880908490600401612f61565b60206040518083038186803b15801561189857600080fd5b505afa1580156118ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d09190612dd0565b6118ec5760405162461bcd60e51b815260040161046a9061317f565b6118f583610447565b6040516305eff7ef60e21b81526000906001600160a01b038316906317bfdfbc90611924903390600401612f61565b602060405180830381600087803b15801561193e57600080fd5b505af1158015611952573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119769190612eeb565b90506000600019841415611c6a57600082116119a45760405162461bcd60e51b815260040161046a90613339565b6119ac612b1a565b6001600160a01b0316856001600160a01b031614611a655734156119e25760405162461bcd60e51b815260040161046a90613265565b604051633e62cd3f60e01b81523090633e62cd3f90600090611a0c90899089903390600401612ffe565b6020604051808303818588803b158015611a2557600080fd5b505af1158015611a39573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611a5e9190612eeb565b9050611c16565b81341015611a855760405162461bcd60e51b815260040161046a90613472565b604051633e62cd3f60e01b81523090633e62cd3f908490611aae90899089903390600401612ffe565b6020604051808303818588803b158015611ac757600080fd5b505af1158015611adb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611b009190612eeb565b905080341115611c1657600033611b1d348463ffffffff612a3116565b603460009054906101000a90046001600160a01b03166001600160a01b0316634f9c751e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b6b57600080fd5b505afa158015611b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba39190612eeb565b90604051611bb090612f5e565b600060405180830381858888f193505050503d8060008114611bee576040519150601f19603f3d011682016040523d82523d6000602084013e611bf3565b606091505b5050905080611c145760405162461bcd60e51b815260040161046a90613404565b505b662a37b5b2b724b760c91b60008051602061359a8339815191528683604051602001611c43929190612fe5565b60408051601f1981840301815290829052611c5d91613092565b60405180910390a2611df5565b8115611d29576000611c7c8386612b32565b9050611c86612b1a565b6001600160a01b0316866001600160a01b031614611ca2575060005b30633e62cd3f8288611cb4878a612b32565b336040518563ffffffff1660e01b8152600401611cd393929190612ffe565b6020604051808303818588803b158015611cec57600080fd5b505af1158015611d00573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611d259190612eeb565b9150505b83811015611dc8576000611d3d8583612a31565b9050611d47612b1a565b6001600160a01b0316866001600160a01b031614611d63575060005b3063942389298288611d758987612a31565b336040518563ffffffff1660e01b8152600401611d9493929190612ffe565b6000604051808303818588803b158015611dad57600080fd5b505af1158015611dc1573d6000803e3d6000fd5b5050505050505b662a37b5b2b724b760c91b60008051602061359a83398151915286866040516020016109d3929190612fe5565b5050505050565b6035546001600160a01b03163314611e265760405162461bcd60e51b815260040161046a906131df565b603480546001600160a01b0319166001600160a01b0392909216919091179055565b60335460ff1615611e6b5760405162461bcd60e51b815260040161046a90613363565b333014611e8a5760405162461bcd60e51b815260040161046a90613131565b603754600160a01b900460ff1615611eb45760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce70890611ef8908790600401612f61565b60206040518083038186803b158015611f1057600080fd5b505afa158015611f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f489190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb90611f79908490600401612f61565b60206040518083038186803b158015611f9157600080fd5b505afa158015611fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc99190612dd0565b611fe55760405162461bcd60e51b815260040161046a9061317f565b6040516340c10f1960e01b81526060906001600160a01b038316906340c10f19906120169086908890600401612fe5565b600060405180830381600087803b15801561203057600080fd5b505af1158015612044573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261206c9190810190612eb0565b60345460405163e4652f4960e01b81529192506001600160a01b03169063e4652f499034906120a39087908a908a90600401612f75565b6000604051808303818588803b1580156120bc57600080fd5b505af11580156120d0573d6000803e3d6000fd5b505060405163256f5a9360e21b81526001600160a01b03861693506395bd6a4c9250612101915087906004016134e5565b600060405180830381600087803b15801561211b57600080fd5b505af115801561212f573d6000803e3d6000fd5b505050506611195c1bdcda5d60ca1b60008051602061359a8339815191528260405161215b9190613092565b60405180910390a250506037805460ff60a01b19169055505050565b6037546001600160a01b031681565b60335461010090046001600160a01b031633146121b55760405162461bcd60e51b815260040161046a90613109565b603680546001600160a01b0319166001600160a01b0392909216919091179055565b6036546001600160a01b031633146122015760405162461bcd60e51b815260040161046a906130a5565b60368054603580546001600160a01b03199081166001600160a01b03841617909155169055565b60335460ff161561224b5760405162461bcd60e51b815260040161046a90613363565b603754600160a01b900460ff16156122755760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055336001600160a01b03851614156122b15760405162461bcd60e51b815260040161046a9061343b565b600081116122d15760405162461bcd60e51b815260040161046a9061338a565b603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce70890612302908790600401612f61565b60206040518083038186803b15801561231a57600080fd5b505afa15801561232e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123529190612c1a565b603454604051631f839ce160e31b81529192506000916001600160a01b039091169063fc1ce70890612388908790600401612f61565b60206040518083038186803b1580156123a057600080fd5b505afa1580156123b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123d89190612c1a565b90506060826001600160a01b03166364fd7078338987866040518563ffffffff1660e01b815260040161240e9493929190612f99565b600060405180830381600087803b15801561242857600080fd5b505af115801561243c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124649190810190612eb0565b60345460405163e4652f4960e01b81529192506001600160a01b03169063e4652f4990349061249b9033908b908a90600401612f75565b6000604051808303818588803b1580156124b457600080fd5b505af11580156124c8573d6000803e3d6000fd5b505060405163256f5a9360e21b81526001600160a01b03871693506395bd6a4c92506124f9915087906004016134e5565b600060405180830381600087803b15801561251357600080fd5b505af1158015612527573d6000803e3d6000fd5b505050506e4c6971756964617465426f72726f7760881b60008051602061359a8339815191528260405161255b9190613092565b60405180910390a250506037805460ff60a01b191690555050505050565b60335460009060ff161561259f5760405162461bcd60e51b815260040161046a90613363565b603754600160a01b900460ff16156125c95760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce7089061260d908790600401612f61565b60206040518083038186803b15801561262557600080fd5b505afa158015612639573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265d9190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb9061268e908490600401612f61565b60206040518083038186803b1580156126a657600080fd5b505afa1580156126ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126de9190612dd0565b6126fa5760405162461bcd60e51b815260040161046a9061317f565b60006060826001600160a01b031663b5c5f672338760006040518463ffffffff1660e01b815260040161272f93929190612fc4565b600060405180830381600087803b15801561274957600080fd5b505af115801561275d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127859190810190612f03565b9150915067576974686472617760c01b60008051602061359a833981519152826040516127b29190613092565b60405180910390a2506037805460ff60a01b19169055949350505050565b6034546001600160a01b031681565b6035546001600160a01b031681565b60335460009060ff16156128145760405162461bcd60e51b815260040161046a90613363565b603754600160a01b900460ff161561283e5760405162461bcd60e51b815260040161046a906134c1565b6037805460ff60a01b1916600160a01b179055603454604051631f839ce160e31b81526000916001600160a01b03169063fc1ce70890612882908790600401612f61565b60206040518083038186803b15801561289a57600080fd5b505afa1580156128ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d29190612c1a565b603454604051639deec7cb60e01b81529192506001600160a01b031690639deec7cb90612903908490600401612f61565b60206040518083038186803b15801561291b57600080fd5b505afa15801561292f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129539190612dd0565b61296f5760405162461bcd60e51b815260040161046a9061317f565b60006060826001600160a01b031663b5c5f672336000886040518463ffffffff1660e01b81526004016129a493929190612fc4565b600060405180830381600087803b1580156129be57600080fd5b505af11580156129d2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129fa9190810190612f03565b91509150715769746864726177556e6465726c79696e6760701b60008051602061359a833981519152826040516127b29190613092565b6000610a9e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612b49565b303b1590565b600082612a8857506000610aa1565b82820282848281612a9557fe5b0414610a9e5760405162461bcd60e51b815260040161046a906132aa565b6000610a9e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612b75565b600082820183811015610a9e5760405162461bcd60e51b815260040161046a906130d2565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90565b600081831115612b425781610a9e565b5090919050565b60008184841115612b6d5760405162461bcd60e51b815260040161046a9190613092565b505050900390565b60008183612b965760405162461bcd60e51b815260040161046a9190613092565b506000838581612ba257fe5b0495945050505050565b600082601f830112612bbc578081fd5b8151612bcf612bca82613523565b6134fc565b9150808252836020828501011115612be657600080fd5b612bf7816020840160208601613547565b5092915050565b600060208284031215612c0f578081fd5b8135610a9e81613573565b600060208284031215612c2b578081fd5b8151610a9e81613573565b60008060408385031215612c48578081fd5b8235612c5381613573565b91506020830135612c6381613573565b809150509250929050565b60008060008060808587031215612c83578182fd5b8435612c8e81613573565b93506020850135612c9e81613573565b92506040850135612cae81613573565b9396929550929360600135925050565b60008060008060808587031215612cd3578384fd5b8435612cde81613573565b93506020850135612cee81613573565b925060408501359150606085013567ffffffffffffffff811115612d10578182fd5b80860187601f820112612d21578283fd5b80359150612d31612bca83613523565b828152886020848401011115612d45578384fd5b8260208301602083013791820160200192909252939692955090935050565b60008060408385031215612d76578182fd5b8235612d8181613573565b946020939093013593505050565b600080600060608486031215612da3578283fd5b8335612dae81613573565b9250602084013591506040840135612dc581613573565b809150509250925092565b600060208284031215612de1578081fd5b8151610a9e8161358b565b60008060408385031215612dfe578182fd5b8251612e098161358b565b602084015190925067ffffffffffffffff811115612e25578182fd5b612e3185828601612bac565b9150509250929050565b600080600060408486031215612e4f578283fd5b83359250602084013567ffffffffffffffff80821115612e6d578384fd5b81860187601f820112612e7e578485fd5b8035925081831115612e8e578485fd5b876020848301011115612e9f578485fd5b949760209095019650909450505050565b600060208284031215612ec1578081fd5b815167ffffffffffffffff811115612ed7578182fd5b612ee384828501612bac565b949350505050565b600060208284031215612efc578081fd5b5051919050565b60008060408385031215612f15578182fd5b82519150602083015167ffffffffffffffff811115612e25578182fd5b60008151808452612f4a816020860160208601613547565b601f01601f19169290920160200192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03948516815292841660208401526040830191909152909116606082015260800190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b600060018060a01b03861682528460208301528360408301526080606083015261304e6080830184612f32565b9695505050505050565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b600060208252610a9e6020830184612f32565b6020808252601390820152722737ba10383937b837b9b2b21030b236b4b71760691b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600e908201526d72657175697265206d756c73696760901b604082015260600190565b6020808252600c908201526b3932b8bab4b9329039b2b63360a11b604082015260600190565b6020808252600e908201526d3932b8bab4b932903830bab9b2b960911b604082015260600190565b6020808252601190820152703ab739bab83837b93a32b2103a37b5b2b760791b604082015260600190565b6020808252818101527f696e73756666696369656e7420666c6173686c6f616e206c6971756964697479604082015260600190565b60208082526009908201526827b7363ca0b236b4b760b91b604082015260600190565b6020808252818101527f696e76616c696420666c6173686c6f616e207061796261636b20616d6f756e74604082015260600190565b6020808252601490820152736e6f20617373657420746f20776974686472617760601b604082015260600190565b60208082526025908201527f6d73672e76616c75652073686f756c64206265203020666f7220455243323020604082015264726570617960d81b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526010908201526f6e6f206465627420746f20726570617960801b604082015260600190565b6020808252600d908201526c14de5cdd195b481c185d5cd959609a1b604082015260600190565b6020808252601a908201527f4c697175696461746520616d6f756e74206e6f742076616c6964000000000000604082015260600190565b60208082526023908201527f6f6e6c7920737570706f727465642066746f6b656e206f7220636f6e74726f6c6040820152623632b960e91b606082015260800190565b6020808252601d908201527f5472616e73666572206f662065786365656420455448206661696c6564000000604082015260600190565b6020808252601d908201527f4c697175696461746f722063616e6e6f7420626520626f72726f776572000000604082015260600190565b6020808252602f908201527f6d73672e76616c7565206e656564206772656174206f7220657175616c20746860408201526e185b8818dd5c9c995b9d081919589d608a1b606082015260800190565b6020808252600a908201526972652d6c6f616e696e6760b01b604082015260600190565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561351b57600080fd5b604052919050565b600067ffffffffffffffff821115613539578081fd5b50601f01601f191660200190565b60005b8381101561356257818101518382015260200161354a565b838111156109f75750506000910152565b6001600160a01b038116811461358857600080fd5b50565b801515811461358857600080fdfe8df0b9408c77393ca0d6ccf0e770ef1432b46111947c518125b420a00207381ea2646970667358221220f6fbbe6f23ce7f30bf37ef50da6cd79da686feef6fa2851f1da248b8ca5e44de64736f6c63430006040033

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.