false
true
0

Contract Address Details

0x5958b1f2113a81EE68b65C0c7102425D41b53bfd

Contract Name
Staking
Creator
0x00c578–0ed253 at 0x8f1c30–78ea0e
Balance
1,785,497,357.974423406918239429 PLS ( )
Tokens
Fetching tokens...
Transactions
14,538 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
25960528
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Staking




Optimization enabled
true
Compiler version
v0.8.20+commit.a1b79de6




Optimization runs
200
EVM Version
default




Verified at
2024-05-02T05:54:43.075283Z

Staking.sol

// SPDX-License-Identifier: Unlicensed

pragma solidity 0.8.20;

import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";

interface IUFOToken {
    function pairs(uint256 index) external view returns (address);
}

interface ILPToken {
    function balanceOf(address owner) external view returns (uint);
    function totalSupply() external view returns (uint);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

contract Staking is ReentrancyGuard {
    using SafeERC20 for IERC20;
	
	IUFOToken public UFOToken;
	
	uint256 public UFOStaked;
	uint256 public rewardPerShare;
	uint256 public precisionFactor;
	uint256 public undistributedReward;
	
	address[] public pairs;
	address[] public stakers;
	
	uint256 currentIndex;
	
	struct StakingInfo {
	  uint256 stakedLP; 
	  uint256 stakedUFO;
	  uint256 rewardExcluded;
	  uint256 pendingReward;
	  address pool;
    }
	
	mapping(address => mapping(address => StakingInfo)) public stakingInfo;
	mapping(address => uint256) public stakerIndexes;
	mapping(address => uint256) public claimedReward;
	mapping(address => bool) public isStaker;
	mapping(address => bool) public isliquidityPair;
	
    event LPStaked(address staker, address pool, uint256 amount);
    event LPUnstaked(address staker, address pool, uint256 amount);
	event RewardClaimed(address staker, uint256 reward);
	event PoolUpdated(uint256 amount);	
	
    constructor () {
	    precisionFactor = 10**18;
	    UFOToken = IUFOToken(0x456548A9B56eFBbD89Ca0309edd17a9E20b04018);
		
	    pairs.push(address(UFOToken.pairs(0)));
	    pairs.push(address(UFOToken.pairs(1)));
	    pairs.push(address(UFOToken.pairs(2)));
	    pairs.push(address(UFOToken.pairs(3)));
	    pairs.push(address(UFOToken.pairs(4)));
	    pairs.push(address(UFOToken.pairs(5)));
	    pairs.push(address(UFOToken.pairs(6)));
		
		isliquidityPair[address(UFOToken.pairs(0))] = true;
		isliquidityPair[address(UFOToken.pairs(1))] = true;
		isliquidityPair[address(UFOToken.pairs(2))] = true;
		isliquidityPair[address(UFOToken.pairs(3))] = true;
		isliquidityPair[address(UFOToken.pairs(4))] = true;
		isliquidityPair[address(UFOToken.pairs(5))] = true;
		isliquidityPair[address(UFOToken.pairs(6))] = true;
    }
	
	receive() external payable {}
	
	function stake(address pool, uint256 amount, address staker) external {
		require(address(msg.sender) == address(UFOToken), "Staker address is not allowed");
		require(isliquidityPair[address(pool)], "Pool address is not correct");
		require(address(staker) != address(0), "Pool address is not correct");
		
		address token0 = ILPToken(pool).token0();
		uint256 supply = ILPToken(pool).totalSupply();
	    (uint256 token0Balance, uint256 token1Balance, ) = ILPToken(pool).getReserves();
		
		uint256 UFOShare;
		if(address(token0) == address(UFOToken))
		{
		   UFOShare = (token0Balance * amount) / (supply);
		}
		else
		{
		   UFOShare = (token1Balance * amount) / (supply);
		}
		
		UFOStaked += UFOShare;
		
		if(stakingInfo[address(staker)][address(pool)].stakedLP > 0) 
		{
            uint256 pending = pendingReward(address(staker), address(pool));
            if(pending > 0) 
			{
			   stakingInfo[address(staker)][address(pool)].pendingReward += pending;
            }
        }
		
		if(!isStaker[address(staker)])
		{
		   isStaker[address(staker)] = true; 
		   addStaker(address(staker));
		}
		
		stakingInfo[address(staker)][address(pool)].stakedLP += amount;
		stakingInfo[address(staker)][address(pool)].stakedUFO += UFOShare;
		stakingInfo[address(staker)][address(pool)].pool = address(pool);
		stakingInfo[address(staker)][address(pool)].rewardExcluded = (((stakingInfo[address(staker)][address(pool)].stakedUFO) * rewardPerShare) / precisionFactor);
        emit LPStaked(address(staker), address(pool), amount);
    }
	
	function claimReward(address pool) external nonReentrant {
		require(isliquidityPair[address(pool)], "Pool address is not correct");
		
		uint256 pending = pendingReward(address(msg.sender), address(pool));
		        pending += stakingInfo[address(msg.sender)][address(pool)].pendingReward;
				
		if(pending > 0) 
		{
		    uint256 cBalance = IERC20(pool).balanceOf(address(msg.sender));
			uint256 sBalance = stakingInfo[address(msg.sender)][address(pool)].stakedLP;
			uint256 sUFOBalance = stakingInfo[address(msg.sender)][address(pool)].stakedUFO;
			
			if(sBalance > cBalance)
			{
			    uint256 newPending = (pending * cBalance) / (sBalance);
				uint256 newUFOBalance = (sUFOBalance * cBalance) / (sBalance);
				
				UFOStaked -= (sUFOBalance - newUFOBalance);
				
				_updatePool((pending - newPending));
			    payable(address(msg.sender)).transfer(newPending);
				
				claimedReward[address(msg.sender)] += newPending;
				stakingInfo[address(msg.sender)][address(pool)].stakedLP = cBalance;
				stakingInfo[address(msg.sender)][address(pool)].stakedUFO = newUFOBalance;
			    stakingInfo[address(msg.sender)][address(pool)].rewardExcluded = (((stakingInfo[address(msg.sender)][address(pool)].stakedUFO) * rewardPerShare) / precisionFactor);
			    stakingInfo[address(msg.sender)][address(pool)].pendingReward = 0;
			    emit RewardClaimed(address(msg.sender), pending);
			}
			else
			{
			    claimedReward[address(msg.sender)] += pending;
			    payable(address(msg.sender)).transfer(pending);
			    stakingInfo[address(msg.sender)][address(pool)].rewardExcluded = (((stakingInfo[address(msg.sender)][address(pool)].stakedUFO) * rewardPerShare) / precisionFactor);
			    stakingInfo[address(msg.sender)][address(pool)].pendingReward = 0;
			    emit RewardClaimed(address(msg.sender), pending);
			}
		}
    }
	
	function claimRewards() external nonReentrant {
	
		for (uint256 i = 0; i < pairs.length; i++) 
	    {
		    address pool = pairs[i];
		    uint256 pending = pendingReward(address(msg.sender), address(pool));
		            pending += stakingInfo[address(msg.sender)][address(pool)].pendingReward;
					
			if(pending > 0) 
			{
				uint256 cBalance = IERC20(pool).balanceOf(address(msg.sender));
				uint256 sBalance = stakingInfo[address(msg.sender)][address(pool)].stakedLP;
				uint256 sUFOBalance = stakingInfo[address(msg.sender)][address(pool)].stakedUFO;
				
				if(sBalance > cBalance)
				{
					uint256 newPending = (pending * cBalance) / (sBalance);
					uint256 newUFOBalance = (sUFOBalance * cBalance) / (sBalance);
					
					UFOStaked -= (sUFOBalance - newUFOBalance);
					
					_updatePool((pending - newPending));
					payable(address(msg.sender)).transfer(newPending);
					
					claimedReward[address(msg.sender)] += newPending;
					stakingInfo[address(msg.sender)][address(pool)].stakedLP = cBalance;
					stakingInfo[address(msg.sender)][address(pool)].stakedUFO = newUFOBalance;
					stakingInfo[address(msg.sender)][address(pool)].rewardExcluded = (((stakingInfo[address(msg.sender)][address(pool)].stakedUFO) * rewardPerShare) / precisionFactor);
					stakingInfo[address(msg.sender)][address(pool)].pendingReward = 0;
					emit RewardClaimed(address(msg.sender), pending);
				}
				else
				{
				     claimedReward[address(msg.sender)] += pending;
					 payable(address(msg.sender)).transfer(pending);
					 stakingInfo[address(msg.sender)][address(pool)].rewardExcluded = (((stakingInfo[address(msg.sender)][address(pool)].stakedUFO) * rewardPerShare) / precisionFactor);
					 stakingInfo[address(msg.sender)][address(pool)].pendingReward = 0;
					 emit RewardClaimed(address(msg.sender), pending);
				}
			}
		}
    }
	
	function process(uint256 gas) external {
	
		uint256 stakerCount = stakers.length;
        if(stakerCount == 0) { return; }

        uint256 gasUsed = 0;
        uint256 gasLeft = gasleft();

        uint256 iterations = 0;
		
        while(gasUsed < gas && iterations < stakerCount)
		{
            if(currentIndex >= stakerCount)
			{
               currentIndex = 0;
            }
			
			updateBalance(stakers[currentIndex]);
			stakerCount = stakers.length;
			
            gasUsed = gasUsed + gasLeft - gasleft();
            gasLeft = gasleft();
            currentIndex++;
            iterations++;
        }
    }
	
	function updateBalance(address staker) internal {
	   bool removeFromList = true;
	   
	   for (uint256 i = 0; i < pairs.length; i++) 
	   {
	       address pool = pairs[i];
		   uint256 sBalance = stakingInfo[address(staker)][address(pool)].stakedLP;
		   uint256 sUFOBalance = stakingInfo[address(staker)][address(pool)].stakedUFO;
		   
		   if(sBalance > 0)
		   {
		       uint256 cBalance = IERC20(pool).balanceOf(address(staker));
			   if(cBalance > 0)
			   {
			       removeFromList = false;
			   }
			   if(sBalance > cBalance)
			   {
			       uint256 pending = pendingReward(address(staker), address(pool));
				           pending += stakingInfo[address(staker)][address(pool)].pendingReward;
				   uint256 newPending = 0; 		   
				   uint256 newUFOBalance = (sUFOBalance * cBalance) / (sBalance);
				   
				   UFOStaked -= (sUFOBalance - newUFOBalance);
				   
				   if(pending > 0)
				   {
				       newPending = (pending * cBalance) / (sBalance);
				       _updatePool((pending - newPending));  
				   }
				   
				   stakingInfo[address(staker)][address(pool)].stakedLP = cBalance;
				   stakingInfo[address(staker)][address(pool)].stakedUFO = newUFOBalance;
				   stakingInfo[address(staker)][address(pool)].rewardExcluded = (((stakingInfo[address(staker)][address(pool)].stakedUFO) * rewardPerShare) / precisionFactor);
				   stakingInfo[address(staker)][address(pool)].pendingReward = newPending;
			   }
		   }
       }
	   
	   if(removeFromList)
	   {
	      removeStaker(staker);
		  isStaker[address(staker)] = false; 
	   }
    }
	
	function _updatePool(uint256 amount) internal {
	    if(UFOStaked > 0)
	    {
	       uint256 totalAmount = undistributedReward + amount; 
	       rewardPerShare += ((totalAmount * precisionFactor) / UFOStaked);
		   undistributedReward = 0;
	    }
	    else
	    {
	       undistributedReward += amount;
	    }
	    emit PoolUpdated(amount);
    }
	
	function updatePool(uint256 amount) external {
	   require(msg.sender == address(UFOToken), "Sender not allowed");
	   
	   if(UFOStaked > 0)
	   {
	       uint256 totalAmount = undistributedReward + amount; 
	       rewardPerShare += ((totalAmount * precisionFactor) / UFOStaked);
		   undistributedReward = 0;
	   }
	   else
	   {
	      undistributedReward += amount;
	   }
	   emit PoolUpdated(amount);
    }
	
	function pendingReward(address staker, address pool) public view returns (uint256) {
	
	   if(stakingInfo[address(staker)][address(pool)].stakedLP > 0)
	   {
		    uint256 staked = stakingInfo[address(staker)][address(pool)].stakedUFO;
		    uint256 claimed = stakingInfo[address(staker)][address(pool)].rewardExcluded;
		   
		    uint256 pending = ((staked * rewardPerShare) / precisionFactor) - (claimed);
		    return pending;
       } 
	   else 
	   {
		   return 0;
	   }
    }
	
	function addStaker(address staker) internal {
       stakerIndexes[staker] = stakers.length;
       stakers.push(staker);
    }
	
    function removeStaker(address staker) internal {
       stakers[stakerIndexes[staker]] = stakers[stakers.length-1];
       stakerIndexes[stakers[stakers.length-1]] = stakerIndexes[staker];
       stakers.pop();
    }
}
        

Address.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
          

IERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        uint256 amount
    ) external returns (bool);
}
          

ReentrancyGuard.sol

// SPDX-License-Identifier: Unlicensed

pragma solidity 0.8.20;

abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
       _status = _NOT_ENTERED;
    }
	
    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        _status = _ENTERED;

        _;
		
        _status = _NOT_ENTERED;
    }
}
          

SafeERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./draft-IERC20Permit.sol";
import "./Address.sol";

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

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

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

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

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

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

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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

draft-IERC20Permit.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"LPStaked","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":false},{"type":"address","name":"pool","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LPUnstaked","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":false},{"type":"address","name":"pool","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PoolUpdated","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardClaimed","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":false},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"UFOStaked","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUFOToken"}],"name":"UFOToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimReward","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimRewards","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"claimedReward","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isStaker","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isliquidityPair","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pairs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingReward","inputs":[{"type":"address","name":"staker","internalType":"address"},{"type":"address","name":"pool","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"precisionFactor","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"process","inputs":[{"type":"uint256","name":"gas","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerShare","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stake","inputs":[{"type":"address","name":"pool","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"staker","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakerIndexes","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"stakers","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"stakedLP","internalType":"uint256"},{"type":"uint256","name":"stakedUFO","internalType":"uint256"},{"type":"uint256","name":"rewardExcluded","internalType":"uint256"},{"type":"uint256","name":"pendingReward","internalType":"uint256"},{"type":"address","name":"pool","internalType":"address"}],"name":"stakingInfo","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"undistributedReward","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePool","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

Verify & Publish
0x608060405234801562000010575f80fd5b5060015f818155670de0b6b3a7640000600490815582546001600160a01b03191673456548a9b56efbbd89ca0309edd17a9e20b0401890811790935560405163172358f160e31b81526006939263b91ac7889262000072920190815260200190565b602060405180830381865afa1580156200008e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620000b4919062000891565b8154600180820184555f93845260209093200180546001600160a01b0319166001600160a01b03928316179055815460405163172358f160e31b8152600481019390935260069291169063b91ac78890602401602060405180830381865afa15801562000123573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000149919062000891565b8154600180820184555f93845260209093200180546001600160a01b0319166001600160a01b03928316179055905460405163172358f160e31b815260026004820152600692919091169063b91ac78890602401602060405180830381865afa158015620001b9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001df919062000891565b8154600180820184555f93845260209093200180546001600160a01b0319166001600160a01b03928316179055905460405163172358f160e31b815260036004820152600692919091169063b91ac78890602401602060405180830381865afa1580156200024f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000275919062000891565b8154600180820184555f93845260209093200180546001600160a01b0319166001600160a01b03928316179055905460405163172358f160e31b8152600480820152600692919091169063b91ac78890602401602060405180830381865afa158015620002e4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200030a919062000891565b8154600180820184555f93845260209093200180546001600160a01b0319166001600160a01b03928316179055905460405163172358f160e31b815260056004820152600692919091169063b91ac78890602401602060405180830381865afa1580156200037a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620003a0919062000891565b8154600180820184555f93845260209093200180546001600160a01b0319166001600160a01b03928316179055905460405163172358f160e31b815260066004820181905292919091169063b91ac78890602401602060405180830381865afa15801562000410573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000436919062000891565b8154600180820184555f9384526020842090910180546001600160a01b0319166001600160a01b03938416179055805460405163172358f160e31b8152600481018590529193600d93909291169063b91ac78890602401602060405180830381865afa158015620004a9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620004cf919062000891565b6001600160a01b039081168252602082019290925260409081015f908120805460ff19169415159490941790935560018054915163172358f160e31b8152600481018290529093600d939092169063b91ac78890602401602060405180830381865afa15801562000542573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000568919062000891565b6001600160a01b039081168252602082019290925260409081015f908120805460ff19169415159490941790935560018054915163172358f160e31b8152600260048201529093600d939092169063b91ac78890602401602060405180830381865afa158015620005db573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000601919062000891565b6001600160a01b039081168252602082019290925260409081015f908120805460ff19169415159490941790935560018054915163172358f160e31b8152600360048201529093600d939092169063b91ac78890602401602060405180830381865afa15801562000674573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200069a919062000891565b6001600160a01b039081168252602082019290925260409081015f908120805460ff19169415159490941790935560018054915163172358f160e31b81526004808201529093600d939092169063b91ac78890602401602060405180830381865afa1580156200070c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000732919062000891565b6001600160a01b039081168252602082019290925260409081015f908120805460ff19169415159490941790935560018054915163172358f160e31b8152600560048201529093600d939092169063b91ac78890602401602060405180830381865afa158015620007a5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620007cb919062000891565b6001600160a01b039081168252602082019290925260409081015f908120805460ff19169415159490941790935560018054915163172358f160e31b8152600660048201529093600d939092169063b91ac78890602401602060405180830381865afa1580156200083e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000864919062000891565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055620008c0565b5f60208284031215620008a2575f80fd5b81516001600160a01b0381168114620008b9575f80fd5b9392505050565b61187b80620008ce5f395ff3fe608060405260043610610108575f3560e01c80636f1e853311610092578063d279c19111610062578063d279c19114610339578063dd4785f514610358578063efa6c1af14610383578063fd5e6dd1146103b1578063ffb2c479146103d0575f80fd5b80636f1e8533146102a85780639ced7e76146102e65780639d902fc014610305578063b91ac7881461031a575f80fd5b8063446a2ec8116100d8578063446a2ec81461019b57806346c003ac146101b057806351eb05a6146101c55780635750ec53146101e45780635e3e4ab614610271575f80fd5b806316a9313b146101135780631e6f3d8a1461013b578063294091cd14610166578063372500ab14610187575f80fd5b3661010f57005b5f80fd5b34801561011e575f80fd5b5061012860055481565b6040519081526020015b60405180910390f35b348015610146575f80fd5b50610128610155366004611601565b600b6020525f908152604090205481565b348015610171575f80fd5b50610185610180366004611623565b6103ef565b005b348015610192575f80fd5b506101856108a4565b3480156101a6575f80fd5b5061012860035481565b3480156101bb575f80fd5b5061012860025481565b3480156101d0575f80fd5b506101856101df366004611662565b610c67565b3480156101ef575f80fd5b506102406101fe366004611679565b600960209081525f928352604080842090915290825290208054600182015460028301546003840154600490940154929391929091906001600160a01b031685565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a001610132565b34801561027c575f80fd5b50600154610290906001600160a01b031681565b6040516001600160a01b039091168152602001610132565b3480156102b3575f80fd5b506102d66102c2366004611601565b600c6020525f908152604090205460ff1681565b6040519015158152602001610132565b3480156102f1575f80fd5b50610128610300366004611679565b610d56565b348015610310575f80fd5b5061012860045481565b348015610325575f80fd5b50610290610334366004611662565b610df2565b348015610344575f80fd5b50610185610353366004611601565b610e1a565b348015610363575f80fd5b50610128610372366004611601565b600a6020525f908152604090205481565b34801561038e575f80fd5b506102d661039d366004611601565b600d6020525f908152604090205460ff1681565b3480156103bc575f80fd5b506102906103cb366004611662565b6111c6565b3480156103db575f80fd5b506101856103ea366004611662565b6111d5565b6001546001600160a01b0316331461044e5760405162461bcd60e51b815260206004820152601d60248201527f5374616b65722061646472657373206973206e6f7420616c6c6f77656400000060448201526064015b60405180910390fd5b6001600160a01b0383165f908152600d602052604090205460ff166104855760405162461bcd60e51b8152600401610445906116b0565b6001600160a01b0381166104ab5760405162461bcd60e51b8152600401610445906116b0565b5f836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061050c91906116e7565b90505f846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561054b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061056f9190611702565b90505f80866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156105af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d39190611734565b506001546001600160701b039283169450911691505f906001600160a01b039081169086160361061957836106088885611789565b61061291906117a0565b9050610631565b836106248884611789565b61062e91906117a0565b90505b8060025f82825461064291906117bf565b90915550506001600160a01b038087165f908152600960209081526040808320938c1683529290522054156106c5575f61067c878a610d56565b905080156106c3576001600160a01b038088165f908152600960209081526040808320938d16835292905290812060030180548392906106bd9084906117bf565b90915550505b505b6001600160a01b0386165f908152600c602052604090205460ff16610756576001600160a01b0386165f818152600c60209081526040808320805460ff1916600190811790915560078054600a909452918420839055820181559091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b03191690911790555b6001600160a01b038087165f908152600960209081526040808320938c168352929052908120805489929061078c9084906117bf565b90915550506001600160a01b038087165f908152600960209081526040808320938c16835292905290812060010180548392906107ca9084906117bf565b90915550506001600160a01b038681165f908152600960209081526040808320938c16808452939091529020600480820180546001600160a01b0319169093179092559054600354600190920154909161082391611789565b61082d91906117a0565b6001600160a01b038781165f818152600960209081526040808320948e1680845294825291829020600201949094558051918252928101919091529081018890527e8bfa58790ca176ab7c8a54d2fa2a44b1b1c883248e56849845d29a6e944aa49060600160405180910390a15050505050505050565b60025f54036108f55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610445565b60025f9081555b600654811015610c60575f6006828154811061091a5761091a6117d2565b5f9182526020822001546001600160a01b031691506109393383610d56565b335f9081526009602090815260408083206001600160a01b038716845290915290206003015490915061096c90826117bf565b90508015610c4b576040516370a0823160e01b81523360048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa1580156109b8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109dc9190611702565b335f9081526009602090815260408083206001600160a01b0388168452909152902080546001909101549192509082821115610b63575f82610a1e8587611789565b610a2891906117a0565b90505f83610a368685611789565b610a4091906117a0565b9050610a4c81846117e6565b60025f828254610a5c91906117e6565b90915550610a749050610a6f83886117e6565b610cb6565b604051339083156108fc029084905f818181858888f19350505050158015610a9e573d5f803e3d5ffd5b50335f908152600b602052604081208054849290610abd9084906117bf565b9091555050335f9081526009602090815260408083206001600160a01b038b1684529091529020858155600101819055600454600354610afd9083611789565b610b0791906117a0565b335f8181526009602090815260408083206001600160a01b038d16845282528083206002810195909555600390940191909155825191825281018890525f80516020611826833981519152910160405180910390a15050610c47565b335f908152600b602052604081208054869290610b819084906117bf565b9091555050604051339085156108fc029086905f818181858888f19350505050158015610bb0573d5f803e3d5ffd5b50600454600354335f9081526009602090815260408083206001600160a01b038b168452909152902060010154610be79190611789565b610bf191906117a0565b335f8181526009602090815260408083206001600160a01b038b16845282528083206002810195909555600390940191909155825191825281018690525f80516020611826833981519152910160405180910390a15b5050505b50508080610c58906117f9565b9150506108fc565b5060015f55565b6001546001600160a01b03163314610cb65760405162461bcd60e51b815260206004820152601260248201527114d95b99195c881b9bdd08185b1b1bddd95960721b6044820152606401610445565b60025415610d09575f81600554610ccd91906117bf565b905060025460045482610ce09190611789565b610cea91906117a0565b60035f828254610cfa91906117bf565b90915550505f60055550610d20565b8060055f828254610d1a91906117bf565b90915550505b6040518181527f141d729c29cc848b27c53f7dbe9f9542cedc4ed2efa7bd2aeb2a4bdce06a407f9060200160405180910390a150565b6001600160a01b038083165f90815260096020908152604080832093851683529290529081205415610de9576001600160a01b038381165f9081526009602090815260408083209386168352929052908120600181015460029091015460045460035492939192839190610dca9086611789565b610dd491906117a0565b610dde91906117e6565b9350610dec92505050565b505f5b92915050565b60068181548110610e01575f80fd5b5f918252602090912001546001600160a01b0316905081565b60025f5403610e6b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610445565b60025f9081556001600160a01b0382168152600d602052604090205460ff16610ea65760405162461bcd60e51b8152600401610445906116b0565b5f610eb13383610d56565b335f9081526009602090815260408083206001600160a01b0387168452909152902060030154909150610ee490826117bf565b905080156111be576040516370a0823160e01b81523360048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015610f30573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f549190611702565b335f9081526009602090815260408083206001600160a01b03881684529091529020805460019091015491925090828211156110d6575f82610f968587611789565b610fa091906117a0565b90505f83610fae8685611789565b610fb891906117a0565b9050610fc481846117e6565b60025f828254610fd491906117e6565b90915550610fe79050610a6f83886117e6565b604051339083156108fc029084905f818181858888f19350505050158015611011573d5f803e3d5ffd5b50335f908152600b6020526040812080548492906110309084906117bf565b9091555050335f9081526009602090815260408083206001600160a01b038b16845290915290208581556001018190556004546003546110709083611789565b61107a91906117a0565b335f8181526009602090815260408083206001600160a01b038d16845282528083206002810195909555600390940191909155825191825281018890525f80516020611826833981519152910160405180910390a150506111ba565b335f908152600b6020526040812080548692906110f49084906117bf565b9091555050604051339085156108fc029086905f818181858888f19350505050158015611123573d5f803e3d5ffd5b50600454600354335f9081526009602090815260408083206001600160a01b038b16845290915290206001015461115a9190611789565b61116491906117a0565b335f8181526009602090815260408083206001600160a01b038b16845282528083206002810195909555600390940191909155825191825281018690525f80516020611826833981519152910160405180910390a15b5050505b505060015f55565b60078181548110610e01575f80fd5b6007545f8190036111e4575050565b5f805a90505f5b84831080156111f957508381105b1561128357836008541061120c575f6008555b61123d600760085481548110611224576112246117d2565b5f918252602090912001546001600160a01b031661128a565b60075493505a61124d83856117bf565b61125791906117e6565b92505a600880549193505f61126b836117f9565b9190505550808061127b906117f9565b9150506111eb565b5050505050565b60015f5b6006548110156114a6575f600682815481106112ac576112ac6117d2565b5f918252602080832091909101546001600160a01b0387811684526009835260408085209190921680855292529091208054600190910154919250908115611490576040516370a0823160e01b81526001600160a01b0387811660048301525f91908516906370a0823190602401602060405180830381865afa158015611335573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113599190611702565b90508015611365575f95505b8083111561148e575f6113788886610d56565b6001600160a01b03808a165f908152600960209081526040808320938a16835292905220600301549091506113ad90826117bf565b90505f80856113bc8587611789565b6113c691906117a0565b90506113d281866117e6565b60025f8282546113e291906117e6565b9091555050821561141157856113f88585611789565b61140291906117a0565b9150611411610a6f83856117e6565b6001600160a01b038a81165f908152600960209081526040808320938b1683529290522084815560010181905560045460035461144e9083611789565b61145891906117a0565b6001600160a01b038b81165f908152600960209081526040808320938c1683529290522060028101919091556003019190915550505b505b505050808061149e906117f9565b91505061128e565b5080156114d6576114b6826114da565b6001600160a01b0382165f908152600c60205260409020805460ff191690555b5050565b600780546114ea906001906117e6565b815481106114fa576114fa6117d2565b5f9182526020808320909101546001600160a01b038481168452600a909252604090922054600780549290931692918110611537576115376117d2565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559183168152600a9182905260408120546007805491939291611582906001906117e6565b81548110611592576115926117d2565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205560078054806115c7576115c7611811565b5f8281526020902081015f1990810180546001600160a01b031916905501905550565b6001600160a01b03811681146115fe575f80fd5b50565b5f60208284031215611611575f80fd5b813561161c816115ea565b9392505050565b5f805f60608486031215611635575f80fd5b8335611640816115ea565b9250602084013591506040840135611657816115ea565b809150509250925092565b5f60208284031215611672575f80fd5b5035919050565b5f806040838503121561168a575f80fd5b8235611695816115ea565b915060208301356116a5816115ea565b809150509250929050565b6020808252601b908201527f506f6f6c2061646472657373206973206e6f7420636f72726563740000000000604082015260600190565b5f602082840312156116f7575f80fd5b815161161c816115ea565b5f60208284031215611712575f80fd5b5051919050565b80516001600160701b038116811461172f575f80fd5b919050565b5f805f60608486031215611746575f80fd5b61174f84611719565b925061175d60208501611719565b9150604084015163ffffffff81168114611657575f80fd5b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610dec57610dec611775565b5f826117ba57634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610dec57610dec611775565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610dec57610dec611775565b5f6001820161180a5761180a611775565b5060010190565b634e487b7160e01b5f52603160045260245ffdfe106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241a2646970667358221220d7831bfee8ec7caf434b754061f8214c0eedc374d7ee1a80648ab005e0812d7b64736f6c63430008140033

Deployed ByteCode

0x608060405260043610610108575f3560e01c80636f1e853311610092578063d279c19111610062578063d279c19114610339578063dd4785f514610358578063efa6c1af14610383578063fd5e6dd1146103b1578063ffb2c479146103d0575f80fd5b80636f1e8533146102a85780639ced7e76146102e65780639d902fc014610305578063b91ac7881461031a575f80fd5b8063446a2ec8116100d8578063446a2ec81461019b57806346c003ac146101b057806351eb05a6146101c55780635750ec53146101e45780635e3e4ab614610271575f80fd5b806316a9313b146101135780631e6f3d8a1461013b578063294091cd14610166578063372500ab14610187575f80fd5b3661010f57005b5f80fd5b34801561011e575f80fd5b5061012860055481565b6040519081526020015b60405180910390f35b348015610146575f80fd5b50610128610155366004611601565b600b6020525f908152604090205481565b348015610171575f80fd5b50610185610180366004611623565b6103ef565b005b348015610192575f80fd5b506101856108a4565b3480156101a6575f80fd5b5061012860035481565b3480156101bb575f80fd5b5061012860025481565b3480156101d0575f80fd5b506101856101df366004611662565b610c67565b3480156101ef575f80fd5b506102406101fe366004611679565b600960209081525f928352604080842090915290825290208054600182015460028301546003840154600490940154929391929091906001600160a01b031685565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a001610132565b34801561027c575f80fd5b50600154610290906001600160a01b031681565b6040516001600160a01b039091168152602001610132565b3480156102b3575f80fd5b506102d66102c2366004611601565b600c6020525f908152604090205460ff1681565b6040519015158152602001610132565b3480156102f1575f80fd5b50610128610300366004611679565b610d56565b348015610310575f80fd5b5061012860045481565b348015610325575f80fd5b50610290610334366004611662565b610df2565b348015610344575f80fd5b50610185610353366004611601565b610e1a565b348015610363575f80fd5b50610128610372366004611601565b600a6020525f908152604090205481565b34801561038e575f80fd5b506102d661039d366004611601565b600d6020525f908152604090205460ff1681565b3480156103bc575f80fd5b506102906103cb366004611662565b6111c6565b3480156103db575f80fd5b506101856103ea366004611662565b6111d5565b6001546001600160a01b0316331461044e5760405162461bcd60e51b815260206004820152601d60248201527f5374616b65722061646472657373206973206e6f7420616c6c6f77656400000060448201526064015b60405180910390fd5b6001600160a01b0383165f908152600d602052604090205460ff166104855760405162461bcd60e51b8152600401610445906116b0565b6001600160a01b0381166104ab5760405162461bcd60e51b8152600401610445906116b0565b5f836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061050c91906116e7565b90505f846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561054b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061056f9190611702565b90505f80866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156105af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d39190611734565b506001546001600160701b039283169450911691505f906001600160a01b039081169086160361061957836106088885611789565b61061291906117a0565b9050610631565b836106248884611789565b61062e91906117a0565b90505b8060025f82825461064291906117bf565b90915550506001600160a01b038087165f908152600960209081526040808320938c1683529290522054156106c5575f61067c878a610d56565b905080156106c3576001600160a01b038088165f908152600960209081526040808320938d16835292905290812060030180548392906106bd9084906117bf565b90915550505b505b6001600160a01b0386165f908152600c602052604090205460ff16610756576001600160a01b0386165f818152600c60209081526040808320805460ff1916600190811790915560078054600a909452918420839055820181559091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b03191690911790555b6001600160a01b038087165f908152600960209081526040808320938c168352929052908120805489929061078c9084906117bf565b90915550506001600160a01b038087165f908152600960209081526040808320938c16835292905290812060010180548392906107ca9084906117bf565b90915550506001600160a01b038681165f908152600960209081526040808320938c16808452939091529020600480820180546001600160a01b0319169093179092559054600354600190920154909161082391611789565b61082d91906117a0565b6001600160a01b038781165f818152600960209081526040808320948e1680845294825291829020600201949094558051918252928101919091529081018890527e8bfa58790ca176ab7c8a54d2fa2a44b1b1c883248e56849845d29a6e944aa49060600160405180910390a15050505050505050565b60025f54036108f55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610445565b60025f9081555b600654811015610c60575f6006828154811061091a5761091a6117d2565b5f9182526020822001546001600160a01b031691506109393383610d56565b335f9081526009602090815260408083206001600160a01b038716845290915290206003015490915061096c90826117bf565b90508015610c4b576040516370a0823160e01b81523360048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa1580156109b8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109dc9190611702565b335f9081526009602090815260408083206001600160a01b0388168452909152902080546001909101549192509082821115610b63575f82610a1e8587611789565b610a2891906117a0565b90505f83610a368685611789565b610a4091906117a0565b9050610a4c81846117e6565b60025f828254610a5c91906117e6565b90915550610a749050610a6f83886117e6565b610cb6565b604051339083156108fc029084905f818181858888f19350505050158015610a9e573d5f803e3d5ffd5b50335f908152600b602052604081208054849290610abd9084906117bf565b9091555050335f9081526009602090815260408083206001600160a01b038b1684529091529020858155600101819055600454600354610afd9083611789565b610b0791906117a0565b335f8181526009602090815260408083206001600160a01b038d16845282528083206002810195909555600390940191909155825191825281018890525f80516020611826833981519152910160405180910390a15050610c47565b335f908152600b602052604081208054869290610b819084906117bf565b9091555050604051339085156108fc029086905f818181858888f19350505050158015610bb0573d5f803e3d5ffd5b50600454600354335f9081526009602090815260408083206001600160a01b038b168452909152902060010154610be79190611789565b610bf191906117a0565b335f8181526009602090815260408083206001600160a01b038b16845282528083206002810195909555600390940191909155825191825281018690525f80516020611826833981519152910160405180910390a15b5050505b50508080610c58906117f9565b9150506108fc565b5060015f55565b6001546001600160a01b03163314610cb65760405162461bcd60e51b815260206004820152601260248201527114d95b99195c881b9bdd08185b1b1bddd95960721b6044820152606401610445565b60025415610d09575f81600554610ccd91906117bf565b905060025460045482610ce09190611789565b610cea91906117a0565b60035f828254610cfa91906117bf565b90915550505f60055550610d20565b8060055f828254610d1a91906117bf565b90915550505b6040518181527f141d729c29cc848b27c53f7dbe9f9542cedc4ed2efa7bd2aeb2a4bdce06a407f9060200160405180910390a150565b6001600160a01b038083165f90815260096020908152604080832093851683529290529081205415610de9576001600160a01b038381165f9081526009602090815260408083209386168352929052908120600181015460029091015460045460035492939192839190610dca9086611789565b610dd491906117a0565b610dde91906117e6565b9350610dec92505050565b505f5b92915050565b60068181548110610e01575f80fd5b5f918252602090912001546001600160a01b0316905081565b60025f5403610e6b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610445565b60025f9081556001600160a01b0382168152600d602052604090205460ff16610ea65760405162461bcd60e51b8152600401610445906116b0565b5f610eb13383610d56565b335f9081526009602090815260408083206001600160a01b0387168452909152902060030154909150610ee490826117bf565b905080156111be576040516370a0823160e01b81523360048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015610f30573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f549190611702565b335f9081526009602090815260408083206001600160a01b03881684529091529020805460019091015491925090828211156110d6575f82610f968587611789565b610fa091906117a0565b90505f83610fae8685611789565b610fb891906117a0565b9050610fc481846117e6565b60025f828254610fd491906117e6565b90915550610fe79050610a6f83886117e6565b604051339083156108fc029084905f818181858888f19350505050158015611011573d5f803e3d5ffd5b50335f908152600b6020526040812080548492906110309084906117bf565b9091555050335f9081526009602090815260408083206001600160a01b038b16845290915290208581556001018190556004546003546110709083611789565b61107a91906117a0565b335f8181526009602090815260408083206001600160a01b038d16845282528083206002810195909555600390940191909155825191825281018890525f80516020611826833981519152910160405180910390a150506111ba565b335f908152600b6020526040812080548692906110f49084906117bf565b9091555050604051339085156108fc029086905f818181858888f19350505050158015611123573d5f803e3d5ffd5b50600454600354335f9081526009602090815260408083206001600160a01b038b16845290915290206001015461115a9190611789565b61116491906117a0565b335f8181526009602090815260408083206001600160a01b038b16845282528083206002810195909555600390940191909155825191825281018690525f80516020611826833981519152910160405180910390a15b5050505b505060015f55565b60078181548110610e01575f80fd5b6007545f8190036111e4575050565b5f805a90505f5b84831080156111f957508381105b1561128357836008541061120c575f6008555b61123d600760085481548110611224576112246117d2565b5f918252602090912001546001600160a01b031661128a565b60075493505a61124d83856117bf565b61125791906117e6565b92505a600880549193505f61126b836117f9565b9190505550808061127b906117f9565b9150506111eb565b5050505050565b60015f5b6006548110156114a6575f600682815481106112ac576112ac6117d2565b5f918252602080832091909101546001600160a01b0387811684526009835260408085209190921680855292529091208054600190910154919250908115611490576040516370a0823160e01b81526001600160a01b0387811660048301525f91908516906370a0823190602401602060405180830381865afa158015611335573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113599190611702565b90508015611365575f95505b8083111561148e575f6113788886610d56565b6001600160a01b03808a165f908152600960209081526040808320938a16835292905220600301549091506113ad90826117bf565b90505f80856113bc8587611789565b6113c691906117a0565b90506113d281866117e6565b60025f8282546113e291906117e6565b9091555050821561141157856113f88585611789565b61140291906117a0565b9150611411610a6f83856117e6565b6001600160a01b038a81165f908152600960209081526040808320938b1683529290522084815560010181905560045460035461144e9083611789565b61145891906117a0565b6001600160a01b038b81165f908152600960209081526040808320938c1683529290522060028101919091556003019190915550505b505b505050808061149e906117f9565b91505061128e565b5080156114d6576114b6826114da565b6001600160a01b0382165f908152600c60205260409020805460ff191690555b5050565b600780546114ea906001906117e6565b815481106114fa576114fa6117d2565b5f9182526020808320909101546001600160a01b038481168452600a909252604090922054600780549290931692918110611537576115376117d2565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559183168152600a9182905260408120546007805491939291611582906001906117e6565b81548110611592576115926117d2565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205560078054806115c7576115c7611811565b5f8281526020902081015f1990810180546001600160a01b031916905501905550565b6001600160a01b03811681146115fe575f80fd5b50565b5f60208284031215611611575f80fd5b813561161c816115ea565b9392505050565b5f805f60608486031215611635575f80fd5b8335611640816115ea565b9250602084013591506040840135611657816115ea565b809150509250925092565b5f60208284031215611672575f80fd5b5035919050565b5f806040838503121561168a575f80fd5b8235611695816115ea565b915060208301356116a5816115ea565b809150509250929050565b6020808252601b908201527f506f6f6c2061646472657373206973206e6f7420636f72726563740000000000604082015260600190565b5f602082840312156116f7575f80fd5b815161161c816115ea565b5f60208284031215611712575f80fd5b5051919050565b80516001600160701b038116811461172f575f80fd5b919050565b5f805f60608486031215611746575f80fd5b61174f84611719565b925061175d60208501611719565b9150604084015163ffffffff81168114611657575f80fd5b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610dec57610dec611775565b5f826117ba57634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610dec57610dec611775565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610dec57610dec611775565b5f6001820161180a5761180a611775565b5060010190565b634e487b7160e01b5f52603160045260245ffdfe106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241a2646970667358221220d7831bfee8ec7caf434b754061f8214c0eedc374d7ee1a80648ab005e0812d7b64736f6c63430008140033