contract GoBrrr is Ownable, MinterRole  {

    using SafeMath for uint256;

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event withdrawhistory(address withdrawer, uint256 tokensPerBlock, uint256 timelog);

    modifier validRecipient(address to) {
        require(to != address(0x0));
        require(to != address(this));
        _;
    }
    
    mapping (address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    string public constant name = "Go BRRR";
    string public constant symbol = "BRRR";
    uint256 public constant decimals = 18;

    uint256 public totalSupply = 108 * (uint256(10) ** decimals);
   
    
    uint256 public lastMintedtime;
    uint256 public totalParticipants = 0;
    uint256 public tokensPerBlock = (5*10**decimals).div(1000);
    address public tokencontractAddress = address(this);
    
    constructor() public {
        _owner = msg.sender;
        
        // Initially assign all tokens to the contract's creator.
        balanceOf[msg.sender] = totalSupply;
        emit Transfer(address(0x0), msg.sender, totalSupply);
       
        lastMintedtime = now;
    }
    

    function transfer(address to, uint256 value) public  validRecipient(to) returns (bool)
    {
        require(balanceOf[msg.sender] >= value);
        
        uint256 leftvalue = value.mul(9997); //99.97%->99.97/10000
        leftvalue = leftvalue.sub(leftvalue.mod(10000));
        leftvalue = leftvalue.div(10000);

        balanceOf[msg.sender] -= value;  // deduct from sender's balance
        balanceOf[to] += leftvalue;          // add to recipient's balance
        
        uint256 decayvalue = value.sub(leftvalue); //3%->3/100->value-leftvalue
        totalSupply = totalSupply.sub(decayvalue);
        
        emit Transfer(msg.sender, to, value);
        
        return true;
    }
    
    function transferFrom(address from, address to, uint256 value) public returns (bool success)
    {
        require(value <= balanceOf[from]);
        require(value <= allowance[from][msg.sender]);
        
        uint256 leftvalue = value.mul(9997); //99.97%->99.97/100
        leftvalue = leftvalue.sub(leftvalue.mod(10000));
        leftvalue = leftvalue.div(10000);

        balanceOf[from] -= value;
        balanceOf[to] += leftvalue;
        allowance[from][msg.sender] -= value;
        
        uint256 decayvalue = value.sub(leftvalue); //0.03%->3/10000->value-leftvalue
        totalSupply = totalSupply.sub(decayvalue);
        
        emit Transfer(from, to, value);
        return true;
    }

    function approve(address spender, uint256 value) public returns (bool success)
    {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public returns (bool)
    {
        allowance[msg.sender][spender] = allowance[msg.sender][spender].add(addedValue);
        emit Approval(msg.sender, spender, allowance[msg.sender][spender]);
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool)
    {
        uint256 oldValue = allowance[msg.sender][spender];
        if (subtractedValue >= oldValue) {
            allowance[msg.sender][spender] = 0;
        } else {
            allowance[msg.sender][spender] = oldValue.sub(subtractedValue);
        }
        emit Approval(msg.sender, spender, allowance[msg.sender][spender]);
        return true;
    }
    
    function changetokensPerBlock(uint256 _newtokensPerBlock) external returns (bool) {
        tokensPerBlock = _newtokensPerBlock*10**decimals;
        return true;
    }
    
    function addMinters(address _minter) external returns (bool) {
        addMinter(_minter);
        totalParticipants = totalParticipants.add(1);
        return true;
    }


    function removeMinters(address _minter) external returns (bool) {
        totalParticipants = totalParticipants.sub(1);
        removeMinter(_minter); 
        return true;
    }

    
    function trigger() external onlyMinter returns (bool) {
        bool res = readyToMint();
        if(res == true && msg.sender != _owner) {
            mintTokens();
            return true;
        } else {
            return false;
        }
    }
    
    function withdraw() external onlyMinter returns (bool) {
        GoBrrr(tokencontractAddress).transfer(msg.sender, tokensPerBlock);
        emit withdrawhistory(msg.sender, tokensPerBlock, now);
        return true;
    }

    
    function readyToMint() public view returns (bool) {
        uint256 currentBlocktime = now;
        uint256 limittime = lastMintedtime + 86400;
        if(currentBlocktime > limittime) { 
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Function to mint new tokens into the economy. 
     * @return A boolean that indicates if the operation was successful.
     */
    function mintTokens() private returns (bool) {
        uint256 tokenReleaseAmount = totalParticipants.mul(tokensPerBlock);
        lastMintedtime = now;
        mint(tokencontractAddress, tokenReleaseAmount);
        return true;
    }
   

    function mint(address account, uint256 value) public onlyMinter {
        require(account != address(0));
        require(account != _owner);
       
        totalSupply = totalSupply.add(value);
        balanceOf[account] = balanceOf[account].add(value);
        emit Transfer(address(0), account, value);
    }
}
function mintTokens() private returns (bool) {
    uint256 tokenReleaseAmount = totalParticipants.mul(tokensPerBlock);
    lastMintedtime = now;
    mint(tokencontractAddress, tokenReleaseAmount);
    return true;
}

/**
 * @dev Function to mint new tokens into the economy. 
 * @return A boolean that indicates if the operation was successful.
 */