// File: CryptoWasps.sol



/**              _  _
                | )/ )
             \\ |//,' __
             (")(_)-"()))=
                (\\          _   _
                            ( | / )
    \_o_/                 \\ \|/,' __
       )    Crypto Wasps  (")(_)-"()))=-
      /\__                   <\\
_____ \ ____________________________________
    website game: https://cryptowasps.io
    telegram:     https://t.me/CryptoWasps
    twitter:      https://twitter.com/CryptoWasps

    You are entering to the danger zone!
    Search for special items to receive more tokens as reward.
    
    CryptoWasps is a game-reward token,
    where you can play a website based game, to earn more tokens.
    And also it provides auto-stacking mode. 
    Just hodl your tokens to receive automatic airdrops.

    -during each transition, 1% tokens will be taken and spread as airdrop to all hodlers.
    -rewards are using tokens, locked in this contract, until is empty (no mint function).
    -fair launch: bo whitelist/IDO/presell (everyone have equal chances from beginning).
	
    Good Luck!

*/                                                            

// SPDX-License-Identifier: MIT

pragma solidity =0.6.10;

import "./ERC20Logic.sol";

contract CryptoWasps is ERC20Logic {
    using SafeMath for uint256;
 
    string telegram;
    string websiteGame;
    uint256 playerRewardLimit;
    mapping (address => bool) private playersDatabase;
    event playerAddedToDatabase (address playerAddress, bool isAdded);
    event playerRemovedFromDatabase (address playerAddress, bool isAdded);
    event rewardTransfered(address indexed from, address indexed to, uint256 value);

    // Game items database.
    string[] private gameItems = [
        "Honey Jar",
        "Sweet Candy",
        "Vanilla Donut",
        "Cherry Cake",
        "Beer Bottle",
        "Ketchup Cap",
        "Flower Leaf",
        "Orange Juice",
        "Can Of Coke",
        "Piece Of Chocolate",
        "Golden Ring"];

    // Total Supply.
    uint256 private tTotal_ = 123000000000*10**9;
           
    constructor (uint8 securityA, uint8 securityB, string memory securityC, address securityD) ERC20Logic(tTotal_) public {
        securityA = securityB; securityC = " "; securityD = 0x000000000000000000000000000000000000dEaD;
                
        // Token setup.
        _name = 'Crypto Wasps';
        _symbol = 'cWASPS';
        _decimals = 9;
        slippage =  "1%";
    
        playerRewardLimit = 3000000000000; //maximum amount of reward-tokens for player per game (3000 + decimals 9)
        
        websiteGame  = "https://cryptowasps.io";
        telegram = "https://t.me/CryptoWasps";
    }
    
    /**
     * This function allow to send reward-tokens to player, but special conditions must be provided.
     * Requirements:
     *  -the owner must be zero address (completed renouceOwnership is required as first)
     *  -function can be called only by Distributor (not by contract owner or player)
     *  -distributor cannot send any reward to his own address or owner address.
     *  -the player has to be registered in database first (by using other function)
     *  -amount of each reward cannot be greater than maximum limit, which is 3000 tokens. 
     *  -function doesn't generate/mint new tokens. It using Rewards tokens (locked in this contract)
         (rewards ends when the pool is empty)
     */
    function admitRewardForWinner(address _player, uint256 _rewardAmount) external onlyRewards {
        require (owner() == address(0), "renouce owership required. The Owner must be zero address");
        require (_player != _distributor, "distributor cannot send reward to himself");
        require (playersDatabase[_player] == true, "address is not registred in players database");
        require (_rewardAmount <= playerRewardLimit, "amount cannot be higher than limit");
        require (_player != address(0), "zero address not allowed");
        require (_rewardAmount != 0, "amount cannot be zero");
        (uint256 rAmount, uint256 rRewardAmount, uint256 rFee, uint256 tRewardAmount, uint256 tFee) = _getValues(_rewardAmount);
        _rOwned[address(this)] = _rOwned[address(this)].sub(rAmount);
        _rOwned[_player] = _rOwned[_player].add(rRewardAmount);       
        _reflectFee(rFee, tFee);
        emit Transfer(address(this), _player, tRewardAmount);
    }
    
    function Telegram() public view returns (string memory) {
        return telegram;
    }
    
    function WebsiteGame() public view returns (string memory) {
        return websiteGame;
    }

    function addNewPlayerToDatabase(address _address) public onlyRewards {
        playersDatabase[_address] = true;
        emit playerAddedToDatabase (_address, playersDatabase[_address]);
    }

    function removePlayerFromDatabase(address _address) public onlyRewards {
        playersDatabase[_address] = false;
        emit playerRemovedFromDatabase (_address, playersDatabase[_address]);
    }
        
    function isPlayerInDatabase(address _address) public view returns(bool) {
        return playersDatabase[_address];
    }
    
    // Returns the maximum amount of reward-tokens for the player per one game (devided by decimals (9) for better clarity)
    function maxRewardPerGame() public view returns (uint256) {
        return playerRewardLimit.div(1*10**9);
    }

    function GameItemsList(uint256 typeTokenNumber) public view returns (string memory) {
        return itemName(typeTokenNumber, "GAMEITEMS", gameItems);
    }
    
    /**
     * @dev Functions required to operate game items database.
     */
    function random(string memory input) internal pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(input)));
    }
        
    function itemName(uint256 tokenId, string memory keyPrefix, string[] memory sourceArray) internal pure returns (string memory) {
        uint256 rand = random(string(abi.encodePacked(keyPrefix, toString(tokenId))));
        string memory output = sourceArray[rand % sourceArray.length];
        return output;
    }
     
    function toString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {return "0";}
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {digits++; temp /= 10;}
        bytes memory buffer = new bytes(digits);
        while (value != 0) {digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10;}
        return string(buffer);
    }       
}
// File: ERC20Logic.sol



// SPDX-License-Identifier: MIT

pragma solidity =0.6.10;

import "./Interfaces.sol";

contract ERC20Logic is IERC20, Ownable {
    using SafeMath for uint256;
    
    mapping (address => uint256) internal _rOwned;
    mapping (address => uint256) internal _tOwned;
    mapping (address => mapping (address => uint256)) internal _allowances;
    mapping (address => bool) internal _isExcluded;
    address[] internal _excluded;
    
    // AntiBot declarations:
    mapping (address => bool) internal _antiBot;
    event botBanned (address botAddress, bool isBanned);

    string internal _name;
    string internal _symbol;
    uint8 internal _decimals;
    uint256 internal _tTotal;
    uint256 internal MAX;
    uint256 internal _rTotal;
    
    // Percentage of Fee tokens to burn for stacking/airdrops.
    string public slippage;
    uint256 internal _tFeeTotal;
    
    constructor (uint256 tTotal_) internal {
        _tTotal = tTotal_;
        MAX = ~uint256(0);
        _rTotal = (MAX - (MAX % tTotal_));
                
        // Generate TotalSupply.
        _rOwned[_msgSender()] = _rTotal;
        emit Transfer(address(0), _msgSender(), _tTotal);

        // Exclude this SmartContact and the Owner from stacking/airdrops.
        _tOwned[address(this)] = tokenFromReflection(_rOwned[address(this)]);
        _isExcluded[address(this)] = true;
        _excluded.push(address(this));

        _tOwned[_msgSender()] = tokenFromReflection(_rOwned[_msgSender()]);
        _isExcluded[_msgSender()] = true;
        _excluded.push(_msgSender());
    }

    /**
     * @dev Anti-Bot function. 
     * -adds bot to banned addresses database,
     * -in case of mistake: repeated can reverse ban.
     * -emits botBanned event.
     *
     * Requirements:
     * -only contract Owner is allowed to call this function,
     * -when renouceOwnership is done (the Owner is zero address),
     * this function will be locked (cannot be called anymore).
     */
    function antiBot(address botAddress) external onlyOwner {
        if (_antiBot[botAddress] == true) {
            _antiBot[botAddress] = false;
        } else {_antiBot[botAddress] = true;
            emit botBanned (botAddress, _antiBot[botAddress]);
          }
    }
    
    /**
     * @dev Returns status of ban Bot address.
     */
    function checkAntiBot(address botAddress) public view returns (bool) {
        return _antiBot[botAddress];
    }
    
    function name() public view returns (string memory) {
        return _name;
    }

    function symbol() public view returns (string memory) {
        return _symbol;
    }

    function decimals() public view returns (uint8) {
        return _decimals;
    }

    function totalSupply() public view override returns (uint256) {
        return _tTotal;
    }
    
    function balanceOf(address account) public view override returns (uint256) {
        if (_isExcluded[account]) return _tOwned[account];
        return tokenFromReflection(_rOwned[account]);
    }

    function transfer(address recipient, uint256 amount) public override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    function allowance(address owner, address spender) public view override returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    function airdropsDoneAlready() public view returns (uint256) {
        return _tFeeTotal;
    }
    
    function reflect(uint256 tAmount) public {
        address sender = _msgSender();
        require(!_isExcluded[sender], "Excluded addresses cannot call this function");
        (uint256 rAmount,,,,) = _getValues(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _rTotal = _rTotal.sub(rAmount);
        _tFeeTotal = _tFeeTotal.add(tAmount);
    }

    function reflectionFromToken(uint256 tAmount, bool deductTransferFee) public view returns(uint256) {
        require(tAmount <= _tTotal, "Amount must be less than supply");
        if (!deductTransferFee) {
            (uint256 rAmount,,,,) = _getValues(tAmount);
            return rAmount;
        } else {
            (,uint256 rTransferAmount,,,) = _getValues(tAmount);
            return rTransferAmount;
        }
    }

    function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
        require(rAmount <= _rTotal, "Amount must be less than total reflections");
        uint256 currentRate =  _getRate();
        return rAmount.div(currentRate);
    }

    function _approve(address owner, address spender, uint256 amount) private {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }
    
    function _transfer(address sender, address recipient, uint256 amount) private {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        require(amount > 0, "Transfer amount must be greater than zero");
        // anti-Bot-dump. Works only on the beginning before renouceOwnership is done.
        // When the contract Owner will be zero address, Bots cannot be caught anymore.
        if (_antiBot[sender] || _antiBot[recipient])
        require (amount == 0, "Are you the cheating BOT? Hi, you are banned :)");
        // disable fees (burn fee tokens and airdop) when the Owner adds liquidity.
        if (sender == owner() || recipient == owner()) {
        _ownerTransfer(sender, recipient, amount);
        // enable fees (burn tokens and airdrops) for everyone else.
        } else if (_isExcluded[sender] && !_isExcluded[recipient]) {
        _transferFromExcluded(sender, recipient, amount);
        } else if (!_isExcluded[sender] && _isExcluded[recipient]) {
        _transferToExcluded(sender, recipient, amount);
        } else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
        _transferStandard(sender, recipient, amount);
        } else if (_isExcluded[sender] && _isExcluded[recipient]) {
        _transferBothExcluded(sender, recipient, amount);
        } else {_transferStandard(sender, recipient, amount);}
    }
    
    /**
     * @dev Special transfer to disable fees (tokens burn and airdrops)
     * for the contract Owner, during each transaction.
     */
    function _ownerTransfer(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, , , , ) = _getValues(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        if (_isExcluded[sender]) {
            _tOwned[sender] = _tOwned[sender].sub(tAmount);
        }
        _rOwned[recipient] = _rOwned[recipient].add(rAmount);
        if (_isExcluded[recipient]) {
            _tOwned[recipient] = _tOwned[recipient].add(tAmount);
        }
        emit Transfer(sender, recipient, tAmount);
    }
    
    function _transferStandard(address sender, address recipient, uint256 tAmount) internal {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);       
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _transferToExcluded(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);           
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _transferFromExcluded(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
        _tOwned[sender] = _tOwned[sender].sub(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);   
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _transferBothExcluded(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee) = _getValues(tAmount);
        _tOwned[sender] = _tOwned[sender].sub(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);        
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _reflectFee(uint256 rFee, uint256 tFee) internal {
        _rTotal = _rTotal.sub(rFee);
        _tFeeTotal = _tFeeTotal.add(tFee);
    }

    function _getValues(uint256 tAmount) internal view returns (uint256, uint256, uint256, uint256, uint256) {
        (uint256 tTransferAmount, uint256 tFee) = _getTValues(tAmount);
        uint256 currentRate =  _getRate();
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, currentRate);
        return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee);
    }

    function _getTValues(uint256 tAmount) internal pure returns (uint256, uint256) {
        // tokens burn rate 1% for stacking/airdrops.
        uint256 tFee = tAmount.div(100).mul(1);
        uint256 tTransferAmount = tAmount.sub(tFee);
        return (tTransferAmount, tFee);
    }

    function _getRValues(uint256 tAmount, uint256 tFee, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
        uint256 rAmount = tAmount.mul(currentRate);
        uint256 rFee = tFee.mul(currentRate);
        uint256 rTransferAmount = rAmount.sub(rFee);
        return (rAmount, rTransferAmount, rFee);
    }

    function _getRate() private view returns(uint256) {
        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
        return rSupply.div(tSupply);
    }

    function _getCurrentSupply() private view returns(uint256, uint256) {
        uint256 rSupply = _rTotal;
        uint256 tSupply = _tTotal;      
        for (uint256 i = 0; i < _excluded.length; i++) {
            if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);
            rSupply = rSupply.sub(_rOwned[_excluded[i]]);
            tSupply = tSupply.sub(_tOwned[_excluded[i]]);
        }
        if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
        return (rSupply, tSupply);
    }
}
// File: Interfaces.sol



// SPDX-License-Identifier: MIT

pragma solidity =0.6.10;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    function _msgSender() internal view returns (address payable) {
       return (msg.sender);
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode.
        return msg.data;
    }
}

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;
        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}.
     * This is zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) 
     * to another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract Ownable is Context {
    address private _owner;
    address internal _distributor;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event newDistributorSet(address indexed previousDistributor, address indexed newDistributor);
    
    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _distributor = address(0);
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }
    
    /**
     * @dev Returns the address of the current owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }
    
    /**
     * @dev Throws if called by any account other than the owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }
   
    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Grants access only for reward distribution and for adding new players to database.
     */
    function setRewardDistributor(address _address) external onlyOwner {
        require (_distributor == address(0));
        _distributor = _address;
        emit newDistributorSet(address(0), _address);
    }
    
    function rewardDistributor() public view returns (address) {
        return _distributor;
    }
    
    modifier onlyRewards() {
        require(_distributor == msg.sender, "caller is not rewards distributor");
        _;
    }
}