ETH Price: $3,999.51 (+2.78%)

Contract

0x4F06912118DD95dA06b97EED80BA593B9e0329f3

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BathToken

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion
File 1 of 8 : BathToken.sol
// SPDX-License-Identifier: BUSL-1.1

/// @author Rubicon DeFi Inc. - bghughes.eth
/// @notice This contract represents a single-asset liquidity pool for Rubicon Pools
/// @notice Any user can deposit assets into this pool and earn yield from successful strategist market making with their liquidity
/// @notice This contract looks to both BathPairs and the BathHouse as its admin

pragma solidity =0.7.6;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../interfaces/IBathHouse.sol";
import "../interfaces/IRubiconMarket.sol";
import "../interfaces/IVestingWallet.sol";

contract BathToken {
    using SafeMath for uint256;

    /// *** Storage Variables ***

    /// @notice The initialization status of the Bath Token
    bool public initialized;

    /// @notice  ** ERC-20 **
    string public symbol;
    string public name;
    uint8 public decimals;

    /// @notice The RubiconMarket.sol instance that all pool liquidity is intially directed to as market-making offers
    address public RubiconMarketAddress;

    /// @notice The Bath House admin of the Bath Token
    address public bathHouse;

    /// @notice The withdrawal fee recipient, typically the Bath Token itself
    address public feeTo;

    /// @notice The underlying ERC-20 token which is the core asset of the Bath Token vault
    IERC20 public underlyingToken;

    /// @notice The basis point fee rate that is paid on withdrawing the underlyingToken and bonusTokens
    uint256 public feeBPS;

    /// @notice ** ERC-20 **
    uint256 public totalSupply;

    /// @notice The amount of underlying deposits that are outstanding attempting market-making on the order book for yield
    /// @dev quantity of underlyingToken that is in the orderbook that the pool still has a claim on
    /// @dev The underlyingToken is effectively mark-to-marketed when it enters the book and it could be returned at a loss due to poor strategist performance
    /// @dev outstandingAmount is NOT inclusive of any non-underlyingToken assets sitting on the Bath Tokens that have filled to here and are awaiting rebalancing to the underlyingToken by strategists
    uint256 public outstandingAmount;

    /// @dev Intentionally unused DEPRECATED STORAGE VARIABLE to maintain contiguous state on proxy-wrapped contracts. Consider it a beautiful scar of incremental progress 📈
    /// @dev Keeping deprecated variables maintains consistent network-agnostic contract abis when moving to new chains and versions
    uint256[] deprecatedStorageArray; // Kept in to avoid storage collision bathTokens that are proxy upgraded

    /// @dev Intentionally unused DEPRECATED STORAGE VARIABLE to maintain contiguous state on proxy-wrapped contracts. Consider it a beautiful scar of incremental progress 📈
    mapping(uint256 => uint256) deprecatedMapping; // Kept in to avoid storage collision on bathTokens that are upgraded
    // *******************************************

    /// @notice  ** ERC-20 **
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    /// @notice EIP-2612
    bytes32 public DOMAIN_SEPARATOR;

    /// @notice EIP-2612
    /// @dev keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    /// @notice EIP-2612
    mapping(address => uint256) public nonces;

    /// @notice Array of Bonus ERC-20 tokens that are given as liquidity incentives to pool withdrawers
    address[] public bonusTokens;

    /// @notice Address of the OZ Vesting Wallet which acts as means to vest bonusToken incentives to pool HODLers
    IVestingWallet public rewardsVestingWallet;

    /// *** Events ***

    /// @notice ** ERC-20 **
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    /// @notice ** ERC-20 **
    event Transfer(address indexed from, address indexed to, uint256 value);

    /// @notice Time of Bath Token instantiation
    event LogInit(uint256 timeOfInit);

    /// @notice Log details about a pool deposit
    event LogDeposit(
        uint256 depositedAmt,
        IERC20 asset,
        uint256 sharesReceived,
        address depositor,
        uint256 underlyingBalance,
        uint256 outstandingAmount,
        uint256 totalSupply
    );

    /// @notice Log details about a pool withdraw
    event LogWithdraw(
        uint256 amountWithdrawn,
        IERC20 asset,
        uint256 sharesWithdrawn,
        address withdrawer,
        uint256 fee,
        address feeTo,
        uint256 underlyingBalance,
        uint256 outstandingAmount,
        uint256 totalSupply
    );

    /// @notice Log details about a pool rebalance
    event LogRebalance(
        IERC20 pool_asset,
        address destination,
        IERC20 transferAsset,
        uint256 rebalAmt,
        uint256 stratReward,
        uint256 underlyingBalance,
        uint256 outstandingAmount,
        uint256 totalSupply
    );

    /// @notice Log details about a pool order canceled in the Rubicon Market book
    event LogPoolCancel(
        uint256 orderId,
        IERC20 pool_asset,
        uint256 outstandingAmountToCancel,
        uint256 underlyingBalance,
        uint256 outstandingAmount,
        uint256 totalSupply
    );

    /// @notice Log details about a pool order placed in the Rubicon Market book
    event LogPoolOffer(
        uint256 id,
        IERC20 pool_asset,
        uint256 underlyingBalance,
        uint256 outstandingAmount,
        uint256 totalSupply
    );

    /// @notice Log the credit to outstanding amount for funds that have been filled market-making
    event LogRemoveFilledTradeAmount(
        IERC20 pool_asset,
        uint256 fillAmount,
        uint256 underlyingBalance,
        uint256 outstandingAmount,
        uint256 totalSupply
    );

    /// @notice * EIP 4626 *
    event Deposit(
        address indexed caller,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /// @notice * EIP 4626 *
    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /// @notice Log bonus token reward event
    event LogClaimBonusTokn(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares,
        IERC20 bonusToken
    );

    /// *** Constructor ***

    /// @notice Proxy-safe initialization of storage; the constructor
    function initialize(
        ERC20 token,
        address market,
        address _feeTo
    ) external {
        require(!initialized);
        string memory _symbol = string(
            abi.encodePacked(("bath"), token.symbol())
        );
        symbol = _symbol;
        underlyingToken = token;
        RubiconMarketAddress = market;
        bathHouse = msg.sender; //NOTE: assumed admin is creator on BathHouse

        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                ),
                keccak256(bytes(name)),
                keccak256(bytes("1")),
                chainId,
                address(this)
            )
        );
        name = string(abi.encodePacked(_symbol, (" v1")));
        decimals = token.decimals(); // v1 Change - 4626 Adherence

        // Add infinite approval of Rubicon Market for this asset
        IERC20(address(token)).approve(RubiconMarketAddress, 2**256 - 1);
        emit LogInit(block.timestamp);

        feeTo = address(this); //This contract is the fee recipient, rewarding HODLers
        feeBPS = 3; //Fee set to 3 BPS initially

        // Complete constract instantiation
        initialized = true;
    }

    /// *** Modifiers ***

    modifier onlyPair() {
        require(
            IBathHouse(bathHouse).isApprovedPair(msg.sender) == true,
            "not an approved pair - bathToken"
        );
        _;
    }

    modifier onlyBathHouse() {
        require(
            msg.sender == bathHouse,
            "caller is not bathHouse - BathToken.sol"
        );
        _;
    }

    /// *** External Functions - Only Bath House / Admin ***

    /// @notice Admin-only function to set a Bath Token's market address
    function setMarket(address newRubiconMarket) external onlyBathHouse {
        RubiconMarketAddress = newRubiconMarket;
    }

    /// @notice Admin-only function to set a Bath Token's Bath House admin
    function setBathHouse(address newBathHouse) external onlyBathHouse {
        bathHouse = newBathHouse;
    }

    /// @notice Admin-only function to approve Bath Token's RubiconMarketAddress with the maximum integer value (infinite approval)
    function approveMarket() external onlyBathHouse {
        underlyingToken.approve(RubiconMarketAddress, 2**256 - 1);
    }

    /// @notice Admin-only function to set a Bath Token's feeBPS
    function setFeeBPS(uint256 _feeBPS) external onlyBathHouse {
        feeBPS = _feeBPS;
    }

    /// @notice Admin-only function to set a Bath Token's fee recipient, typically the pool itself
    function setFeeTo(address _feeTo) external onlyBathHouse {
        feeTo = _feeTo;
    }

    /// @notice Admin-only function to add a bonus token to bonusTokens for pool incentives
    function setBonusToken(address newBonusERC20) external onlyBathHouse {
        bonusTokens.push(newBonusERC20);
    }

    /// *** External Functions - Only Approved Bath Pair / Strategist Contract ***

    /// ** Rubicon Market Functions **

    /// @notice The function for a strategist to cancel an outstanding Market Offer
    function cancel(uint256 id, uint256 amt) external onlyPair {
        outstandingAmount = outstandingAmount.sub(amt);
        IRubiconMarket(RubiconMarketAddress).cancel(id);

        emit LogPoolCancel(
            id,
            IERC20(underlyingToken),
            amt,
            underlyingBalance(),
            outstandingAmount,
            totalSupply
        );
    }

    /// @notice A function called by BathPair to maintain proper accounting of outstandingAmount
    function removeFilledTradeAmount(uint256 amt) external onlyPair {
        outstandingAmount = outstandingAmount.sub(amt);
        emit LogRemoveFilledTradeAmount(
            IERC20(underlyingToken),
            amt,
            underlyingBalance(),
            outstandingAmount,
            totalSupply
        );
    }

    /// @notice The function that places a bid and/or ask in the orderbook for a given pair from this pool
    function placeOffer(
        uint256 pay_amt,
        ERC20 pay_gem,
        uint256 buy_amt,
        ERC20 buy_gem
    ) external onlyPair returns (uint256) {
        // Place an offer in RubiconMarket
        // If incomplete offer return 0
        if (
            pay_amt == 0 ||
            pay_gem == ERC20(0) ||
            buy_amt == 0 ||
            buy_gem == ERC20(0)
        ) {
            return 0;
        }

        uint256 id = IRubiconMarket(RubiconMarketAddress).offer(
            pay_amt,
            pay_gem,
            buy_amt,
            buy_gem,
            0,
            false
        );
        outstandingAmount = outstandingAmount.add(pay_amt);

        emit LogPoolOffer(
            id,
            IERC20(underlyingToken),
            underlyingBalance(),
            outstandingAmount,
            totalSupply
        );
        return (id);
    }

    /// @notice This function returns filled orders to the correct liquidity pool and sends strategist rewards to the Bath Pair
    /// @dev Sends non-underlyingToken fill elsewhere in the Pools system, typically it's sister asset within a trading pair (e.g. ETH-USDC)
    /// @dev Strategists presently accrue rewards in the filled asset not underlyingToken
    function rebalance(
        address destination,
        address filledAssetToRebalance, /* sister or fill asset */
        uint256 stratProportion,
        uint256 rebalAmt
    ) external onlyPair {
        uint256 stratReward = (stratProportion.mul(rebalAmt)).div(10000);
        IERC20(filledAssetToRebalance).transfer(
            destination,
            rebalAmt.sub(stratReward)
        );
        IERC20(filledAssetToRebalance).transfer(msg.sender, stratReward);

        emit LogRebalance(
            IERC20(underlyingToken),
            destination,
            IERC20(filledAssetToRebalance),
            rebalAmt,
            stratReward,
            underlyingBalance(),
            outstandingAmount,
            totalSupply
        );
    }

    /// *** EIP 4626 Implementation ***
    // https://eips.ethereum.org/EIPS/eip-4626#specification

    /// @notice Withdraw your bathTokens for the underlyingToken
    function withdraw(uint256 _shares)
        external
        returns (uint256 amountWithdrawn)
    {
        return _withdraw(_shares, msg.sender);
    }

    /// @notice * EIP 4626 *
    function asset() public view returns (address assetTokenAddress) {
        assetTokenAddress = address(underlyingToken);
    }

    /// @notice * EIP 4626 *
    function totalAssets() public view returns (uint256 totalManagedAssets) {
        return underlyingBalance();
    }

    /// @notice * EIP 4626 *
    function convertToShares(uint256 assets)
        public
        view
        returns (uint256 shares)
    {
        // Note: Inflationary tokens may affect this logic
        (totalSupply == 0) ? shares = assets : shares = (
            assets.mul(totalSupply)
        )
        .div(totalAssets());
    }

    // Note: MUST NOT be inclusive of any fees that are charged against assets in the Vault.
    /// @notice * EIP 4626 *
    function convertToAssets(uint256 shares)
        public
        view
        returns (uint256 assets)
    {
        assets = (totalAssets().mul(shares)).div(totalSupply);
    }

    // Note: Unused function param to adhere to standard
    /// @notice * EIP 4626 *
    function maxDeposit(address receiver)
        public
        pure
        returns (uint256 maxAssets)
    {
        maxAssets = 2**256 - 1; // No limit on deposits in current implementation  = Max UINT
    }

    /// @notice * EIP 4626 *
    function previewDeposit(uint256 assets)
        public
        view
        returns (uint256 shares)
    {
        // The exact same logic is used, no deposit fee - only difference is deflationary token check (rare condition and probably redundant)
        shares = convertToShares(assets);
    }

    // Single asset override to reflect old functionality
    function deposit(uint256 assets) public returns (uint256 shares) {
        // Note: msg.sender is the same throughout the same contract context
        return _deposit(assets, msg.sender);
    }

    /// @notice * EIP 4626 *
    function deposit(uint256 assets, address receiver)
        public
        returns (uint256 shares)
    {
        return _deposit(assets, receiver);
    }

    // Note: Unused function param to adhere to standard
    /// @notice * EIP 4626 *
    function maxMint(address receiver) public pure returns (uint256 maxShares) {
        maxShares = 2**256 - 1; // No limit on shares that could be created via deposit in current implementation - Max UINT
    }

    // Given I want these shares, how much do I have to deposit
    /// @notice * EIP 4626 *
    function previewMint(uint256 shares) public view returns (uint256 assets) {
        (totalSupply == 0) ? assets = shares : assets = (
            shares.mul(totalAssets())
        )
        .div(totalSupply);
    }

    // Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
    /// @notice * EIP 4626 *
    function mint(uint256 shares, address receiver)
        public
        returns (uint256 assets)
    {
        assets = previewMint(shares);
        uint256 _shares = _deposit(assets, receiver);
        require(_shares == shares, "did not mint expected share count");
    }

    // A user can withdraw whatever they hold
    /// @notice * EIP 4626 *
    function maxWithdraw(address owner)
        public
        view
        returns (uint256 maxAssets)
    {
        if (totalSupply == 0) {
            maxAssets = 0;
        } else {
            uint256 ownerShares = balanceOf[owner];
            maxAssets = convertToAssets(ownerShares);
        }
    }

    /// @notice * EIP 4626 *
    function previewWithdraw(uint256 assets)
        public
        view
        returns (uint256 shares)
    {
        if (totalSupply == 0) {
            shares = 0;
        } else {
            uint256 amountWithdrawn;
            uint256 _fee = assets.mul(feeBPS).div(10000);
            amountWithdrawn = assets.sub(_fee);
            shares = convertToShares(amountWithdrawn);
        }
    }

    /// @notice * EIP 4626 *
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public returns (uint256 shares) {
        require(
            owner == msg.sender,
            "This implementation does not support non-sender owners from withdrawing user shares"
        );
        uint256 expectedShares = previewWithdraw(assets);
        uint256 assetsReceived = _withdraw(expectedShares, receiver);
        require(
            assetsReceived >= assets,
            "You cannot withdraw the amount of assets you expected"
        );
        shares = expectedShares;
    }

    // Constraint: msg.sender is owner of shares when withdrawing
    /// @notice * EIP 4626 *
    function maxRedeem(address owner) public view returns (uint256 maxShares) {
        return balanceOf[owner];
    }

    // Constraint: msg.sender is owner of shares when withdrawing
    /// @notice * EIP 4626 *
    function previewRedeem(uint256 shares)
        public
        view
        returns (uint256 assets)
    {
        uint256 r = (underlyingBalance().mul(shares)).div(totalSupply);
        uint256 _fee = r.mul(feeBPS).div(10000);
        assets = r.sub(_fee);
    }

    /// @notice * EIP 4626 *
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public returns (uint256 assets) {
        require(
            owner == msg.sender,
            "This implementation does not support non-sender owners from withdrawing user shares"
        );
        assets = _withdraw(shares, receiver);
    }

    /// *** Internal Functions ***

    /// @notice Deposit assets for the user and mint Bath Token shares to receiver
    function _deposit(uint256 assets, address receiver)
        internal
        returns (uint256 shares)
    {
        uint256 _pool = underlyingBalance();
        uint256 _before = underlyingToken.balanceOf(address(this));

        // **Assume caller is depositor**
        underlyingToken.transferFrom(msg.sender, address(this), assets);
        uint256 _after = underlyingToken.balanceOf(address(this));
        assets = _after.sub(_before); // Additional check for deflationary tokens

        (totalSupply == 0) ? shares = assets : shares = (
            assets.mul(totalSupply)
        )
        .div(_pool);


        // Send shares to designated target
        _mint(receiver, shares);
        emit LogDeposit(
            assets,
            underlyingToken,
            shares,
            msg.sender,
            underlyingBalance(),
            outstandingAmount,
            totalSupply
        );
        emit Deposit(msg.sender, msg.sender, assets, shares);
    }

    /// @notice Withdraw share for the user and send underlyingToken to receiver with any accrued yield and incentive tokens
    function _withdraw(uint256 _shares, address receiver)
        internal
        returns (uint256 amountWithdrawn)
    {
        uint256 _initialTotalSupply = totalSupply;

        // Distribute network rewards first in order to handle bonus token == underlying token case; it only releases vested tokens in this call
        distributeBonusTokenRewards(receiver, _shares, _initialTotalSupply);

        uint256 r = (underlyingBalance().mul(_shares)).div(_initialTotalSupply);
        _burn(msg.sender, _shares);
        uint256 _fee = r.mul(feeBPS).div(10000);
        // If FeeTo == address(0) then the fee is effectively accrued by the pool
        if (feeTo != address(0)) {
            underlyingToken.transfer(feeTo, _fee);
        }
        amountWithdrawn = r.sub(_fee);
        underlyingToken.transfer(receiver, amountWithdrawn);

        emit LogWithdraw(
            amountWithdrawn,
            underlyingToken,
            _shares,
            msg.sender,
            _fee,
            feeTo,
            underlyingBalance(),
            outstandingAmount,
            totalSupply
        );
        emit Withdraw(
            msg.sender,
            receiver,
            msg.sender,
            amountWithdrawn,
            _shares
        );
    }

    /// @notice Function to distibute non-underlyingToken Bath Token incentives to pool withdrawers
    /// @dev Note that bonusTokens adhere to the same feeTo and feeBPS pattern
    /// @dev Note the edge case in which the bonus token is the underlyingToken, here we simply release() to the pool and skip
    function distributeBonusTokenRewards(
        address receiver,
        uint256 sharesWithdrawn,
        uint256 initialTotalSupply
    ) internal {
        // Verbose check:
        // require(initialTotalSupply == sharesWithdrawn + totalSupply);
        if (bonusTokens.length > 0) {
            for (uint256 index = 0; index < bonusTokens.length; index++) {
                IERC20 token = IERC20(bonusTokens[index]);

                // Pair each bonus token with an OZ Vesting wallet. Each time a user withdraws, they can release() the
                //  vested amount to this pool. Note, this pool must be the beneficiary of the VestingWallet.
                if (rewardsVestingWallet != IVestingWallet(0)) {
                    rewardsVestingWallet.release(address(token));
                }

                // avoid underlyingToken == token double spend
                if (address(token) == address(underlyingToken)) {
                    continue; // Skip because logic below fails on underlying token and release() already called so bonus tokens are already accrued and withdrawn
                }

                uint256 bonusTokenBalance = token.balanceOf(address(this));
                if (bonusTokenBalance > 0) {
                    uint256 amount = bonusTokenBalance.mul(sharesWithdrawn).div(
                        initialTotalSupply
                    );
                    // Note: Shares already burned in _withdraw

                    uint256 _fee = amount.mul(feeBPS).div(10000);
                    // If FeeTo == address(0) then the fee is effectively accrued by the pool
                    if (feeTo != address(0)) {
                        token.transfer(feeTo, _fee);
                    }
                    uint256 amountWithdrawn = amount.sub(_fee);
                    token.transfer(receiver, amountWithdrawn);

                    emit LogClaimBonusTokn(
                        msg.sender,
                        receiver,
                        msg.sender,
                        amountWithdrawn,
                        sharesWithdrawn,
                        token
                    );
                }
            }
        }
    }

    /// *** ERC - 20 Standard ***

    function _mint(address to, uint256 value) internal {
        totalSupply = totalSupply.add(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(address(0), to, value);
    }

    function _burn(address from, uint256 value) internal {
        balanceOf[from] = balanceOf[from].sub(value);
        totalSupply = totalSupply.sub(value);
        emit Transfer(from, address(0), value);
    }

    function _approve(
        address owner,
        address spender,
        uint256 value
    ) private {
        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _transfer(
        address from,
        address to,
        uint256 value
    ) private {
        balanceOf[from] = balanceOf[from].sub(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(from, to, value);
    }

    function approve(address spender, uint256 value) external returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool) {
        if (allowance[from][msg.sender] != uint256(-1)) {
            allowance[from][msg.sender] = allowance[from][msg.sender].sub(
                value
            );
        }
        _transfer(from, to, value);
        return true;
    }

    /// @notice EIP 2612
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        require(deadline >= block.timestamp, "bathToken: EXPIRED");
        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(
                    abi.encode(
                        PERMIT_TYPEHASH,
                        owner,
                        spender,
                        value,
                        nonces[owner]++,
                        deadline
                    )
                )
            )
        );
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(
            recoveredAddress != address(0) && recoveredAddress == owner,
            "bathToken: INVALID_SIGNATURE"
        );
        _approve(owner, spender, value);
    }

    /// *** View Functions ***

    /// @notice The underlying ERC-20 that this bathToken handles
    function underlyingERC20() external view returns (address) {
        return address(underlyingToken);
    }

    /// @notice The best-guess total claim on assets the Bath Token has
    /// @dev returns the amount of underlying ERC20 tokens in this pool in addition to any tokens that are outstanding in the Rubicon order book seeking market-making yield (outstandingAmount)
    function underlyingBalance() public view returns (uint256) {
        uint256 _pool = IERC20(underlyingToken).balanceOf(address(this));
        return _pool.add(outstandingAmount);
    }
}

File 2 of 8 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../../utils/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";

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

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

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

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

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

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

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

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

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

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

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

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

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

        _beforeTokenTransfer(address(0), account, amount);

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

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

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

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

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

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal virtual {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

File 3 of 8 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

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

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

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

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

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        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) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        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, reverting 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) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

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

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

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * 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);
        return a / b;
    }

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

File 4 of 8 : IBathHouse.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.7.6;

interface IBathHouse {
    function getMarket() external view returns (address);

    function initialized() external returns (bool);

    function reserveRatio() external view returns (uint256);

    function tokenToBathToken(address erc20Address)
        external
        view
        returns (address bathTokenAddress);

    function isApprovedStrategist(address wouldBeStrategist)
        external
        view
        returns (bool);

    function getBPSToStrats() external view returns (uint8);

    function isApprovedPair(address pair) external view returns (bool);
}

File 5 of 8 : IRubiconMarket.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IRubiconMarket {
    function cancel(uint256 id) external;

    function offer(
        uint256 pay_amt, //maker (ask) sell how much
        IERC20 pay_gem, //maker (ask) sell which token
        uint256 buy_amt, //maker (ask) buy how much
        IERC20 buy_gem, //maker (ask) buy which token
        uint256 pos, //position to insert offer, 0 should be used if unknown
        bool matching //match "close enough" orders?
    ) external returns (uint256);

    // Get best offer
    function getBestOffer(IERC20 sell_gem, IERC20 buy_gem)
        external
        view
        returns (uint256);

    // get offer
    function getOffer(uint256 id)
        external
        view
        returns (
            uint256,
            IERC20,
            uint256,
            IERC20
        );
}

File 6 of 8 : IVestingWallet.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.7.6;

interface IVestingWallet {
    function beneficiary() external view returns (address);

    function release(address token) external;

    function vestedAmount(address token, uint64 timestamp)
        external
        view
        returns (uint256);
}

File 7 of 8 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 8 of 8 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface 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.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"bonusToken","type":"address"}],"name":"LogClaimBonusTokn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"depositedAmt","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesReceived","type":"uint256"},{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outstandingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timeOfInit","type":"uint256"}],"name":"LogInit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"pool_asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"outstandingAmountToCancel","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outstandingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogPoolCancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"pool_asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outstandingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogPoolOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"pool_asset","type":"address"},{"indexed":false,"internalType":"address","name":"destination","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"transferAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"rebalAmt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stratReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outstandingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogRebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"pool_asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"fillAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outstandingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogRemoveFilledTradeAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountWithdrawn","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesWithdrawn","type":"uint256"},{"indexed":false,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outstandingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RubiconMarketAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"approveMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"assetTokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bathHouse","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bonusTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"_feeTo","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"outstandingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract ERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract ERC20","name":"buy_gem","type":"address"}],"name":"placeOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"destination","type":"address"},{"internalType":"address","name":"filledAssetToRebalance","type":"address"},{"internalType":"uint256","name":"stratProportion","type":"uint256"},{"internalType":"uint256","name":"rebalAmt","type":"uint256"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"removeFilledTradeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsVestingWallet","outputs":[{"internalType":"contract IVestingWallet","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBathHouse","type":"address"}],"name":"setBathHouse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newBonusERC20","type":"address"}],"name":"setBonusToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeBPS","type":"uint256"}],"name":"setFeeBPS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRubiconMarket","type":"address"}],"name":"setMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalManagedAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlyingBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingERC20","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"amountWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50612e5b806100206000396000f3fe608060405234801561001057600080fd5b50600436106102665760003560e01c8062efa8951461026b578063017e7e581461029057806301e1d114146102b457806306fdde03146102ce57806307a2d13a1461034b578063095ea7b3146103685780630a28a477146103a8578063158ef93e146103c557806318160ddd146103cd5780631a1c6e53146103d557806323b872dd146103dd5780632495a59914610413578063271e44261461041b5780632e1a7d4d1461045757806330adf81f14610474578063313ce5671461047c5780633644e5151461049a57806338d52e0f146104a25780633c8f96f1146104aa578063402d267d146104c75780634cdad506146104ed57806359356c5c1461050a578063604b6a9c1461051257806360c38b281461052f57806360f71b24146105375780636823b523146104a25780636dcea85f1461053f5780636e49db1c146105655780636e553f65146105a157806370a08231146105cd5780637ecebe00146105f3578063831d26781461061957806394bf804d1461063657806395d89b4114610662578063a9059cbb1461066a578063b2eaeaaa14610696578063b3d7f6b9146106bc578063b42337c9146106d9578063b460af94146106e1578063b6b55f2514610715578063ba08765214610732578063bd0b172214610766578063c0c53b8b1461076e578063c2560f2a146107a6578063c63d75b6146104c7578063c6e6f592146107ae578063ce96cb77146107cb578063d505accf146107f1578063d905777e14610842578063dd62ed3e14610868578063ebbc208214610896578063ef8b30f7146108bc578063f46901ed146108d9575b600080fd5b61028e6004803603604081101561028157600080fd5b50803590602001356108ff565b005b610298610ab1565b604080516001600160a01b039092168252519081900360200190f35b6102bc610ac0565b60408051918252519081900360200190f35b6102d6610acf565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103105781810151838201526020016102f8565b50505050905090810190601f16801561033d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bc6004803603602081101561036157600080fd5b5035610b5a565b6103946004803603604081101561037e57600080fd5b506001600160a01b038135169060200135610b80565b604080519115158252519081900360200190f35b6102bc600480360360208110156103be57600080fd5b5035610b96565b610394610bea565b6102bc610bf3565b6102bc610bf9565b610394600480360360608110156103f357600080fd5b506001600160a01b03813581169160208101359091169060400135610bff565b610298610c93565b6102bc6004803603608081101561043157600080fd5b508035906001600160a01b03602082013581169160408101359160609091013516610ca2565b6102bc6004803603602081101561046d57600080fd5b5035610ed0565b6102bc610edc565b610484610eee565b6040805160ff9092168252519081900360200190f35b6102bc610ef7565b610298610efd565b610298600480360360208110156104c057600080fd5b5035610f0c565b6102bc600480360360208110156104dd57600080fd5b50356001600160a01b0316610f36565b6102bc6004803603602081101561050357600080fd5b5035610f3d565b6102bc610f7d565b61028e6004803603602081101561052857600080fd5b5035611010565b61029861105e565b61029861106d565b61028e6004803603602081101561055557600080fd5b50356001600160a01b0316611081565b61028e6004803603608081101561057b57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356110f2565b6102bc600480360360408110156105b757600080fd5b50803590602001356001600160a01b031661135f565b6102bc600480360360208110156105e357600080fd5b50356001600160a01b0316611372565b6102bc6004803603602081101561060957600080fd5b50356001600160a01b0316611384565b61028e6004803603602081101561062f57600080fd5b5035611396565b6102bc6004803603604081101561064c57600080fd5b50803590602001356001600160a01b03166114d6565b6102d6611536565b6103946004803603604081101561068057600080fd5b506001600160a01b038135169060200135611590565b61028e600480360360208110156106ac57600080fd5b50356001600160a01b031661159d565b6102bc600480360360208110156106d257600080fd5b5035611638565b6102bc61166e565b6102bc600480360360608110156106f757600080fd5b508035906001600160a01b0360208201358116916040013516611674565b6102bc6004803603602081101561072b57600080fd5b5035611720565b6102bc6004803603606081101561074857600080fd5b508035906001600160a01b036020820135811691604001351661172c565b61029861177f565b61028e6004803603606081101561078457600080fd5b506001600160a01b03813581169160208101358216916040909101351661178e565b61028e611c7e565b6102bc600480360360208110156107c457600080fd5b5035611d54565b6102bc600480360360208110156107e157600080fd5b50356001600160a01b0316611d79565b61028e600480360360e081101561080757600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611db0565b6102bc6004803603602081101561085857600080fd5b50356001600160a01b0316611f9f565b6102bc6004803603604081101561087e57600080fd5b506001600160a01b0381358116916020013516611fba565b61028e600480360360208110156108ac57600080fd5b50356001600160a01b0316611fd7565b6102bc600480360360208110156108d257600080fd5b5035612042565b61028e600480360360208110156108ef57600080fd5b50356001600160a01b031661204d565b600480546040805163ca3a86cd60e01b81523393810193909352516001600160a01b039091169163ca3a86cd916024808301926020929190829003018186803b15801561094b57600080fd5b505afa15801561095f573d6000803e3d6000fd5b505050506040513d602081101561097557600080fd5b505115156001146109bb576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b6009546109c890826120b8565b600955600354604080516340e58ee560e01b81526004810185905290516101009092046001600160a01b0316916340e58ee59160248082019260009290919082900301818387803b158015610a1c57600080fd5b505af1158015610a30573d6000803e3d6000fd5b50506006547f948b667935c2235a252417dceae34a9e3b516f743acdd8fc849e9ebcae16147692508491506001600160a01b031683610a6d610f7d565b600954600854604080519687526001600160a01b039095166020870152858501939093526060850191909152608084015260a0830152519081900360c00190a15050565b6005546001600160a01b031681565b6000610aca610f7d565b905090565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610b525780601f10610b2757610100808354040283529160200191610b52565b820191906000526020600020905b815481529060010190602001808311610b3557829003601f168201915b505050505081565b6000610b7a600854610b7484610b6e610ac0565b90612115565b9061216e565b92915050565b6000610b8d3384846121d2565b50600192915050565b600060085460001415610bab57506000610be5565b600080610bc9612710610b746007548761211590919063ffffffff16565b9050610bd584826120b8565b9150610be082611d54565b925050505b919050565b60005460ff1681565b60085481565b60075481565b6001600160a01b0383166000908152600d6020908152604080832033845290915281205460001914610c7e576001600160a01b0384166000908152600d60209081526040808320338452909152902054610c5990836120b8565b6001600160a01b0385166000908152600d602090815260408083203384529091529020555b610c89848484612234565b5060019392505050565b6006546001600160a01b031681565b600480546040805163ca3a86cd60e01b81523393810193909352516000926001600160a01b039092169163ca3a86cd916024808301926020929190829003018186803b158015610cf157600080fd5b505afa158015610d05573d6000803e3d6000fd5b505050506040513d6020811015610d1b57600080fd5b50511515600114610d61576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b841580610d7557506001600160a01b038416155b80610d7e575082155b80610d9057506001600160a01b038216155b15610d9d57506000610ec8565b60035460408051633869bc0560e21b8152600481018890526001600160a01b03878116602483015260448201879052858116606483015260006084830181905260a48301819052925192936101009004169163e1a6f0149160c48082019260209290919082900301818787803b158015610e1657600080fd5b505af1158015610e2a573d6000803e3d6000fd5b505050506040513d6020811015610e4057600080fd5b5051600954909150610e5290876122d0565b6009556006547f360c58efcda3cbfaa91dd0fbb328656f6fa68693aa284a863dd4d659d4f9e1369082906001600160a01b0316610e8d610f7d565b600954600854604080519586526001600160a01b0390941660208601528484019290925260608401526080830152519081900360a00190a190505b949350505050565b6000610b7a8233612328565b600080516020612de683398151915281565b60035460ff1681565b600e5481565b6006546001600160a01b031690565b60108181548110610f1c57600080fd5b6000918252602090912001546001600160a01b0316905081565b5060001990565b600080610f52600854610b7485610b6e610f7d565b90506000610f71612710610b746007548561211590919063ffffffff16565b9050610be082826120b8565b600654604080516370a0823160e01b8152306004820152905160009283926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b158015610fcd57600080fd5b505afa158015610fe1573d6000803e3d6000fd5b505050506040513d6020811015610ff757600080fd5b505160095490915061100a9082906122d0565b91505090565b6004546001600160a01b031633146110595760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600755565b6004546001600160a01b031681565b60035461010090046001600160a01b031681565b6004546001600160a01b031633146110ca5760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600480546040805163ca3a86cd60e01b81523393810193909352516001600160a01b039091169163ca3a86cd916024808301926020929190829003018186803b15801561113e57600080fd5b505afa158015611152573d6000803e3d6000fd5b505050506040513d602081101561116857600080fd5b505115156001146111ae576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b60006111c0612710610b748585612115565b90506001600160a01b03841663a9059cbb866111dc85856120b8565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505050506040513d602081101561124c57600080fd5b50506040805163a9059cbb60e01b81523360048201526024810183905290516001600160a01b0386169163a9059cbb9160448083019260209291908290030181600087803b15801561129d57600080fd5b505af11580156112b1573d6000803e3d6000fd5b505050506040513d60208110156112c757600080fd5b50506006547f9fc6dffd7a9978e1ea266a3324e9ed3e3011b1878fbe0074a699519561d7a87a906001600160a01b031686868585611303610f7d565b600954600854604080516001600160a01b03998a168152978916602089015295909716868601526060860193909352608085019190915260a084015260c083015260e08201929092529051908190036101000190a15050505050565b600061136b8383612593565b9392505050565b600c6020526000908152604090205481565b600f6020526000908152604090205481565b600480546040805163ca3a86cd60e01b81523393810193909352516001600160a01b039091169163ca3a86cd916024808301926020929190829003018186803b1580156113e257600080fd5b505afa1580156113f6573d6000803e3d6000fd5b505050506040513d602081101561140c57600080fd5b50511515600114611452576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b60095461145f90826120b8565b6009556006547fb2e3b8ff25f9ea875d9c7d1332a97a955997395e3aae7cc9a0e20ab8c7279d16906001600160a01b031682611499610f7d565b600954600854604080516001600160a01b03909616865260208601949094528484019290925260608401526080830152519081900360a00190a150565b60006114e183611638565b905060006114ef8284612593565b905083811461152f5760405162461bcd60e51b8152600401808060200182810382526021815260200180612d846021913960400191505060405180910390fd5b5092915050565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610b525780601f10610b2757610100808354040283529160200191610b52565b6000610b8d338484612234565b6004546001600160a01b031633146115e65760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b601080546001810182556000919091527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b0319166001600160a01b0392909216919091179055565b60006008546000146116645761165c600854610b74611655610ac0565b8590612115565b905080611668565b5080805b50919050565b60095481565b60006001600160a01b03821633146116bd5760405162461bcd60e51b8152600401808060200182810382526053815260200180612d316053913960600191505060405180910390fd5b60006116c885610b96565b905060006116d68286612328565b9050858110156117175760405162461bcd60e51b8152600401808060200182810382526035815260200180612cd56035913960400191505060405180910390fd5b50949350505050565b6000610b7a8233612593565b60006001600160a01b03821633146117755760405162461bcd60e51b8152600401808060200182810382526053815260200180612d316053913960600191505060405180910390fd5b610ec88484612328565b6011546001600160a01b031681565b60005460ff161561179e57600080fd5b6000836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561181657600080fd5b8101908080516040519392919084600160201b82111561183557600080fd5b90830190602082018581111561184a57600080fd5b8251600160201b81118282018810171561186357600080fd5b82525081516020918201929091019080838360005b83811015611890578181015183820152602001611878565b50505050905090810190601f1680156118bd5780820380516001836020036101000a031916815260200191505b506040525050506040516020018080630c4c2e8d60e31b81525060040182805190602001908083835b602083106119055780518252601f1990920191602091820191016118e6565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405290508060019080519060200190611951929190612c33565b50600680546001600160a01b03199081166001600160a01b038781169190911790925560038054610100600160a81b0319166101009387168402179055600480543392169190911790556040516002805446937f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f939182918491600181161590910260001901168190048015611a1e5780601f106119fc576101008083540402835291820191611a1e565b820191906000526020600020905b815481529060010190602001808311611a0a575b505060408051918290038220828201825260018352603160f81b602093840152815180840196909652858201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060860152608085018690523060a0808701919091528151808703909101815260c08601909152805190820120600e558551869460e0019350839250908401908083835b60208310611acf5780518252601f199092019160209182019101611ab0565b51815160209384036101000a60001901801990921691161790526220763160e81b9190930190815260408051808303601c19018152600390920190528051611b209550600294509201919050612c33565b50846001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611b5a57600080fd5b505afa158015611b6e573d6000803e3d6000fd5b505050506040513d6020811015611b8457600080fd5b50516003805460ff191660ff90921691909117908190556040805163095ea7b360e01b81526001600160a01b0361010090930483166004820152600019602482015290519187169163095ea7b3916044808201926020929091908290030181600087803b158015611bf457600080fd5b505af1158015611c08573d6000803e3d6000fd5b505050506040513d6020811015611c1e57600080fd5b50506040805142815290517f62d3d1f1d9801a81e18d50c29dbd4af6f8aa76a0859f432482ac2574e3d2a4f69181900360200190a15050600580546001600160a01b0319163017905550506003600755506000805460ff19166001179055565b6004546001600160a01b03163314611cc75760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b6006546003546040805163095ea7b360e01b81526101009092046001600160a01b0390811660048401526000196024840152905192169163095ea7b3916044808201926020929091908290030181600087803b158015611d2657600080fd5b505af1158015611d3a573d6000803e3d6000fd5b505050506040513d6020811015611d5057600080fd5b5050565b60006008546000146116645761165c611d6b610ac0565b600854610b74908590612115565b600060085460001415611d8e57506000610be5565b6001600160a01b0382166000908152600c602052604090205461136b81610b5a565b42841015611dfa576040805162461bcd60e51b815260206004820152601260248201527118985d1a151bdad95b8e881156141254915160721b604482015290519081900360640190fd5b600e546001600160a01b038089166000818152600f60209081526040808320805460018082019092558251600080516020612de68339815191528186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e08501825280519083012061190160f01b6101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e280820193601f1981019281900390910190855afa158015611f03573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611f395750886001600160a01b0316816001600160a01b0316145b611f89576040805162461bcd60e51b815260206004820152601c60248201527b62617468546f6b656e3a20494e56414c49445f5349474e415455524560201b604482015290519081900360640190fd5b611f948989896121d2565b505050505050505050565b6001600160a01b03166000908152600c602052604090205490565b600d60209081526000928352604080842090915290825290205481565b6004546001600160a01b031633146120205760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000610b7a82611d54565b6004546001600160a01b031633146120965760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b60008282111561210f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60008261212457506000610b7a565b8282028284828161213157fe5b041461136b5760405162461bcd60e51b8152600401808060200182810382526021815260200180612da56021913960400191505060405180910390fd5b60008082116121c1576040805162461bcd60e51b815260206004820152601a602482015279536166654d6174683a206469766973696f6e206279207a65726f60301b604482015290519081900360640190fd5b8183816121ca57fe5b049392505050565b6001600160a01b038084166000818152600d6020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166000908152600c602052604090205461225790826120b8565b6001600160a01b038085166000908152600c6020526040808220939093559084168152205461228690826122d0565b6001600160a01b038084166000818152600c60209081526040918290209490945580518581529051919392871692600080516020612dc683398151915292918290030190a3505050565b60008282018381101561136b576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b600854600090612339838583612832565b600061234b82610b7487610b6e610f7d565b90506123573386612b3b565b6000612374612710610b746007548561211590919063ffffffff16565b6005549091506001600160a01b03161561240e576006546005546040805163a9059cbb60e01b81526001600160a01b039283166004820152602481018590529051919092169163a9059cbb9160448083019260209291908290030181600087803b1580156123e157600080fd5b505af11580156123f5573d6000803e3d6000fd5b505050506040513d602081101561240b57600080fd5b50505b61241882826120b8565b6006546040805163a9059cbb60e01b81526001600160a01b03898116600483015260248201859052915193975091169163a9059cbb916044808201926020929091908290030181600087803b15801561247057600080fd5b505af1158015612484573d6000803e3d6000fd5b505050506040513d602081101561249a57600080fd5b50506006546005547f7e06a1682a005aab8a0eb8e6e366e1996b23069ddcf47931669eb54d6d2ede869186916001600160a01b03918216918a9133918791166124e1610f7d565b60095460085460408051998a526001600160a01b0398891660208b01528981019790975294871660608901526080880193909352941660a086015260c085019390935260e084019290925261010083019190915251908190036101200190a16040805185815260208101889052815133926001600160a01b0389169284927ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db929181900390910190a450505092915050565b60008061259e610f7d565b600654604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b1580156125ef57600080fd5b505afa158015612603573d6000803e3d6000fd5b505050506040513d602081101561261957600080fd5b5051600654604080516323b872dd60e01b81523360048201523060248201526044810189905290519293506001600160a01b03909116916323b872dd916064808201926020929091908290030181600087803b15801561267857600080fd5b505af115801561268c573d6000803e3d6000fd5b505050506040513d60208110156126a257600080fd5b5050600654604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156126ef57600080fd5b505afa158015612703573d6000803e3d6000fd5b505050506040513d602081101561271957600080fd5b5051905061272781836120b8565b95506008546000146127545761274c83610b746008548961211590919063ffffffff16565b935083612759565b859350835b506127648585612bba565b6006547f98c2489a97b81ca0e2c92a8e8c85cea665ca75cc1fee59262d8b604780bb58d69087906001600160a01b0316863361279e610f7d565b600954600854604080519788526001600160a01b03968716602089015287810195909552929094166060860152608085015260a084019290925260c0830191909152519081900360e00190a160408051878152602081018690528151339283927fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7929081900390910190a350505092915050565b60105415612b365760005b601054811015612b345760006010828154811061285657fe5b6000918252602090912001546011546001600160a01b03918216925016156128df5760115460408051631916558760e01b81526001600160a01b03848116600483015291519190921691631916558791602480830192600092919082900301818387803b1580156128c657600080fd5b505af11580156128da573d6000803e3d6000fd5b505050505b6006546001600160a01b03828116911614156128fb5750612b2c565b6000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561294a57600080fd5b505afa15801561295e573d6000803e3d6000fd5b505050506040513d602081101561297457600080fd5b505190508015612b2957600061298e85610b748489612115565b905060006129ad612710610b746007548561211590919063ffffffff16565b6005549091506001600160a01b031615612a44576005546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810184905290519186169163a9059cbb916044808201926020929091908290030181600087803b158015612a1757600080fd5b505af1158015612a2b573d6000803e3d6000fd5b505050506040513d6020811015612a4157600080fd5b50505b6000612a5083836120b8565b9050846001600160a01b031663a9059cbb8a836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612aa957600080fd5b505af1158015612abd573d6000803e3d6000fd5b505050506040513d6020811015612ad357600080fd5b505060408051828152602081018a90526001600160a01b0387811682840152915133928c169183917f60b2262e5f86af935143ddc6a4d67100654fe2ff3b51081cfc767e6825031e5e9181900360600190a45050505b50505b60010161283d565b505b505050565b6001600160a01b0382166000908152600c6020526040902054612b5e90826120b8565b6001600160a01b0383166000908152600c6020526040902055600854612b8490826120b8565b6008556040805182815290516000916001600160a01b03851691600080516020612dc68339815191529181900360200190a35050565b600854612bc790826122d0565b6008556001600160a01b0382166000908152600c6020526040902054612bed90826122d0565b6001600160a01b0383166000818152600c60209081526040808320949094558351858152935192939192600080516020612dc68339815191529281900390910190a35050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612c695760008555612caf565b82601f10612c8257805160ff1916838001178555612caf565b82800160010185558215612caf579182015b82811115612caf578251825591602001919060010190612c94565b50612cbb929150612cbf565b5090565b5b80821115612cbb5760008155600101612cc056fe596f752063616e6e6f742077697468647261772074686520616d6f756e74206f662061737365747320796f7520657870656374656463616c6c6572206973206e6f742062617468486f757365202d2042617468546f6b656e2e736f6c5468697320696d706c656d656e746174696f6e20646f6573206e6f7420737570706f7274206e6f6e2d73656e646572206f776e6572732066726f6d207769746864726177696e67207573657220736861726573646964206e6f74206d696e7420657870656374656420736861726520636f756e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96e6f7420616e20617070726f7665642070616972202d2062617468546f6b656ea2646970667358221220b8d4138716ff3181755dd63d33a374bd91c97d88de58b464c96764f7b73df23464736f6c63430007060033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102665760003560e01c8062efa8951461026b578063017e7e581461029057806301e1d114146102b457806306fdde03146102ce57806307a2d13a1461034b578063095ea7b3146103685780630a28a477146103a8578063158ef93e146103c557806318160ddd146103cd5780631a1c6e53146103d557806323b872dd146103dd5780632495a59914610413578063271e44261461041b5780632e1a7d4d1461045757806330adf81f14610474578063313ce5671461047c5780633644e5151461049a57806338d52e0f146104a25780633c8f96f1146104aa578063402d267d146104c75780634cdad506146104ed57806359356c5c1461050a578063604b6a9c1461051257806360c38b281461052f57806360f71b24146105375780636823b523146104a25780636dcea85f1461053f5780636e49db1c146105655780636e553f65146105a157806370a08231146105cd5780637ecebe00146105f3578063831d26781461061957806394bf804d1461063657806395d89b4114610662578063a9059cbb1461066a578063b2eaeaaa14610696578063b3d7f6b9146106bc578063b42337c9146106d9578063b460af94146106e1578063b6b55f2514610715578063ba08765214610732578063bd0b172214610766578063c0c53b8b1461076e578063c2560f2a146107a6578063c63d75b6146104c7578063c6e6f592146107ae578063ce96cb77146107cb578063d505accf146107f1578063d905777e14610842578063dd62ed3e14610868578063ebbc208214610896578063ef8b30f7146108bc578063f46901ed146108d9575b600080fd5b61028e6004803603604081101561028157600080fd5b50803590602001356108ff565b005b610298610ab1565b604080516001600160a01b039092168252519081900360200190f35b6102bc610ac0565b60408051918252519081900360200190f35b6102d6610acf565b6040805160208082528351818301528351919283929083019185019080838360005b838110156103105781810151838201526020016102f8565b50505050905090810190601f16801561033d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bc6004803603602081101561036157600080fd5b5035610b5a565b6103946004803603604081101561037e57600080fd5b506001600160a01b038135169060200135610b80565b604080519115158252519081900360200190f35b6102bc600480360360208110156103be57600080fd5b5035610b96565b610394610bea565b6102bc610bf3565b6102bc610bf9565b610394600480360360608110156103f357600080fd5b506001600160a01b03813581169160208101359091169060400135610bff565b610298610c93565b6102bc6004803603608081101561043157600080fd5b508035906001600160a01b03602082013581169160408101359160609091013516610ca2565b6102bc6004803603602081101561046d57600080fd5b5035610ed0565b6102bc610edc565b610484610eee565b6040805160ff9092168252519081900360200190f35b6102bc610ef7565b610298610efd565b610298600480360360208110156104c057600080fd5b5035610f0c565b6102bc600480360360208110156104dd57600080fd5b50356001600160a01b0316610f36565b6102bc6004803603602081101561050357600080fd5b5035610f3d565b6102bc610f7d565b61028e6004803603602081101561052857600080fd5b5035611010565b61029861105e565b61029861106d565b61028e6004803603602081101561055557600080fd5b50356001600160a01b0316611081565b61028e6004803603608081101561057b57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356110f2565b6102bc600480360360408110156105b757600080fd5b50803590602001356001600160a01b031661135f565b6102bc600480360360208110156105e357600080fd5b50356001600160a01b0316611372565b6102bc6004803603602081101561060957600080fd5b50356001600160a01b0316611384565b61028e6004803603602081101561062f57600080fd5b5035611396565b6102bc6004803603604081101561064c57600080fd5b50803590602001356001600160a01b03166114d6565b6102d6611536565b6103946004803603604081101561068057600080fd5b506001600160a01b038135169060200135611590565b61028e600480360360208110156106ac57600080fd5b50356001600160a01b031661159d565b6102bc600480360360208110156106d257600080fd5b5035611638565b6102bc61166e565b6102bc600480360360608110156106f757600080fd5b508035906001600160a01b0360208201358116916040013516611674565b6102bc6004803603602081101561072b57600080fd5b5035611720565b6102bc6004803603606081101561074857600080fd5b508035906001600160a01b036020820135811691604001351661172c565b61029861177f565b61028e6004803603606081101561078457600080fd5b506001600160a01b03813581169160208101358216916040909101351661178e565b61028e611c7e565b6102bc600480360360208110156107c457600080fd5b5035611d54565b6102bc600480360360208110156107e157600080fd5b50356001600160a01b0316611d79565b61028e600480360360e081101561080757600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611db0565b6102bc6004803603602081101561085857600080fd5b50356001600160a01b0316611f9f565b6102bc6004803603604081101561087e57600080fd5b506001600160a01b0381358116916020013516611fba565b61028e600480360360208110156108ac57600080fd5b50356001600160a01b0316611fd7565b6102bc600480360360208110156108d257600080fd5b5035612042565b61028e600480360360208110156108ef57600080fd5b50356001600160a01b031661204d565b600480546040805163ca3a86cd60e01b81523393810193909352516001600160a01b039091169163ca3a86cd916024808301926020929190829003018186803b15801561094b57600080fd5b505afa15801561095f573d6000803e3d6000fd5b505050506040513d602081101561097557600080fd5b505115156001146109bb576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b6009546109c890826120b8565b600955600354604080516340e58ee560e01b81526004810185905290516101009092046001600160a01b0316916340e58ee59160248082019260009290919082900301818387803b158015610a1c57600080fd5b505af1158015610a30573d6000803e3d6000fd5b50506006547f948b667935c2235a252417dceae34a9e3b516f743acdd8fc849e9ebcae16147692508491506001600160a01b031683610a6d610f7d565b600954600854604080519687526001600160a01b039095166020870152858501939093526060850191909152608084015260a0830152519081900360c00190a15050565b6005546001600160a01b031681565b6000610aca610f7d565b905090565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610b525780601f10610b2757610100808354040283529160200191610b52565b820191906000526020600020905b815481529060010190602001808311610b3557829003601f168201915b505050505081565b6000610b7a600854610b7484610b6e610ac0565b90612115565b9061216e565b92915050565b6000610b8d3384846121d2565b50600192915050565b600060085460001415610bab57506000610be5565b600080610bc9612710610b746007548761211590919063ffffffff16565b9050610bd584826120b8565b9150610be082611d54565b925050505b919050565b60005460ff1681565b60085481565b60075481565b6001600160a01b0383166000908152600d6020908152604080832033845290915281205460001914610c7e576001600160a01b0384166000908152600d60209081526040808320338452909152902054610c5990836120b8565b6001600160a01b0385166000908152600d602090815260408083203384529091529020555b610c89848484612234565b5060019392505050565b6006546001600160a01b031681565b600480546040805163ca3a86cd60e01b81523393810193909352516000926001600160a01b039092169163ca3a86cd916024808301926020929190829003018186803b158015610cf157600080fd5b505afa158015610d05573d6000803e3d6000fd5b505050506040513d6020811015610d1b57600080fd5b50511515600114610d61576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b841580610d7557506001600160a01b038416155b80610d7e575082155b80610d9057506001600160a01b038216155b15610d9d57506000610ec8565b60035460408051633869bc0560e21b8152600481018890526001600160a01b03878116602483015260448201879052858116606483015260006084830181905260a48301819052925192936101009004169163e1a6f0149160c48082019260209290919082900301818787803b158015610e1657600080fd5b505af1158015610e2a573d6000803e3d6000fd5b505050506040513d6020811015610e4057600080fd5b5051600954909150610e5290876122d0565b6009556006547f360c58efcda3cbfaa91dd0fbb328656f6fa68693aa284a863dd4d659d4f9e1369082906001600160a01b0316610e8d610f7d565b600954600854604080519586526001600160a01b0390941660208601528484019290925260608401526080830152519081900360a00190a190505b949350505050565b6000610b7a8233612328565b600080516020612de683398151915281565b60035460ff1681565b600e5481565b6006546001600160a01b031690565b60108181548110610f1c57600080fd5b6000918252602090912001546001600160a01b0316905081565b5060001990565b600080610f52600854610b7485610b6e610f7d565b90506000610f71612710610b746007548561211590919063ffffffff16565b9050610be082826120b8565b600654604080516370a0823160e01b8152306004820152905160009283926001600160a01b03909116916370a0823191602480820192602092909190829003018186803b158015610fcd57600080fd5b505afa158015610fe1573d6000803e3d6000fd5b505050506040513d6020811015610ff757600080fd5b505160095490915061100a9082906122d0565b91505090565b6004546001600160a01b031633146110595760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600755565b6004546001600160a01b031681565b60035461010090046001600160a01b031681565b6004546001600160a01b031633146110ca5760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600480546040805163ca3a86cd60e01b81523393810193909352516001600160a01b039091169163ca3a86cd916024808301926020929190829003018186803b15801561113e57600080fd5b505afa158015611152573d6000803e3d6000fd5b505050506040513d602081101561116857600080fd5b505115156001146111ae576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b60006111c0612710610b748585612115565b90506001600160a01b03841663a9059cbb866111dc85856120b8565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561122257600080fd5b505af1158015611236573d6000803e3d6000fd5b505050506040513d602081101561124c57600080fd5b50506040805163a9059cbb60e01b81523360048201526024810183905290516001600160a01b0386169163a9059cbb9160448083019260209291908290030181600087803b15801561129d57600080fd5b505af11580156112b1573d6000803e3d6000fd5b505050506040513d60208110156112c757600080fd5b50506006547f9fc6dffd7a9978e1ea266a3324e9ed3e3011b1878fbe0074a699519561d7a87a906001600160a01b031686868585611303610f7d565b600954600854604080516001600160a01b03998a168152978916602089015295909716868601526060860193909352608085019190915260a084015260c083015260e08201929092529051908190036101000190a15050505050565b600061136b8383612593565b9392505050565b600c6020526000908152604090205481565b600f6020526000908152604090205481565b600480546040805163ca3a86cd60e01b81523393810193909352516001600160a01b039091169163ca3a86cd916024808301926020929190829003018186803b1580156113e257600080fd5b505afa1580156113f6573d6000803e3d6000fd5b505050506040513d602081101561140c57600080fd5b50511515600114611452576040805162461bcd60e51b81526020600482018190526024820152600080516020612e06833981519152604482015290519081900360640190fd5b60095461145f90826120b8565b6009556006547fb2e3b8ff25f9ea875d9c7d1332a97a955997395e3aae7cc9a0e20ab8c7279d16906001600160a01b031682611499610f7d565b600954600854604080516001600160a01b03909616865260208601949094528484019290925260608401526080830152519081900360a00190a150565b60006114e183611638565b905060006114ef8284612593565b905083811461152f5760405162461bcd60e51b8152600401808060200182810382526021815260200180612d846021913960400191505060405180910390fd5b5092915050565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610b525780601f10610b2757610100808354040283529160200191610b52565b6000610b8d338484612234565b6004546001600160a01b031633146115e65760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b601080546001810182556000919091527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b0319166001600160a01b0392909216919091179055565b60006008546000146116645761165c600854610b74611655610ac0565b8590612115565b905080611668565b5080805b50919050565b60095481565b60006001600160a01b03821633146116bd5760405162461bcd60e51b8152600401808060200182810382526053815260200180612d316053913960600191505060405180910390fd5b60006116c885610b96565b905060006116d68286612328565b9050858110156117175760405162461bcd60e51b8152600401808060200182810382526035815260200180612cd56035913960400191505060405180910390fd5b50949350505050565b6000610b7a8233612593565b60006001600160a01b03821633146117755760405162461bcd60e51b8152600401808060200182810382526053815260200180612d316053913960600191505060405180910390fd5b610ec88484612328565b6011546001600160a01b031681565b60005460ff161561179e57600080fd5b6000836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561181657600080fd5b8101908080516040519392919084600160201b82111561183557600080fd5b90830190602082018581111561184a57600080fd5b8251600160201b81118282018810171561186357600080fd5b82525081516020918201929091019080838360005b83811015611890578181015183820152602001611878565b50505050905090810190601f1680156118bd5780820380516001836020036101000a031916815260200191505b506040525050506040516020018080630c4c2e8d60e31b81525060040182805190602001908083835b602083106119055780518252601f1990920191602091820191016118e6565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405290508060019080519060200190611951929190612c33565b50600680546001600160a01b03199081166001600160a01b038781169190911790925560038054610100600160a81b0319166101009387168402179055600480543392169190911790556040516002805446937f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f939182918491600181161590910260001901168190048015611a1e5780601f106119fc576101008083540402835291820191611a1e565b820191906000526020600020905b815481529060010190602001808311611a0a575b505060408051918290038220828201825260018352603160f81b602093840152815180840196909652858201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060860152608085018690523060a0808701919091528151808703909101815260c08601909152805190820120600e558551869460e0019350839250908401908083835b60208310611acf5780518252601f199092019160209182019101611ab0565b51815160209384036101000a60001901801990921691161790526220763160e81b9190930190815260408051808303601c19018152600390920190528051611b209550600294509201919050612c33565b50846001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611b5a57600080fd5b505afa158015611b6e573d6000803e3d6000fd5b505050506040513d6020811015611b8457600080fd5b50516003805460ff191660ff90921691909117908190556040805163095ea7b360e01b81526001600160a01b0361010090930483166004820152600019602482015290519187169163095ea7b3916044808201926020929091908290030181600087803b158015611bf457600080fd5b505af1158015611c08573d6000803e3d6000fd5b505050506040513d6020811015611c1e57600080fd5b50506040805142815290517f62d3d1f1d9801a81e18d50c29dbd4af6f8aa76a0859f432482ac2574e3d2a4f69181900360200190a15050600580546001600160a01b0319163017905550506003600755506000805460ff19166001179055565b6004546001600160a01b03163314611cc75760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b6006546003546040805163095ea7b360e01b81526101009092046001600160a01b0390811660048401526000196024840152905192169163095ea7b3916044808201926020929091908290030181600087803b158015611d2657600080fd5b505af1158015611d3a573d6000803e3d6000fd5b505050506040513d6020811015611d5057600080fd5b5050565b60006008546000146116645761165c611d6b610ac0565b600854610b74908590612115565b600060085460001415611d8e57506000610be5565b6001600160a01b0382166000908152600c602052604090205461136b81610b5a565b42841015611dfa576040805162461bcd60e51b815260206004820152601260248201527118985d1a151bdad95b8e881156141254915160721b604482015290519081900360640190fd5b600e546001600160a01b038089166000818152600f60209081526040808320805460018082019092558251600080516020612de68339815191528186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e08501825280519083012061190160f01b6101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e280820193601f1981019281900390910190855afa158015611f03573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611f395750886001600160a01b0316816001600160a01b0316145b611f89576040805162461bcd60e51b815260206004820152601c60248201527b62617468546f6b656e3a20494e56414c49445f5349474e415455524560201b604482015290519081900360640190fd5b611f948989896121d2565b505050505050505050565b6001600160a01b03166000908152600c602052604090205490565b600d60209081526000928352604080842090915290825290205481565b6004546001600160a01b031633146120205760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000610b7a82611d54565b6004546001600160a01b031633146120965760405162461bcd60e51b8152600401808060200182810382526027815260200180612d0a6027913960400191505060405180910390fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b60008282111561210f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60008261212457506000610b7a565b8282028284828161213157fe5b041461136b5760405162461bcd60e51b8152600401808060200182810382526021815260200180612da56021913960400191505060405180910390fd5b60008082116121c1576040805162461bcd60e51b815260206004820152601a602482015279536166654d6174683a206469766973696f6e206279207a65726f60301b604482015290519081900360640190fd5b8183816121ca57fe5b049392505050565b6001600160a01b038084166000818152600d6020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166000908152600c602052604090205461225790826120b8565b6001600160a01b038085166000908152600c6020526040808220939093559084168152205461228690826122d0565b6001600160a01b038084166000818152600c60209081526040918290209490945580518581529051919392871692600080516020612dc683398151915292918290030190a3505050565b60008282018381101561136b576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b600854600090612339838583612832565b600061234b82610b7487610b6e610f7d565b90506123573386612b3b565b6000612374612710610b746007548561211590919063ffffffff16565b6005549091506001600160a01b03161561240e576006546005546040805163a9059cbb60e01b81526001600160a01b039283166004820152602481018590529051919092169163a9059cbb9160448083019260209291908290030181600087803b1580156123e157600080fd5b505af11580156123f5573d6000803e3d6000fd5b505050506040513d602081101561240b57600080fd5b50505b61241882826120b8565b6006546040805163a9059cbb60e01b81526001600160a01b03898116600483015260248201859052915193975091169163a9059cbb916044808201926020929091908290030181600087803b15801561247057600080fd5b505af1158015612484573d6000803e3d6000fd5b505050506040513d602081101561249a57600080fd5b50506006546005547f7e06a1682a005aab8a0eb8e6e366e1996b23069ddcf47931669eb54d6d2ede869186916001600160a01b03918216918a9133918791166124e1610f7d565b60095460085460408051998a526001600160a01b0398891660208b01528981019790975294871660608901526080880193909352941660a086015260c085019390935260e084019290925261010083019190915251908190036101200190a16040805185815260208101889052815133926001600160a01b0389169284927ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db929181900390910190a450505092915050565b60008061259e610f7d565b600654604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b1580156125ef57600080fd5b505afa158015612603573d6000803e3d6000fd5b505050506040513d602081101561261957600080fd5b5051600654604080516323b872dd60e01b81523360048201523060248201526044810189905290519293506001600160a01b03909116916323b872dd916064808201926020929091908290030181600087803b15801561267857600080fd5b505af115801561268c573d6000803e3d6000fd5b505050506040513d60208110156126a257600080fd5b5050600654604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156126ef57600080fd5b505afa158015612703573d6000803e3d6000fd5b505050506040513d602081101561271957600080fd5b5051905061272781836120b8565b95506008546000146127545761274c83610b746008548961211590919063ffffffff16565b935083612759565b859350835b506127648585612bba565b6006547f98c2489a97b81ca0e2c92a8e8c85cea665ca75cc1fee59262d8b604780bb58d69087906001600160a01b0316863361279e610f7d565b600954600854604080519788526001600160a01b03968716602089015287810195909552929094166060860152608085015260a084019290925260c0830191909152519081900360e00190a160408051878152602081018690528151339283927fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7929081900390910190a350505092915050565b60105415612b365760005b601054811015612b345760006010828154811061285657fe5b6000918252602090912001546011546001600160a01b03918216925016156128df5760115460408051631916558760e01b81526001600160a01b03848116600483015291519190921691631916558791602480830192600092919082900301818387803b1580156128c657600080fd5b505af11580156128da573d6000803e3d6000fd5b505050505b6006546001600160a01b03828116911614156128fb5750612b2c565b6000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561294a57600080fd5b505afa15801561295e573d6000803e3d6000fd5b505050506040513d602081101561297457600080fd5b505190508015612b2957600061298e85610b748489612115565b905060006129ad612710610b746007548561211590919063ffffffff16565b6005549091506001600160a01b031615612a44576005546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810184905290519186169163a9059cbb916044808201926020929091908290030181600087803b158015612a1757600080fd5b505af1158015612a2b573d6000803e3d6000fd5b505050506040513d6020811015612a4157600080fd5b50505b6000612a5083836120b8565b9050846001600160a01b031663a9059cbb8a836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612aa957600080fd5b505af1158015612abd573d6000803e3d6000fd5b505050506040513d6020811015612ad357600080fd5b505060408051828152602081018a90526001600160a01b0387811682840152915133928c169183917f60b2262e5f86af935143ddc6a4d67100654fe2ff3b51081cfc767e6825031e5e9181900360600190a45050505b50505b60010161283d565b505b505050565b6001600160a01b0382166000908152600c6020526040902054612b5e90826120b8565b6001600160a01b0383166000908152600c6020526040902055600854612b8490826120b8565b6008556040805182815290516000916001600160a01b03851691600080516020612dc68339815191529181900360200190a35050565b600854612bc790826122d0565b6008556001600160a01b0382166000908152600c6020526040902054612bed90826122d0565b6001600160a01b0383166000818152600c60209081526040808320949094558351858152935192939192600080516020612dc68339815191529281900390910190a35050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612c695760008555612caf565b82601f10612c8257805160ff1916838001178555612caf565b82800160010185558215612caf579182015b82811115612caf578251825591602001919060010190612c94565b50612cbb929150612cbf565b5090565b5b80821115612cbb5760008155600101612cc056fe596f752063616e6e6f742077697468647261772074686520616d6f756e74206f662061737365747320796f7520657870656374656463616c6c6572206973206e6f742062617468486f757365202d2042617468546f6b656e2e736f6c5468697320696d706c656d656e746174696f6e20646f6573206e6f7420737570706f7274206e6f6e2d73656e646572206f776e6572732066726f6d207769746864726177696e67207573657220736861726573646964206e6f74206d696e7420657870656374656420736861726520636f756e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96e6f7420616e20617070726f7665642070616972202d2062617468546f6b656ea2646970667358221220b8d4138716ff3181755dd63d33a374bd91c97d88de58b464c96764f7b73df23464736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

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