ETH Price: $3,881.92 (+7.57%)

Contract

0xe60F6b54F6Ac0a41caf41B324c2B7e8280fCf749
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Transaction Hash
Method
Block
From
To
Unstake With Fee189992122024-01-13 16:38:35326 days ago1705163915IN
0xe60F6b54...280fCf749
0 ETH0.0023683922.61814364
Request Unstake189901582024-01-12 10:15:35327 days ago1705054535IN
0xe60F6b54...280fCf749
0 ETH0.0019658517.5764537
Request Unstake189660782024-01-09 1:13:59330 days ago1704762839IN
0xe60F6b54...280fCf749
0 ETH0.0020831118.62481235
Add Token Stake ...189627522024-01-08 14:01:59331 days ago1704722519IN
0xe60F6b54...280fCf749
0 ETH0.0056302923.71291304
Claim189497692024-01-06 17:58:11333 days ago1704563891IN
0xe60F6b54...280fCf749
0 ETH0.0036708217.45502499
Add Token Stake ...189443612024-01-05 23:35:47333 days ago1704497747IN
0xe60F6b54...280fCf749
0 ETH0.0023837516.88392194
Add Token Stake ...189442152024-01-05 23:06:11333 days ago1704495971IN
0xe60F6b54...280fCf749
0 ETH0.0040610417.10238208
Unstake189358722024-01-04 18:52:59335 days ago1704394379IN
0xe60F6b54...280fCf749
0 ETH0.0028291725.45981923
Add Token Stake ...189260762024-01-03 9:55:11336 days ago1704275711IN
0xe60F6b54...280fCf749
0 ETH0.0034121818.820544
Restake189260012024-01-03 9:40:11336 days ago1704274811IN
0xe60F6b54...280fCf749
0 ETH0.0030763617.94574745
Unstake189209482024-01-02 16:41:11337 days ago1704213671IN
0xe60F6b54...280fCf749
0 ETH0.0023875322.63111909
Unstake189188272024-01-02 9:31:47337 days ago1704187907IN
0xe60F6b54...280fCf749
0 ETH0.001805717.48736058
Claim189188012024-01-02 9:26:35337 days ago1704187595IN
0xe60F6b54...280fCf749
0 ETH0.0030246719.61424085
Unstake189083182023-12-31 22:04:35338 days ago1704060275IN
0xe60F6b54...280fCf749
0 ETH0.0012608911.58030703
Unstake With Fee189067932023-12-31 16:57:59339 days ago1704041879IN
0xe60F6b54...280fCf749
0 ETH0.0018976916.85700668
Unstake189067702023-12-31 16:53:23339 days ago1704041603IN
0xe60F6b54...280fCf749
0 ETH0.002527618.20343597
Unstake189005902023-12-30 20:04:11340 days ago1703966651IN
0xe60F6b54...280fCf749
0 ETH0.0018729216.85456524
Request Unstake188988192023-12-30 14:07:11340 days ago1703945231IN
0xe60F6b54...280fCf749
0 ETH0.002841517.90589688
Unstake188980542023-12-30 11:31:23340 days ago1703935883IN
0xe60F6b54...280fCf749
0 ETH0.0013600512.89174517
Claim188910622023-12-29 11:53:11341 days ago1703850791IN
0xe60F6b54...280fCf749
0 ETH0.0033581419.60297693
Unstake With Fee188870742023-12-28 22:27:35341 days ago1703802455IN
0xe60F6b54...280fCf749
0 ETH0.0025542120.23043287
Request Unstake188870712023-12-28 22:26:59341 days ago1703802419IN
0xe60F6b54...280fCf749
0 ETH0.0026944119.92633186
Request Unstake188856942023-12-28 17:49:23342 days ago1703785763IN
0xe60F6b54...280fCf749
0 ETH0.0044916728.81293652
Unstake188607412023-12-25 5:41:23345 days ago1703482883IN
0xe60F6b54...280fCf749
0 ETH0.0014471213.29064386
Unstake188584242023-12-24 21:53:23345 days ago1703454803IN
0xe60F6b54...280fCf749
0 ETH0.0020039818.0339362
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SynapseStaking

Compiler Version
v0.8.6+commit.11564f7e

Optimization Enabled:
Yes with 999999 runs

Other Settings:
default evmVersion, MIT license
File 1 of 8 : SynapseStaking.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.6;

import { ReentrancyGuard } from "./external/openzeppelin/ReentrancyGuard.sol";

import { RewardsDistribution } from "./abstract/RewardsDistribution.sol";
import { StableMath } from "./libraries/StableMath.sol";
import { SafeERC20, IERC20 } from "./libraries/SafeERC20.sol";
import { Parameterized } from "./Parameterized.sol";

/**
 * @title  SynapseStaking
 * @notice Rewards stakers of SNP token and a given LP token with rewards in form of SNP token, on a pro-rata basis.
 * @dev    Uses an ever increasing 'rewardPerTokenStored' variable to distribute rewards
 *         each time a write action is called in the contract. This allows for passive reward accrual.
 */
contract SynapseStaking is RewardsDistribution, ReentrancyGuard, Parameterized {
    using StableMath for uint256;
    using SafeERC20 for IERC20;

    /// @notice stake/reward token address
    address public tokenAddress;
    /// @notice LP stake token address
    address public liquidityAddress;
    /// @notice vesting contract address
    address public vestingAddress;

    /// @notice timestamp for current period finish
    uint256 public periodFinish;
    /// @notice timestamp for current super period finish
    uint256 public superPeriodFinish;

    struct Data {
        uint256 depositedTokens; // deposited tokens amount
        uint256 depositedLiquidity; // deposited lp amount
        uint256 totalRewardsAdded; // accumulated amount of rewards added to token and liquidity staking
        uint256 totalRewardsClaimed; // accumulated amount of rewards claimed
        uint256 totalRewardsFromFees; // accumulated amount of rewards collected from fee-on-transfer
    }

    Data public data;

    struct StakingData {
        uint256 rewardRate; // rewardRate for the rest of the period
        uint256 superRewardRate; // superRewardRate for the rest of the super period
        uint256 lastUpdateTime; // last time any user took action
        uint256 lastSuperUpdateTime; // last time super staker took action
        uint256 rewardPerTokenStored; // accumulated per token reward since the beginning of time
        uint256 superRewardPerTokenStored; // super accumulated per token reward since the beginning of time
        uint256 stakedTokens; // amount of tokens that is used in reward per token calculation
        uint256 stakedSuperTokens; // amount of tokens that is used in super reward per token calculation
    }

    StakingData public tokenStaking;
    StakingData public lpStaking;

    struct Stake {
        uint256 stakeStart; // timestamp of stake creation
        uint256 superStakerPossibleAt; // timestamp after which user can claim super staker status
        //
        uint256 rewardPerTokenPaid; // user accumulated per token rewards
        uint256 superRewardPerTokenPaid; // user accumulated per token super staker rewards
        //
        uint256 tokens; // total tokens staked by user snp or lp
        uint256 rewards; // current not-claimed rewards from last update
        //
        uint256 withdrawalPossibleAt; // timestamp after which stake can be removed without fee
        bool isWithdrawing; // true = user call to remove stake
        bool isSuperStaker; // true = user is super staker
    }

    /// @dev each holder have one stake
    /// @notice token stakes storage
    mapping(address => Stake) public tokenStake;
    /// @notice LP token stakes storage
    mapping(address => Stake) public liquidityStake;

    /// @dev events
    event Claimed(address indexed user, uint256 amount);
    event StakeAdded(address indexed user, uint256 amount);
    event StakeLiquidityAdded(address indexed user, uint256 amount);
    event StakeRemoveRequested(address indexed user);
    event StakeLiquidityRemoveRequested(address indexed user);
    event StakeRemoved(address indexed user, uint256 amount);
    event StakeLiquidityRemoved(address indexed user, uint256 amount);
    event Recalculation(uint256 reward, uint256 lpReward);
    event SuperRecalculation(uint256 superReward, uint256 superLpReward);

    /**
     * @param _timeToSuper time needed to become a super staker
     * @param _timeToUnstake time needed to unstake without fee
     */
    constructor(uint256 _timeToSuper, uint256 _timeToUnstake) {
        timeToSuper.value = _timeToSuper;
        timeToUnstake.value = _timeToUnstake;
        timeToSuper.lastChange = block.timestamp;
        timeToUnstake.lastChange = block.timestamp;
        timeToSuper.minDelay = WEEK;
        timeToUnstake.minDelay = WEEK;
        unstakeFee.value = 1000;
    }

    /**
     * @dev One time initialization function
     * @param _token SNP token address
     * @param _liquidity SNP/USDC LP token address
     * @param _vesting public vesting contract address
     */
    function init(
        address _token,
        address _liquidity,
        address _vesting
    ) external onlyOwner {
        require(_token != address(0), "_token address cannot be 0");
        require(_liquidity != address(0), "_liquidity address cannot be 0");
        require(_vesting != address(0), "_vesting address cannot be 0");
        require(tokenAddress == address(0), "Init already done");
        tokenAddress = _token;
        liquidityAddress = _liquidity;
        vestingAddress = _vesting;
    }

    /**
     * @dev Updates the reward for a given address,
     *      for token and LP pool, before executing function
     * @param _account address of staker for which rewards will be updated
     */
    modifier updateRewards(address _account) {
        _updateReward(_account, false);
        _updateReward(_account, true);
        _;
    }

    /**
     * @dev Updates the reward for a given address,
     *      for given pool, before executing function
     * @param _account address for which rewards will be updated
     * @param _lp true=lpStaking, false=tokenStaking
     */
    modifier updateReward(address _account, bool _lp) {
        _updateReward(_account, _lp);
        _;
    }

    /**
     * @dev Updates the super rewards for a given address,
     *      for token and LP pool, before executing function
     * @param _account address of super staker for which super rewards will be updated
     */
    modifier updateSuperRewards(address _account) {
        bool success = _updateSuperReward(_account, false);
        success = _updateSuperReward(_account, true) || success;
        if (success) {
            _calculateSuperRewardAmount();
        }
        _;
    }

    /**
     * @dev guards that the given address has selected stake
     * @param _account address to check
     * @param _lp true=lpStaking, false=tokenStaking
     */
    modifier hasPoolStake(address _account, bool _lp) {
        bool accountHasStake = _lp ? (liquidityStake[_account].tokens > 0) : (tokenStake[_account].tokens > 0);
        require(accountHasStake, "Nothing staked");
        _;
    }

    /**
     * @dev guards that the msg.sender has token or LP stake
     */
    modifier hasStake() {
        require((liquidityStake[msg.sender].tokens > 0) || (tokenStake[msg.sender].tokens > 0), "Nothing staked");
        _;
    }

    /**
     * @dev guards that the given address can be a super staker in selected stake
     * @param _account address to check
     * @param _lp true=lpStaking, false=tokenStaking
     */
    modifier canBeSuper(address _account, bool _lp) {
        Stake memory s = _lp ? liquidityStake[_account] : tokenStake[_account];
        require(!s.isWithdrawing, "Cannot when withdrawing");
        require(!s.isSuperStaker, "Already super staker");
        require(block.timestamp >= s.superStakerPossibleAt, "Too soon");
        _;
    }

    /**
     * @dev checks if the msg.sender can withdraw requested unstake
     */
    modifier canUnstake() {
        require(_canUnstake(), "Cannot unstake");
        _;
    }

    /**
     * @dev checks if for the msg.sender there is possibility to
     *      withdraw staked tokens without fee.
     */
    modifier cantUnstake() {
        require(!_canUnstake(), "Unstake first");
        _;
    }

    /***************************************
                    ACTIONS
    ****************************************/

    /**
     * @dev Updates reward in selected pool
     * @param _account address for which rewards will be updated
     * @param _lp true=lpStaking, false=tokenStaking
     */
    function _updateReward(address _account, bool _lp) internal {
        uint256 newRewardPerTokenStored = currentRewardPerTokenStored(_lp);
        // if statement protects against loss in initialization case
        if (newRewardPerTokenStored > 0) {
            StakingData storage sd = _lp ? lpStaking : tokenStaking;
            sd.rewardPerTokenStored = newRewardPerTokenStored;
            sd.lastUpdateTime = lastTimeRewardApplicable();

            // setting of personal vars based on new globals
            if (_account != address(0)) {
                Stake storage s = _lp ? liquidityStake[_account] : tokenStake[_account];
                if (!s.isWithdrawing) {
                    s.rewards = _earned(_account, _lp);
                    s.rewardPerTokenPaid = newRewardPerTokenStored;
                }
            }
        }
    }

    /**
     * @dev Updates super reward in selected pool
     * @param _account address of super staker for which super rewards will be updated
     * @param _lp true=lpStaking, false=tokenStaking
     */
    function _updateSuperReward(address _account, bool _lp) internal returns (bool success) {
        Stake storage s = _lp ? liquidityStake[_account] : tokenStake[_account];
        // save gas for non super stakers
        if (s.isSuperStaker || _account == address(0)) {
            uint256 newSuperRewardPerTokenStored = currentSuperRewardPerTokenStored(_lp);
            // if statement protects against loss in initialization case
            if (newSuperRewardPerTokenStored > 0) {
                StakingData storage sd = _lp ? lpStaking : tokenStaking;
                sd.superRewardPerTokenStored = newSuperRewardPerTokenStored;
                sd.lastSuperUpdateTime = lastTimeSuperRewardApplicable();

                // setting of personal vars based on new globals
                if (_account != address(0)) {
                    // setting of personal vars based on new globals
                    if (!s.isWithdrawing) {
                        s.rewards = _earnedSuper(_account, _lp);
                        s.superRewardPerTokenPaid = newSuperRewardPerTokenStored;
                    }
                }
            }

            success = true;
        }
    }

    /**
     * @dev Add tokens for staking from vesting contract
     * @param _account address that call claimAndStake in vesting
     * @param _amount number of tokens sent to contract
     */
    function onClaimAndStake(address _account, uint256 _amount)
        external
        nonReentrant
        updateReward(_account, false)
        updateSuperRewards(_account)
    {
        require(msg.sender == vestingAddress, "Only vesting contract");
        require(!tokenStake[_account].isWithdrawing, "Cannot when withdrawing");
        require(_amount > 0, "Zero Amount");

        Stake storage s = tokenStake[_account];
        StakingData storage sd = tokenStaking;

        if (s.stakeStart == 0) {
            // new stake
            s.stakeStart = block.timestamp;
            s.superStakerPossibleAt = s.stakeStart + timeToSuper.value;
        }

        // update account stake data
        s.tokens += _amount;

        // update pool staking data
        sd.stakedTokens += _amount;
        if (s.isSuperStaker) {
            sd.stakedSuperTokens += _amount;
        }

        // update global data
        data.depositedTokens += _amount;

        emit StakeAdded(_account, _amount);
    }

    /**
     * @dev Add tokens to staking contract
     * @param _amount of tokens to stake
     */
    function addTokenStake(uint256 _amount) external {
        _addStake(msg.sender, _amount, false);
        emit StakeAdded(msg.sender, _amount);
    }

    /**
     * @dev Add tokens to staking contract by using permit to set allowance
     * @param _amount of tokens to stake
     * @param _deadline of permit signature
     * @param _approveMax allowance for the token
     */
    function addTokenStakeWithPermit(
        uint256 _amount,
        uint256 _deadline,
        bool _approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        uint256 value = _approveMax ? type(uint256).max : _amount;
        IERC20(tokenAddress).permit(msg.sender, address(this), value, _deadline, v, r, s);
        _addStake(msg.sender, _amount, false);
        emit StakeAdded(msg.sender, _amount);
    }

    /**
     * @dev Add liquidity tokens to staking contract
     * @param _amount of LP tokens to stake
     */
    function addLiquidityStake(uint256 _amount) external {
        _addStake(msg.sender, _amount, true);
        emit StakeLiquidityAdded(msg.sender, _amount);
    }

    /**
     * @dev Add liquidity tokens to staking contract
     * @param _amount of tokens to stake
     * @param _deadline of permit signature
     * @param _approveMax allowance for the token
     */
    function addLiquidityStakeWithPermit(
        uint256 _amount,
        uint256 _deadline,
        bool _approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        uint256 value = _approveMax ? type(uint256).max : _amount;
        IERC20(liquidityAddress).permit(msg.sender, address(this), value, _deadline, v, r, s);
        _addStake(msg.sender, _amount, true);
        emit StakeLiquidityAdded(msg.sender, _amount);
    }

    /**
     * @dev Internal add stake function
     * @param _account selected staked tokens are credited to this address
     * @param _amount of staked tokens
     * @param _lp true=LP token, false=SNP token
     */
    function _addStake(
        address _account,
        uint256 _amount,
        bool _lp
    ) internal nonReentrant updateReward(_account, _lp) updateSuperRewards(_account) {
        require(_amount > 0, "Zero Amount");
        Stake storage s = _lp ? liquidityStake[_account] : tokenStake[_account];
        require(!s.isWithdrawing, "Cannot when withdrawing");

        address token = _lp ? liquidityAddress : tokenAddress;

        // check for fee-on-transfer and proceed with received amount
        _amount = _transferFrom(token, msg.sender, _amount);

        if (s.stakeStart == 0) {
            // new stake
            s.stakeStart = block.timestamp;
            s.superStakerPossibleAt = s.stakeStart + timeToSuper.value;
        }

        StakingData storage sd = _lp ? lpStaking : tokenStaking;

        // update account stake data
        s.tokens += _amount;

        // update pool staking data
        sd.stakedTokens += _amount;
        if (s.isSuperStaker) {
            sd.stakedSuperTokens += _amount;
        }

        // update global data
        if (_lp) {
            data.depositedLiquidity += _amount;
        } else {
            data.depositedTokens += _amount;
        }
    }

    /**
     * @dev Restake earned tokens and add them to token stake (instead of claiming)
     *      If have LP stake but not token stake - token stake will be created.
     */
    function restake() external hasStake updateRewards(msg.sender) updateSuperRewards(msg.sender) {
        Stake storage ts = tokenStake[msg.sender];
        Stake storage ls = liquidityStake[msg.sender];
        require(!ts.isWithdrawing, "Cannot when withdrawing");

        uint256 rewards = ts.rewards + ls.rewards;
        require(rewards > 0, "Nothing to restake");

        delete ts.rewards;
        delete ls.rewards;

        if (ts.stakeStart == 0) {
            // new stake
            ts.stakeStart = block.timestamp;
            ts.superStakerPossibleAt = ts.stakeStart + timeToSuper.value;
        }

        // update account stake data
        ts.tokens += rewards;

        // update pool staking data
        tokenStaking.stakedTokens += rewards;
        if (ts.isSuperStaker) {
            tokenStaking.stakedSuperTokens += rewards;
        }

        data.totalRewardsClaimed += rewards;
        data.depositedTokens += rewards;

        emit Claimed(msg.sender, rewards);
        emit StakeAdded(msg.sender, rewards);
    }

    /**
     * @dev Claims rewards for the msg.sender.
     */
    function claim() external {
        _claim(msg.sender, msg.sender);
    }

    /**
     * @dev Claim msg.sender rewards to provided address
     * @param _recipient address where claimed tokens should be sent
     */
    function claimTo(address _recipient) external {
        _claim(msg.sender, _recipient);
    }

    /**
     * @dev Internal claim function. First updates rewards in normal and super pools
     *      and then transfers.
     * @param _account claim rewards for this address
     * @param _recipient claimed tokens are sent to this address
     */
    function _claim(address _account, address _recipient) internal nonReentrant hasStake updateRewards(_account) updateSuperRewards(_account) {
        uint256 rewards = tokenStake[_account].rewards + liquidityStake[_account].rewards;

        require(rewards > 0, "Nothing to claim");

        delete tokenStake[_account].rewards;
        delete liquidityStake[_account].rewards;

        data.totalRewardsClaimed += rewards;
        _transfer(tokenAddress, _recipient, rewards);

        emit Claimed(_account, rewards);
    }

    /**
     * @dev Request unstake for deposited tokens. Marks user token stake as withdrawing,
     *      and start withdrawing period.
     */
    function requestUnstake() external {
        _requestUnstake(msg.sender, false);
        emit StakeRemoveRequested(msg.sender);
    }

    /**
     * @dev Request unstake for deposited LP tokens. Marks user lp stake as withdrawing
     *      and start withdrawing period.
     */
    function requestUnstakeLp() external {
        _requestUnstake(msg.sender, true);
        emit StakeLiquidityRemoveRequested(msg.sender);
    }

    /**
     * @dev Internal request unstake function. Update normal and super rewards for the user first.
     * @param _account User address
     * @param _lp true=it is LP stake
     */
    function _requestUnstake(address _account, bool _lp)
        internal
        hasPoolStake(_account, _lp)
        updateReward(_account, _lp)
        updateSuperRewards(_account)
    {
        Stake storage s = _lp ? liquidityStake[_account] : tokenStake[_account];
        require(!s.isWithdrawing, "Cannot when withdrawing");
        StakingData storage sd = _lp ? lpStaking : tokenStaking;

        // update account stake data
        s.isWithdrawing = true;
        s.withdrawalPossibleAt = block.timestamp + timeToUnstake.value;

        // update pool staking data
        sd.stakedTokens -= s.tokens;
        if (s.isSuperStaker) {
            delete s.isSuperStaker;
            sd.stakedSuperTokens -= s.tokens;
        }
    }

    /**
     * @dev Withdraw stake for msg.sender from both stakes (if possible)
     */
    function unstake() external nonReentrant hasStake canUnstake {
        bool success;
        uint256 reward;
        uint256 tokens;
        uint256 rewards;

        (reward, success) = _unstake(msg.sender, false);
        rewards += reward;
        if (success) {
            tokens += tokenStake[msg.sender].tokens;
            data.depositedTokens -= tokenStake[msg.sender].tokens;
            emit StakeRemoved(msg.sender, tokenStake[msg.sender].tokens);
            delete tokenStake[msg.sender];
        }

        (reward, success) = _unstake(msg.sender, true);
        rewards += reward;
        if (success) {
            delete liquidityStake[msg.sender];
        }

        if (tokens + rewards > 0) {
            _transfer(tokenAddress, msg.sender, tokens + rewards);
            if (rewards > 0) {
                emit Claimed(msg.sender, rewards);
            }
        }
    }

    /**
     * @dev Internal unstake function, withdraw staked LP tokens
     * @param _account address of account to transfer LP tokens
     * @param _lp true = LP stake
     * @return stake rewards amount
     * @return bool true if success
     */
    function _unstake(address _account, bool _lp) internal returns (uint256, bool) {
        Stake memory s = _lp ? liquidityStake[_account] : tokenStake[_account];
        if (!s.isWithdrawing) return (0, false);
        if (s.withdrawalPossibleAt > block.timestamp) return (0, false);

        data.totalRewardsClaimed += s.rewards;

        // only LP stake
        if (_lp && s.tokens > 0) {
            data.depositedLiquidity -= s.tokens;
            _transfer(liquidityAddress, _account, s.tokens);
            emit StakeLiquidityRemoved(_account, s.tokens);
        }

        return (s.rewards, true);
    }

    /**
     * @dev Unstake requested stake at any time accepting 10% penalty fee
     */
    function unstakeWithFee() external nonReentrant hasStake cantUnstake {
        Stake memory ts = tokenStake[msg.sender];
        Stake memory ls = liquidityStake[msg.sender];
        uint256 tokens;
        uint256 rewards;

        if (ls.isWithdrawing) {
            uint256 lpTokens = _minusFee(ls.tokens); //remaining tokens remain on the contract

            rewards += ls.rewards;

            data.totalRewardsClaimed += ls.rewards;
            data.depositedLiquidity -= ls.tokens;
            emit StakeLiquidityRemoved(msg.sender, ls.tokens);

            if (lpTokens > 0) {
                _transfer(liquidityAddress, msg.sender, lpTokens);
            }

            delete liquidityStake[msg.sender];
        }

        if (ts.isWithdrawing) {
            tokens = _minusFee(ts.tokens); // remaining tokens goes to Super Stakers

            rewards += ts.rewards;

            data.totalRewardsClaimed += ts.rewards;
            data.depositedTokens -= ts.tokens;
            emit StakeRemoved(msg.sender, ts.tokens);

            delete tokenStake[msg.sender];
        }

        if (tokens + rewards > 0) {
            _transfer(tokenAddress, msg.sender, tokens + rewards);
            if (rewards > 0) {
                emit Claimed(msg.sender, rewards);
            }
        }
    }

    /**
     * @dev Set Super Staker status for token pool stake if possible.
     */
    function setSuperToken() external {
        _setSuper(msg.sender, false);
    }

    /**
     * @dev Set Super Staker status for LP pool stake if possible.
     */
    function setSuperLp() external {
        _setSuper(msg.sender, true);
    }

    /**
     * @dev Set Super Staker status if possible for selected pool.
     *      Update super reward pools.
     * @param _account address of account to set super
     * @param _lp true=LP stake super staker, false=token stake super staker
     */
    function _setSuper(address _account, bool _lp)
        internal
        hasPoolStake(_account, _lp)
        canBeSuper(_account, _lp)
        updateSuperRewards(address(0))
    {
        Stake storage s = _lp ? liquidityStake[_account] : tokenStake[_account];
        StakingData storage sd = _lp ? lpStaking : tokenStaking;

        sd.stakedSuperTokens += s.tokens;

        s.isSuperStaker = true;
        s.superRewardPerTokenPaid = sd.superRewardPerTokenStored;
    }

    /***************************************
                    GETTERS
    ****************************************/

    /**
     * @dev Gets the last applicable timestamp for this reward period
     */
    function lastTimeRewardApplicable() public view returns (uint256) {
        return StableMath.min(block.timestamp, periodFinish);
    }

    /**
     * @dev Gets the last applicable timestamp for this super reward period
     */
    function lastTimeSuperRewardApplicable() public view returns (uint256) {
        return StableMath.min(block.timestamp, superPeriodFinish);
    }

    /**
     * @dev Calculates the amount of unclaimed rewards per token since last update,
     *      and sums with stored to give the new cumulative reward per token
     * @param _lp true=lpStaking, false=tokenStaking
     * @return 'Reward' per staked token
     */
    function currentRewardPerTokenStored(bool _lp) public view returns (uint256) {
        StakingData memory sd = _lp ? lpStaking : tokenStaking;
        uint256 stakedTokens = sd.stakedTokens;
        uint256 rewardPerTokenStored = sd.rewardPerTokenStored;
        // If there is no staked tokens, avoid div(0)
        if (stakedTokens == 0) {
            return (rewardPerTokenStored);
        }
        // new reward units to distribute = rewardRate * timeSinceLastUpdate
        uint256 timeDelta = lastTimeRewardApplicable() - sd.lastUpdateTime;
        uint256 rewardUnitsToDistribute = sd.rewardRate * timeDelta;
        // new reward units per token = (rewardUnitsToDistribute * 1e18) / stakedTokens
        uint256 unitsToDistributePerToken = rewardUnitsToDistribute.divPrecisely(stakedTokens);
        // return summed rate
        return (rewardPerTokenStored + unitsToDistributePerToken);
    }

    /**
     * @dev Calculates the amount of unclaimed super rewards per token since last update,
     * and sums with stored to give the new cumulative reward per token
     * @param _lp true=lpStaking, false=tokenStaking
     * @return 'Reward' per staked token
     */
    function currentSuperRewardPerTokenStored(bool _lp) public view returns (uint256) {
        StakingData memory sd = _lp ? lpStaking : tokenStaking;
        uint256 stakedSuperTokens = sd.stakedSuperTokens;
        uint256 superRewardPerTokenStored = sd.superRewardPerTokenStored;
        // If there is no staked tokens, avoid div(0)
        if (stakedSuperTokens == 0) {
            return (superRewardPerTokenStored);
        }

        // new reward units to distribute = superRewardRate * timeSinceLastSuperUpdate
        uint256 timeDelta = lastTimeSuperRewardApplicable() - sd.lastSuperUpdateTime;
        uint256 rewardUnitsToDistribute = sd.superRewardRate * timeDelta;
        // new reward units per token = (rewardUnitsToDistribute * 1e18) / totalSuperTokens
        uint256 unitsToDistributePerToken = rewardUnitsToDistribute.divPrecisely(stakedSuperTokens);

        // return summed rate
        return (superRewardPerTokenStored + unitsToDistributePerToken);
    }

    /**
     * @dev Calculates the amount of unclaimed rewards a user has earned
     * @param _account user address
     * @param _lp true=liquidityStake, false=tokenStake
     * @return Total reward amount earned
     */
    function _earned(address _account, bool _lp) internal view returns (uint256) {
        Stake memory s = _lp ? liquidityStake[_account] : tokenStake[_account];
        if (s.isWithdrawing) return s.rewards;
        // current rate per token - rate user previously received
        uint256 rewardPerTokenStored = currentRewardPerTokenStored(_lp);
        uint256 userRewardDelta = rewardPerTokenStored - s.rewardPerTokenPaid;
        uint256 userNewReward = s.tokens.mulTruncate(userRewardDelta);
        // add to previous rewards
        return (s.rewards + userNewReward);
    }

    /**
     * @dev Calculates the amount of unclaimed super rewards a user has earned
     * @param _account user address
     * @param _lp true=liquidityStake, false=tokenStake
     * @return Total reward amount earned
     */
    function _earnedSuper(address _account, bool _lp) internal view returns (uint256) {
        Stake memory s = _lp ? liquidityStake[_account] : tokenStake[_account];
        if (!s.isSuperStaker || s.isWithdrawing) return s.rewards;
        // current rate per token - rate user previously received
        uint256 superRewardPerTokenStored = currentSuperRewardPerTokenStored(_lp);
        uint256 superRewardDelta = superRewardPerTokenStored - s.superRewardPerTokenPaid;
        uint256 userNewSuperReward = s.tokens.mulTruncate(superRewardDelta);
        // add to previous rewards
        return (s.rewards + userNewSuperReward);
    }

    /**
     * @dev Calculates the claimable amounts for token and lp stake from normal and super rewards
     * @param _account user address
     * @return token - claimable reward amount for token stake
     * @return lp - claimable reward amount for lp stake
     */
    function claimable(address _account) external view returns (uint256 token, uint256 lp) {
        token = _earned(_account, false) + _earnedSuper(_account, false) - tokenStake[_account].rewards;
        lp = _earned(_account, true) + _earnedSuper(_account, true) - liquidityStake[_account].rewards;
    }

    /**
     * @dev Check if staker can set super staker status on token or LP stake
     * @param _account address to check
     * @return token true if can set super staker on token stake
     * @return lp true if can set super staker on LP stake
     */
    function canSetSuper(address _account) external view returns (bool token, bool lp) {
        Stake memory ts = tokenStake[_account];
        Stake memory ls = liquidityStake[_account];
        if (ts.tokens > 0 && block.timestamp >= ts.superStakerPossibleAt && !ts.isSuperStaker && !ts.isWithdrawing) token = true;
        if (ls.tokens > 0 && block.timestamp >= ls.superStakerPossibleAt && !ls.isSuperStaker && !ls.isWithdrawing) lp = true;
    }

    /**
     * @dev internal view to check if msg.sender can unstake
     * @return true if user requested unstake and time for unstake has passed
     */
    function _canUnstake() private view returns (bool) {
        return
            (liquidityStake[msg.sender].isWithdrawing && block.timestamp >= liquidityStake[msg.sender].withdrawalPossibleAt) ||
            (tokenStake[msg.sender].isWithdrawing && block.timestamp >= tokenStake[msg.sender].withdrawalPossibleAt);
    }

    /**
     * @dev external view to check if address can stake tokens
     * @return true if user can stake tokens
     */
    function canStakeTokens(address _account) external view returns (bool) {
        return !tokenStake[_account].isWithdrawing;
    }

    /**
     * @dev external view to check if address can stake lp
     * @return true if user can stake lp
     */
    function canStakeLp(address _account) external view returns (bool) {
        return !liquidityStake[_account].isWithdrawing;
    }

    /***************************************
                    REWARDER
    ****************************************/

    /**
     * @dev Notifies the contract that new rewards have been added.
     *      Calculates an updated rewardRate based on the rewards in period.
     * @param _reward Units of SNP token that have been added to the token pool
     * @param _lpReward Units of SNP token that have been added to the lp pool
     */
    function notifyRewardAmount(uint256 _reward, uint256 _lpReward) external onlyRewardsDistributor updateRewards(address(0)) {
        uint256 currentTime = block.timestamp;

        // pull tokens
        require(_transferFrom(tokenAddress, msg.sender, _reward + _lpReward) == _reward + _lpReward, "Exclude Rewarder from fee");

        // If previous period over, reset rewardRate
        if (currentTime >= periodFinish) {
            tokenStaking.rewardRate = _reward / WEEK;
            lpStaking.rewardRate = _lpReward / WEEK;
        }
        // If additional reward to existing period, calc sum
        else {
            uint256 remaining = periodFinish - currentTime;

            uint256 leftoverReward = remaining * tokenStaking.rewardRate;
            tokenStaking.rewardRate = (_reward + leftoverReward) / WEEK;

            uint256 leftoverLpReward = remaining * lpStaking.rewardRate;
            lpStaking.rewardRate = (_lpReward + leftoverLpReward) / WEEK;
        }

        tokenStaking.lastUpdateTime = currentTime;
        lpStaking.lastUpdateTime = currentTime;
        periodFinish = currentTime + WEEK;

        data.totalRewardsAdded += _reward + _lpReward;

        emit Recalculation(_reward, _lpReward);
    }

    /***************************************
                    SUPER STAKER
    ****************************************/

    /**
     * @dev Notifies the contract that new super rewards have been added based on the collected fee.
     *      Calculates an updated superRewardRate based on the rewards in period.
     *      Function can be triggered by any super staker once a day.
     */
    function _calculateSuperRewardAmount() internal {
        uint256 currentTime = block.timestamp;
        // Do nothing if less then a day from last calculation, save gas
        uint256 lastTime = superPeriodFinish > 0 ? superPeriodFinish - (MONTH - 1 days) : 0;
        if (currentTime >= lastTime) {
            uint256 contractBalance = _balance(tokenAddress, address(this));
            uint256 feesCollected = contractBalance -
                data.depositedTokens -
                (data.totalRewardsAdded + data.totalRewardsFromFees - data.totalRewardsClaimed);
            data.totalRewardsFromFees += feesCollected;

            uint256 superRewards;
            unchecked {
                superRewards = feesCollected / 2;
            }

            // If previous period over, reset rewardRate
            if (currentTime >= superPeriodFinish) {
                tokenStaking.superRewardRate = superRewards / MONTH;
                lpStaking.superRewardRate = superRewards / MONTH;
            }
            // If additional reward to existing period, calc sum
            else {
                uint256 remaining = superPeriodFinish - currentTime;

                uint256 leftoverSuperReward = remaining * tokenStaking.superRewardRate;
                tokenStaking.superRewardRate = (superRewards + leftoverSuperReward) / MONTH;

                uint256 leftoverSuperLpReward = remaining * lpStaking.superRewardRate;
                lpStaking.superRewardRate = (superRewards + leftoverSuperLpReward) / MONTH;
            }

            tokenStaking.lastSuperUpdateTime = currentTime;
            lpStaking.lastSuperUpdateTime = currentTime;
            superPeriodFinish = currentTime + MONTH;

            emit SuperRecalculation(superRewards, superRewards);
        }
    }

    /***************************************
                    TOKEN
    ****************************************/

    /**
     * @dev internal ERC20 tools
     */

    function _balance(address token, address user) internal view returns (uint256) {
        return IERC20(token).balanceOf(user);
    }

    function _transferFrom(
        address token,
        address from,
        uint256 amount
    ) internal returns (uint256) {
        return IERC20(token).safeTransferFromDeluxe(from, amount);
    }

    function _transfer(
        address token,
        address to,
        uint256 amount
    ) internal {
        IERC20(token).safeTransfer(to, amount);
    }
}

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

import { Ownable } from "./abstract/Ownable.sol";

pragma solidity 0.8.6;

contract Parameterized is Ownable {
    uint256 internal constant WEEK = 7 days;
    uint256 internal constant MONTH = 30 days;

    struct StakeParameters {
        uint256 value;
        uint256 lastChange;
        uint256 minDelay;
    }

    /// @notice time to allow to be Super Staker (30*24*60*60)
    StakeParameters public timeToSuper;
    /// @notice time to wait for unstake (7*24*60*60)
    StakeParameters public timeToUnstake;

    /// @notice fee for premature unstake in 1/10 percent,
    /// @dev value 1000 = 10%
    StakeParameters public unstakeFee;

    function _minusFee(uint256 val) internal view returns (uint256) {
        return val - ((val * unstakeFee.value) / 10000);
    }

    function updateFee(uint256 val) external onlyOwner {
        require(block.timestamp > unstakeFee.lastChange + unstakeFee.minDelay, "Soon");
        require(val <= 2500, "max fee is 25%");
        unstakeFee.lastChange = block.timestamp;
        unstakeFee.value = val;
    }

    function updateTimeToUnstake(uint256 val) external onlyOwner {
        require(block.timestamp > timeToUnstake.lastChange + timeToUnstake.minDelay, "Soon");
        require(val <= 2 * WEEK, "Max delay is 14 days");
        timeToUnstake.lastChange = block.timestamp;
        timeToUnstake.value = val;
    }

    function updateTimeToSuper(uint256 val) external onlyOwner {
        require(block.timestamp > timeToSuper.lastChange + timeToSuper.minDelay, "Soon");
        require(val <= 3 * MONTH && val >= WEEK, "Delay is 1 week - 3 months");
        timeToSuper.lastChange = block.timestamp;
        timeToSuper.value = val;
    }
}

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

pragma solidity 0.8.6;

abstract contract OwnableData {
    address public owner;
    address public pendingOwner;
}

abstract contract Ownable is OwnableData {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev `owner` defaults to msg.sender on construction.
     */
    constructor() {
        _setOwner(msg.sender);
    }

    /**
     * @dev Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
     *      Can only be invoked by the current `owner`.
     * @param _newOwner Address of the new owner.
     * @param _direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
     */
    function transferOwnership(address _newOwner, bool _direct) external onlyOwner {
        if (_direct) {
            require(_newOwner != address(0), "zero address");

            emit OwnershipTransferred(owner, _newOwner);
            owner = _newOwner;
            pendingOwner = address(0);
        } else {
            pendingOwner = _newOwner;
        }
    }

    /**
     * @dev Needs to be called by `pendingOwner` to claim ownership.
     */
    function claimOwnership() external {
        address _pendingOwner = pendingOwner;
        require(msg.sender == _pendingOwner, "caller != pending owner");

        emit OwnershipTransferred(owner, _pendingOwner);
        owner = _pendingOwner;
        pendingOwner = address(0);
    }

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

    function _setOwner(address newOwner) internal {
        address oldOwner = owner;
        owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

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

pragma solidity 0.8.6;

import { Ownable } from "./Ownable.sol";

abstract contract RewardsDistributionData {
    address public rewardsDistributor;
}

abstract contract RewardsDistribution is Ownable, RewardsDistributionData {
    event RewardsDistributorChanged(address indexed previousDistributor, address indexed newDistributor);

    /**
     * @dev `rewardsDistributor` defaults to msg.sender on construction.
     */
    constructor() {
        rewardsDistributor = msg.sender;
        emit RewardsDistributorChanged(address(0), msg.sender);
    }

    /**
     * @dev Throws if called by any account other than the Reward Distributor.
     */
    modifier onlyRewardsDistributor() {
        require(msg.sender == rewardsDistributor, "caller is not reward distributor");
        _;
    }

    /**
     * @dev Change the rewardsDistributor - only called by owner
     * @param _rewardsDistributor Address of the new distributor
     */
    function setRewardsDistribution(address _rewardsDistributor) external onlyOwner {
        require(_rewardsDistributor != address(0), "zero address");

        emit RewardsDistributorChanged(rewardsDistributor, _rewardsDistributor);
        rewardsDistributor = _rewardsDistributor;
    }
}

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

pragma solidity 0.8.6;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

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

pragma solidity 0.8.6;

interface IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    function totalSupply() external view returns (uint256);
    function decimals() external view returns (uint8);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);

    // EIP 2612
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function nonces(address owner) external view returns (uint256);
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
    function transferWithPermit(address target, address to, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (bool);
}

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

pragma solidity 0.8.6;

import { IERC20 } from "../interfaces/IERC20.sol";

library SafeERC20 {
    function safeSymbol(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x95d89b41));
        return success && data.length > 0 ? abi.decode(data, (string)) : "???";
    }

    function safeName(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x06fdde03));
        return success && data.length > 0 ? abi.decode(data, (string)) : "???";
    }

    function safeDecimals(IERC20 token) internal view returns (uint8) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x313ce567));
        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
    }

    function safeTransfer(IERC20 token, address to, uint256 amount) internal {
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0xa9059cbb, to, amount));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "SafeERC20: Transfer failed");
    }

    function safeTransferFrom(IERC20 token, address from, uint256 amount) internal {
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0x23b872dd, from, address(this), amount));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "SafeERC20: TransferFrom failed");
    }

    function safeTransferFromDeluxe(IERC20 token, address from, uint256 amount) internal returns (uint256) {
        uint256 preBalance = token.balanceOf(address(this));
        safeTransferFrom(token, from, amount);
        uint256 postBalance = token.balanceOf(address(this));
        return postBalance - preBalance;
    }
}

File 8 of 8 : StableMath.sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.6;

// Based on StableMath from mStable
// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol

library StableMath {
    /**
     * @dev Scaling unit for use in specific calculations,
     * where 1 * 10**18, or 1e18 represents a unit '1'
     */
    uint256 private constant FULL_SCALE = 1e18;

    /**
     * @dev Provides an interface to the scaling unit
     * @return Scaling unit (1e18 or 1 * 10**18)
     */
    function getFullScale() internal pure returns (uint256) {
        return FULL_SCALE;
    }

    /**
     * @dev Scales a given integer to the power of the full scale.
     * @param x   Simple uint256 to scale
     * @return    Scaled value a to an exact number
     */
    function scaleInteger(uint256 x) internal pure returns (uint256) {
        return x * FULL_SCALE;
    }

    /***************************************
              PRECISE ARITHMETIC
    ****************************************/

    /**
     * @dev Multiplies two precise units, and then truncates by the full scale
     * @param x     Left hand input to multiplication
     * @param y     Right hand input to multiplication
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              scale unit
     */
    function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulTruncateScale(x, y, FULL_SCALE);
    }

    /**
     * @dev Multiplies two precise units, and then truncates by the given scale. For example,
     * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18
     * @param x     Left hand input to multiplication
     * @param y     Right hand input to multiplication
     * @param scale Scale unit
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              scale unit
     */
    function mulTruncateScale(
        uint256 x,
        uint256 y,
        uint256 scale
    ) internal pure returns (uint256) {
        // e.g. assume scale = fullScale
        // z = 10e18 * 9e17 = 9e36
        // return 9e36 / 1e18 = 9e18
        return (x * y) / scale;
    }

    /**
     * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result
     * @param x     Left hand input to multiplication
     * @param y     Right hand input to multiplication
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              scale unit, rounded up to the closest base unit.
     */
    function mulTruncateCeil(uint256 x, uint256 y) internal pure returns (uint256) {
        // e.g. 8e17 * 17268172638 = 138145381104e17
        uint256 scaled = x * y;
        // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17
        uint256 ceil = scaled + FULL_SCALE - 1;
        // e.g. 13814538111.399...e18 / 1e18 = 13814538111
        return ceil / FULL_SCALE;
    }

    /**
     * @dev Precisely divides two units, by first scaling the left hand operand. Useful
     *      for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)
     * @param x     Left hand input to division
     * @param y     Right hand input to division
     * @return      Result after multiplying the left operand by the scale, and
     *              executing the division on the right hand input.
     */
    function divPrecisely(uint256 x, uint256 y) internal pure returns (uint256) {
        // e.g. 8e18 * 1e18 = 8e36
        // e.g. 8e36 / 10e18 = 8e17
        return (x * FULL_SCALE) / y;
    }

    /***************************************
                    HELPERS
    ****************************************/

    /**
     * @dev Calculates minimum of two numbers
     * @param x     Left hand input
     * @param y     Right hand input
     * @return      Minimum of the two inputs
     */
    function min(uint256 x, uint256 y) internal pure returns (uint256) {
        return x > y ? y : x;
    }

    /**
     * @dev Calculated maximum of two numbers
     * @param x     Left hand input
     * @param y     Right hand input
     * @return      Maximum of the two inputs
     */
    function max(uint256 x, uint256 y) internal pure returns (uint256) {
        return x > y ? x : y;
    }

    /**
     * @dev Clamps a value to an upper bound
     * @param x           Left hand input
     * @param upperBound  Maximum possible value to return
     * @return            Input x clamped to a maximum value, upperBound
     */
    function clamp(uint256 x, uint256 upperBound) internal pure returns (uint256) {
        return x > upperBound ? upperBound : x;
    }
}

Settings
{
  "evmVersion": "berlin",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 999999
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_timeToSuper","type":"uint256"},{"internalType":"uint256","name":"_timeToUnstake","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpReward","type":"uint256"}],"name":"Recalculation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousDistributor","type":"address"},{"indexed":true,"internalType":"address","name":"newDistributor","type":"address"}],"name":"RewardsDistributorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeLiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"StakeLiquidityRemoveRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeLiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"StakeRemoveRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"superReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"superLpReward","type":"uint256"}],"name":"SuperRecalculation","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addLiquidityStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bool","name":"_approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"addLiquidityStakeWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addTokenStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bool","name":"_approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"addTokenStakeWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"canSetSuper","outputs":[{"internalType":"bool","name":"token","type":"bool"},{"internalType":"bool","name":"lp","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"canStakeLp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"canStakeTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"claimable","outputs":[{"internalType":"uint256","name":"token","type":"uint256"},{"internalType":"uint256","name":"lp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_lp","type":"bool"}],"name":"currentRewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_lp","type":"bool"}],"name":"currentSuperRewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"data","outputs":[{"internalType":"uint256","name":"depositedTokens","type":"uint256"},{"internalType":"uint256","name":"depositedLiquidity","type":"uint256"},{"internalType":"uint256","name":"totalRewardsAdded","type":"uint256"},{"internalType":"uint256","name":"totalRewardsClaimed","type":"uint256"},{"internalType":"uint256","name":"totalRewardsFromFees","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_liquidity","type":"address"},{"internalType":"address","name":"_vesting","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeSuperRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidityStake","outputs":[{"internalType":"uint256","name":"stakeStart","type":"uint256"},{"internalType":"uint256","name":"superStakerPossibleAt","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenPaid","type":"uint256"},{"internalType":"uint256","name":"superRewardPerTokenPaid","type":"uint256"},{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"},{"internalType":"uint256","name":"withdrawalPossibleAt","type":"uint256"},{"internalType":"bool","name":"isWithdrawing","type":"bool"},{"internalType":"bool","name":"isSuperStaker","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpStaking","outputs":[{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"superRewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"lastSuperUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"},{"internalType":"uint256","name":"superRewardPerTokenStored","type":"uint256"},{"internalType":"uint256","name":"stakedTokens","type":"uint256"},{"internalType":"uint256","name":"stakedSuperTokens","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_reward","type":"uint256"},{"internalType":"uint256","name":"_lpReward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"onClaimAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestUnstakeLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsDistributor","type":"address"}],"name":"setRewardsDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setSuperLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setSuperToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superPeriodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeToSuper","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"lastChange","type":"uint256"},{"internalType":"uint256","name":"minDelay","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeToUnstake","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"lastChange","type":"uint256"},{"internalType":"uint256","name":"minDelay","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenStake","outputs":[{"internalType":"uint256","name":"stakeStart","type":"uint256"},{"internalType":"uint256","name":"superStakerPossibleAt","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenPaid","type":"uint256"},{"internalType":"uint256","name":"superRewardPerTokenPaid","type":"uint256"},{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"},{"internalType":"uint256","name":"withdrawalPossibleAt","type":"uint256"},{"internalType":"bool","name":"isWithdrawing","type":"bool"},{"internalType":"bool","name":"isSuperStaker","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenStaking","outputs":[{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"superRewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"lastSuperUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"},{"internalType":"uint256","name":"superRewardPerTokenStored","type":"uint256"},{"internalType":"uint256","name":"stakedTokens","type":"uint256"},{"internalType":"uint256","name":"stakedSuperTokens","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"},{"internalType":"bool","name":"_direct","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeFee","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"lastChange","type":"uint256"},{"internalType":"uint256","name":"minDelay","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unstakeWithFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"updateFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"updateTimeToSuper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"updateTimeToUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vestingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b5060405162004c9c38038062004c9c8339810160408190526200003491620000fe565b6200003f33620000ae565b600280546001600160a01b031916339081179091556040516000907f52cd8e0a7f86e9df123b3357ab2ee1c4cd0f5ac84ca8c98d93beb2679b2bb806908290a3600160035560049190915560075542600581905560085562093a8060068190556009556103e8600a5562000123565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156200011257600080fd5b505080516020909101519092909150565b614b6980620001336000396000f3fe608060405234801561001057600080fd5b506004361061030a5760003560e01c80639012c4a81161019c578063c18c7a7d116100ee578063e8d4ced011610097578063ee14613a11610071578063ee14613a14610865578063f4aac09d14610878578063fc63958e1461088057600080fd5b8063e8d4ced014610841578063eb4e495014610849578063ebe2b12b1461085c57600080fd5b8063db46cc3e116100c8578063db46cc3e146107e5578063dd3cc0ad1461080f578063e30c39781461082157600080fd5b8063c18c7a7d1461079f578063c77c7387146107b2578063d054472e146107d257600080fd5b8063ace2b91611610150578063ba2313f21161012a578063ba2313f214610770578063bac93f2014610783578063bf394ff71461079657600080fd5b8063ace2b9161461065b578063ad6a71a314610700578063b242e5341461075d57600080fd5b80639bf1401c116101815780639bf1401c146106025780639d76ea5814610628578063a262f5f81461064857600080fd5b80639012c4a8146105b257806395ba0bee146105c557600080fd5b806345837a961161026057806373d4a13a1161020957806380faa57d116101e357806380faa57d146105785780638da5cb5b146105805780638ea97d26146105a057600080fd5b806373d4a13a146104cd57806374ef2a961461050f5780637dc30ede1461051757600080fd5b80634f91440d1161023a5780634f91440d1461049c57806360f6b6e8146104a457806364beca15146104c557600080fd5b806345837a96146104795780634e71d92d1461048c5780634e71e0c81461049457600080fd5b80632d7e877f116102c2578063368cafc81161029c578063368cafc8146104045780633f2a554014610431578063402914f51461045157600080fd5b80632d7e877f146103655780632def6620146103b75780633221c93f146103bf57600080fd5b806319762143116102f3578063197621431461032c578063246132f91461033f57806329b31b391461035257600080fd5b80630f1fa81e1461030f578063184b955914610319575b600080fd5b610317610888565b005b610317610327366004614880565b610895565b61031761033a366004614865565b610b76565b61031761034d366004614990565b610d02565b6103176103603660046149b2565b610f53565b6103a2610373366004614865565b73ffffffffffffffffffffffffffffffffffffffff1660009081526028602052604090206007015460ff161590565b60405190151581526020015b60405180910390f35b61031761107c565b600e546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103ae565b60075460085460095461041692919083565b604080519384526020840192909252908201526060016103ae565b6002546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b61046461045f366004614865565b611422565b604080519283526020830191909152016103ae565b6103176104873660046149b2565b6114d3565b6103176115ef565b6103176115f9565b61031761170f565b6104b76104b2366004614924565b611a2a565b6040519081526020016103ae565b6104b7611afb565b6012546013546014546015546016546104e7949392919085565b604080519586526020860194909452928401919091526060830152608082015260a0016103ae565b610317611b0e565b601754601854601954601a54601b54601c54601d54601e5461053d979695949392919088565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e0820152610100016103ae565b6104b7611b19565b6000546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b600a54600b54600c5461041692919083565b6103176105c036600461495e565b611b27565b6103a26105d3366004614865565b73ffffffffffffffffffffffffffffffffffffffff1660009081526027602052604090206007015460ff161590565b601f5460205460215460225460235460245460255460265461053d979695949392919088565b600d546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b610317610656366004614865565b611c97565b6106b8610669366004614865565b6028602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460079097015495969495939492939192909160ff8082169161010090041689565b60408051998a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c0840152151560e08301521515610100820152610120016103ae565b6106b861070e366004614865565b6027602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460079097015495969495939492939192909160ff8082169161010090041689565b61031761076b3660046148c3565b611ca4565b61031761077e36600461495e565b611e83565b61031761079136600461495e565b61200d565b6104b760115481565b6104b76107ad366004614924565b612052565b600f546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b6103176107e036600461495e565b6120fe565b6107f86107f3366004614865565b61213c565b6040805192151583529015156020830152016103ae565b60045460055460065461041692919083565b6001546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b61031761235a565b61031761085736600461495e565b612392565b6104b760105481565b6103176108733660046148fa565b61250d565b610317612855565b610317612da7565b610893336000612ddf565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461091b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5f746f6b656e20616464726573732063616e6e6f7420626520300000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff8216610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5f6c697175696469747920616464726573732063616e6e6f74206265203000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff8116610a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f5f76657374696e6720616464726573732063616e6e6f742062652030000000006044820152606401610912565b600d5473ffffffffffffffffffffffffffffffffffffffff1615610b12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f496e697420616c726561647920646f6e650000000000000000000000000000006044820152606401610912565b600d805473ffffffffffffffffffffffffffffffffffffffff9485167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600e805493851693821693909317909255600f8054919093169116179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610bf7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff8116610c74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f206164647265737300000000000000000000000000000000000000006044820152606401610912565b60025460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f52cd8e0a7f86e9df123b3357ab2ee1c4cd0f5ac84ca8c98d93beb2679b2bb80690600090a3600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60025473ffffffffffffffffffffffffffffffffffffffff163314610d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f7420726577617264206469737472696275746f726044820152606401610912565b6000610d908160006131bd565b610d9b8160016131bd565b42610da68385614a4f565b600d54610dd39073ffffffffffffffffffffffffffffffffffffffff1633610dce8789614a4f565b613299565b14610e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4578636c7564652052657761726465722066726f6d20666565000000000000006044820152606401610912565b6010548110610e6857610e5062093a8085614a67565b601755610e6062093a8084614a67565b601f55610ed9565b600081601054610e789190614adf565b601754909150600090610e8b9083614aa2565b905062093a80610e9b8288614a4f565b610ea59190614a67565b601755601f54600090610eb89084614aa2565b905062093a80610ec88288614a4f565b610ed29190614a67565b601f555050505b60198190556021819055610ef062093a8082614a4f565b601055610efd8385614a4f565b60148054600090610f0f908490614a4f565b909155505060408051858152602081018590527f921b4a29d08cacb4cf0c6f947f21a44dbad2a9817be4327b7bbdc9ff505e557b910160405180910390a150505050565b600084610f605786610f82565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b600d546040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526064810189905260ff8716608482015260a4810186905260c4810185905291925073ffffffffffffffffffffffffffffffffffffffff169063d505accf9060e401600060405180830381600087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b5050505061103d338860006132c4565b60405187815233907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f906020015b60405180910390a250505050505050565b600260035414156110e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b60026003553360009081526028602052604090206004015415158061111f57503360009081526027602052604090206004015415155b611185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b61118d6135d8565b6111f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f43616e6e6f7420756e7374616b650000000000000000000000000000000000006044820152606401610912565b600080600080611204336000613649565b945092506112128382614a4f565b9050831561131457336000908152602760205260409020600401546112379083614a4f565b33600090815260276020526040812060040154601280549395509092909190611261908490614adf565b9091555050336000818152602760209081526040918290206004015491519182527fa018dcbc822f59fb0d0c3e7a86c8e4259b9676cdea9e5fc26279b9c4c5d86eef910160405180910390a23360009081526027602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600681019190915560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b61131f336001613649565b9450925061132d8382614a4f565b9050831561139c573360009081526028602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600681019190915560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b60006113a88284614a4f565b111561141757600d546113db9073ffffffffffffffffffffffffffffffffffffffff16336113d68486614a4f565b613824565b80156114175760405181815233907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a25b505060016003555050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526027602052604081206005015481906114578483613845565b611462856000613986565b61146c9190614a4f565b6114769190614adf565b73ffffffffffffffffffffffffffffffffffffffff84166000908152602860205260409020600501549092506114ad846001613845565b6114b8856001613986565b6114c29190614a4f565b6114cc9190614adf565b9050915091565b6000846114e05786611502565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b600e546040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526064810189905260ff8716608482015260a4810186905260c4810185905291925073ffffffffffffffffffffffffffffffffffffffff169063d505accf9060e401600060405180830381600087803b15801561159957600080fd5b505af11580156115ad573d6000803e3d6000fd5b505050506115bd338860016132c4565b60405187815233907f642e84c995db6386df09873e261eca65270d7b8bec64957fa3cba3a3878c25299060200161106b565b6108933333613a82565b60015473ffffffffffffffffffffffffffffffffffffffff1633811461167b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c657220213d2070656e64696e67206f776e65720000000000000000006044820152606401610912565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179055600180549091169055565b3360009081526028602052604090206004015415158061174057503360009081526027602052604090206004015415155b6117a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b336117b28160006131bd565b6117bd8160016131bd565b3360006117cb826000613d56565b90506117d8826001613d56565b806117e05750805b905080156117f0576117f0613e6a565b3360009081526027602090815260408083206028909252909120600782015460ff1615611879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b60008160050154836005015461188f9190614a4f565b9050600081116118fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4e6f7468696e6720746f2072657374616b6500000000000000000000000000006044820152606401610912565b600060058085018290558301558254611924574280845560045461191e91614a4f565b60018401555b808360040160008282546119389190614a4f565b9091555050601d8054829190600090611952908490614a4f565b90915550506007830154610100900460ff161561198457806017600701600082825461197e9190614a4f565b90915550505b80601260030160008282546119999190614a4f565b9091555050601280548291906000906119b3908490614a4f565b909155505060405181815233907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a260405181815233907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f9060200160405180910390a2505050505050565b60008082611a39576017611a3c565b601f5b6040805161010081018252825481526001830154602082015260028301549181019190915260038201546060820152600482015460808201819052600583015460a0830152600683015460c0830181905260079093015460e083015290925081611aa857949350505050565b60008360400151611ab7611b19565b611ac19190614adf565b90506000818560000151611ad59190614aa2565b90506000611ae3828661401d565b9050611aef8185614a4f565b98975050505050505050565b6000611b0942601154614043565b905090565b610893336001612ddf565b6000611b0942601054614043565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ba8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b600c54600b54611bb89190614a4f565b4211611c22576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109129060208082526004908201527f536f6f6e00000000000000000000000000000000000000000000000000000000604082015260600190565b6109c4811115611c8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f6d617820666565206973203235250000000000000000000000000000000000006044820152606401610912565b42600b55600a55565b611ca13382613a82565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611d25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b8015611e3e5773ffffffffffffffffffffffffffffffffffffffff8216611da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f206164647265737300000000000000000000000000000000000000006044820152606401610912565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808616939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff84167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556001805490911690555050565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611f04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b600654600554611f149190614a4f565b4211611f7e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109129060208082526004908201527f536f6f6e00000000000000000000000000000000000000000000000000000000604082015260600190565b611f8c62278d006003614aa2565b8111158015611f9e575062093a808110155b612004576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f44656c61792069732031207765656b202d2033206d6f6e7468730000000000006044820152606401610912565b42600555600455565b612019338260016132c4565b60405181815233907f642e84c995db6386df09873e261eca65270d7b8bec64957fa3cba3a3878c2529906020015b60405180910390a250565b60008082612061576017612064565b601f5b604080516101008101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a08201819052600683015460c083015260079092015460e0820181905290925090816120d157949350505050565b600083606001516120e0611afb565b6120ea9190614adf565b90506000818560200151611ad59190614aa2565b61210a338260006132c4565b60405181815233907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f90602001612047565b6000806000602760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff16151515158152505090506000602860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff1615151515815250509050600082608001511180156122ed575081602001514210155b80156122fc5750816101000151155b801561230a57508160e00151155b1561231457600193505b6000816080015111801561232c575080602001514210155b801561233b5750806101000151155b801561234957508060e00151155b1561235357600192505b5050915091565b612365336001614058565b60405133907fa910809dd00789e69d04a11fbe59837fa35aec1429cb5d20048dfe9b0cc0eead90600090a2565b60005473ffffffffffffffffffffffffffffffffffffffff163314612413576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b6009546008546124239190614a4f565b421161248d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109129060208082526004908201527f536f6f6e00000000000000000000000000000000000000000000000000000000604082015260600190565b61249b62093a806002614aa2565b811115612504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d61782064656c617920697320313420646179730000000000000000000000006044820152606401610912565b42600855600755565b6002600354141561257a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b600260035581600061258c82826131bd565b83600061259a826000613d56565b90506125a7826001613d56565b806125af5750805b905080156125bf576125bf613e6a565b600f5473ffffffffffffffffffffffffffffffffffffffff163314612640576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f6e6c792076657374696e6720636f6e747261637400000000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff861660009081526027602052604090206007015460ff16156126d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b6000851161273d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a65726f20416d6f756e740000000000000000000000000000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff861660009081526027602052604090208054601790612781574280835560045461277b91614a4f565b60018301555b868260040160008282546127959190614a4f565b92505081905550868160060160008282546127b09190614a4f565b90915550506007820154610100900460ff16156127e157868160070160008282546127db9190614a4f565b90915550505b86601260000160008282546127f69190614a4f565b909155505060405187815273ffffffffffffffffffffffffffffffffffffffff8916907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f9060200160405180910390a250506001600355505050505050565b600260035414156128c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b6002600355336000908152602860205260409020600401541515806128f857503360009081526027602052604090206004015415155b61295e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b6129666135d8565b156129cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f556e7374616b65206669727374000000000000000000000000000000000000006044820152606401610912565b6000602760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff16151515158152505090506000602860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff16151515158152505090506000808260e0015115612c99576000612b7f8460800151614308565b90508360a0015182612b919190614a4f565b91508360a0015160126003016000828254612bac9190614a4f565b9091555050608084015160138054600090612bc8908490614adf565b9091555050608084015160405190815233907fbb37929ba745d1c183522217faa28a183a44c70dd5fc0a135bb7242d1e4f97739060200160405180910390a28015612c3157600e54612c319073ffffffffffffffffffffffffffffffffffffffff163383613824565b503360009081526028602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600681019190915560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b8360e001511561139c57612cb08460800151614308565b91508360a0015181612cc29190614a4f565b90508360a0015160126003016000828254612cdd9190614a4f565b9091555050608084015160128054600090612cf9908490614adf565b9091555050608084015160405190815233907fa018dcbc822f59fb0d0c3e7a86c8e4259b9676cdea9e5fc26279b9c4c5d86eef9060200160405180910390a233600090815260276020526040812081815560018101829055600281018290556003810182905560048101829055600581018290556006810182905560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556113a88284614a4f565b612db2336000614058565b60405133907fc0e0022681c64867610b70899a07bee5aa6e6c0d5e40cf3351a426fa9a81052990600090a2565b8181600081612e185773ffffffffffffffffffffffffffffffffffffffff83166000908152602760205260409020600401541515612e44565b73ffffffffffffffffffffffffffffffffffffffff831660009081526028602052604090206004015415155b905080612ead576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b8484600081612ee05773ffffffffffffffffffffffffffffffffffffffff83166000908152602760205260409020612f06565b73ffffffffffffffffffffffffffffffffffffffff831660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff80821615801560e085015261010092839004909116151591830191909152909150612fe2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b8061010001511561304f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f416c7265616479207375706572207374616b65720000000000000000000000006044820152606401610912565b80602001514210156130bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f546f6f20736f6f6e0000000000000000000000000000000000000000000000006044820152606401610912565b6000806130cb826000613d56565b90506130d8826001613d56565b806130e05750805b905080156130f0576130f0613e6a565b6000896131215773ffffffffffffffffffffffffffffffffffffffff8b166000908152602760205260409020613147565b73ffffffffffffffffffffffffffffffffffffffff8b1660009081526028602052604090205b905060008a61315757601761315a565b601f5b905081600401548160070160008282546131749190614a4f565b90915550506007820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556005015460039091015550505050505050505050565b60006131c882611a2a565b90508015613294576000826131de5760176131e1565b601f5b6004810183905590506131f2611b19565b600282015573ffffffffffffffffffffffffffffffffffffffff841615613292576000836132445773ffffffffffffffffffffffffffffffffffffffff8516600090815260276020526040902061326a565b73ffffffffffffffffffffffffffffffffffffffff851660009081526028602052604090205b600781015490915060ff16613290576132838585613986565b6005820155600281018390555b505b505b505050565b60006132bc73ffffffffffffffffffffffffffffffffffffffff85168484614330565b949350505050565b60026003541415613331576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b6002600355828161334282826131bd565b846000613350826000613d56565b905061335d826001613d56565b806133655750805b9050801561337557613375613e6a565b600086116133df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a65726f20416d6f756e740000000000000000000000000000000000000000006044820152606401610912565b6000856134105773ffffffffffffffffffffffffffffffffffffffff88166000908152602760205260409020613436565b73ffffffffffffffffffffffffffffffffffffffff881660009081526028602052604090205b600781015490915060ff16156134a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b6000866134cd57600d5473ffffffffffffffffffffffffffffffffffffffff166134e7565b600e5473ffffffffffffffffffffffffffffffffffffffff165b90506134f481338a613299565b8254909850613513574280835560045461350d91614a4f565b60018301555b600087613521576017613524565b601f5b90508883600401600082825461353a9190614a4f565b92505081905550888160060160008282546135559190614a4f565b90915550506007830154610100900460ff161561358657888160070160008282546135809190614a4f565b90915550505b87156135ac5788601260010160008282546135a19190614a4f565b909155506135c79050565b88601260000160008282546135c19190614a4f565b90915550505b505060016003555050505050505050565b3360009081526028602052604081206007015460ff16801561360c5750336000908152602860205260409020600601544210155b80611b0957503360009081526027602052604090206007015460ff168015611b095750503360009081526027602052604090206006015442101590565b60008060008361367d5773ffffffffffffffffffffffffffffffffffffffff851660009081526027602052604090206136a3565b73ffffffffffffffffffffffffffffffffffffffff851660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e084018190526101009283900490911615159183019190915290915061372b57600080925092505061381d565b428160c00151111561374457600080925092505061381d565b60a08101516015805460009061375b908490614a4f565b909155508490508015613772575060008160800151115b156138125760808101516013805460009061378e908490614adf565b9091555050600e5460808201516137bd9173ffffffffffffffffffffffffffffffffffffffff16908790613824565b8473ffffffffffffffffffffffffffffffffffffffff167fbb37929ba745d1c183522217faa28a183a44c70dd5fc0a135bb7242d1e4f9773826080015160405161380991815260200190565b60405180910390a25b60a001519150600190505b9250929050565b61329473ffffffffffffffffffffffffffffffffffffffff84168383614495565b600080826138775773ffffffffffffffffffffffffffffffffffffffff8416600090815260276020526040902061389d565b73ffffffffffffffffffffffffffffffffffffffff841660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e08401526101009182900416158015918301919091529091508061391d57508060e001515b1561392d5760a001519050613980565b600061393884612052565b9050600082606001518261394c9190614adf565b905060006139678285608001516145fe90919063ffffffff16565b9050808460a001516139799190614a4f565b9450505050505b92915050565b600080826139b85773ffffffffffffffffffffffffffffffffffffffff841660009081526027602052604090206139de565b73ffffffffffffffffffffffffffffffffffffffff841660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff80821615801560e085015261010092839004909116151591830191909152909150613a635760a001519050613980565b6000613a6e84611a2a565b9050600082604001518261394c9190614adf565b60026003541415613aef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b600260035533600090815260286020526040902060040154151580613b2557503360009081526027602052604090206004015415155b613b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b81613b978160006131bd565b613ba28160016131bd565b826000613bb0826000613d56565b9050613bbd826001613d56565b80613bc55750805b90508015613bd557613bd5613e6a565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260286020908152604080832060059081015460279093529083200154613c179190614a4f565b905060008111613c83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7468696e6720746f20636c61696d000000000000000000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff861660009081526027602090815260408083206005908101849055602890925282200181905560158054839290613cd0908490614a4f565b9091555050600d54613cf99073ffffffffffffffffffffffffffffffffffffffff168683613824565b8573ffffffffffffffffffffffffffffffffffffffff167fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a82604051613d4191815260200190565b60405180910390a25050600160035550505050565b60008082613d885773ffffffffffffffffffffffffffffffffffffffff84166000908152602760205260409020613dae565b73ffffffffffffffffffffffffffffffffffffffff841660009081526028602052604090205b6007810154909150610100900460ff1680613ddd575073ffffffffffffffffffffffffffffffffffffffff8416155b15613e63576000613ded84612052565b90508015613e5d57600084613e03576017613e06565b601f5b600581018390559050613e17611afb565b600382015573ffffffffffffffffffffffffffffffffffffffff861615613e5b57600783015460ff16613e5b57613e4e8686613845565b6005840155600383018290555b505b60019250505b5092915050565b6011544290600090613e7d576000613e9a565b613e8d6201518062278d00614adf565b601154613e9a9190614adf565b9050808210611e7f57600d54600090613ec99073ffffffffffffffffffffffffffffffffffffffff1630614613565b601554601654601454929350600092613ee29190614a4f565b613eec9190614adf565b601254613ef99084614adf565b613f039190614adf565b90508060126004016000828254613f1a9190614a4f565b909155505060115460028204908510613f5257613f3a62278d0082614a67565b601855613f4a62278d0082614a67565b602055613fc3565b600085601154613f629190614adf565b601854909150600090613f759083614aa2565b905062278d00613f858285614a4f565b613f8f9190614a67565b601855602054600090613fa29084614aa2565b905062278d00613fb28286614a4f565b613fbc9190614a67565b6020555050505b601a8590556022859055613fda62278d0086614a4f565b60115560408051828152602081018390527fb2e45d21bc3a556247a4a3ad6cd0b08145d486b943b9e671263fca15bef18b6d910160405180910390a15050505050565b600081614032670de0b6b3a764000085614aa2565b61403c9190614a67565b9392505050565b6000818311614052578261403c565b50919050565b81816000816140915773ffffffffffffffffffffffffffffffffffffffff831660009081526027602052604090206004015415156140bd565b73ffffffffffffffffffffffffffffffffffffffff831660009081526028602052604090206004015415155b905080614126576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b848461413282826131bd565b866000614140826000613d56565b905061414d826001613d56565b806141555750805b9050801561416557614165613e6a565b6000886141965773ffffffffffffffffffffffffffffffffffffffff8a1660009081526027602052604090206141bc565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526028602052604090205b600781015490915060ff161561422e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b60008961423c57601761423f565b601f5b600780840180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555490915061427b9042614a4f565b8260060181905550816004015481600601600082825461429b9190614adf565b90915550506007820154610100900460ff16156142fb57600780830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055600483015490820180546000906142f5908490614adf565b90915550505b5050505050505050505050565b600a546000906127109061431c9084614aa2565b6143269190614a67565b6139809083614adf565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff8616906370a082319060240160206040518083038186803b15801561439a57600080fd5b505afa1580156143ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143d29190614977565b90506143df8585856146b6565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8716906370a082319060240160206040518083038186803b15801561444757600080fd5b505afa15801561445b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061447f9190614977565b905061448b8282614adf565b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169161452c9190614a14565b6000604051808303816000865af19150503d8060008114614569576040519150601f19603f3d011682016040523d82523d6000602084013e61456e565b606091505b50915091508180156145985750805115806145985750808060200190518101906145989190614941565b613290576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a205472616e73666572206661696c65640000000000006044820152606401610912565b600061403c8383670de0b6b3a7640000614825565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152600091908416906370a082319060240160206040518083038186803b15801561467e57600080fd5b505afa158015614692573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061403c9190614977565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152306044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908716916147539190614a14565b6000604051808303816000865af19150503d8060008114614790576040519150601f19603f3d011682016040523d82523d6000602084013e614795565b606091505b50915091508180156147bf5750805115806147bf5750808060200190518101906147bf9190614941565b613290576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5361666545524332303a205472616e7366657246726f6d206661696c656400006044820152606401610912565b6000816148328486614aa2565b6132bc9190614a67565b803573ffffffffffffffffffffffffffffffffffffffff8116811461486057600080fd5b919050565b60006020828403121561487757600080fd5b61403c8261483c565b60008060006060848603121561489557600080fd5b61489e8461483c565b92506148ac6020850161483c565b91506148ba6040850161483c565b90509250925092565b600080604083850312156148d657600080fd5b6148df8361483c565b915060208301356148ef81614b25565b809150509250929050565b6000806040838503121561490d57600080fd5b6149168361483c565b946020939093013593505050565b60006020828403121561493657600080fd5b813561403c81614b25565b60006020828403121561495357600080fd5b815161403c81614b25565b60006020828403121561497057600080fd5b5035919050565b60006020828403121561498957600080fd5b5051919050565b600080604083850312156149a357600080fd5b50508035926020909101359150565b60008060008060008060c087890312156149cb57600080fd5b863595506020870135945060408701356149e481614b25565b9350606087013560ff811681146149fa57600080fd5b9598949750929560808101359460a0909101359350915050565b6000825160005b81811015614a355760208186018101518583015201614a1b565b81811115614a44576000828501525b509190910192915050565b60008219821115614a6257614a62614af6565b500190565b600082614a9d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ada57614ada614af6565b500290565b600082821015614af157614af1614af6565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8015158114611ca157600080fdfea2646970667358221220ab857582abc76de18375965040d6e7cddc1fa05da9db05efc941556c24cbcc5864736f6c634300080600330000000000000000000000000000000000000000000000000000000000278d000000000000000000000000000000000000000000000000000000000000093a80

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061030a5760003560e01c80639012c4a81161019c578063c18c7a7d116100ee578063e8d4ced011610097578063ee14613a11610071578063ee14613a14610865578063f4aac09d14610878578063fc63958e1461088057600080fd5b8063e8d4ced014610841578063eb4e495014610849578063ebe2b12b1461085c57600080fd5b8063db46cc3e116100c8578063db46cc3e146107e5578063dd3cc0ad1461080f578063e30c39781461082157600080fd5b8063c18c7a7d1461079f578063c77c7387146107b2578063d054472e146107d257600080fd5b8063ace2b91611610150578063ba2313f21161012a578063ba2313f214610770578063bac93f2014610783578063bf394ff71461079657600080fd5b8063ace2b9161461065b578063ad6a71a314610700578063b242e5341461075d57600080fd5b80639bf1401c116101815780639bf1401c146106025780639d76ea5814610628578063a262f5f81461064857600080fd5b80639012c4a8146105b257806395ba0bee146105c557600080fd5b806345837a961161026057806373d4a13a1161020957806380faa57d116101e357806380faa57d146105785780638da5cb5b146105805780638ea97d26146105a057600080fd5b806373d4a13a146104cd57806374ef2a961461050f5780637dc30ede1461051757600080fd5b80634f91440d1161023a5780634f91440d1461049c57806360f6b6e8146104a457806364beca15146104c557600080fd5b806345837a96146104795780634e71d92d1461048c5780634e71e0c81461049457600080fd5b80632d7e877f116102c2578063368cafc81161029c578063368cafc8146104045780633f2a554014610431578063402914f51461045157600080fd5b80632d7e877f146103655780632def6620146103b75780633221c93f146103bf57600080fd5b806319762143116102f3578063197621431461032c578063246132f91461033f57806329b31b391461035257600080fd5b80630f1fa81e1461030f578063184b955914610319575b600080fd5b610317610888565b005b610317610327366004614880565b610895565b61031761033a366004614865565b610b76565b61031761034d366004614990565b610d02565b6103176103603660046149b2565b610f53565b6103a2610373366004614865565b73ffffffffffffffffffffffffffffffffffffffff1660009081526028602052604090206007015460ff161590565b60405190151581526020015b60405180910390f35b61031761107c565b600e546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103ae565b60075460085460095461041692919083565b604080519384526020840192909252908201526060016103ae565b6002546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b61046461045f366004614865565b611422565b604080519283526020830191909152016103ae565b6103176104873660046149b2565b6114d3565b6103176115ef565b6103176115f9565b61031761170f565b6104b76104b2366004614924565b611a2a565b6040519081526020016103ae565b6104b7611afb565b6012546013546014546015546016546104e7949392919085565b604080519586526020860194909452928401919091526060830152608082015260a0016103ae565b610317611b0e565b601754601854601954601a54601b54601c54601d54601e5461053d979695949392919088565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e0820152610100016103ae565b6104b7611b19565b6000546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b600a54600b54600c5461041692919083565b6103176105c036600461495e565b611b27565b6103a26105d3366004614865565b73ffffffffffffffffffffffffffffffffffffffff1660009081526027602052604090206007015460ff161590565b601f5460205460215460225460235460245460255460265461053d979695949392919088565b600d546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b610317610656366004614865565b611c97565b6106b8610669366004614865565b6028602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460079097015495969495939492939192909160ff8082169161010090041689565b60408051998a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c0840152151560e08301521515610100820152610120016103ae565b6106b861070e366004614865565b6027602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460079097015495969495939492939192909160ff8082169161010090041689565b61031761076b3660046148c3565b611ca4565b61031761077e36600461495e565b611e83565b61031761079136600461495e565b61200d565b6104b760115481565b6104b76107ad366004614924565b612052565b600f546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b6103176107e036600461495e565b6120fe565b6107f86107f3366004614865565b61213c565b6040805192151583529015156020830152016103ae565b60045460055460065461041692919083565b6001546103df9073ffffffffffffffffffffffffffffffffffffffff1681565b61031761235a565b61031761085736600461495e565b612392565b6104b760105481565b6103176108733660046148fa565b61250d565b610317612855565b610317612da7565b610893336000612ddf565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461091b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5f746f6b656e20616464726573732063616e6e6f7420626520300000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff8216610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5f6c697175696469747920616464726573732063616e6e6f74206265203000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff8116610a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f5f76657374696e6720616464726573732063616e6e6f742062652030000000006044820152606401610912565b600d5473ffffffffffffffffffffffffffffffffffffffff1615610b12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f496e697420616c726561647920646f6e650000000000000000000000000000006044820152606401610912565b600d805473ffffffffffffffffffffffffffffffffffffffff9485167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600e805493851693821693909317909255600f8054919093169116179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610bf7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff8116610c74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f206164647265737300000000000000000000000000000000000000006044820152606401610912565b60025460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f52cd8e0a7f86e9df123b3357ab2ee1c4cd0f5ac84ca8c98d93beb2679b2bb80690600090a3600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60025473ffffffffffffffffffffffffffffffffffffffff163314610d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f63616c6c6572206973206e6f7420726577617264206469737472696275746f726044820152606401610912565b6000610d908160006131bd565b610d9b8160016131bd565b42610da68385614a4f565b600d54610dd39073ffffffffffffffffffffffffffffffffffffffff1633610dce8789614a4f565b613299565b14610e3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4578636c7564652052657761726465722066726f6d20666565000000000000006044820152606401610912565b6010548110610e6857610e5062093a8085614a67565b601755610e6062093a8084614a67565b601f55610ed9565b600081601054610e789190614adf565b601754909150600090610e8b9083614aa2565b905062093a80610e9b8288614a4f565b610ea59190614a67565b601755601f54600090610eb89084614aa2565b905062093a80610ec88288614a4f565b610ed29190614a67565b601f555050505b60198190556021819055610ef062093a8082614a4f565b601055610efd8385614a4f565b60148054600090610f0f908490614a4f565b909155505060408051858152602081018590527f921b4a29d08cacb4cf0c6f947f21a44dbad2a9817be4327b7bbdc9ff505e557b910160405180910390a150505050565b600084610f605786610f82565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b600d546040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526064810189905260ff8716608482015260a4810186905260c4810185905291925073ffffffffffffffffffffffffffffffffffffffff169063d505accf9060e401600060405180830381600087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b5050505061103d338860006132c4565b60405187815233907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f906020015b60405180910390a250505050505050565b600260035414156110e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b60026003553360009081526028602052604090206004015415158061111f57503360009081526027602052604090206004015415155b611185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b61118d6135d8565b6111f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f43616e6e6f7420756e7374616b650000000000000000000000000000000000006044820152606401610912565b600080600080611204336000613649565b945092506112128382614a4f565b9050831561131457336000908152602760205260409020600401546112379083614a4f565b33600090815260276020526040812060040154601280549395509092909190611261908490614adf565b9091555050336000818152602760209081526040918290206004015491519182527fa018dcbc822f59fb0d0c3e7a86c8e4259b9676cdea9e5fc26279b9c4c5d86eef910160405180910390a23360009081526027602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600681019190915560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b61131f336001613649565b9450925061132d8382614a4f565b9050831561139c573360009081526028602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600681019190915560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b60006113a88284614a4f565b111561141757600d546113db9073ffffffffffffffffffffffffffffffffffffffff16336113d68486614a4f565b613824565b80156114175760405181815233907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a25b505060016003555050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526027602052604081206005015481906114578483613845565b611462856000613986565b61146c9190614a4f565b6114769190614adf565b73ffffffffffffffffffffffffffffffffffffffff84166000908152602860205260409020600501549092506114ad846001613845565b6114b8856001613986565b6114c29190614a4f565b6114cc9190614adf565b9050915091565b6000846114e05786611502565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b600e546040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526064810189905260ff8716608482015260a4810186905260c4810185905291925073ffffffffffffffffffffffffffffffffffffffff169063d505accf9060e401600060405180830381600087803b15801561159957600080fd5b505af11580156115ad573d6000803e3d6000fd5b505050506115bd338860016132c4565b60405187815233907f642e84c995db6386df09873e261eca65270d7b8bec64957fa3cba3a3878c25299060200161106b565b6108933333613a82565b60015473ffffffffffffffffffffffffffffffffffffffff1633811461167b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c657220213d2070656e64696e67206f776e65720000000000000000006044820152606401610912565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179055600180549091169055565b3360009081526028602052604090206004015415158061174057503360009081526027602052604090206004015415155b6117a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b336117b28160006131bd565b6117bd8160016131bd565b3360006117cb826000613d56565b90506117d8826001613d56565b806117e05750805b905080156117f0576117f0613e6a565b3360009081526027602090815260408083206028909252909120600782015460ff1615611879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b60008160050154836005015461188f9190614a4f565b9050600081116118fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4e6f7468696e6720746f2072657374616b6500000000000000000000000000006044820152606401610912565b600060058085018290558301558254611924574280845560045461191e91614a4f565b60018401555b808360040160008282546119389190614a4f565b9091555050601d8054829190600090611952908490614a4f565b90915550506007830154610100900460ff161561198457806017600701600082825461197e9190614a4f565b90915550505b80601260030160008282546119999190614a4f565b9091555050601280548291906000906119b3908490614a4f565b909155505060405181815233907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a260405181815233907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f9060200160405180910390a2505050505050565b60008082611a39576017611a3c565b601f5b6040805161010081018252825481526001830154602082015260028301549181019190915260038201546060820152600482015460808201819052600583015460a0830152600683015460c0830181905260079093015460e083015290925081611aa857949350505050565b60008360400151611ab7611b19565b611ac19190614adf565b90506000818560000151611ad59190614aa2565b90506000611ae3828661401d565b9050611aef8185614a4f565b98975050505050505050565b6000611b0942601154614043565b905090565b610893336001612ddf565b6000611b0942601054614043565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ba8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b600c54600b54611bb89190614a4f565b4211611c22576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109129060208082526004908201527f536f6f6e00000000000000000000000000000000000000000000000000000000604082015260600190565b6109c4811115611c8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f6d617820666565206973203235250000000000000000000000000000000000006044820152606401610912565b42600b55600a55565b611ca13382613a82565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611d25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b8015611e3e5773ffffffffffffffffffffffffffffffffffffffff8216611da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f206164647265737300000000000000000000000000000000000000006044820152606401610912565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808616939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff84167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556001805490911690555050565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611f04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b600654600554611f149190614a4f565b4211611f7e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109129060208082526004908201527f536f6f6e00000000000000000000000000000000000000000000000000000000604082015260600190565b611f8c62278d006003614aa2565b8111158015611f9e575062093a808110155b612004576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f44656c61792069732031207765656b202d2033206d6f6e7468730000000000006044820152606401610912565b42600555600455565b612019338260016132c4565b60405181815233907f642e84c995db6386df09873e261eca65270d7b8bec64957fa3cba3a3878c2529906020015b60405180910390a250565b60008082612061576017612064565b601f5b604080516101008101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a08201819052600683015460c083015260079092015460e0820181905290925090816120d157949350505050565b600083606001516120e0611afb565b6120ea9190614adf565b90506000818560200151611ad59190614aa2565b61210a338260006132c4565b60405181815233907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f90602001612047565b6000806000602760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff16151515158152505090506000602860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff1615151515815250509050600082608001511180156122ed575081602001514210155b80156122fc5750816101000151155b801561230a57508160e00151155b1561231457600193505b6000816080015111801561232c575080602001514210155b801561233b5750806101000151155b801561234957508060e00151155b1561235357600192505b5050915091565b612365336001614058565b60405133907fa910809dd00789e69d04a11fbe59837fa35aec1429cb5d20048dfe9b0cc0eead90600090a2565b60005473ffffffffffffffffffffffffffffffffffffffff163314612413576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f63616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610912565b6009546008546124239190614a4f565b421161248d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109129060208082526004908201527f536f6f6e00000000000000000000000000000000000000000000000000000000604082015260600190565b61249b62093a806002614aa2565b811115612504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d61782064656c617920697320313420646179730000000000000000000000006044820152606401610912565b42600855600755565b6002600354141561257a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b600260035581600061258c82826131bd565b83600061259a826000613d56565b90506125a7826001613d56565b806125af5750805b905080156125bf576125bf613e6a565b600f5473ffffffffffffffffffffffffffffffffffffffff163314612640576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f6e6c792076657374696e6720636f6e747261637400000000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff861660009081526027602052604090206007015460ff16156126d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b6000851161273d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a65726f20416d6f756e740000000000000000000000000000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff861660009081526027602052604090208054601790612781574280835560045461277b91614a4f565b60018301555b868260040160008282546127959190614a4f565b92505081905550868160060160008282546127b09190614a4f565b90915550506007820154610100900460ff16156127e157868160070160008282546127db9190614a4f565b90915550505b86601260000160008282546127f69190614a4f565b909155505060405187815273ffffffffffffffffffffffffffffffffffffffff8916907f7c717985ac273e663b7f3050f5b15a4388ff6ed952338954f650e2093e13937f9060200160405180910390a250506001600355505050505050565b600260035414156128c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b6002600355336000908152602860205260409020600401541515806128f857503360009081526027602052604090206004015415155b61295e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b6129666135d8565b156129cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f556e7374616b65206669727374000000000000000000000000000000000000006044820152606401610912565b6000602760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff16151515158152505090506000602860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180610120016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff161515151581526020016007820160019054906101000a900460ff16151515158152505090506000808260e0015115612c99576000612b7f8460800151614308565b90508360a0015182612b919190614a4f565b91508360a0015160126003016000828254612bac9190614a4f565b9091555050608084015160138054600090612bc8908490614adf565b9091555050608084015160405190815233907fbb37929ba745d1c183522217faa28a183a44c70dd5fc0a135bb7242d1e4f97739060200160405180910390a28015612c3157600e54612c319073ffffffffffffffffffffffffffffffffffffffff163383613824565b503360009081526028602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600681019190915560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b8360e001511561139c57612cb08460800151614308565b91508360a0015181612cc29190614a4f565b90508360a0015160126003016000828254612cdd9190614a4f565b9091555050608084015160128054600090612cf9908490614adf565b9091555050608084015160405190815233907fa018dcbc822f59fb0d0c3e7a86c8e4259b9676cdea9e5fc26279b9c4c5d86eef9060200160405180910390a233600090815260276020526040812081815560018101829055600281018290556003810182905560048101829055600581018290556006810182905560070180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556113a88284614a4f565b612db2336000614058565b60405133907fc0e0022681c64867610b70899a07bee5aa6e6c0d5e40cf3351a426fa9a81052990600090a2565b8181600081612e185773ffffffffffffffffffffffffffffffffffffffff83166000908152602760205260409020600401541515612e44565b73ffffffffffffffffffffffffffffffffffffffff831660009081526028602052604090206004015415155b905080612ead576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b8484600081612ee05773ffffffffffffffffffffffffffffffffffffffff83166000908152602760205260409020612f06565b73ffffffffffffffffffffffffffffffffffffffff831660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff80821615801560e085015261010092839004909116151591830191909152909150612fe2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b8061010001511561304f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f416c7265616479207375706572207374616b65720000000000000000000000006044820152606401610912565b80602001514210156130bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f546f6f20736f6f6e0000000000000000000000000000000000000000000000006044820152606401610912565b6000806130cb826000613d56565b90506130d8826001613d56565b806130e05750805b905080156130f0576130f0613e6a565b6000896131215773ffffffffffffffffffffffffffffffffffffffff8b166000908152602760205260409020613147565b73ffffffffffffffffffffffffffffffffffffffff8b1660009081526028602052604090205b905060008a61315757601761315a565b601f5b905081600401548160070160008282546131749190614a4f565b90915550506007820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556005015460039091015550505050505050505050565b60006131c882611a2a565b90508015613294576000826131de5760176131e1565b601f5b6004810183905590506131f2611b19565b600282015573ffffffffffffffffffffffffffffffffffffffff841615613292576000836132445773ffffffffffffffffffffffffffffffffffffffff8516600090815260276020526040902061326a565b73ffffffffffffffffffffffffffffffffffffffff851660009081526028602052604090205b600781015490915060ff16613290576132838585613986565b6005820155600281018390555b505b505b505050565b60006132bc73ffffffffffffffffffffffffffffffffffffffff85168484614330565b949350505050565b60026003541415613331576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b6002600355828161334282826131bd565b846000613350826000613d56565b905061335d826001613d56565b806133655750805b9050801561337557613375613e6a565b600086116133df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a65726f20416d6f756e740000000000000000000000000000000000000000006044820152606401610912565b6000856134105773ffffffffffffffffffffffffffffffffffffffff88166000908152602760205260409020613436565b73ffffffffffffffffffffffffffffffffffffffff881660009081526028602052604090205b600781015490915060ff16156134a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b6000866134cd57600d5473ffffffffffffffffffffffffffffffffffffffff166134e7565b600e5473ffffffffffffffffffffffffffffffffffffffff165b90506134f481338a613299565b8254909850613513574280835560045461350d91614a4f565b60018301555b600087613521576017613524565b601f5b90508883600401600082825461353a9190614a4f565b92505081905550888160060160008282546135559190614a4f565b90915550506007830154610100900460ff161561358657888160070160008282546135809190614a4f565b90915550505b87156135ac5788601260010160008282546135a19190614a4f565b909155506135c79050565b88601260000160008282546135c19190614a4f565b90915550505b505060016003555050505050505050565b3360009081526028602052604081206007015460ff16801561360c5750336000908152602860205260409020600601544210155b80611b0957503360009081526027602052604090206007015460ff168015611b095750503360009081526027602052604090206006015442101590565b60008060008361367d5773ffffffffffffffffffffffffffffffffffffffff851660009081526027602052604090206136a3565b73ffffffffffffffffffffffffffffffffffffffff851660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e084018190526101009283900490911615159183019190915290915061372b57600080925092505061381d565b428160c00151111561374457600080925092505061381d565b60a08101516015805460009061375b908490614a4f565b909155508490508015613772575060008160800151115b156138125760808101516013805460009061378e908490614adf565b9091555050600e5460808201516137bd9173ffffffffffffffffffffffffffffffffffffffff16908790613824565b8473ffffffffffffffffffffffffffffffffffffffff167fbb37929ba745d1c183522217faa28a183a44c70dd5fc0a135bb7242d1e4f9773826080015160405161380991815260200190565b60405180910390a25b60a001519150600190505b9250929050565b61329473ffffffffffffffffffffffffffffffffffffffff84168383614495565b600080826138775773ffffffffffffffffffffffffffffffffffffffff8416600090815260276020526040902061389d565b73ffffffffffffffffffffffffffffffffffffffff841660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff808216151560e08401526101009182900416158015918301919091529091508061391d57508060e001515b1561392d5760a001519050613980565b600061393884612052565b9050600082606001518261394c9190614adf565b905060006139678285608001516145fe90919063ffffffff16565b9050808460a001516139799190614a4f565b9450505050505b92915050565b600080826139b85773ffffffffffffffffffffffffffffffffffffffff841660009081526027602052604090206139de565b73ffffffffffffffffffffffffffffffffffffffff841660009081526028602052604090205b604080516101208101825282548152600183015460208201526002830154918101919091526003820154606082015260048201546080820152600582015460a0820152600682015460c082015260079091015460ff80821615801560e085015261010092839004909116151591830191909152909150613a635760a001519050613980565b6000613a6e84611a2a565b9050600082604001518261394c9190614adf565b60026003541415613aef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610912565b600260035533600090815260286020526040902060040154151580613b2557503360009081526027602052604090206004015415155b613b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b81613b978160006131bd565b613ba28160016131bd565b826000613bb0826000613d56565b9050613bbd826001613d56565b80613bc55750805b90508015613bd557613bd5613e6a565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260286020908152604080832060059081015460279093529083200154613c179190614a4f565b905060008111613c83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7468696e6720746f20636c61696d000000000000000000000000000000006044820152606401610912565b73ffffffffffffffffffffffffffffffffffffffff861660009081526027602090815260408083206005908101849055602890925282200181905560158054839290613cd0908490614a4f565b9091555050600d54613cf99073ffffffffffffffffffffffffffffffffffffffff168683613824565b8573ffffffffffffffffffffffffffffffffffffffff167fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a82604051613d4191815260200190565b60405180910390a25050600160035550505050565b60008082613d885773ffffffffffffffffffffffffffffffffffffffff84166000908152602760205260409020613dae565b73ffffffffffffffffffffffffffffffffffffffff841660009081526028602052604090205b6007810154909150610100900460ff1680613ddd575073ffffffffffffffffffffffffffffffffffffffff8416155b15613e63576000613ded84612052565b90508015613e5d57600084613e03576017613e06565b601f5b600581018390559050613e17611afb565b600382015573ffffffffffffffffffffffffffffffffffffffff861615613e5b57600783015460ff16613e5b57613e4e8686613845565b6005840155600383018290555b505b60019250505b5092915050565b6011544290600090613e7d576000613e9a565b613e8d6201518062278d00614adf565b601154613e9a9190614adf565b9050808210611e7f57600d54600090613ec99073ffffffffffffffffffffffffffffffffffffffff1630614613565b601554601654601454929350600092613ee29190614a4f565b613eec9190614adf565b601254613ef99084614adf565b613f039190614adf565b90508060126004016000828254613f1a9190614a4f565b909155505060115460028204908510613f5257613f3a62278d0082614a67565b601855613f4a62278d0082614a67565b602055613fc3565b600085601154613f629190614adf565b601854909150600090613f759083614aa2565b905062278d00613f858285614a4f565b613f8f9190614a67565b601855602054600090613fa29084614aa2565b905062278d00613fb28286614a4f565b613fbc9190614a67565b6020555050505b601a8590556022859055613fda62278d0086614a4f565b60115560408051828152602081018390527fb2e45d21bc3a556247a4a3ad6cd0b08145d486b943b9e671263fca15bef18b6d910160405180910390a15050505050565b600081614032670de0b6b3a764000085614aa2565b61403c9190614a67565b9392505050565b6000818311614052578261403c565b50919050565b81816000816140915773ffffffffffffffffffffffffffffffffffffffff831660009081526027602052604090206004015415156140bd565b73ffffffffffffffffffffffffffffffffffffffff831660009081526028602052604090206004015415155b905080614126576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7468696e67207374616b65640000000000000000000000000000000000006044820152606401610912565b848461413282826131bd565b866000614140826000613d56565b905061414d826001613d56565b806141555750805b9050801561416557614165613e6a565b6000886141965773ffffffffffffffffffffffffffffffffffffffff8a1660009081526027602052604090206141bc565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526028602052604090205b600781015490915060ff161561422e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207768656e207769746864726177696e670000000000000000006044820152606401610912565b60008961423c57601761423f565b601f5b600780840180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555490915061427b9042614a4f565b8260060181905550816004015481600601600082825461429b9190614adf565b90915550506007820154610100900460ff16156142fb57600780830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055600483015490820180546000906142f5908490614adf565b90915550505b5050505050505050505050565b600a546000906127109061431c9084614aa2565b6143269190614a67565b6139809083614adf565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff8616906370a082319060240160206040518083038186803b15801561439a57600080fd5b505afa1580156143ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143d29190614977565b90506143df8585856146b6565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8716906370a082319060240160206040518083038186803b15801561444757600080fd5b505afa15801561445b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061447f9190614977565b905061448b8282614adf565b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169161452c9190614a14565b6000604051808303816000865af19150503d8060008114614569576040519150601f19603f3d011682016040523d82523d6000602084013e61456e565b606091505b50915091508180156145985750805115806145985750808060200190518101906145989190614941565b613290576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a205472616e73666572206661696c65640000000000006044820152606401610912565b600061403c8383670de0b6b3a7640000614825565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152600091908416906370a082319060240160206040518083038186803b15801561467e57600080fd5b505afa158015614692573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061403c9190614977565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152306044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908716916147539190614a14565b6000604051808303816000865af19150503d8060008114614790576040519150601f19603f3d011682016040523d82523d6000602084013e614795565b606091505b50915091508180156147bf5750805115806147bf5750808060200190518101906147bf9190614941565b613290576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5361666545524332303a205472616e7366657246726f6d206661696c656400006044820152606401610912565b6000816148328486614aa2565b6132bc9190614a67565b803573ffffffffffffffffffffffffffffffffffffffff8116811461486057600080fd5b919050565b60006020828403121561487757600080fd5b61403c8261483c565b60008060006060848603121561489557600080fd5b61489e8461483c565b92506148ac6020850161483c565b91506148ba6040850161483c565b90509250925092565b600080604083850312156148d657600080fd5b6148df8361483c565b915060208301356148ef81614b25565b809150509250929050565b6000806040838503121561490d57600080fd5b6149168361483c565b946020939093013593505050565b60006020828403121561493657600080fd5b813561403c81614b25565b60006020828403121561495357600080fd5b815161403c81614b25565b60006020828403121561497057600080fd5b5035919050565b60006020828403121561498957600080fd5b5051919050565b600080604083850312156149a357600080fd5b50508035926020909101359150565b60008060008060008060c087890312156149cb57600080fd5b863595506020870135945060408701356149e481614b25565b9350606087013560ff811681146149fa57600080fd5b9598949750929560808101359460a0909101359350915050565b6000825160005b81811015614a355760208186018101518583015201614a1b565b81811115614a44576000828501525b509190910192915050565b60008219821115614a6257614a62614af6565b500190565b600082614a9d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ada57614ada614af6565b500290565b600082821015614af157614af1614af6565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8015158114611ca157600080fdfea2646970667358221220ab857582abc76de18375965040d6e7cddc1fa05da9db05efc941556c24cbcc5864736f6c63430008060033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000000000000000000000000000000000000278d000000000000000000000000000000000000000000000000000000000000093a80

-----Decoded View---------------
Arg [0] : _timeToSuper (uint256): 2592000
Arg [1] : _timeToUnstake (uint256): 604800

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000278d00
Arg [1] : 0000000000000000000000000000000000000000000000000000000000093a80


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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