false
false
0

Contract Address Details

0x7FCA2B3E1047291f65c2C914083d970c027f4290

Contract Name
FuseStakingV3
Creator
0x5128e3–22e4bb at 0x17c5d4–04ad34
Balance
0.004186955 Fuse
Tokens
Fetching tokens...
Transactions
3 Transactions
Transfers
0 Transfers
Gas Used
65,725
Last Balance Update
23688815
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
FuseStakingV3




Optimization enabled
true
Compiler version
v0.6.12+commit.27d51765




Optimization runs
200
EVM Version
default




Verified at
2021-03-03T08:19:16.780306Z

Contract source code

// SPDX-License-Identifier: MIT
// File: @openzeppelin/contracts-upgradeable/proxy/Initializable.sol


// solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0;


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

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

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

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

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

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

// File: @openzeppelin/contracts-upgradeable/GSN/ContextUpgradeable.sol



/*
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal initializer {
        __Context_init_unchained();
    }

    function __Context_init_unchained() internal initializer {
    }
    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;
    }
    uint256[50] private __gap;
}

// File: @openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol



/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal initializer {
        __Context_init_unchained();
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal initializer {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

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

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
    uint256[49] private __gap;
}

// File: @openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol


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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

// File: contracts/utils/DSMath.sol


/// math.sol -- mixin for inline numerical wizardry

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

contract DSMath {
	function WAD() internal pure returns (uint256) {
		return 10**18;
	}

	function RAY() internal pure returns (uint256) {
		return 10**27;
	}

	function add(uint256 x, uint256 y) public pure returns (uint256 z) {
		require((z = x + y) >= x, "ds-math-add-overflow");
	}

	function sub(uint256 x, uint256 y) public pure returns (uint256 z) {
		require((z = x - y) <= x, "ds-math-sub-underflow");
	}

	function mul(uint256 x, uint256 y) public pure returns (uint256 z) {
		require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
	}

	function min(uint256 x, uint256 y) public pure returns (uint256 z) {
		return x <= y ? x : y;
	}

	function max(uint256 x, uint256 y) public pure returns (uint256 z) {
		return x >= y ? x : y;
	}

	function imin(int256 x, int256 y) public pure returns (int256 z) {
		return x <= y ? x : y;
	}

	function imax(int256 x, int256 y) public pure returns (int256 z) {
		return x >= y ? x : y;
	}

	function wmul(uint256 x, uint256 y) public pure returns (uint256 z) {
		z = add(mul(x, y), WAD() / 2) / WAD();
	}

	function rmul(uint256 x, uint256 y) public pure returns (uint256 z) {
		z = add(mul(x, y), RAY() / 2) / RAY();
	}

	function wdiv(uint256 x, uint256 y) public pure returns (uint256 z) {
		z = add(mul(x, WAD()), y / 2) / y;
	}

	function rdiv(uint256 x, uint256 y) public pure returns (uint256 z) {
		z = add(mul(x, RAY()), y / 2) / y;
	}

	// This famous algorithm is called "exponentiation by squaring"
	// and calculates x^n with x as fixed-point and n as regular unsigned.
	//
	// It's O(log n), instead of O(n) for naive repeated multiplication.
	//
	// These facts are why it works:
	//
	//  If n is even, then x^n = (x^2)^(n/2).
	//  If n is odd,  then x^n = x * x^(n-1),
	//   and applying the equation for even x gives
	//    x^n = x * (x^2)^((n-1) / 2).
	//
	//  Also, EVM division is flooring and
	//    floor[(n-1) / 2] = floor[n / 2].
	//
	function rpow(uint256 x, uint256 n) public pure returns (uint256 z) {
		z = n % 2 != 0 ? x : RAY();

		for (n /= 2; n != 0; n /= 2) {
			x = rmul(x, x);

			if (n % 2 != 0) {
				z = rmul(z, x);
			}
		}
	}
}

// File: contracts/Interfaces.sol


pragma experimental ABIEncoderV2;

interface cERC20 {
	function mint(uint256 mintAmount) external returns (uint256);

	function redeemUnderlying(uint256 mintAmount) external returns (uint256);

	function exchangeRateCurrent() external returns (uint256);

	function exchangeRateStored() external view returns (uint256);

	function balanceOf(address addr) external view returns (uint256);

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

	function approve(address spender, uint256 amount) external returns (bool);
}

interface GoodDollar is cERC20 {
	function getFees(uint256 value) external view returns (uint256, bool);

	function mint(address to, uint256 mintAmount) external returns (uint256);
}

interface Staking {
	struct Staker {
		// The staked DAI amount
		uint256 stakedDAI;
		// The latest block number which the
		// staker has staked tokens
		uint256 lastStake;
	}

	function stakeDAI(uint256 amount) external;

	function withdrawStake() external;

	function stakers(address staker) external view returns (Staker memory);
}

interface Uniswap {
	function swapExactETHForTokens(
		uint256 amountOutMin,
		address[] calldata path,
		address to,
		uint256 deadline
	) external payable returns (uint256[] memory amounts);

	function swapExactTokensForETH(
		uint256 amountIn,
		uint256 amountOutMin,
		address[] calldata path,
		address to,
		uint256 deadline
	) external returns (uint256[] memory amounts);

	function swapExactTokensForTokens(
		uint256 amountIn,
		uint256 amountOutMin,
		address[] calldata path,
		address to,
		uint256 deadline
	) external returns (uint256[] memory amounts);

	function WETH() external pure returns (address);

	function factory() external pure returns (address);

	function quote(
		uint256 amountA,
		uint256 reserveA,
		uint256 reserveB
	) external pure returns (uint256 amountB);

	function getAmountIn(
		uint256 amountOut,
		uint256 reserveIn,
		uint256 reserveOut
	) external pure returns (uint256 amountIn);

	function getAmountOut(
		uint256 amountI,
		uint256 reserveIn,
		uint256 reserveOut
	) external pure returns (uint256 amountOut);
}

interface UniswapFactory {
	function getPair(address tokenA, address tokenB)
		external
		view
		returns (address);
}

interface UniswapPair {
	function getReserves()
		external
		view
		returns (
			uint112 reserve0,
			uint112 reserve1,
			uint32 blockTimestampLast
		);

	function kLast() external view returns (uint256);
}

interface Reserve {
	function buy(
		address _buyWith,
		uint256 _tokenAmount,
		uint256 _minReturn
	) external returns (uint256);
}

interface IIdentity {
	function isWhitelisted(address user) external view returns (bool);

	function addWhitelistedWithDID(address account, string memory did) external;

	function removeWhitelisted(address account) external;

	function addIdentityAdmin(address account) external returns (bool);

	function setAvatar(address _avatar) external;
}

interface UBIScheme {
	function currentDay() external view returns (uint256);
}

interface ProxyAdmin {
	function getProxyImplementation(address proxy)
		external
		view
		returns (address);

	function getProxyAdmin(address proxy) external view returns (address);

	function upgrade(address proxy, address implementation) external;

	function owner() external view returns (address);

	function transferOwnership(address newOwner) external;
}

// File: contracts/staking/FuseStakingV3.sol







interface IConsensus {
	/**
	 * @dev delegate to a validator
	 * @param _validator the address of the validator msg.sender is delegating to
	 */
	function delegate(address _validator) external payable;

	/**
	 * @dev Function to be called when a delegator whishes to withdraw some of his staked funds for a validator
	 * @param _validator the address of the validator msg.sender has delegating to
	 * @param _amount the amount msg.sender wishes to withdraw from the contract
	 */
	function withdraw(address _validator, uint256 _amount) external;

	function delegatedAmount(address _address, address _validator)
		external
		view
		returns (uint256);

	function stakeAmount(address _address) external view returns (uint256);

	function delegators(address _validator)
		external
		view
		returns (address[] memory);
}

contract FuseStakingV3 is Initializable, OwnableUpgradeable, DSMath {
	using SafeMathUpgradeable for uint256;

	mapping(address => uint256) public stakers;
	address[] public validators;

	IConsensus public consensus;

	Uniswap public uniswap;
	GoodDollar public GD;
	UBIScheme public ubischeme;
	UniswapFactory public uniswapFactory;
	UniswapPair public uniswapPair;

	uint256 public lastDayCollected; //ubi day from ubischeme

	uint256 public stakeBackRatio;
	uint256 public maxSlippageRatio;
	uint256 public keeperFeeRatio;
	uint256 public RATIO_BASE;
	uint256 public communityPoolRatio; //out of G$ bought how much should goto pool

	uint256 communityPoolBalance;
	uint256 pendingFuseEarnings; //earnings not  used because of slippage

	event UBICollected(
		uint256 indexed currentDay,
		uint256 ubi, //G$ sent to ubischeme
		uint256 communityPool, //G$ added to pool
		uint256 gdBought, //actual G$ we got out of swapping stakingRewards + pendingFuseEarnings
		uint256 stakingRewards, //rewards earned since previous collection,
		uint256 pendingFuseEarnings, //new balance of fuse pending to be swapped for G$
		address keeper,
		uint256 keeperGDFee
	);

	/**
	 * @dev initialize
	 */
	function initialize() public initializer {
		__Ownable_init_unchained();
		consensus = IConsensus(
			address(0x3014ca10b91cb3D0AD85fEf7A3Cb95BCAc9c0f79)
		);
		validators.push(address(0xcb876A393F05a6677a8a029f1C6D7603B416C0A6));
	}

	function upgrade0() public {
		if (RATIO_BASE == 0) {
			stakeBackRatio = 33333; //%33
			communityPoolRatio = 33333; //%33
			maxSlippageRatio = 3000; //3%
			keeperFeeRatio = 30; //0.03%
			RATIO_BASE = 100000; //100%
		}
	}

	function upgrade1(
		address _gd,
		address _ubischeme,
		address _uniswap
	) public {
		if (address(uniswapPair) == address(0)) {
			uniswap = Uniswap(
				_uniswap == address(0)
					? 0xFB76e9E7d88E308aB530330eD90e84a952570319
					: _uniswap
			);
			GD = GoodDollar(_gd);
			ubischeme = UBIScheme(_ubischeme);

			uniswapFactory = UniswapFactory(uniswap.factory());
			uniswapPair = UniswapPair(
				uniswapFactory.getPair(uniswap.WETH(), _gd)
			);
			upgrade0();
		}
	}

	function setContracts(address _gd, address _ubischeme) public onlyOwner {
		if (_gd != address(0)) {
			GD = GoodDollar(_gd);
		}
		if (_ubischeme != address(0)) {
			ubischeme = UBIScheme(_ubischeme);
		}
	}

	function stake() public payable returns (bool) {
		return stake(address(0));
	}

	function stake(address _validator) public payable returns (bool) {
		require(msg.value > 0, "stake must be > 0");
		require(validators.length > 0, "no approved validators");
		bool found;
		for (
			uint256 i = 0;
			_validator != address(0) && i < validators.length;
			i++
		) {
			if (validators[i] != _validator) {
				found = true;
				break;
			}
		}
		require(
			_validator == address(0) || found,
			"validator not in approved list"
		);

		bool staked = stakeNextValidator(msg.value, _validator);
		stakers[msg.sender] = stakers[msg.sender].add(msg.value);
		return staked;
	}

	function balanceOf(address _owner) public view returns (uint256) {
		return stakers[_owner];
	}

	function withdraw(uint256 _value) public returns (uint256) {
		uint256 effectiveBalance = balance(); //use only undelegated funds
		uint256 toWithdraw = _value == 0 ? stakers[msg.sender] : _value;
		uint256 toCollect = toWithdraw;
		require(
			toWithdraw > 0 && toWithdraw <= stakers[msg.sender],
			"invalid withdraw amount"
		);
		uint256 perValidator = _value.div(validators.length);
		for (uint256 i = 0; i < validators.length; i++) {
			uint256 cur =
				consensus.delegatedAmount(address(this), validators[i]);
			if (cur == 0) continue;
			if (cur <= perValidator) {
				undelegateWithCatch(validators[i], cur);
				toCollect = toCollect.sub(cur);
			} else {
				undelegateWithCatch(validators[i], perValidator);
				toCollect = toCollect.sub(perValidator);
			}
			if (toCollect == 0) break;
		}

		effectiveBalance = balance().sub(effectiveBalance); //use only undelegated funds

		// in case some funds where not withdrawn
		if (toWithdraw > effectiveBalance) {
			toWithdraw = effectiveBalance;
		}

		stakers[msg.sender] = stakers[msg.sender].sub(toWithdraw);
		if (toWithdraw > 0) payable(msg.sender).transfer(toWithdraw);
		return toWithdraw;
	}

	function stakeNextValidator(uint256 _value, address _validator)
		internal
		returns (bool)
	{
		if (validators.length == 0) return false;
		if (_validator != address(0)) {
			consensus.delegate{ value: _value }(_validator);
			return true;
		}

		uint256 perValidator =
			totalDelegated().add(_value).div(validators.length);
		uint256 left = _value;
		for (uint256 i = 0; i < validators.length && left > 0; i++) {
			uint256 cur =
				consensus.delegatedAmount(address(this), validators[i]);

			if (cur < perValidator) {
				uint256 toDelegate = perValidator.sub(cur);
				toDelegate = toDelegate < left ? toDelegate : left;
				consensus.delegate{ value: toDelegate }(validators[i]);
				left = left.sub(toDelegate);
			}
		}

		return true;
	}

	function addValidator(address _v) public onlyOwner {
		validators.push(_v);
	}

	function totalDelegated() public view returns (uint256) {
		uint256 total = 0;
		for (uint256 i = 0; i < validators.length; i++) {
			uint256 cur =
				consensus.delegatedAmount(address(this), validators[i]);
			total = total.add(cur);
		}
		return total;
	}

	function removeValidator(address _validator) public onlyOwner {
		uint256 delegated =
			consensus.delegatedAmount(address(this), _validator);
		if (delegated > 0) {
			uint256 prevBalance = balance();
			undelegateWithCatch(_validator, delegated);

			// wasnt withdrawn because validator needs to be taken of active validators
			if (balance() == prevBalance) {
				// pendingValidators.push(_validator);
				return;
			}
		}

		for (uint256 i = 0; i < validators.length; i++) {
			if (validators[i] == _validator) {
				if (i < validators.length - 1)
					validators[i] = validators[validators.length - 1];
				validators.pop();
				break;
			}
		}
	}

	function collectUBIInterest() public {
		uint256 curDay = ubischeme.currentDay();
		require(
			curDay != lastDayCollected,
			"can collect only once in a ubi cycle"
		);

		uint256 earnings = balance() - pendingFuseEarnings;
		require(pendingFuseEarnings + earnings > 0, "no earnings to collect");

		lastDayCollected = curDay;
		uint256 fuseUBI =
			earnings.mul(RATIO_BASE - stakeBackRatio).div(RATIO_BASE);
		uint256 stakeBack = earnings - fuseUBI;

		uint256[] memory fuseswapResult =
			_buyGD(fuseUBI.add(pendingFuseEarnings)); //buy GD with X% of earnings
		pendingFuseEarnings = fuseUBI.add(pendingFuseEarnings).sub(
			fuseswapResult[0]
		);
		stakeNextValidator(stakeBack, address(0)); //stake back the rest of the earnings

		uint256 gdBought = fuseswapResult[1];
		uint256 keeperFee = gdBought.mul(keeperFeeRatio).div(RATIO_BASE);
		if (keeperFee > 0) GD.transfer(msg.sender, keeperFee);

		uint256 communityPoolContribution =
			gdBought
				.sub(keeperFee) //subtract fee
				.mul(communityPoolRatio) // * ommunityPoolRatio
				.div(RATIO_BASE); // = G$ after fee * communityPoolRatio%

		uint256 ubiAfterFeeAndPool = gdBought.sub(communityPoolContribution);

		GD.transfer(address(ubischeme), ubiAfterFeeAndPool); //transfer to ubischeme
		communityPoolBalance = communityPoolBalance.add(
			communityPoolContribution
		);

		emit UBICollected(
			curDay,
			ubiAfterFeeAndPool,
			communityPoolContribution,
			gdBought,
			earnings,
			pendingFuseEarnings,
			msg.sender,
			keeperFee
		);
	}

	/**
	 * @dev internal method to buy GD from fuseswap
	 * @param _value fuse to be sold
	 * @return uniswap coversion results uint256[2]
	 */
	function _buyGD(uint256 _value) internal returns (uint256[] memory) {
		//buy from uniwasp
		require(_value > 0, "buy value should be > 0");
		uint256 maxFuse = calcMaxFuseWithSlippage(_value);
		address[] memory path = new address[](2);
		path[1] = address(GD);
		path[0] = uniswap.WETH();
		return
			uniswap.swapExactETHForTokens{ value: maxFuse }(
				0,
				path,
				address(this),
				now
			);
	}

	function calcMaxFuseWithSlippage(uint256 _value)
		public
		view
		returns (uint256)
	{
		(uint256 r_fuse, uint256 r_gd, ) = uniswapPair.getReserves();

		return calcMaxFuseWithSlippage(r_fuse, r_gd, _value);
	}

	/**
	 * uniswap amountOut helper
	 */
	function getAmountOut(
		uint256 _amountIn,
		uint256 _reserveIn,
		uint256 _reserveOut
	) internal pure returns (uint256 amountOut) {
		uint256 amountInWithFee = _amountIn.mul(997);
		uint256 numerator = amountInWithFee.mul(_reserveOut);
		uint256 denominator = _reserveIn.mul(1000).add(amountInWithFee);
		amountOut = numerator / denominator;
	}

	/**
	 * @dev use binary search to find quantity that will result with slippage < maxSlippageRatio
	 */
	function calcMaxFuseWithSlippage(
		uint256 r_fuse,
		uint256 r_gd,
		uint256 _value
	) public view returns (uint256) {
		uint256 start = 0;
		uint256 end = _value.div(1e18); //save iterations by moving precision to whole Fuse quantity
		uint256 curPriceWei = uint256(100).mul(r_fuse) / r_gd; //uniswap quote  formula UniswapV2Library.sol
		uint256 maxPriceWei =
			curPriceWei.mul(RATIO_BASE.add(maxSlippageRatio)).div(RATIO_BASE);
		uint256 fuseAmount = _value;

		//Iterate while start not meets end
		while (start <= end) {
			// Find the mid index
			uint256 midQuantityWei = start.add(end).mul(1e18).div(2); //restore quantity precision
			if (midQuantityWei == 0) break;
			uint256 gdForQuantity = getAmountOut(midQuantityWei, r_fuse, r_gd);
			uint256 priceForQuantityWei =
				rdiv(midQuantityWei, gdForQuantity.mul(1e16)).div(1e9);

			if (priceForQuantityWei <= maxPriceWei) {
				start = midQuantityWei.div(1e18) + 1; //reduce precision to whole quantity div 1e18
				fuseAmount = midQuantityWei;
			} else end = midQuantityWei.div(1e18) - 1; //reduce precision to whole quantity div 1e18
		}

		return fuseAmount;
	}

	function undelegateWithCatch(address _validator, uint256 _amount)
		internal
		returns (bool)
	{
		try consensus.withdraw(_validator, _amount) {
			return true;
		} catch Error(
			string memory /*reason*/
		) {
			// This is executed in case
			// revert was called inside getData
			// and a reason string was provided.
			return false;
		} catch (
			bytes memory /*lowLevelData*/
		) {
			// This is executed in case revert() was used
			// or there was a failing assertion, division
			// by zero, etc. inside getData.
			return false;
		}
	}

	function balance() internal view returns (uint256) {
		return payable(address(this)).balance;
	}

	receive() external payable {}
}
        

Contract ABI

[{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"UBICollected","inputs":[{"type":"uint256","name":"currentDay","internalType":"uint256","indexed":true},{"type":"uint256","name":"ubi","internalType":"uint256","indexed":false},{"type":"uint256","name":"communityPool","internalType":"uint256","indexed":false},{"type":"uint256","name":"gdBought","internalType":"uint256","indexed":false},{"type":"uint256","name":"stakingRewards","internalType":"uint256","indexed":false},{"type":"uint256","name":"pendingFuseEarnings","internalType":"uint256","indexed":false},{"type":"address","name":"keeper","internalType":"address","indexed":false},{"type":"uint256","name":"keeperGDFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract GoodDollar"}],"name":"GD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"RATIO_BASE","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"add","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addValidator","inputs":[{"type":"address","name":"_v","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calcMaxFuseWithSlippage","inputs":[{"type":"uint256","name":"r_fuse","internalType":"uint256"},{"type":"uint256","name":"r_gd","internalType":"uint256"},{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calcMaxFuseWithSlippage","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"collectUBIInterest","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"communityPoolRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IConsensus"}],"name":"consensus","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"int256","name":"z","internalType":"int256"}],"name":"imax","inputs":[{"type":"int256","name":"x","internalType":"int256"},{"type":"int256","name":"y","internalType":"int256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"int256","name":"z","internalType":"int256"}],"name":"imin","inputs":[{"type":"int256","name":"x","internalType":"int256"},{"type":"int256","name":"y","internalType":"int256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"keeperFeeRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastDayCollected","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"max","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxSlippageRatio","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"min","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"mul","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"rdiv","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeValidator","inputs":[{"type":"address","name":"_validator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"rmul","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"rpow","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"n","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContracts","inputs":[{"type":"address","name":"_gd","internalType":"address"},{"type":"address","name":"_ubischeme","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"stake","inputs":[{"type":"address","name":"_validator","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"stake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeBackRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"sub","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalDelegated","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract UBIScheme"}],"name":"ubischeme","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract Uniswap"}],"name":"uniswap","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract UniswapFactory"}],"name":"uniswapFactory","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract UniswapPair"}],"name":"uniswapPair","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgrade0","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgrade1","inputs":[{"type":"address","name":"_gd","internalType":"address"},{"type":"address","name":"_ubischeme","internalType":"address"},{"type":"address","name":"_uniswap","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"validators","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"wdiv","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdraw","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"wmul","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x608060405234801561001057600080fd5b506129df806100206000396000f3fe6080604052600436106102605760003560e01c8063771602f7116101445780639168ae72116100b6578063c816841b1161007a578063c816841b14610669578063c8a4ac9c1461067e578063c8e6c7d91461069e578063d22e9b06146106be578063d8952a49146106d3578063f2fde38b146106f357610267565b80639168ae72146105df578063a5a90636146105ff578063ae94e44814610614578063b67d77c514610634578063c11a56301461065457610267565b80638918c4a2116101085780638918c4a21461054b5780638b9af5c1146105605780638bdb2afa146105805780638da5cb5b146105955780638ef3f761146105aa5780638f907195146105bf57610267565b8063771602f7146104cc5780637ae2b5c7146104ec57806380d04de81461050c57806381028f67146105215780638129fc1c1461053657610267565b80633fb1ccf1116101dd5780636021a9d5116101a15780636021a9d51461042d5780636711281c1461044257806367457022146104575780636d5433e61461047757806370a0823114610497578063715018a6146104b757610267565b80633fb1ccf11461039657806340a141ff146103ab57806347a1671a146103cd5780634d238c8e146103ed5780635fde731c1461040d57610267565b80632681f7e4116102245780632681f7e41461030c5780632cda89431461032e5780632e1a7d4d1461034e57806335aa2e441461036e5780633a4b66f11461038e57610267565b806304d26ebf1461026c57806309b6afb2146102975780630e2286d3146102b7578063150d7e47146102d757806326476204146102ec57610267565b3661026757005b600080fd5b34801561027857600080fd5b50610281610713565b60405161028e919061244f565b60405180910390f35b3480156102a357600080fd5b506102816102b23660046123d2565b610719565b3480156102c357600080fd5b506102816102d2366004612338565b610835565b3480156102e357600080fd5b50610281610860565b6102ff6102fa3660046121c9565b610866565b60405161028e9190612444565b34801561031857600080fd5b50610321610983565b60405161028e91906123fd565b34801561033a57600080fd5b506102816103493660046123a2565b610992565b34801561035a57600080fd5b506102816103693660046123a2565b610a47565b34801561037a57600080fd5b506103216103893660046123a2565b610ca7565b6102ff610cce565b3480156103a257600080fd5b50610321610ce0565b3480156103b757600080fd5b506103cb6103c63660046121c9565b610cef565b005b3480156103d957600080fd5b506103cb6103e8366004612239565b610ed2565b3480156103f957600080fd5b506103cb6104083660046121c9565b6110ea565b34801561041957600080fd5b50610281610428366004612338565b611171565b34801561043957600080fd5b50610281611183565b34801561044e57600080fd5b506103cb611189565b34801561046357600080fd5b50610281610472366004612338565b6111b0565b34801561048357600080fd5b50610281610492366004612338565b6111d8565b3480156104a357600080fd5b506102816104b23660046121c9565b6111f3565b3480156104c357600080fd5b506103cb61120e565b3480156104d857600080fd5b506102816104e7366004612338565b61128d565b3480156104f857600080fd5b50610281610507366004612338565b6112b0565b34801561051857600080fd5b506102816112c0565b34801561052d57600080fd5b5061032161139a565b34801561054257600080fd5b506103cb6113a9565b34801561055757600080fd5b506102816114ab565b34801561056c57600080fd5b5061028161057b366004612338565b6114b1565b34801561058c57600080fd5b506103216114d2565b3480156105a157600080fd5b506103216114e1565b3480156105b657600080fd5b506103216114f0565b3480156105cb57600080fd5b506102816105da366004612338565b6114ff565b3480156105eb57600080fd5b506102816105fa3660046121c9565b611554565b34801561060b57600080fd5b506103cb611566565b34801561062057600080fd5b5061028161062f366004612338565b6118a1565b34801561064057600080fd5b5061028161064f366004612338565b6118b1565b34801561066057600080fd5b506102816118d4565b34801561067557600080fd5b506103216118da565b34801561068a57600080fd5b50610281610699366004612338565b6118e9565b3480156106aa57600080fd5b506102816106b9366004612338565b611920565b3480156106ca57600080fd5b50610281611930565b3480156106df57600080fd5b506103cb6106ee366004612201565b611936565b3480156106ff57600080fd5b506103cb61070e3660046121c9565b6119c5565b606f5481565b6000808061072f84670de0b6b3a7640000611a7c565b905060008561073f606489611abe565b8161074657fe5b049050600061077860715461077261076b606f54607154611af890919063ffffffff16565b8590611abe565b90611a7c565b9050855b8385116108295760006107a66002610772670de0b6b3a76400006107a08a8a611af8565b90611abe565b9050806107b35750610829565b60006107c0828c8c611b1d565b905060006107e1633b9aca00610772856102d286662386f26fc10000611abe565b9050848111610809576107fc83670de0b6b3a7640000611a7c565b6001019750829350610821565b600161081d84670de0b6b3a7640000611a7c565b0396505b50505061077c565b98975050505050505050565b60008161085161084785610699611b6b565b6002855b0461128d565b8161085857fe5b049392505050565b60705481565b60008034116108905760405162461bcd60e51b8152600401610887906127c2565b60405180910390fd5b6066546108af5760405162461bcd60e51b8152600401610887906127ed565b6000805b6001600160a01b038416158015906108cc575060665481105b1561091357836001600160a01b0316606682815481106108e857fe5b6000918252602090912001546001600160a01b03161461090b5760019150610913565b6001016108b3565b506001600160a01b03831615806109275750805b6109435760405162461bcd60e51b81526004016108879061281d565b600061094f3485611b7b565b3360009081526065602052604090205490915061096c9034611af8565b336000908152606560205260409020559392505050565b6068546001600160a01b031681565b6000806000606c60009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156109e557600080fd5b505afa1580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190612359565b506001600160701b031691506001600160701b03169150610a3f828286610719565b949350505050565b600080610a52611dcc565b905060008315610a625783610a73565b336000908152606560205260409020545b9050808015801590610a945750336000908152606560205260409020548211155b610ab05760405162461bcd60e51b815260040161088790612756565b606654600090610ac1908790611a7c565b905060005b606654811015610c1d57606754606680546000926001600160a01b0316916321429e609130919086908110610af757fe5b6000918252602090912001546040516001600160e01b031960e085901b168152610b2e92916001600160a01b031690600401612411565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7e91906123ba565b905080610b8b5750610c15565b828111610bcf57610bbd60668381548110610ba257fe5b6000918252602090912001546001600160a01b031682611dd1565b50610bc88482611e92565b9350610c08565b610bfa60668381548110610bdf57fe5b6000918252602090912001546001600160a01b031684611dd1565b50610c058484611e92565b93505b83610c135750610c1d565b505b600101610ac6565b50610c3084610c2a611dcc565b90611e92565b935083831115610c3e578392505b33600090815260656020526040902054610c589084611e92565b336000908152606560205260409020558215610c9d57604051339084156108fc029085906000818181858888f19350505050158015610c9b573d6000803e3d6000fd5b505b5090949350505050565b60668181548110610cb457fe5b6000918252602090912001546001600160a01b0316905081565b6000610cda6000610866565b90505b90565b6069546001600160a01b031681565b610cf7611ed4565b6033546001600160a01b03908116911614610d245760405162461bcd60e51b81526004016108879061278d565b60675460405163010a14f360e51b81526000916001600160a01b0316906321429e6090610d579030908690600401612411565b60206040518083038186803b158015610d6f57600080fd5b505afa158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da791906123ba565b90508015610dde576000610db9611dcc565b9050610dc58383611dd1565b5080610dcf611dcc565b1415610ddc575050610ecf565b505b60005b606654811015610ecc57826001600160a01b031660668281548110610e0257fe5b6000918252602090912001546001600160a01b03161415610ec45760665460001901811015610e9257606680546000198101908110610e3d57fe5b600091825260209091200154606680546001600160a01b039092169183908110610e6357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6066805480610e9d57fe5b600082815260209020810160001990810180546001600160a01b0319169055019055610ecc565b600101610de1565b50505b50565b606c546001600160a01b0316610ecc576001600160a01b03811615610ef75780610f0d565b73fb76e9e7d88e308ab530330ed90e84a9525703195b606880546001600160a01b03199081166001600160a01b039384161791829055606980548216878516179055606a80549091168584161790556040805163c45a015560e01b81529051919092169163c45a0155916004808301926020929190829003018186803b158015610f8057600080fd5b505afa158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb891906121e5565b606b80546001600160a01b0319166001600160a01b039283161790819055606854604080516315ab88c960e31b815290519284169363e6a439059392169163ad5c464891600480820192602092909190829003018186803b15801561101c57600080fd5b505afa158015611030573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105491906121e5565b856040518363ffffffff1660e01b8152600401611072929190612411565b60206040518083038186803b15801561108a57600080fd5b505afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c291906121e5565b606c80546001600160a01b0319166001600160a01b0392909216919091179055610ecc611189565b6110f2611ed4565b6033546001600160a01b0390811691161461111f5760405162461bcd60e51b81526004016108879061278d565b606680546001810182556000919091527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943540180546001600160a01b0319166001600160a01b0392909216919091179055565b60008161085161084785610699611ed8565b606e5481565b6071546111ae57618235606e819055607255610bb8606f55601e607055620186a06071555b565b60006111ba611b6b565b6108516111c785856118e9565b60026111d1611b6b565b8161084b57fe5b6000818310156111e857816111ea565b825b90505b92915050565b6001600160a01b031660009081526065602052604090205490565b611216611ed4565b6033546001600160a01b039081169116146112435760405162461bcd60e51b81526004016108879061278d565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b808201828110156111ed5760405162461bcd60e51b815260040161088790612625565b6000818311156111e857816111ea565b600080805b60665481101561139457606754606680546000926001600160a01b0316916321429e6091309190869081106112f657fe5b6000918252602090912001546040516001600160e01b031960e085901b16815261132d92916001600160a01b031690600401612411565b60206040518083038186803b15801561134557600080fd5b505afa158015611359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137d91906123ba565b90506113898382611af8565b9250506001016112c5565b50905090565b606a546001600160a01b031681565b600054610100900460ff16806113c257506113c2611ee4565b806113d0575060005460ff16155b6113ec5760405162461bcd60e51b815260040161088790612683565b600054610100900460ff16158015611417576000805460ff1961ff0019909116610100171660011790555b61141f611eea565b606780546001600160a01b0319908116733014ca10b91cb3d0ad85fef7a3cb95bcac9c0f7917909155606680546001810182556000919091527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e9435401805490911673cb876a393f05a6677a8a029f1c6d7603b416c0a61790558015610ecf576000805461ff001916905550565b606d5481565b60006114bb611ed8565b6108516114c885856118e9565b60026111d1611ed8565b606b546001600160a01b031681565b6033546001600160a01b031690565b6067546001600160a01b031681565b60006002820661151657611511611b6b565b611518565b825b90506002820491505b81156111ed5761153183846111b0565b925060028206156115495761154681846111b0565b90505b600282049150611521565b60656020526000908152604090205481565b606a5460408051635c9302c960e01b815290516000926001600160a01b031691635c9302c9916004808301926020929190829003018186803b1580156115ab57600080fd5b505afa1580156115bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e391906123ba565b9050606d548114156116075760405162461bcd60e51b8152600401610887906126d1565b6000607454611614611dcc565b039050600081607454011161163b5760405162461bcd60e51b815260040161088790612653565b606d829055607154606e5460009161165a916107729085908303611abe565b905060008183039050606061168261167d60745485611af890919063ffffffff16565b611fc4565b90506116b18160008151811061169457fe5b6020026020010151610c2a60745486611af890919063ffffffff16565b6074556116bf826000611b7b565b506000816001815181106116cf57fe5b6020026020010151905060006116f660715461077260705485611abe90919063ffffffff16565b905080156117845760695460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611730903390859060040161242b565b602060405180830381600087803b15801561174a57600080fd5b505af115801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190612318565b505b60006117a56071546107726072546107a08688611e9290919063ffffffff16565b905060006117b38483611e92565b606954606a5460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb926117eb921690859060040161242b565b602060405180830381600087803b15801561180557600080fd5b505af1158015611819573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183d9190612318565b5060735461184b9083611af8565b6073556074546040518a917f49a079c90e07ed02ae8283e86eaeb643c637381d30aa7ba06d155e5b744a85439161188e91859187918a918f919033908c90612854565b60405180910390a2505050505050505050565b6000818312156111e857816111ea565b808203828111156111ed5760405162461bcd60e51b815260040161088790612514565b60715481565b606c546001600160a01b031681565b60008115806119045750508082028282828161190157fe5b04145b6111ed5760405162461bcd60e51b8152600401610887906125c0565b6000818313156111e857816111ea565b60725481565b61193e611ed4565b6033546001600160a01b0390811691161461196b5760405162461bcd60e51b81526004016108879061278d565b6001600160a01b0382161561199657606980546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038116156119c157606a80546001600160a01b0319166001600160a01b0383161790555b5050565b6119cd611ed4565b6033546001600160a01b039081169116146119fa5760405162461bcd60e51b81526004016108879061278d565b6001600160a01b038116611a205760405162461bcd60e51b81526004016108879061257a565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b60006111ea83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612166565b600082611acd575060006111ed565b82820282848281611ada57fe5b04146111ea5760405162461bcd60e51b815260040161088790612715565b6000828201838110156111ea5760405162461bcd60e51b8152600401610887906125ee565b600080611b2c856103e5611abe565b90506000611b3a8285611abe565b90506000611b5483611b4e886103e8611abe565b90611af8565b9050808281611b5f57fe5b04979650505050505050565b6b033b2e3c9fd0803ce800000090565b606654600090611b8d575060006111ed565b6001600160a01b03821615611c09576067546040516317066a5760e21b81526001600160a01b0390911690635c19a95c908590611bce9086906004016123fd565b6000604051808303818588803b158015611be757600080fd5b505af1158015611bfb573d6000803e3d6000fd5b5050505050600190506111ed565b606654600090611c1f9061077286611b4e6112c0565b90508360005b60665481108015611c365750600082115b15611dc057606754606680546000926001600160a01b0316916321429e609130919086908110611c6257fe5b6000918252602090912001546040516001600160e01b031960e085901b168152611c9992916001600160a01b031690600401612411565b60206040518083038186803b158015611cb157600080fd5b505afa158015611cc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce991906123ba565b905083811015611db7576000611cff8583611e92565b9050838110611d0e5783611d10565b805b606754606680549293506001600160a01b0390911691635c19a95c91849187908110611d3857fe5b6000918252602090912001546040516001600160e01b031960e085901b168152611d6e916001600160a01b0316906004016123fd565b6000604051808303818588803b158015611d8757600080fd5b505af1158015611d9b573d6000803e3d6000fd5b5050505050611db38185611e9290919063ffffffff16565b9350505b50600101611c25565b50600195945050505050565b303190565b60675460405163f3fef3a360e01b81526000916001600160a01b03169063f3fef3a390611e04908690869060040161242b565b600060405180830381600087803b158015611e1e57600080fd5b505af1925050508015611e2f575060015b611e8a57611e3b6128da565b80611e465750611e50565b60009150506111ed565b3d808015611e7a576040519150601f19603f3d011682016040523d82523d6000602084013e611e7f565b606091505b5060009150506111ed565b5060016111ed565b60006111ea83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061219d565b3390565b670de0b6b3a764000090565b303b1590565b600054610100900460ff1680611f035750611f03611ee4565b80611f11575060005460ff16155b611f2d5760405162461bcd60e51b815260040161088790612683565b600054610100900460ff16158015611f58576000805460ff1961ff0019909116610100171660011790555b6000611f62611ed4565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508015610ecf576000805461ff001916905550565b606060008211611fe65760405162461bcd60e51b815260040161088790612543565b6000611ff183610992565b604080516002808252606080830184529394509091602083019080368337505060695482519293506001600160a01b031691839150600190811061203157fe5b6001600160a01b03928316602091820292909201810191909152606854604080516315ab88c960e31b81529051919093169263ad5c4648926004808301939192829003018186803b15801561208557600080fd5b505afa158015612099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bd91906121e5565b816000815181106120ca57fe5b6001600160a01b039283166020918202929092010152606854604051637ff36ab560e01b8152911690637ff36ab590849061211090600090869030904290600401612458565b6000604051808303818588803b15801561212957600080fd5b505af115801561213d573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610a3f9190810190612283565b600081836121875760405162461bcd60e51b815260040161088791906124c1565b50600083858161219357fe5b0495945050505050565b600081848411156121c15760405162461bcd60e51b815260040161088791906124c1565b505050900390565b6000602082840312156121da578081fd5b81356111ea8161297f565b6000602082840312156121f6578081fd5b81516111ea8161297f565b60008060408385031215612213578081fd5b823561221e8161297f565b9150602083013561222e8161297f565b809150509250929050565b60008060006060848603121561224d578081fd5b83356122588161297f565b925060208401356122688161297f565b915060408401356122788161297f565b809150509250925092565b60006020808385031215612295578182fd5b825167ffffffffffffffff8111156122ab578283fd5b8301601f810185136122bb578283fd5b80516122ce6122c9826128b4565b61288d565b81815283810190838501858402850186018910156122ea578687fd5b8694505b8385101561230c5780518352600194909401939185019185016122ee565b50979650505050505050565b600060208284031215612329578081fd5b815180151581146111ea578182fd5b6000806040838503121561234a578182fd5b50508035926020909101359150565b60008060006060848603121561236d578283fd5b835161237881612994565b602085015190935061238981612994565b604085015190925063ffffffff81168114612278578182fd5b6000602082840312156123b3578081fd5b5035919050565b6000602082840312156123cb578081fd5b5051919050565b6000806000606084860312156123e6578283fd5b505081359360208301359350604090920135919050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b600060808201868352602060808185015281875180845260a0860191508289019350845b818110156124a15784516001600160a01b03168352938301939183019160010161247c565b50506001600160a01b039690961660408501525050506060015292915050565b6000602080835283518082850152825b818110156124ed578581018301518582016040015282016124d1565b818111156124fe5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b60208082526017908201527f6275792076616c75652073686f756c64206265203e2030000000000000000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601690820152751b9bc819585c9b9a5b99dcc81d1bc818dbdb1b1958dd60521b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526024908201527f63616e20636f6c6c656374206f6e6c79206f6e636520696e206120756269206360408201526379636c6560e01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f696e76616c696420776974686472617720616d6f756e74000000000000000000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526011908201527007374616b65206d757374206265203e203607c1b604082015260600190565b6020808252601690820152756e6f20617070726f7665642076616c696461746f727360501b604082015260600190565b6020808252601e908201527f76616c696461746f72206e6f7420696e20617070726f766564206c6973740000604082015260600190565b96875260208701959095526040860193909352606085019190915260808401526001600160a01b031660a083015260c082015260e00190565b60405181810167ffffffffffffffff811182821017156128ac57600080fd5b604052919050565b600067ffffffffffffffff8211156128ca578081fd5b5060209081020190565b60e01c90565b600060443d10156128ea57610cdd565b600481823e6308c379a06128fe82516128d4565b1461290857610cdd565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156129385750505050610cdd565b828401925082519150808211156129525750505050610cdd565b503d8301602082840101111561296a57505050610cdd565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114610ecf57600080fd5b6001600160701b0381168114610ecf57600080fdfea2646970667358221220c81644fb5118b2211dedf7e78b5379ae287bb2d47b14cc2f7cefe056fc6ac46564736f6c634300060c0033

Deployed ByteCode

0x6080604052600436106102605760003560e01c8063771602f7116101445780639168ae72116100b6578063c816841b1161007a578063c816841b14610669578063c8a4ac9c1461067e578063c8e6c7d91461069e578063d22e9b06146106be578063d8952a49146106d3578063f2fde38b146106f357610267565b80639168ae72146105df578063a5a90636146105ff578063ae94e44814610614578063b67d77c514610634578063c11a56301461065457610267565b80638918c4a2116101085780638918c4a21461054b5780638b9af5c1146105605780638bdb2afa146105805780638da5cb5b146105955780638ef3f761146105aa5780638f907195146105bf57610267565b8063771602f7146104cc5780637ae2b5c7146104ec57806380d04de81461050c57806381028f67146105215780638129fc1c1461053657610267565b80633fb1ccf1116101dd5780636021a9d5116101a15780636021a9d51461042d5780636711281c1461044257806367457022146104575780636d5433e61461047757806370a0823114610497578063715018a6146104b757610267565b80633fb1ccf11461039657806340a141ff146103ab57806347a1671a146103cd5780634d238c8e146103ed5780635fde731c1461040d57610267565b80632681f7e4116102245780632681f7e41461030c5780632cda89431461032e5780632e1a7d4d1461034e57806335aa2e441461036e5780633a4b66f11461038e57610267565b806304d26ebf1461026c57806309b6afb2146102975780630e2286d3146102b7578063150d7e47146102d757806326476204146102ec57610267565b3661026757005b600080fd5b34801561027857600080fd5b50610281610713565b60405161028e919061244f565b60405180910390f35b3480156102a357600080fd5b506102816102b23660046123d2565b610719565b3480156102c357600080fd5b506102816102d2366004612338565b610835565b3480156102e357600080fd5b50610281610860565b6102ff6102fa3660046121c9565b610866565b60405161028e9190612444565b34801561031857600080fd5b50610321610983565b60405161028e91906123fd565b34801561033a57600080fd5b506102816103493660046123a2565b610992565b34801561035a57600080fd5b506102816103693660046123a2565b610a47565b34801561037a57600080fd5b506103216103893660046123a2565b610ca7565b6102ff610cce565b3480156103a257600080fd5b50610321610ce0565b3480156103b757600080fd5b506103cb6103c63660046121c9565b610cef565b005b3480156103d957600080fd5b506103cb6103e8366004612239565b610ed2565b3480156103f957600080fd5b506103cb6104083660046121c9565b6110ea565b34801561041957600080fd5b50610281610428366004612338565b611171565b34801561043957600080fd5b50610281611183565b34801561044e57600080fd5b506103cb611189565b34801561046357600080fd5b50610281610472366004612338565b6111b0565b34801561048357600080fd5b50610281610492366004612338565b6111d8565b3480156104a357600080fd5b506102816104b23660046121c9565b6111f3565b3480156104c357600080fd5b506103cb61120e565b3480156104d857600080fd5b506102816104e7366004612338565b61128d565b3480156104f857600080fd5b50610281610507366004612338565b6112b0565b34801561051857600080fd5b506102816112c0565b34801561052d57600080fd5b5061032161139a565b34801561054257600080fd5b506103cb6113a9565b34801561055757600080fd5b506102816114ab565b34801561056c57600080fd5b5061028161057b366004612338565b6114b1565b34801561058c57600080fd5b506103216114d2565b3480156105a157600080fd5b506103216114e1565b3480156105b657600080fd5b506103216114f0565b3480156105cb57600080fd5b506102816105da366004612338565b6114ff565b3480156105eb57600080fd5b506102816105fa3660046121c9565b611554565b34801561060b57600080fd5b506103cb611566565b34801561062057600080fd5b5061028161062f366004612338565b6118a1565b34801561064057600080fd5b5061028161064f366004612338565b6118b1565b34801561066057600080fd5b506102816118d4565b34801561067557600080fd5b506103216118da565b34801561068a57600080fd5b50610281610699366004612338565b6118e9565b3480156106aa57600080fd5b506102816106b9366004612338565b611920565b3480156106ca57600080fd5b50610281611930565b3480156106df57600080fd5b506103cb6106ee366004612201565b611936565b3480156106ff57600080fd5b506103cb61070e3660046121c9565b6119c5565b606f5481565b6000808061072f84670de0b6b3a7640000611a7c565b905060008561073f606489611abe565b8161074657fe5b049050600061077860715461077261076b606f54607154611af890919063ffffffff16565b8590611abe565b90611a7c565b9050855b8385116108295760006107a66002610772670de0b6b3a76400006107a08a8a611af8565b90611abe565b9050806107b35750610829565b60006107c0828c8c611b1d565b905060006107e1633b9aca00610772856102d286662386f26fc10000611abe565b9050848111610809576107fc83670de0b6b3a7640000611a7c565b6001019750829350610821565b600161081d84670de0b6b3a7640000611a7c565b0396505b50505061077c565b98975050505050505050565b60008161085161084785610699611b6b565b6002855b0461128d565b8161085857fe5b049392505050565b60705481565b60008034116108905760405162461bcd60e51b8152600401610887906127c2565b60405180910390fd5b6066546108af5760405162461bcd60e51b8152600401610887906127ed565b6000805b6001600160a01b038416158015906108cc575060665481105b1561091357836001600160a01b0316606682815481106108e857fe5b6000918252602090912001546001600160a01b03161461090b5760019150610913565b6001016108b3565b506001600160a01b03831615806109275750805b6109435760405162461bcd60e51b81526004016108879061281d565b600061094f3485611b7b565b3360009081526065602052604090205490915061096c9034611af8565b336000908152606560205260409020559392505050565b6068546001600160a01b031681565b6000806000606c60009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156109e557600080fd5b505afa1580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190612359565b506001600160701b031691506001600160701b03169150610a3f828286610719565b949350505050565b600080610a52611dcc565b905060008315610a625783610a73565b336000908152606560205260409020545b9050808015801590610a945750336000908152606560205260409020548211155b610ab05760405162461bcd60e51b815260040161088790612756565b606654600090610ac1908790611a7c565b905060005b606654811015610c1d57606754606680546000926001600160a01b0316916321429e609130919086908110610af757fe5b6000918252602090912001546040516001600160e01b031960e085901b168152610b2e92916001600160a01b031690600401612411565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7e91906123ba565b905080610b8b5750610c15565b828111610bcf57610bbd60668381548110610ba257fe5b6000918252602090912001546001600160a01b031682611dd1565b50610bc88482611e92565b9350610c08565b610bfa60668381548110610bdf57fe5b6000918252602090912001546001600160a01b031684611dd1565b50610c058484611e92565b93505b83610c135750610c1d565b505b600101610ac6565b50610c3084610c2a611dcc565b90611e92565b935083831115610c3e578392505b33600090815260656020526040902054610c589084611e92565b336000908152606560205260409020558215610c9d57604051339084156108fc029085906000818181858888f19350505050158015610c9b573d6000803e3d6000fd5b505b5090949350505050565b60668181548110610cb457fe5b6000918252602090912001546001600160a01b0316905081565b6000610cda6000610866565b90505b90565b6069546001600160a01b031681565b610cf7611ed4565b6033546001600160a01b03908116911614610d245760405162461bcd60e51b81526004016108879061278d565b60675460405163010a14f360e51b81526000916001600160a01b0316906321429e6090610d579030908690600401612411565b60206040518083038186803b158015610d6f57600080fd5b505afa158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da791906123ba565b90508015610dde576000610db9611dcc565b9050610dc58383611dd1565b5080610dcf611dcc565b1415610ddc575050610ecf565b505b60005b606654811015610ecc57826001600160a01b031660668281548110610e0257fe5b6000918252602090912001546001600160a01b03161415610ec45760665460001901811015610e9257606680546000198101908110610e3d57fe5b600091825260209091200154606680546001600160a01b039092169183908110610e6357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6066805480610e9d57fe5b600082815260209020810160001990810180546001600160a01b0319169055019055610ecc565b600101610de1565b50505b50565b606c546001600160a01b0316610ecc576001600160a01b03811615610ef75780610f0d565b73fb76e9e7d88e308ab530330ed90e84a9525703195b606880546001600160a01b03199081166001600160a01b039384161791829055606980548216878516179055606a80549091168584161790556040805163c45a015560e01b81529051919092169163c45a0155916004808301926020929190829003018186803b158015610f8057600080fd5b505afa158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb891906121e5565b606b80546001600160a01b0319166001600160a01b039283161790819055606854604080516315ab88c960e31b815290519284169363e6a439059392169163ad5c464891600480820192602092909190829003018186803b15801561101c57600080fd5b505afa158015611030573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105491906121e5565b856040518363ffffffff1660e01b8152600401611072929190612411565b60206040518083038186803b15801561108a57600080fd5b505afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c291906121e5565b606c80546001600160a01b0319166001600160a01b0392909216919091179055610ecc611189565b6110f2611ed4565b6033546001600160a01b0390811691161461111f5760405162461bcd60e51b81526004016108879061278d565b606680546001810182556000919091527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943540180546001600160a01b0319166001600160a01b0392909216919091179055565b60008161085161084785610699611ed8565b606e5481565b6071546111ae57618235606e819055607255610bb8606f55601e607055620186a06071555b565b60006111ba611b6b565b6108516111c785856118e9565b60026111d1611b6b565b8161084b57fe5b6000818310156111e857816111ea565b825b90505b92915050565b6001600160a01b031660009081526065602052604090205490565b611216611ed4565b6033546001600160a01b039081169116146112435760405162461bcd60e51b81526004016108879061278d565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b808201828110156111ed5760405162461bcd60e51b815260040161088790612625565b6000818311156111e857816111ea565b600080805b60665481101561139457606754606680546000926001600160a01b0316916321429e6091309190869081106112f657fe5b6000918252602090912001546040516001600160e01b031960e085901b16815261132d92916001600160a01b031690600401612411565b60206040518083038186803b15801561134557600080fd5b505afa158015611359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137d91906123ba565b90506113898382611af8565b9250506001016112c5565b50905090565b606a546001600160a01b031681565b600054610100900460ff16806113c257506113c2611ee4565b806113d0575060005460ff16155b6113ec5760405162461bcd60e51b815260040161088790612683565b600054610100900460ff16158015611417576000805460ff1961ff0019909116610100171660011790555b61141f611eea565b606780546001600160a01b0319908116733014ca10b91cb3d0ad85fef7a3cb95bcac9c0f7917909155606680546001810182556000919091527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e9435401805490911673cb876a393f05a6677a8a029f1c6d7603b416c0a61790558015610ecf576000805461ff001916905550565b606d5481565b60006114bb611ed8565b6108516114c885856118e9565b60026111d1611ed8565b606b546001600160a01b031681565b6033546001600160a01b031690565b6067546001600160a01b031681565b60006002820661151657611511611b6b565b611518565b825b90506002820491505b81156111ed5761153183846111b0565b925060028206156115495761154681846111b0565b90505b600282049150611521565b60656020526000908152604090205481565b606a5460408051635c9302c960e01b815290516000926001600160a01b031691635c9302c9916004808301926020929190829003018186803b1580156115ab57600080fd5b505afa1580156115bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e391906123ba565b9050606d548114156116075760405162461bcd60e51b8152600401610887906126d1565b6000607454611614611dcc565b039050600081607454011161163b5760405162461bcd60e51b815260040161088790612653565b606d829055607154606e5460009161165a916107729085908303611abe565b905060008183039050606061168261167d60745485611af890919063ffffffff16565b611fc4565b90506116b18160008151811061169457fe5b6020026020010151610c2a60745486611af890919063ffffffff16565b6074556116bf826000611b7b565b506000816001815181106116cf57fe5b6020026020010151905060006116f660715461077260705485611abe90919063ffffffff16565b905080156117845760695460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611730903390859060040161242b565b602060405180830381600087803b15801561174a57600080fd5b505af115801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190612318565b505b60006117a56071546107726072546107a08688611e9290919063ffffffff16565b905060006117b38483611e92565b606954606a5460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb926117eb921690859060040161242b565b602060405180830381600087803b15801561180557600080fd5b505af1158015611819573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183d9190612318565b5060735461184b9083611af8565b6073556074546040518a917f49a079c90e07ed02ae8283e86eaeb643c637381d30aa7ba06d155e5b744a85439161188e91859187918a918f919033908c90612854565b60405180910390a2505050505050505050565b6000818312156111e857816111ea565b808203828111156111ed5760405162461bcd60e51b815260040161088790612514565b60715481565b606c546001600160a01b031681565b60008115806119045750508082028282828161190157fe5b04145b6111ed5760405162461bcd60e51b8152600401610887906125c0565b6000818313156111e857816111ea565b60725481565b61193e611ed4565b6033546001600160a01b0390811691161461196b5760405162461bcd60e51b81526004016108879061278d565b6001600160a01b0382161561199657606980546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038116156119c157606a80546001600160a01b0319166001600160a01b0383161790555b5050565b6119cd611ed4565b6033546001600160a01b039081169116146119fa5760405162461bcd60e51b81526004016108879061278d565b6001600160a01b038116611a205760405162461bcd60e51b81526004016108879061257a565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b60006111ea83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612166565b600082611acd575060006111ed565b82820282848281611ada57fe5b04146111ea5760405162461bcd60e51b815260040161088790612715565b6000828201838110156111ea5760405162461bcd60e51b8152600401610887906125ee565b600080611b2c856103e5611abe565b90506000611b3a8285611abe565b90506000611b5483611b4e886103e8611abe565b90611af8565b9050808281611b5f57fe5b04979650505050505050565b6b033b2e3c9fd0803ce800000090565b606654600090611b8d575060006111ed565b6001600160a01b03821615611c09576067546040516317066a5760e21b81526001600160a01b0390911690635c19a95c908590611bce9086906004016123fd565b6000604051808303818588803b158015611be757600080fd5b505af1158015611bfb573d6000803e3d6000fd5b5050505050600190506111ed565b606654600090611c1f9061077286611b4e6112c0565b90508360005b60665481108015611c365750600082115b15611dc057606754606680546000926001600160a01b0316916321429e609130919086908110611c6257fe5b6000918252602090912001546040516001600160e01b031960e085901b168152611c9992916001600160a01b031690600401612411565b60206040518083038186803b158015611cb157600080fd5b505afa158015611cc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce991906123ba565b905083811015611db7576000611cff8583611e92565b9050838110611d0e5783611d10565b805b606754606680549293506001600160a01b0390911691635c19a95c91849187908110611d3857fe5b6000918252602090912001546040516001600160e01b031960e085901b168152611d6e916001600160a01b0316906004016123fd565b6000604051808303818588803b158015611d8757600080fd5b505af1158015611d9b573d6000803e3d6000fd5b5050505050611db38185611e9290919063ffffffff16565b9350505b50600101611c25565b50600195945050505050565b303190565b60675460405163f3fef3a360e01b81526000916001600160a01b03169063f3fef3a390611e04908690869060040161242b565b600060405180830381600087803b158015611e1e57600080fd5b505af1925050508015611e2f575060015b611e8a57611e3b6128da565b80611e465750611e50565b60009150506111ed565b3d808015611e7a576040519150601f19603f3d011682016040523d82523d6000602084013e611e7f565b606091505b5060009150506111ed565b5060016111ed565b60006111ea83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061219d565b3390565b670de0b6b3a764000090565b303b1590565b600054610100900460ff1680611f035750611f03611ee4565b80611f11575060005460ff16155b611f2d5760405162461bcd60e51b815260040161088790612683565b600054610100900460ff16158015611f58576000805460ff1961ff0019909116610100171660011790555b6000611f62611ed4565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508015610ecf576000805461ff001916905550565b606060008211611fe65760405162461bcd60e51b815260040161088790612543565b6000611ff183610992565b604080516002808252606080830184529394509091602083019080368337505060695482519293506001600160a01b031691839150600190811061203157fe5b6001600160a01b03928316602091820292909201810191909152606854604080516315ab88c960e31b81529051919093169263ad5c4648926004808301939192829003018186803b15801561208557600080fd5b505afa158015612099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bd91906121e5565b816000815181106120ca57fe5b6001600160a01b039283166020918202929092010152606854604051637ff36ab560e01b8152911690637ff36ab590849061211090600090869030904290600401612458565b6000604051808303818588803b15801561212957600080fd5b505af115801561213d573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610a3f9190810190612283565b600081836121875760405162461bcd60e51b815260040161088791906124c1565b50600083858161219357fe5b0495945050505050565b600081848411156121c15760405162461bcd60e51b815260040161088791906124c1565b505050900390565b6000602082840312156121da578081fd5b81356111ea8161297f565b6000602082840312156121f6578081fd5b81516111ea8161297f565b60008060408385031215612213578081fd5b823561221e8161297f565b9150602083013561222e8161297f565b809150509250929050565b60008060006060848603121561224d578081fd5b83356122588161297f565b925060208401356122688161297f565b915060408401356122788161297f565b809150509250925092565b60006020808385031215612295578182fd5b825167ffffffffffffffff8111156122ab578283fd5b8301601f810185136122bb578283fd5b80516122ce6122c9826128b4565b61288d565b81815283810190838501858402850186018910156122ea578687fd5b8694505b8385101561230c5780518352600194909401939185019185016122ee565b50979650505050505050565b600060208284031215612329578081fd5b815180151581146111ea578182fd5b6000806040838503121561234a578182fd5b50508035926020909101359150565b60008060006060848603121561236d578283fd5b835161237881612994565b602085015190935061238981612994565b604085015190925063ffffffff81168114612278578182fd5b6000602082840312156123b3578081fd5b5035919050565b6000602082840312156123cb578081fd5b5051919050565b6000806000606084860312156123e6578283fd5b505081359360208301359350604090920135919050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b600060808201868352602060808185015281875180845260a0860191508289019350845b818110156124a15784516001600160a01b03168352938301939183019160010161247c565b50506001600160a01b039690961660408501525050506060015292915050565b6000602080835283518082850152825b818110156124ed578581018301518582016040015282016124d1565b818111156124fe5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b60208082526017908201527f6275792076616c75652073686f756c64206265203e2030000000000000000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601690820152751b9bc819585c9b9a5b99dcc81d1bc818dbdb1b1958dd60521b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526024908201527f63616e20636f6c6c656374206f6e6c79206f6e636520696e206120756269206360408201526379636c6560e01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f696e76616c696420776974686472617720616d6f756e74000000000000000000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526011908201527007374616b65206d757374206265203e203607c1b604082015260600190565b6020808252601690820152756e6f20617070726f7665642076616c696461746f727360501b604082015260600190565b6020808252601e908201527f76616c696461746f72206e6f7420696e20617070726f766564206c6973740000604082015260600190565b96875260208701959095526040860193909352606085019190915260808401526001600160a01b031660a083015260c082015260e00190565b60405181810167ffffffffffffffff811182821017156128ac57600080fd5b604052919050565b600067ffffffffffffffff8211156128ca578081fd5b5060209081020190565b60e01c90565b600060443d10156128ea57610cdd565b600481823e6308c379a06128fe82516128d4565b1461290857610cdd565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156129385750505050610cdd565b828401925082519150808211156129525750505050610cdd565b503d8301602082840101111561296a57505050610cdd565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114610ecf57600080fd5b6001600160701b0381168114610ecf57600080fdfea2646970667358221220c81644fb5118b2211dedf7e78b5379ae287bb2d47b14cc2f7cefe056fc6ac46564736f6c634300060c0033