contract KeyTangoStakingLMETH3m {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    mapping(address => uint256) private _stakes;

    string public name;
    address private immutable tokenAddress;
    uint256 private immutable stakingStarts;
    uint256 public immutable stakingEnds;
    uint256 public stakedTotal;
    uint256 private immutable stakingCap;
    uint256 public stakedBalance;
    uint256 private constant ONE_MONTH = 30 days;
    uint256 private immutable DEPOSIT_TIME;
    uint256 private constant REWARD_PERC = 80; //80% stake 
    address private constant REWARDADDRESS =
        0x30548e72549C7A57c82C2258fcb640BcD6B5aA20; //reward multisig 
    bool public depositEnabled = true;
    address private operator = 0x300F78e978c1327E8A58c385E29f80324d0FF40d;

   // IERC20 private immutable KeytangoToken;
    IERC20 private immutable LMToken;

    mapping(address => uint256) public deposited;

    event Staked(
        address indexed token,
        address indexed staker_,
        uint256 requestedAmount_,
        uint256 stakedAmount_
    );
    event PaidOut(
        address indexed token,
        address indexed staker_,
        uint256 amount_
    );
    event Refunded(
        address indexed token,
        address indexed staker_,
        uint256 amount_
    );

    modifier _positive(uint256 amount) {
        require(amount > 0, "Error: negative amount");
        _;
    }

    modifier _after(uint256 eventTime) {
        require(
            block.timestamp >= eventTime,
            "Error: bad timing for the request"
        );
        _;
    }

    modifier _before(uint256 eventTime) {
        require(
            block.timestamp < eventTime,
            "Error: bad timing for the request"
        );
        _;
    }

    constructor(
        string memory name_,
        address lmtoken,
        uint256 _startTime
    ) public {
        require(lmtoken != address(0x0),"Error: zero address");
        name = name_;
        tokenAddress = lmtoken;
        LMToken = IERC20(lmtoken);
        stakingStarts = _startTime;
        stakingEnds = _startTime.add(5 days);
        stakingCap = 75000 ether;
        DEPOSIT_TIME = ONE_MONTH.mul(3);
    }

    function stakeOf(address account) external view returns (uint256) {
        return _stakes[account];
    }

    function timeStaked(address account) external view returns (uint256) {
        return deposited[account];
    }

    function canWithdraw(address _addy) external view returns (bool) {
        if (block.timestamp >= deposited[_addy].add(DEPOSIT_TIME)) {
            return true;
        } else {
            return false;
        }
    }

       function setDepositDisabled() external {
        require(msg.sender == operator);
        depositEnabled = !depositEnabled;
    }

    /**
     * Requirements:
     * - `amount` Amount to be staked
     */
    function stake(uint256 amount)
        external
        _positive(amount)
    {
        _stake(msg.sender, amount);
    }

    function withdraw(uint256 amount)
        external
        _positive(amount)
    {
        require(amount <= _stakes[msg.sender], "Error: not enough balance");
        require(
            block.timestamp >= deposited[msg.sender].add(DEPOSIT_TIME),
            "Error: Staking period not passed yet"
        );
        _withdrawAfterClose(msg.sender, amount);
    }

    function _withdrawAfterClose(address from, uint256 amount) private {
       // uint256 reward = amount.mul(REWARD_PERC).div(100);
        _stakes[from] = _stakes[from].sub(amount);
        stakedTotal = stakedTotal.sub(amount);
        stakedBalance = stakedBalance.sub(amount);
       // KeytangoToken.safeTransferFrom(REWARDADDRESS, from, reward); //transfer Reward
        LMToken.safeTransfer(from, amount); //transfer initial stake
        emit PaidOut(tokenAddress, from, amount);
    }

    function _stake(address staker, uint256 amount)
        private
        _after(stakingStarts)
        _before(stakingEnds)
    {
        require(depositEnabled,"Deposit disabled.");
        // check the remaining amount to be staked
        uint256 remaining = amount;
        if (remaining > (stakingCap.sub(stakedBalance))) {
            remaining = stakingCap.sub(stakedBalance);
        }
        // These requires are not necessary, because it will never happen, but won't hurt to double check
        // this is because stakedTotal and stakedBalance are only modified in this method during the staking period
        require(remaining > 0, "Error: Staking cap is filled");
        require(
            (remaining.add(stakedTotal)) <= stakingCap,
            "Error: this will increase staking amount pass the cap"
        );

        LMToken.safeTransferFrom(staker, address(this), remaining);

        if (remaining < amount) {
            // Return the unstaked amount to sender (from allowance)
            uint256 refund = amount.sub(remaining);
            LMToken.safeTransferFrom(address(this), staker, refund);
            emit Refunded(tokenAddress, staker, refund);
        }

        // Transfer is completed
        stakedBalance = stakedBalance.add(remaining);
        stakedTotal = stakedTotal.add(remaining);
        _stakes[staker] = _stakes[staker].add(remaining);
        deposited[msg.sender] = block.timestamp;
        emit Staked(tokenAddress, staker, amount, remaining);
    }
}
function stake(uint256 amount)
    external
    _positive(amount)
{
    _stake(msg.sender, amount);
}

/**
 * Requirements:
 * - `amount` Amount to be staked
 */