contract YRXpooltwo is LPTokenWrapper, IRewardDistributionRecipient {
    IERC20 public yrx = IERC20(0x21634B64a6915b879aD13d96418a82b2a48Fcbe9);
    uint8 public constant NUMBER_EPOCHS = 5;
    uint256 public constant EPOCH_REWARD = 666666666666666700000;
    uint256 public constant TOTAL_REWARD = EPOCH_REWARD * NUMBER_EPOCHS;
    uint256 public constant DURATION = 7 days;
    uint256 public currentEpochReward = EPOCH_REWARD;
    uint256 public totalAccumulatedReward = 0;
    uint8 public currentEpoch = 0;
    uint256 public starttime = 1602842400; //Friday, October 16, 2020 12:00:00 PM GMT+02:00 || Friday, October 16, 6 PM SGT
    uint256 public periodFinish = 0;
    uint256 public rewardRate = 0;
    uint256 public lastUpdateTime;
    uint256 public rewardPerTokenStored;
    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;

    event RewardAdded(uint256 reward);
    event Staked(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);

    modifier updateReward(address account) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdateTime = lastTimeRewardApplicable();
        if (account != address(0)) {
            rewards[account] = earned(account);
            userRewardPerTokenPaid[account] = rewardPerTokenStored;
        }
        _;
    }

    function lastTimeRewardApplicable() public view returns (uint256) {
        return Math.min(block.timestamp, periodFinish);
    }

    function rewardPerToken() public view returns (uint256) {
        if (totalSupply() == 0) {
            return rewardPerTokenStored;
        }
        return
            rewardPerTokenStored.add(
                lastTimeRewardApplicable()
                    .sub(lastUpdateTime)
                    .mul(rewardRate)
                    .mul(1e18)
                    .div(totalSupply())
            );
    }

    function earned(address account) public view returns (uint256) {
        return
            balanceOf(account)
                .mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
                .div(1e18)
                .add(rewards[account]);
    }

    // stake visibility is public as overriding LPTokenWrapper's stake() function
    function stake(uint256 amount)
        public
        updateReward(msg.sender)
        checkNextEpoch
        checkStart
    {
        require(amount > 0, "Cannot stake 0");
        super.stake(amount);
        emit Staked(msg.sender, amount);
    }

    function withdraw(uint256 amount)
        public
        updateReward(msg.sender)
        checkStart
    {
        require(amount > 0, "Cannot withdraw 0");
        super.withdraw(amount);
        emit Withdrawn(msg.sender, amount);
    }

    function exit() external {
        withdraw(balanceOf(msg.sender));
        getReward();
    }

    function getReward()
        public
        updateReward(msg.sender)
        checkNextEpoch
        checkStart
    {
        uint256 reward = earned(msg.sender);
        if (reward > 0) {
            rewards[msg.sender] = 0;
            yrx.safeTransfer(msg.sender, reward);
            emit RewardPaid(msg.sender, reward);
        }
    }

    modifier checkNextEpoch() {
        if (block.timestamp >= periodFinish) {
            currentEpochReward = EPOCH_REWARD;

            if (totalAccumulatedReward.add(currentEpochReward) > TOTAL_REWARD) {
                currentEpochReward = TOTAL_REWARD.sub(totalAccumulatedReward); // limit total reward
            }

            if (currentEpochReward > 0) {
                totalAccumulatedReward = totalAccumulatedReward.add(
                    currentEpochReward
                );
                currentEpoch++;
            }

            rewardRate = currentEpochReward.div(DURATION);
            lastUpdateTime = block.timestamp;
            periodFinish = block.timestamp.add(DURATION);
            emit RewardAdded(currentEpochReward);
        }
        _;
    }

    function emergencyDrain(address _addy) public onlyRewardDistribution {
        IERC20 token = IERC20(_addy);
        token.safeTransfer(msg.sender, token.balanceOf(address(this)));
    }

    modifier checkStart() {
        require(block.timestamp > starttime, "not start");
        _;
    }

    function notifyRewardAmount()
        external
        onlyRewardDistribution
        updateReward(address(0))
    {
        if (totalAccumulatedReward.add(currentEpochReward) > TOTAL_REWARD) {
            currentEpochReward = TOTAL_REWARD.sub(totalAccumulatedReward); // limit total reward
        }

        rewardRate = currentEpochReward.div(DURATION);
        totalAccumulatedReward = totalAccumulatedReward.add(currentEpochReward);
        currentEpoch++;
        lastUpdateTime = block.timestamp;
        periodFinish = starttime.add(DURATION);
        emit RewardAdded(currentEpochReward);
    }
}
function stake(uint256 amount)
        public
        updateReward(msg.sender)
        checkNextEpoch
        checkStart
    {
        require(amount > 0, "Cannot stake 0");
        super.stake(amount);
        emit Staked(msg.sender, amount);
    }
// stake visibility is public as overriding LPTokenWrapper's stake() function